Merge branch 'android-bridge-2.6.29'

* 'android-bridge-2.6.29'
* of git://dev.omapzoom.org/pub/scm/tidspbridge/kernel-dspbridge:
  Mailbox: flush pending deferred works before freeing blk queue
  Mailbox: free mailbox interrupt before freeing blk queue
  Mailbox: Check valid registered callback before calling
  DSPBRIDGE: Initialize status in bridge_release
  DSPBRIDGE: fix regression introduced by other patch
  DSPBRIDGE: DSP recovery feature
  Revert "DSPBRIDGE: cache operation against kernel address instead of user's"
  Revert "DSPBRIDGE: Replace flushtype with ulFlags"
  Revert "DSPBRIDGE: cache against kernel address fix"
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 7453ae8..f48c25b 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -160,6 +160,12 @@
 
 if OPROFILE
 
+config OPROFILE_OMAP_GPTIMER
+	def_bool y
+	depends on ARCH_OMAP
+	select CONFIG_OMAP_32K_TIMER
+	select CONFIG_OMAP_DM_TIMER
+
 config OPROFILE_ARMV6
 	def_bool y
 	depends on CPU_V6 && !SMP
@@ -174,7 +180,7 @@
 	bool
 
 config OPROFILE_ARMV7
-	def_bool y
+	def_bool n
 	depends on CPU_V7 && !SMP
 	bool
 
@@ -709,18 +715,49 @@
 comment "errata"
 
 config ARM_ERRATA_430973
-	bool "430973: Stale prediction on replaced interworking branch on Cortex-A8"
-	depends on CPU_V7
-	default n
-	help
-	  This option enables the workaround for the 430973 Cortex-A8
-	  (r1p0) erratum. If a code sequence containing an ARM/Thumb
-	  interworking branch is replaced with another code sequence
-	  at the same virtual address, whether due to self-modifying
-	  code or virtual to physical address re-mapping, Cortex-A8
-	  does not recover from the stale interworking branch
-	  prediction. This results in Cortex-A8 executing the new code
-	  sequence in the incorrect ARM or Thumb state.
+
+        bool "ARM errata: Stale prediction on replaced interworking branch"
+        depends on CPU_V7
+        help
+          This option enables the workaround for the 430973 Cortex-A8
+          (r1p0..r1p2) erratum. If a code sequence containing an ARM/Thumb
+          interworking branch is replaced with another code sequence at the
+          same virtual address, whether due to self-modifying code or virtual
+          to physical address re-mapping, Cortex-A8 does not recover from the
+          stale interworking branch prediction. This results in Cortex-A8
+          executing the new code sequence in the incorrect ARM or Thumb state.
+          The workaround enables the BTB/BTAC operations by setting ACTLR.IBE
+          and also flushes the branch target cache at every context switch.
+          Note that setting specific bits in the ACTLR register may not be
+          available in non-secure mode.
+
+config ARM_ERRATA_451027
+        bool "Neon loads/stores may incorrectly report data abort on Cortex-A8"
+        depends on CPU_V7 && NEON
+        default n
+        help
+          This option enables the workaround for the erratum 451027
+	  Cortex-A8(r1p0,r1p1,r1p2,r1p3).
+	  For a specific sequence of load and store operations, it is possible
+	  for an erroneous abort response to be reported on a Neon load or
+	  store instruction.
+	  This workaround fixes the AXI errors generated on cache lines issue.
+
+config ARM_ERRATUM_451034
+        bool "Enable workaround for ARM erratum 451034"
+        depends on VFPv3 && NEON
+        help
+          On Cortex-A8 r1p0 and r1p1, executing a NEON store with an integer
+          store in the store buffer, can cause a processor deadlock under
+          certain conditions.
+
+          See ARM Cortex-A8 Errata Notice (PR120-PRDC-008070) for full details.
+
+          Say Y to include a partial workaround.
+
+          WARNING: Even with this option enabled, userspace code can trigger
+          the deadlock.  To safely run untrusted code, a different fix is
+          required.
 
 endmenu
 
diff --git a/arch/arm/configs/zoom2_pm_defconfig b/arch/arm/configs/omap_3430sdp_android_defconfig
similarity index 82%
rename from arch/arm/configs/zoom2_pm_defconfig
rename to arch/arm/configs/omap_3430sdp_android_defconfig
index 28988a3..2fe5ab2 100644
--- a/arch/arm/configs/zoom2_pm_defconfig
+++ b/arch/arm/configs/omap_3430sdp_android_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.29-omap1
-# Mon Aug  3 10:55:29 2009
+# Tue Oct  6 20:05:14 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -23,6 +23,8 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_OMAP_GPTIMER=y
+# CONFIG_OPROFILE_ARMV7 is not set
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -94,7 +96,10 @@
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
@@ -108,7 +113,7 @@
 # CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
@@ -198,22 +203,38 @@
 CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_OMAP_MUX_WARNINGS=y
 CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MBOX_FWK is not set
-# CONFIG_OMAP_IOMMU is not set
+CONFIG_OMAP_MBOX_FWK=y
+CONFIG_OMAP_IOMMU=y
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 # CONFIG_OMAP3_DEBOBS is not set
 CONFIG_OMAP_32K_TIMER_HZ=128
 CONFIG_OMAP_TICK_GPTIMER=1
 CONFIG_OMAP_DM_TIMER=y
-# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_LL_DEBUG_UART_EXT=y
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
 CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# USBHOST Port Configuration
+#
+CONFIG_OMAP_EHCI_PHY_MODE_PORT1=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1 is not set
+CONFIG_OMAP_EHCI_PHY_MODE_PORT2=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2 is not set
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT3 is not set
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3 is not set
 # CONFIG_OMAP_PM_NONE is not set
 # CONFIG_OMAP_PM_NOOP is not set
 CONFIG_OMAP_PM_SRF=y
+# CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND is not set
 CONFIG_ARCH_OMAP34XX=y
 CONFIG_ARCH_OMAP3430=y
 
@@ -222,10 +243,10 @@
 #
 # CONFIG_MACH_NOKIA_RX51 is not set
 # CONFIG_MACH_OMAP_LDP is not set
-CONFIG_MACH_OMAP_ZOOM2=y
-CONFIG_WIFI_CONTROL_FUNC=y
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
 # CONFIG_TIWLAN_SDIO is not set
-# CONFIG_MACH_OMAP_3430SDP is not set
+CONFIG_MACH_OMAP_3430SDP=y
 # CONFIG_MACH_OMAP3EVM is not set
 # CONFIG_MACH_OMAP3_BEAGLE is not set
 # CONFIG_MACH_OVERO is not set
@@ -256,13 +277,14 @@
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
 # CONFIG_HAS_TLS_REG is not set
 # CONFIG_OUTER_CACHE is not set
 
 #
 # errata
 #
-# CONFIG_ARM_ERRATA_430973 is not set
+CONFIG_ARM_ERRATA_430973=y
 
 #
 # Bus support
@@ -301,6 +323,7 @@
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -329,7 +352,7 @@
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 # CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 CONFIG_CPU_FREQ_MIN_TICKS=10
 CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
@@ -349,7 +372,7 @@
 # CONFIG_FPE_FASTFPE is not set
 CONFIG_VFP=y
 CONFIG_VFPv3=y
-CONFIG_NEON=y
+# CONFIG_NEON is not set
 
 #
 # Userspace binary formats
@@ -357,7 +380,7 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_HAVE_AOUT=y
-CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=y
 
 #
@@ -371,7 +394,15 @@
 CONFIG_SUSPEND=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_SUSPEND_FREEZER=y
-# CONFIG_WAKELOCK is not set
+CONFIG_HAS_WAKELOCK=y
+CONFIG_HAS_EARLYSUSPEND=y
+CONFIG_WAKELOCK=y
+CONFIG_WAKELOCK_STAT=y
+CONFIG_USER_WAKELOCK=y
+CONFIG_EARLYSUSPEND=y
+# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set
+# CONFIG_CONSOLE_EARLYSUSPEND is not set
+CONFIG_FB_EARLYSUSPEND=y
 # CONFIG_APM_EMULATION is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
@@ -386,12 +417,12 @@
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
 # CONFIG_XFRM_SUB_POLICY is not set
-CONFIG_XFRM_MIGRATE=y
+# CONFIG_XFRM_MIGRATE is not set
 # CONFIG_XFRM_STATISTICS is not set
 CONFIG_NET_KEY=y
-CONFIG_NET_KEY_MIGRATE=y
+# CONFIG_NET_KEY_MIGRATE is not set
 CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
+# CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
 CONFIG_IP_FIB_HASH=y
 CONFIG_IP_PNP=y
@@ -400,7 +431,6 @@
 CONFIG_IP_PNP_RARP=y
 # CONFIG_NET_IPIP is not set
 # CONFIG_NET_IPGRE is not set
-# CONFIG_IP_MROUTE is not set
 # CONFIG_ARPD is not set
 # CONFIG_SYN_COOKIES is not set
 # CONFIG_INET_AH is not set
@@ -447,44 +477,17 @@
 # CONFIG_HAMRADIO is not set
 # CONFIG_CAN is not set
 # CONFIG_IRDA 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_BNEP_MC_FILTER is not set
-# CONFIG_BT_BNEP_PROTO_FILTER is not set
-CONFIG_BT_HIDP=y
-
-#
-# Bluetooth device drivers
-#
-# CONFIG_BT_HCIBTUSB is not set
-# CONFIG_BT_HCIBTSDIO is not set
-CONFIG_BT_HCIUART=y
-CONFIG_BT_HCIUART_H4=y
-# CONFIG_BT_HCIUART_BCSP is not set
-CONFIG_BT_HCIUART_LL=y
-# CONFIG_BT_HCIBCM203X is not set
-# CONFIG_BT_HCIBPA10X is not set
-# CONFIG_BT_HCIBFUSB is not set
-# CONFIG_BT_HCIBRF6150 is not set
-# CONFIG_BT_HCIH4P is not set
-# CONFIG_BT_HCIVHCI is not set
+# CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
 # CONFIG_PHONET is not set
 CONFIG_WIRELESS=y
 # CONFIG_CFG80211 is not set
 CONFIG_WIRELESS_OLD_REGULATORY=y
-CONFIG_WIRELESS_EXT=y
-CONFIG_WIRELESS_EXT_SYSFS=y
+# CONFIG_WIRELESS_EXT is not set
 # CONFIG_LIB80211 is not set
 # CONFIG_MAC80211 is not set
 # CONFIG_WIMAX is not set
-CONFIG_RFKILL=y
-CONFIG_RFKILL_PM=y
-# CONFIG_RFKILL_INPUT is not set
+# CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
 #
@@ -501,11 +504,9 @@
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
-CONFIG_CONNECTOR=y
-CONFIG_PROC_EVENTS=y
+# CONFIG_CONNECTOR is not set
 CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_DEBUG is not set
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_TESTS is not set
@@ -530,8 +531,10 @@
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI=y
 # CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
 CONFIG_MTD_MAP_BANK_WIDTH_2=y
 CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -542,6 +545,10 @@
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
@@ -550,6 +557,9 @@
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -570,17 +580,22 @@
 # CONFIG_MTD_DOC2001PLUS is not set
 CONFIG_MTD_NAND=y
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
-# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND_ECC_SMC=y
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
 # CONFIG_MTD_NAND_GPIO is not set
 CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_NAND_OMAP_HWECC=y
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
 # CONFIG_MTD_NAND_PLATFORM is not set
 # CONFIG_MTD_ALAUDA is not set
-# CONFIG_MTD_ONENAND is not set
+CONFIG_MTD_ONENAND=y
+CONFIG_MTD_ONENAND_VERIFY_WRITE=y
+# CONFIG_MTD_ONENAND_GENERIC is not set
+CONFIG_MTD_ONENAND_OMAP2=y
+# CONFIG_MTD_ONENAND_OTP is not set
+# CONFIG_MTD_ONENAND_2X_PROGRAM is not set
+# CONFIG_MTD_ONENAND_SIM is not set
 
 #
 # LPDDR flash memory drivers
@@ -600,7 +615,7 @@
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_SIZE=16384
 # CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
@@ -611,7 +626,6 @@
 # CONFIG_ENCLOSURE_SERVICES is not set
 # CONFIG_KERNEL_DEBUGGER_CORE is not set
 # CONFIG_UID_STAT is not set
-# CONFIG_WL127X_RFKILL is not set
 # CONFIG_C2PORT is not set
 
 #
@@ -661,7 +675,10 @@
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
 # CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
@@ -670,16 +687,16 @@
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
-CONFIG_TUN=y
+# CONFIG_TUN is not set
 # CONFIG_VETH is not set
 # CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
-# CONFIG_SMC91X is not set
+CONFIG_SMC91X=y
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
+# CONFIG_SMC911X is not set
 # CONFIG_SMSC911X is not set
 # CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
@@ -690,8 +707,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -712,7 +729,6 @@
 # CONFIG_USB_PEGASUS is not set
 # CONFIG_USB_RTL8150 is not set
 # CONFIG_USB_USBNET is not set
-# CONFIG_USB_HSO is not set
 # CONFIG_WAN is not set
 # CONFIG_PPP is not set
 # CONFIG_SLIP is not set
@@ -749,12 +765,12 @@
 # CONFIG_KEYBOARD_STOWAWAY is not set
 # CONFIG_KEYBOARD_OMAP is not set
 CONFIG_KEYBOARD_TWL4030=y
-# CONFIG_KEYBOARD_GPIO is not set
+CONFIG_KEYBOARD_GPIO=y
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_TOUCHSCREEN_ADS7846 is not set
+CONFIG_TOUCHSCREEN_ADS7846=y
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -763,7 +779,7 @@
 # CONFIG_TOUCHSCREEN_INEXIO is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
 # CONFIG_TOUCHSCREEN_PENMOUNT is not set
-CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI=y
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
 # CONFIG_TOUCHSCREEN_TSC2005 is not set
@@ -771,17 +787,7 @@
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
 # CONFIG_TOUCHSCREEN_TSC2007 is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_ATI_REMOTE is not set
-# CONFIG_INPUT_ATI_REMOTE2 is not set
-# CONFIG_INPUT_KEYSPAN_REMOTE is not set
-# CONFIG_INPUT_POWERMATE is not set
-# CONFIG_INPUT_YEALINK is not set
-# CONFIG_INPUT_CM109 is not set
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
-# CONFIG_INPUT_UINPUT is not set
-# CONFIG_INPUT_GPIO is not set
-# CONFIG_INPUT_KEYCHORD is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
@@ -867,8 +873,8 @@
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
-CONFIG_TWL4030_MADC=y
-CONFIG_TWL4030_POWEROFF=y
+# CONFIG_TWL4030_MADC is not set
+# CONFIG_TWL4030_POWEROFF is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_SENSORS_PCA963X is not set
@@ -877,7 +883,7 @@
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
+# CONFIG_SPI_DEBUG is not set
 CONFIG_SPI_MASTER=y
 
 #
@@ -920,38 +926,13 @@
 #
 # CONFIG_GPIO_MAX7301 is not set
 # CONFIG_GPIO_MCP23S08 is not set
-CONFIG_W1=y
-CONFIG_W1_CON=y
-
-#
-# 1-wire Bus Masters
-#
-# CONFIG_W1_MASTER_DS2490 is not set
-# CONFIG_W1_MASTER_DS2482 is not set
-# CONFIG_W1_MASTER_DS1WM is not set
-# CONFIG_W1_MASTER_GPIO is not set
-CONFIG_HDQ_MASTER_OMAP=y
-
-#
-# 1-wire Slaves
-#
-# CONFIG_W1_SLAVE_THERM is not set
-# CONFIG_W1_SLAVE_SMEM is not set
-# CONFIG_W1_SLAVE_DS2431 is not set
-# CONFIG_W1_SLAVE_DS2433 is not set
-# CONFIG_W1_SLAVE_DS2760 is not set
-# CONFIG_W1_SLAVE_BQ27000 is not set
-CONFIG_POWER_SUPPLY=y
-# CONFIG_POWER_SUPPLY_DEBUG is not set
-# CONFIG_PDA_POWER is not set
-# CONFIG_BATTERY_DS2760 is not set
-CONFIG_TWL4030_BCI_BATTERY=y
-# CONFIG_BATTERY_BQ27x00 is not set
+# CONFIG_W1 is not set
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_THERMAL is not set
 # CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_NOWAYOUT=y
 
 #
 # Watchdog Device Drivers
@@ -980,7 +961,7 @@
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TPS65010 is not set
 CONFIG_TWL4030_CORE=y
-CONFIG_TWL4030_POWER=y
+# CONFIG_TWL4030_POWER is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_T7L66XB is not set
 # CONFIG_MFD_TC6387XB is not set
@@ -1004,17 +985,75 @@
 #
 # Multimedia drivers
 #
-# CONFIG_DAB is not set
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
 # CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_FB_OMAP_LCD_WVGA is not set
-# CONFIG_OMAP2_DSS is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+CONFIG_FB_SYS_FILLRECT=y
+CONFIG_FB_SYS_COPYAREA=y
+CONFIG_FB_SYS_IMAGEBLIT=y
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+CONFIG_FB_SYS_FOPS=y
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_VIRTUAL=y
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+CONFIG_FB_OMAP_LCD_VGA=y
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_DSS_VRAM_SIZE=4
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+CONFIG_OMAP2_DSS_VENC=y
+# CONFIG_OMAP2_DSS_SDI is not set
+# CONFIG_OMAP2_DSS_DSI is not set
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+
+#
+# OMAP2/3 Display Device Drivers
+#
+# CONFIG_PANEL_GENERIC is not set
+# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
+CONFIG_PANEL_SHARP_LS037V7DW01=y
+# CONFIG_PANEL_N800 is not set
+# CONFIG_PANEL_ZOOM2 is not set
+# CONFIG_CTRL_BLIZZARD is not set
+# CONFIG_SIL9022 is not set
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
+CONFIG_FB_OMAP2_NUM_FBS=3
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=m
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+# CONFIG_LCD_PLATFORM is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=m
+CONFIG_BACKLIGHT_GENERIC=m
 
 #
 # Display device support
@@ -1026,22 +1065,75 @@
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
 # CONFIG_SOUND is not set
-# CONFIG_HID_SUPPORT is not set
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 
 #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_OTG=y
@@ -1055,10 +1147,24 @@
 # USB Host Controller Drivers
 #
 # CONFIG_USB_C67X00_HCD is not set
-# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_OMAP_OHCI_PHY_MODE=y
+CONFIG_OMAP_OHCI_PHY_MODE_PINS=y
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DAT_SE0 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DP_DM is not set
+# CONFIG_OMAP_OHCI_TLL_MODE is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_SL811_HCD is not set
 # CONFIG_USB_R8A66597_HCD is not set
 # CONFIG_USB_HWA_HCD is not set
@@ -1094,7 +1200,7 @@
 # see USB_STORAGE Help for more information
 #
 CONFIG_USB_STORAGE=y
-# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE_DEBUG=y
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
@@ -1137,16 +1243,17 @@
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_TEST is not set
+CONFIG_USB_TEST=y
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
+# CONFIG_USB_GADGET_DEBUG_FS is not set
 CONFIG_USB_GADGET_VBUS_DRAW=2
 CONFIG_USB_GADGET_SELECTED=y
 # CONFIG_USB_GADGET_AT91 is not set
@@ -1166,14 +1273,15 @@
 # CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
 # CONFIG_USB_ETH is not set
 # CONFIG_USB_GADGETFS is not set
 # CONFIG_USB_FILE_STORAGE is not set
 # CONFIG_USB_G_SERIAL is not set
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
-CONFIG_USB_ANDROID=y
+# CONFIG_USB_ANDROID is not set
 # CONFIG_USB_CDC_COMPOSITE is not set
 
 #
@@ -1183,9 +1291,10 @@
 # CONFIG_USB_GPIO_VBUS is not set
 # CONFIG_ISP1301_OMAP is not set
 CONFIG_TWL4030_USB=y
+CONFIG_ISP1301_HOST=y
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
-CONFIG_MMC_UNSAFE_RESUME=y
+# CONFIG_MMC_UNSAFE_RESUME is not set
 # CONFIG_MMC_EMBEDDED_SDIO is not set
 # CONFIG_MMC_PARANOID_SD_INIT is not set
 
@@ -1209,8 +1318,7 @@
 # CONFIG_MEMSTICK is not set
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
-CONFIG_SWITCH=y
-# CONFIG_SWITCH_GPIO is not set
+# CONFIG_SWITCH is not set
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1276,7 +1384,7 @@
 #
 # CONFIG_DMADEVICES is not set
 CONFIG_REGULATOR=y
-CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_DEBUG is not set
 # CONFIG_REGULATOR_FIXED_VOLTAGE is not set
 # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
 # CONFIG_REGULATOR_BQ24022 is not set
@@ -1310,7 +1418,20 @@
 # CBUS support
 #
 # CONFIG_CBUS is not set
-# CONFIG_MPU_BRIDGE is not set
+CONFIG_MPU_BRIDGE=y
+CONFIG_BRIDGE_DVFS=y
+CONFIG_BRIDGE_MEMPOOL_SIZE=0x600000
+# CONFIG_BRIDGE_DEBUG is not set
+
+#
+# Bridge Hacking
+#
+# CONFIG_BRIDGE_CHECK_ALIGN_128 is not set
+
+#
+# Bridge Notifications
+#
+# CONFIG_BRIDGE_NTFY_PWRERR is not set
 
 #
 # File systems
@@ -1379,7 +1500,16 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1517,8 +1647,9 @@
 # CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
 # CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
@@ -1534,7 +1665,10 @@
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
 
 #
 # Tracers
@@ -1547,6 +1681,7 @@
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_PRINTK_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
@@ -1554,8 +1689,7 @@
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_ERRORS is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
diff --git a/arch/arm/configs/omap_3430sdp_defconfig b/arch/arm/configs/omap_3430sdp_defconfig
index b686f34..eb94c77 100644
--- a/arch/arm/configs/omap_3430sdp_defconfig
+++ b/arch/arm/configs/omap_3430sdp_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.27-omap1
-# Fri Oct 17 13:41:54 2008
+# Linux kernel version: 2.6.29-omap1
+# Fri Sep 18 18:30:00 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -22,8 +22,6 @@
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
-CONFIG_ARCH_SUPPORTS_AOUT=y
-CONFIG_ZONE_DMA=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
@@ -44,14 +42,23 @@
 # CONFIG_BSD_PROCESS_ACCT_V3 is not set
 # CONFIG_TASKSTATS is not set
 # CONFIG_AUDIT is not set
+
+#
+# RCU Subsystem
+#
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
 # CONFIG_IKCONFIG is not set
 CONFIG_LOG_BUF_SHIFT=14
-# CONFIG_CGROUPS is not set
 CONFIG_GROUP_SCHED=y
 CONFIG_FAIR_GROUP_SCHED=y
 # CONFIG_RT_GROUP_SCHED is not set
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
+# CONFIG_CGROUPS is not set
 CONFIG_SYSFS_DEPRECATED=y
 CONFIG_SYSFS_DEPRECATED_V2=y
 # CONFIG_RELAY is not set
@@ -60,6 +67,8 @@
 CONFIG_INITRAMFS_SOURCE=""
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
+CONFIG_ANON_INODES=y
+CONFIG_PANIC_TIMEOUT=0
 CONFIG_EMBEDDED=y
 CONFIG_UID16=y
 # CONFIG_SYSCTL_SYSCALL is not set
@@ -70,36 +79,29 @@
 CONFIG_PRINTK=y
 CONFIG_BUG=y
 CONFIG_ELF_CORE=y
-CONFIG_COMPAT_BRK=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
-CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
+CONFIG_AIO=y
+# CONFIG_ASHMEM is not set
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_COMPAT_BRK=y
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
 # CONFIG_PROFILING is not set
-# CONFIG_MARKERS is not set
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
-# CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS is not set
-# CONFIG_HAVE_IOREMAP_PROT is not set
 CONFIG_HAVE_KPROBES=y
 CONFIG_HAVE_KRETPROBES=y
-# CONFIG_HAVE_ARCH_TRACEHOOK is not set
-# CONFIG_HAVE_DMA_ATTRS is not set
-# CONFIG_USE_GENERIC_SMP_HELPERS is not set
 CONFIG_HAVE_CLK=y
-CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_HAVE_GENERIC_DMA_COHERENT=y
 CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
-# CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
 CONFIG_MODULES=y
 # CONFIG_MODULE_FORCE_LOAD is not set
@@ -107,11 +109,9 @@
 # CONFIG_MODULE_FORCE_UNLOAD is not set
 CONFIG_MODVERSIONS=y
 CONFIG_MODULE_SRCVERSION_ALL=y
-CONFIG_KMOD=y
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
-# CONFIG_LSF is not set
 # CONFIG_BLK_DEV_BSG is not set
 # CONFIG_BLK_DEV_INTEGRITY is not set
 
@@ -127,7 +127,7 @@
 # CONFIG_DEFAULT_CFQ is not set
 # CONFIG_DEFAULT_NOOP is not set
 CONFIG_DEFAULT_IOSCHED="anticipatory"
-CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
 
 #
 # System Type
@@ -137,7 +137,6 @@
 # CONFIG_ARCH_REALVIEW is not set
 # CONFIG_ARCH_VERSATILE is not set
 # CONFIG_ARCH_AT91 is not set
-# CONFIG_ARCH_CLPS7500 is not set
 # CONFIG_ARCH_CLPS711X is not set
 # CONFIG_ARCH_EBSA110 is not set
 # CONFIG_ARCH_EP93XX is not set
@@ -164,11 +163,13 @@
 # CONFIG_ARCH_RPC is not set
 # CONFIG_ARCH_SA1100 is not set
 # CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_S3C64XX is not set
 # CONFIG_ARCH_SHARK is not set
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_DAVINCI is not set
 CONFIG_ARCH_OMAP=y
-# CONFIG_ARCH_MSM7X00A is not set
+# CONFIG_ARCH_MSM is not set
+# CONFIG_ARCH_W90X900 is not set
 
 #
 # TI OMAP Implementations
@@ -181,6 +182,8 @@
 #
 # OMAP Feature Selections
 #
+CONFIG_ARCH_OMAP3_GP=y
+# CONFIG_ARCH_OMAP3_HS is not set
 # CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
 # CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
 CONFIG_OMAP_SMARTREFLEX=y
@@ -194,36 +197,52 @@
 CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_OMAP_MUX_WARNINGS=y
 # CONFIG_OMAP_MCBSP is not set
-# CONFIG_OMAP_MMU_FWK is not set
 # CONFIG_OMAP_MBOX_FWK is not set
+# CONFIG_OMAP_IOMMU is not set
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 CONFIG_OMAP_32K_TIMER_HZ=128
+CONFIG_OMAP_TICK_GPTIMER=1
 CONFIG_OMAP_DM_TIMER=y
 CONFIG_OMAP_LL_DEBUG_UART1=y
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
 CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# USBHOST Port Configuration
+#
+CONFIG_OMAP_EHCI_PHY_MODE_PORT1=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1 is not set
+CONFIG_OMAP_EHCI_PHY_MODE_PORT2=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2 is not set
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT3 is not set
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3 is not set
+# CONFIG_OMAP_PM_NONE is not set
+# CONFIG_OMAP_PM_NOOP is not set
+CONFIG_OMAP_PM_SRF=y
 CONFIG_ARCH_OMAP34XX=y
 CONFIG_ARCH_OMAP3430=y
 
 #
 # OMAP Board Type
 #
+# CONFIG_MACH_NOKIA_RX51 is not set
 # CONFIG_MACH_OMAP_LDP is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
+# CONFIG_TIWLAN_SDIO is not set
 CONFIG_MACH_OMAP_3430SDP=y
 # CONFIG_MACH_OMAP3EVM is not set
 # CONFIG_MACH_OMAP3_BEAGLE is not set
 # CONFIG_MACH_OVERO is not set
-CONFIG_OMAP_TICK_GPTIMER=1
-
-#
-# Boot options
-#
-
-#
-# Power management
-#
+# CONFIG_MACH_OMAP3_PANDORA is not set
 
 #
 # Processor Type
@@ -250,10 +269,16 @@
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
-CONFIG_HAS_TLS_REG=y
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
+# CONFIG_HAS_TLS_REG is not set
 # CONFIG_OUTER_CACHE is not set
 
 #
+# errata
+#
+# CONFIG_ARM_ERRATA_430973 is not set
+
+#
 # Bus support
 #
 # CONFIG_PCI_SYSCALL is not set
@@ -267,26 +292,30 @@
 CONFIG_NO_HZ=y
 CONFIG_HIGH_RES_TIMERS=y
 CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
 # CONFIG_PREEMPT is not set
 CONFIG_HZ=128
 CONFIG_AEABI=y
 CONFIG_OABI_COMPAT=y
 CONFIG_ARCH_FLATMEM_HAS_HOLES=y
-# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+# CONFIG_ARCH_SPARSEMEM_DEFAULT is not set
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
 CONFIG_SELECT_MEMORY_MODEL=y
 CONFIG_FLATMEM_MANUAL=y
 # CONFIG_DISCONTIGMEM_MANUAL is not set
 # CONFIG_SPARSEMEM_MANUAL is not set
 CONFIG_FLATMEM=y
 CONFIG_FLAT_NODE_MEM_MAP=y
-# CONFIG_SPARSEMEM_STATIC is not set
-# CONFIG_SPARSEMEM_VMEMMAP_ENABLE is not set
 CONFIG_PAGEFLAGS_EXTENDED=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
-# CONFIG_RESOURCES_64BIT is not set
-CONFIG_ZONE_DMA_FLAG=1
-CONFIG_BOUNCE=y
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -300,9 +329,28 @@
 # CONFIG_KEXEC is not set
 
 #
-# CPU Frequency scaling
+# CPU Power Management
 #
-# CONFIG_CPU_FREQ is not set
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_MIN_TICKS=10
+CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
+CONFIG_CPU_IDLE=y
+CONFIG_CPU_IDLE_GOV_LADDER=y
+CONFIG_CPU_IDLE_GOV_MENU=y
 
 #
 # Floating point emulation
@@ -322,6 +370,8 @@
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
 # CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=y
 
@@ -333,6 +383,7 @@
 CONFIG_PM_SLEEP=y
 CONFIG_SUSPEND=y
 CONFIG_SUSPEND_FREEZER=y
+# CONFIG_WAKELOCK is not set
 # CONFIG_APM_EMULATION is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
@@ -340,6 +391,7 @@
 #
 # Networking options
 #
+CONFIG_COMPAT_NET_DEV_OPS=y
 CONFIG_PACKET=y
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -378,6 +430,7 @@
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
 # CONFIG_IPV6 is not set
+CONFIG_ANDROID_PARANOID_NETWORK=y
 # CONFIG_NETWORK_SECMARK is not set
 # CONFIG_NETFILTER is not set
 # CONFIG_IP_DCCP is not set
@@ -385,6 +438,7 @@
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
 # CONFIG_VLAN_8021Q is not set
 # CONFIG_DECNET is not set
 # CONFIG_LLC2 is not set
@@ -395,6 +449,7 @@
 # CONFIG_ECONET is not set
 # CONFIG_WAN_ROUTER is not set
 # CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
 
 #
 # Network testing
@@ -405,14 +460,14 @@
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
-
-#
-# Wireless
-#
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
 # CONFIG_CFG80211 is not set
+CONFIG_WIRELESS_OLD_REGULATORY=y
 # CONFIG_WIRELESS_EXT is not set
+# CONFIG_LIB80211 is not set
 # CONFIG_MAC80211 is not set
-# CONFIG_IEEE80211 is not set
+# CONFIG_WIMAX is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -435,6 +490,7 @@
 # CONFIG_MTD_DEBUG is not set
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_TESTS is not set
 # CONFIG_MTD_REDBOOT_PARTS is not set
 CONFIG_MTD_CMDLINE_PARTS=y
 # CONFIG_MTD_AFS_PARTS is not set
@@ -507,6 +563,7 @@
 # CONFIG_MTD_NAND_VERIFY_WRITE is not set
 CONFIG_MTD_NAND_ECC_SMC=y
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
 CONFIG_MTD_NAND_OMAP2=y
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
@@ -522,6 +579,11 @@
 # CONFIG_MTD_ONENAND_SIM is not set
 
 #
+# LPDDR flash memory drivers
+#
+# CONFIG_MTD_LPDDR is not set
+
+#
 # UBI - Unsorted block images
 #
 # CONFIG_MTD_UBI is not set
@@ -539,9 +601,21 @@
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
 CONFIG_MISC_DEVICES=y
-# CONFIG_EEPROM_93CX6 is not set
+CONFIG_ANDROID_PMEM=y
+# CONFIG_ICS932S401 is not set
 # CONFIG_OMAP_STI is not set
 # CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_KERNEL_DEBUGGER_CORE is not set
+# CONFIG_UID_STAT is not set
+# CONFIG_C2PORT is not set
+
+#
+# EEPROM support
+#
+# CONFIG_EEPROM_AT24 is not set
+# CONFIG_EEPROM_AT25 is not set
+# CONFIG_EEPROM_LEGACY is not set
+# CONFIG_EEPROM_93CX6 is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -584,6 +658,7 @@
 # CONFIG_SCSI_SRP_ATTRS is not set
 CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_ATA is not set
@@ -603,10 +678,15 @@
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
 # CONFIG_SMC911X is not set
+# CONFIG_SMSC911X is not set
+# CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
 # CONFIG_IBM_NEW_EMAC_TAH is not set
 # CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
 CONFIG_NETDEV_1000=y
 CONFIG_NETDEV_10000=y
@@ -619,6 +699,10 @@
 # CONFIG_IWLWIFI_LEDS is not set
 
 #
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
 # USB Network Adapters
 #
 # CONFIG_USB_CATC is not set
@@ -648,6 +732,7 @@
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
+# CONFIG_INPUT_KEYRESET is not set
 
 #
 # Input Device Drivers
@@ -659,8 +744,8 @@
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
+# CONFIG_KEYBOARD_OMAP is not set
 CONFIG_KEYBOARD_TWL4030=y
-# CONFIG_KEYBOARD_LM8323 is not set
 # CONFIG_KEYBOARD_GPIO is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
@@ -670,18 +755,19 @@
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_WACOM_W8001 is not set
 # CONFIG_TOUCHSCREEN_MTOUCH is not set
 # CONFIG_TOUCHSCREEN_INEXIO is not set
 # CONFIG_TOUCHSCREEN_MK712 is not set
 # CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI is not set
 # CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
 # CONFIG_TOUCHSCREEN_TOUCHWIN is not set
 # CONFIG_TOUCHSCREEN_TSC2005 is not set
-# CONFIG_TOUCHSCREEN_TSC2102 is not set
 # CONFIG_TOUCHSCREEN_TSC210X is not set
-# CONFIG_TOUCHSCREEN_UCB1400 is not set
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_TOUCHSCREEN_TSC2007 is not set
 # CONFIG_INPUT_MISC is not set
 
 #
@@ -698,35 +784,34 @@
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
 # CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVMEM=y
 CONFIG_DEVKMEM=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_OMAP_DMA_UART1 is not set
+# CONFIG_SERIAL_OMAP_DMA_UART2 is not set
+# CONFIG_SERIAL_OMAP_DMA_UART3 is not set
 CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
 CONFIG_HW_RANDOM=y
-# CONFIG_NVRAM is not set
 # CONFIG_R3964 is not set
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_TCG_TPM is not set
+# CONFIG_DCC_TTY is not set
 CONFIG_I2C=y
 CONFIG_I2C_BOARDINFO=y
 CONFIG_I2C_CHARDEV=y
@@ -761,22 +846,15 @@
 # Miscellaneous I2C Chip support
 #
 # CONFIG_DS1682 is not set
-# CONFIG_AT24 is not set
-# CONFIG_SENSORS_EEPROM is not set
 # CONFIG_SENSORS_PCF8574 is not set
 # CONFIG_PCF8575 is not set
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
-# CONFIG_ISP1301_OMAP is not set
-# CONFIG_TPS65010 is not set
-# CONFIG_SENSORS_TLV320AIC23 is not set
 # CONFIG_TWL4030_MADC is not set
-CONFIG_TWL4030_USB=y
-# CONFIG_TWL4030_PWRBUTTON is not set
 # CONFIG_TWL4030_POWEROFF is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
-# CONFIG_LP5521 is not set
+# CONFIG_SENSORS_PCA963X is not set
 # CONFIG_I2C_DEBUG_CORE is not set
 # CONFIG_I2C_DEBUG_ALGO is not set
 # CONFIG_I2C_DEBUG_BUS is not set
@@ -789,14 +867,12 @@
 # SPI Master Controller Drivers
 #
 # CONFIG_SPI_BITBANG is not set
+# CONFIG_SPI_GPIO is not set
 CONFIG_SPI_OMAP24XX=y
 
 #
 # SPI Protocol Masters
 #
-# CONFIG_SPI_AT25 is not set
-# CONFIG_SPI_TSC2101 is not set
-# CONFIG_SPI_TSC2102 is not set
 # CONFIG_SPI_TSC210X is not set
 # CONFIG_SPI_TSC2301 is not set
 # CONFIG_SPI_SPIDEV is not set
@@ -807,6 +883,10 @@
 # CONFIG_GPIO_SYSFS is not set
 
 #
+# Memory mapped GPIO expanders:
+#
+
+#
 # I2C GPIO expanders:
 #
 # CONFIG_GPIO_MAX732X is not set
@@ -826,6 +906,8 @@
 # CONFIG_W1 is not set
 # CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
 CONFIG_WATCHDOG_NOWAYOUT=y
 
@@ -839,11 +921,11 @@
 # USB-based Watchdog Cards
 #
 # CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
 
 #
 # Sonics Silicon Backplane
 #
-CONFIG_SSB_POSSIBLE=y
 # CONFIG_SSB is not set
 
 #
@@ -854,11 +936,17 @@
 # CONFIG_MFD_ASIC3 is not set
 # CONFIG_HTC_EGPIO is not set
 # CONFIG_HTC_PASIC3 is not set
+# CONFIG_TPS65010 is not set
 CONFIG_TWL4030_CORE=y
+# CONFIG_TWL4030_POWER is not set
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_T7L66XB is not set
 # CONFIG_MFD_TC6387XB is not set
 # CONFIG_MFD_TC6393XB is not set
+# CONFIG_PMIC_DA903X is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
 
 #
 # Multimedia devices
@@ -885,6 +973,7 @@
 CONFIG_FB=y
 # CONFIG_FIRMWARE_EDID is not set
 # CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
@@ -905,10 +994,14 @@
 #
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
 CONFIG_FB_OMAP=y
+# CONFIG_FB_OMAP_LCD_VGA is not set
 # CONFIG_FB_OMAP_LCDC_EXTERNAL is not set
 # CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
 CONFIG_FB_OMAP_CONSISTENT_DMA_SIZE=2
+# CONFIG_OMAP2_DSS is not set
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
 
 #
@@ -941,9 +1034,34 @@
 # USB Input Devices
 #
 CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
+# CONFIG_HID_PID is not set
 # CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
@@ -963,6 +1081,8 @@
 # CONFIG_USB_OTG_WHITELIST is not set
 # CONFIG_USB_OTG_BLACKLIST_HUB is not set
 CONFIG_USB_MON=y
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
 
 #
 # USB Host Controller Drivers
@@ -973,11 +1093,22 @@
 # CONFIG_OMAP_EHCI_TLL_MODE is not set
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_ISP1760_HCD is not set
-# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_OMAP_OHCI_PHY_MODE=y
+CONFIG_OMAP_OHCI_PHY_MODE_PINS=y
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DAT_SE0 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DP_DM is not set
+# CONFIG_OMAP_OHCI_TLL_MODE is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_SL811_HCD is not set
 # CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
 CONFIG_USB_MUSB_HDRC=y
 CONFIG_USB_MUSB_SOC=y
 
@@ -1000,20 +1131,20 @@
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
 
 #
-# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
 #
 
 #
-# may also be needed; see USB_STORAGE Help for more information
+# see USB_STORAGE Help for more information
 #
 CONFIG_USB_STORAGE=y
 CONFIG_USB_STORAGE_DEBUG=y
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
 # CONFIG_USB_STORAGE_USBAT is not set
 # CONFIG_USB_STORAGE_SDDR09 is not set
 # CONFIG_USB_STORAGE_SDDR55 is not set
@@ -1041,6 +1172,7 @@
 # CONFIG_USB_EMI62 is not set
 # CONFIG_USB_EMI26 is not set
 # CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
 # CONFIG_USB_RIO500 is not set
 # CONFIG_USB_LEGOTOWER is not set
 # CONFIG_USB_LCD is not set
@@ -1058,22 +1190,27 @@
 # CONFIG_USB_IOWARRIOR is not set
 CONFIG_USB_TEST=y
 # CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
 CONFIG_USB_GADGET=y
 CONFIG_USB_GADGET_DEBUG=y
 CONFIG_USB_GADGET_DEBUG_FILES=y
+CONFIG_USB_GADGET_VBUS_DRAW=2
 CONFIG_USB_GADGET_SELECTED=y
-# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_AT91 is not set
 # CONFIG_USB_GADGET_ATMEL_USBA is not set
 # CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-# CONFIG_USB_GADGET_PXA25X is not set
-# CONFIG_USB_GADGET_M66592 is not set
-# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGET_LH7A40X is not set
 # CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
 # CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_IMX is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_CI13XXX is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 CONFIG_USB_GADGET_DUALSPEED=y
 CONFIG_USB_ZERO=m
@@ -1084,26 +1221,44 @@
 # CONFIG_USB_G_SERIAL is not set
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
+# CONFIG_USB_ANDROID is not set
 # CONFIG_USB_CDC_COMPOSITE is not set
+
+#
+# OTG and related infrastructure
+#
+CONFIG_USB_OTG_UTILS=y
+# CONFIG_USB_GPIO_VBUS is not set
+# CONFIG_ISP1301_OMAP is not set
+CONFIG_TWL4030_USB=y
+CONFIG_ISP1301_HOST=y
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 # CONFIG_MMC_UNSAFE_RESUME is not set
+# CONFIG_MMC_EMBEDDED_SDIO is not set
+# CONFIG_MMC_PARANOID_SD_INIT is not set
 
 #
-# MMC/SD Card Drivers
+# MMC/SD/SDIO Card Drivers
 #
 CONFIG_MMC_BLOCK=y
 CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
 # CONFIG_SDIO_UART is not set
 # CONFIG_MMC_TEST is not set
 
 #
-# MMC/SD Host Controller Drivers
+# MMC/SD/SDIO Host Controller Drivers
 #
 # CONFIG_MMC_SDHCI is not set
 CONFIG_MMC_OMAP_HS=m
+# CONFIG_OMAP_HS_MMC2 is not set
+# CONFIG_OMAP_HS_MMC3 is not set
 # CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
+# CONFIG_SWITCH is not set
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1117,6 +1272,7 @@
 CONFIG_RTC_INTF_PROC=y
 CONFIG_RTC_INTF_DEV=y
 # CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+CONFIG_RTC_INTF_ALARM=y
 # CONFIG_RTC_DRV_TEST is not set
 
 #
@@ -1135,47 +1291,52 @@
 CONFIG_RTC_DRV_TWL4030=y
 # CONFIG_RTC_DRV_S35390A is not set
 # CONFIG_RTC_DRV_FM3130 is not set
+# CONFIG_RTC_DRV_RX8581 is not set
 
 #
 # SPI RTC drivers
 #
 # CONFIG_RTC_DRV_M41T94 is not set
 # CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
 # CONFIG_RTC_DRV_MAX6902 is not set
 # CONFIG_RTC_DRV_R9701 is not set
 # CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
 
 #
 # Platform RTC drivers
 #
 # CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
 # CONFIG_RTC_DRV_DS1511 is not set
 # CONFIG_RTC_DRV_DS1553 is not set
 # CONFIG_RTC_DRV_DS1742 is not set
 # CONFIG_RTC_DRV_STK17TA8 is not set
 # CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
 # CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
 # CONFIG_RTC_DRV_V3020 is not set
 
 #
 # on-CPU RTC drivers
 #
 # CONFIG_DMADEVICES is not set
-
-#
-# Voltage and Current regulators
-#
 CONFIG_REGULATOR=y
+# CONFIG_REGULATOR_DEBUG is not set
 # CONFIG_REGULATOR_FIXED_VOLTAGE is not set
 # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
 # CONFIG_REGULATOR_BQ24022 is not set
 CONFIG_REGULATOR_TWL4030=y
 # CONFIG_UIO is not set
+# CONFIG_STAGING is not set
 
 #
 # CBUS support
 #
 # CONFIG_CBUS is not set
+# CONFIG_MPU_BRIDGE is not set
 
 #
 # File systems
@@ -1185,19 +1346,22 @@
 # CONFIG_EXT2_FS_XIP is not set
 CONFIG_EXT3_FS=y
 # CONFIG_EXT3_FS_XATTR is not set
-# CONFIG_EXT4DEV_FS is not set
+# CONFIG_EXT4_FS is not set
 CONFIG_JBD=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
+CONFIG_FILE_LOCKING=y
 # CONFIG_XFS_FS is not set
 # CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
 CONFIG_DNOTIFY=y
 CONFIG_INOTIFY=y
 CONFIG_INOTIFY_USER=y
 CONFIG_QUOTA=y
 # CONFIG_QUOTA_NETLINK_INTERFACE is not set
 CONFIG_PRINT_QUOTA_WARNING=y
+CONFIG_QUOTA_TREE=y
 # CONFIG_QFMT_V1 is not set
 CONFIG_QFMT_V2=y
 CONFIG_QUOTACTL=y
@@ -1226,15 +1390,13 @@
 #
 CONFIG_PROC_FS=y
 CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
 CONFIG_SYSFS=y
 CONFIG_TMPFS=y
 # CONFIG_TMPFS_POSIX_ACL is not set
 # CONFIG_HUGETLB_PAGE is not set
 # CONFIG_CONFIGFS_FS is not set
-
-#
-# Miscellaneous filesystems
-#
+CONFIG_MISC_FILESYSTEMS=y
 # CONFIG_ADFS_FS is not set
 # CONFIG_AFFS_FS is not set
 # CONFIG_HFS_FS is not set
@@ -1242,6 +1404,7 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
+# CONFIG_YAFFS_FS is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1258,6 +1421,7 @@
 # CONFIG_JFFS2_CMODE_SIZE is not set
 # CONFIG_JFFS2_CMODE_FAVOURLZO is not set
 # CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_MINIX_FS is not set
 # CONFIG_OMFS_FS is not set
@@ -1278,6 +1442,7 @@
 CONFIG_NFS_COMMON=y
 CONFIG_SUNRPC=y
 CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
 CONFIG_RPCSEC_GSS_KRB5=y
 # CONFIG_RPCSEC_GSS_SPKM3 is not set
 # CONFIG_SMB_FS is not set
@@ -1387,18 +1552,28 @@
 # CONFIG_DEBUG_MEMORY_INIT is not set
 # CONFIG_DEBUG_LIST is not set
 # CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
 CONFIG_FRAME_POINTER=y
 # CONFIG_BOOT_PRINTK_DELAY is not set
 # CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
 # CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
-CONFIG_HAVE_FTRACE=y
-CONFIG_HAVE_DYNAMIC_FTRACE=y
-# CONFIG_FTRACE is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
 # CONFIG_IRQSOFF_TRACER is not set
 # CONFIG_SCHED_TRACER is not set
 # CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
 # CONFIG_KGDB is not set
@@ -1413,15 +1588,24 @@
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
 
 #
 # Crypto core or helper
 #
+# CONFIG_CRYPTO_FIPS is not set
 CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
 CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
 CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
 # CONFIG_CRYPTO_GF128MUL is not set
 # CONFIG_CRYPTO_NULL is not set
 # CONFIG_CRYPTO_CRYPTD is not set
@@ -1455,7 +1639,7 @@
 #
 # Digest
 #
-# CONFIG_CRYPTO_CRC32C is not set
+CONFIG_CRYPTO_CRC32C=y
 # CONFIG_CRYPTO_MD4 is not set
 CONFIG_CRYPTO_MD5=y
 # CONFIG_CRYPTO_MICHAEL_MIC is not set
@@ -1493,14 +1677,18 @@
 #
 # CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
 CONFIG_CRYPTO_HW=y
 
 #
 # Library routines
 #
 CONFIG_BITREVERSE=y
-# CONFIG_GENERIC_FIND_FIRST_BIT is not set
-# CONFIG_GENERIC_FIND_NEXT_BIT is not set
+CONFIG_GENERIC_FIND_LAST_BIT=y
 CONFIG_CRC_CCITT=y
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_T10DIF is not set
diff --git a/arch/arm/configs/zoom2_pm_defconfig b/arch/arm/configs/omap_3630sdp_defconfig
old mode 100644
new mode 100755
similarity index 81%
copy from arch/arm/configs/zoom2_pm_defconfig
copy to arch/arm/configs/omap_3630sdp_defconfig
index 28988a3..c8dbaa0
--- a/arch/arm/configs/zoom2_pm_defconfig
+++ b/arch/arm/configs/omap_3630sdp_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.29-omap1
-# Mon Aug  3 10:55:29 2009
+# Tue Dec  1 00:45:33 2009
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -23,6 +23,8 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_OMAP_GPTIMER=y
+# CONFIG_OPROFILE_ARMV7 is not set
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -60,8 +62,7 @@
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -94,7 +95,10 @@
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
@@ -108,7 +112,7 @@
 # CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
@@ -198,22 +202,39 @@
 CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_OMAP_MUX_WARNINGS=y
 CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MBOX_FWK is not set
-# CONFIG_OMAP_IOMMU is not set
+CONFIG_OMAP_MBOX_FWK=y
+CONFIG_OMAP_IOMMU=y
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 # CONFIG_OMAP3_DEBOBS is not set
 CONFIG_OMAP_32K_TIMER_HZ=128
 CONFIG_OMAP_TICK_GPTIMER=1
 CONFIG_OMAP_DM_TIMER=y
-# CONFIG_OMAP_LL_DEBUG_UART1 is not set
+CONFIG_OMAP_LL_DEBUG_UART1=y
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_LL_DEBUG_UART_EXT=y
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
 CONFIG_OMAP_SERIAL_WAKE=y
+
+#
+# USBHOST Port Configuration
+#
+CONFIG_OMAP_EHCI_PHY_MODE_PORT1=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1 is not set
+CONFIG_OMAP_EHCI_PHY_MODE_PORT2=y
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2 is not set
+# CONFIG_OMAP_EHCI_TLL_MODE_PORT3 is not set
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3 is not set
 # CONFIG_OMAP_PM_NONE is not set
 # CONFIG_OMAP_PM_NOOP is not set
 CONFIG_OMAP_PM_SRF=y
+CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND=y
+CONFIG_VOLTSCALE_VPFORCE=y
 CONFIG_ARCH_OMAP34XX=y
 CONFIG_ARCH_OMAP3430=y
 
@@ -222,9 +243,12 @@
 #
 # CONFIG_MACH_NOKIA_RX51 is not set
 # CONFIG_MACH_OMAP_LDP is not set
-CONFIG_MACH_OMAP_ZOOM2=y
-CONFIG_WIFI_CONTROL_FUNC=y
-# CONFIG_TIWLAN_SDIO is not set
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+CONFIG_MACH_OMAP_3630SDP=y
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
+CONFIG_TIWLAN_SDIO=y
+CONFIG_TIWLAN_MMC_CONTROLLER=3
 # CONFIG_MACH_OMAP_3430SDP is not set
 # CONFIG_MACH_OMAP3EVM is not set
 # CONFIG_MACH_OMAP3_BEAGLE is not set
@@ -256,13 +280,16 @@
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
 # CONFIG_HAS_TLS_REG is not set
 # CONFIG_OUTER_CACHE is not set
 
 #
 # errata
 #
-# CONFIG_ARM_ERRATA_430973 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_451027=y
+CONFIG_ARM_ERRATUM_451034=y
 
 #
 # Bus support
@@ -301,6 +328,7 @@
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -329,7 +357,7 @@
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
 # CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
 # CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 CONFIG_CPU_FREQ_MIN_TICKS=10
 CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
@@ -357,7 +385,7 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_HAVE_AOUT=y
-CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=y
 
 #
@@ -371,7 +399,15 @@
 CONFIG_SUSPEND=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_SUSPEND_FREEZER=y
-# CONFIG_WAKELOCK is not set
+CONFIG_HAS_WAKELOCK=y
+CONFIG_HAS_EARLYSUSPEND=y
+CONFIG_WAKELOCK=y
+CONFIG_WAKELOCK_STAT=y
+CONFIG_USER_WAKELOCK=y
+CONFIG_EARLYSUSPEND=y
+# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set
+# CONFIG_CONSOLE_EARLYSUSPEND is not set
+CONFIG_FB_EARLYSUSPEND=y
 # CONFIG_APM_EMULATION is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
@@ -384,7 +420,7 @@
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
+CONFIG_XFRM_USER=y
 # CONFIG_XFRM_SUB_POLICY is not set
 CONFIG_XFRM_MIGRATE=y
 # CONFIG_XFRM_STATISTICS is not set
@@ -504,8 +540,7 @@
 CONFIG_CONNECTOR=y
 CONFIG_PROC_EVENTS=y
 CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_DEBUG is not set
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_TESTS is not set
@@ -530,8 +565,10 @@
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI=y
 # CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
 CONFIG_MTD_MAP_BANK_WIDTH_2=y
 CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -542,6 +579,10 @@
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
@@ -550,6 +591,9 @@
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -574,7 +618,6 @@
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
 # CONFIG_MTD_NAND_GPIO is not set
 CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_NAND_OMAP_HWECC=y
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
@@ -600,7 +643,7 @@
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_SIZE=16384
 # CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
@@ -611,7 +654,9 @@
 # CONFIG_ENCLOSURE_SERVICES is not set
 # CONFIG_KERNEL_DEBUGGER_CORE is not set
 # CONFIG_UID_STAT is not set
-# CONFIG_WL127X_RFKILL is not set
+CONFIG_WL127X_RFKILL=y
+# CONFIG_APANIC is not set
+CONFIG_APANIC_PLABEL="kpanic"
 # CONFIG_C2PORT is not set
 
 #
@@ -661,7 +706,10 @@
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
 # CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
@@ -670,16 +718,16 @@
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
-CONFIG_TUN=y
+# CONFIG_TUN is not set
 # CONFIG_VETH is not set
 # CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
-# CONFIG_SMC91X is not set
+CONFIG_SMC91X=y
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
+# CONFIG_SMC911X is not set
 # CONFIG_SMSC911X is not set
 # CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
@@ -690,8 +738,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -771,17 +819,7 @@
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
 # CONFIG_TOUCHSCREEN_TSC2007 is not set
-CONFIG_INPUT_MISC=y
-# CONFIG_INPUT_ATI_REMOTE is not set
-# CONFIG_INPUT_ATI_REMOTE2 is not set
-# CONFIG_INPUT_KEYSPAN_REMOTE is not set
-# CONFIG_INPUT_POWERMATE is not set
-# CONFIG_INPUT_YEALINK is not set
-# CONFIG_INPUT_CM109 is not set
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
-# CONFIG_INPUT_UINPUT is not set
-# CONFIG_INPUT_GPIO is not set
-# CONFIG_INPUT_KEYCHORD is not set
+# CONFIG_INPUT_MISC is not set
 
 #
 # Hardware I/O ports
@@ -804,22 +842,18 @@
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_OMAP is not set
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_OMAP_DMA_UART1 is not set
+# CONFIG_SERIAL_OMAP_DMA_UART2 is not set
+# CONFIG_SERIAL_OMAP_DMA_UART3 is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
@@ -868,7 +902,7 @@
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 CONFIG_TWL4030_MADC=y
-CONFIG_TWL4030_POWEROFF=y
+# CONFIG_TWL4030_POWEROFF is not set
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_SENSORS_PCA963X is not set
@@ -877,7 +911,7 @@
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
+# CONFIG_SPI_DEBUG is not set
 CONFIG_SPI_MASTER=y
 
 #
@@ -940,7 +974,7 @@
 # CONFIG_W1_SLAVE_DS2431 is not set
 # CONFIG_W1_SLAVE_DS2433 is not set
 # CONFIG_W1_SLAVE_DS2760 is not set
-# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_W1_SLAVE_BQ27000=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_POWER_SUPPLY_DEBUG is not set
 # CONFIG_PDA_POWER is not set
@@ -951,7 +985,7 @@
 # CONFIG_THERMAL is not set
 # CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_NOWAYOUT=y
 
 #
 # Watchdog Device Drivers
@@ -997,24 +1031,99 @@
 #
 # Multimedia core support
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
 # CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
+CONFIG_VIDEO_MEDIA=y
 
 #
 # Multimedia drivers
 #
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+# CONFIG_VIDEO_CAPTURE_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
 # CONFIG_DAB is not set
 
 #
 # Graphics support
 #
 # CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_FB_OMAP_LCD_WVGA is not set
-# CONFIG_OMAP2_DSS is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_DSS_VRAM_SIZE=4
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+# CONFIG_OMAP2_DSS_VENC is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+# CONFIG_OMAP2_DSS_DSI is not set
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+
+#
+# OMAP2/3 Display Device Drivers
+#
+# CONFIG_PANEL_GENERIC is not set
+# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
+# CONFIG_PANEL_SHARP_LS037V7DW01 is not set
+# CONFIG_PANEL_N800 is not set
+CONFIG_PANEL_ZOOM2=y
+# CONFIG_CTRL_BLIZZARD is not set
+# CONFIG_SIL9022 is not set
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
+CONFIG_FB_OMAP2_NUM_FBS=1
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
 
 #
 # Display device support
@@ -1026,25 +1135,99 @@
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_SOUND is not set
-# CONFIG_HID_SUPPORT is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 
 #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 CONFIG_USB_SUSPEND=y
-CONFIG_USB_OTG=y
+# CONFIG_USB_OTG is not set
 # CONFIG_USB_OTG_WHITELIST is not set
 # CONFIG_USB_OTG_BLACKLIST_HUB is not set
 CONFIG_USB_MON=y
@@ -1055,10 +1238,24 @@
 # USB Host Controller Drivers
 #
 # CONFIG_USB_C67X00_HCD is not set
-# CONFIG_USB_EHCI_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_OMAP_EHCI_PHY_MODE=y
+# CONFIG_OMAP_EHCI_TLL_MODE is not set
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
 # CONFIG_USB_OXU210HP_HCD is not set
 # CONFIG_USB_ISP116X_HCD is not set
-# CONFIG_USB_OHCI_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+CONFIG_OMAP_OHCI_PHY_MODE=y
+CONFIG_OMAP_OHCI_PHY_MODE_PINS=y
+CONFIG_OMAP_OHCI_PHY_MODE_3PIN=y
+# CONFIG_OMAP_OHCI_PHY_MODE_4PIN is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DAT_SE0 is not set
+# CONFIG_OMAP_OHCI_PHY_MODE_6PIN_DP_DM is not set
+# CONFIG_OMAP_OHCI_TLL_MODE is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 # CONFIG_USB_SL811_HCD is not set
 # CONFIG_USB_R8A66597_HCD is not set
 # CONFIG_USB_HWA_HCD is not set
@@ -1069,10 +1266,9 @@
 # OMAP 343x high speed USB support
 #
 # CONFIG_USB_MUSB_HOST is not set
-# CONFIG_USB_MUSB_PERIPHERAL is not set
-CONFIG_USB_MUSB_OTG=y
+CONFIG_USB_MUSB_PERIPHERAL=y
+# CONFIG_USB_MUSB_OTG is not set
 CONFIG_USB_GADGET_MUSB_HDRC=y
-CONFIG_USB_MUSB_HDRC_HCD=y
 # CONFIG_MUSB_PIO_ONLY is not set
 CONFIG_USB_INVENTRA_DMA=y
 # CONFIG_USB_TI_CPPI_DMA is not set
@@ -1084,7 +1280,7 @@
 # CONFIG_USB_ACM is not set
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_WDM is not set
-# CONFIG_USB_TMC is not set
+CONFIG_USB_TMC=y
 
 #
 # NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
@@ -1137,16 +1333,17 @@
 # CONFIG_USB_IDMOUSE is not set
 # CONFIG_USB_FTDI_ELAN is not set
 # CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
 # CONFIG_USB_LD is not set
 # CONFIG_USB_TRANCEVIBRATOR is not set
 # CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_TEST is not set
+CONFIG_USB_TEST=y
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
 CONFIG_USB_GADGET_VBUS_DRAW=2
 CONFIG_USB_GADGET_SELECTED=y
 # CONFIG_USB_GADGET_AT91 is not set
@@ -1166,14 +1363,14 @@
 # CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
+CONFIG_USB_ZERO=y
 # CONFIG_USB_ETH is not set
 # CONFIG_USB_GADGETFS is not set
 # CONFIG_USB_FILE_STORAGE is not set
 # CONFIG_USB_G_SERIAL is not set
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
-CONFIG_USB_ANDROID=y
+# CONFIG_USB_ANDROID is not set
 # CONFIG_USB_CDC_COMPOSITE is not set
 
 #
@@ -1183,6 +1380,7 @@
 # CONFIG_USB_GPIO_VBUS is not set
 # CONFIG_ISP1301_OMAP is not set
 CONFIG_TWL4030_USB=y
+CONFIG_ISP1301_HOST=y
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 CONFIG_MMC_UNSAFE_RESUME=y
@@ -1204,13 +1402,13 @@
 # CONFIG_MMC_SDHCI is not set
 CONFIG_MMC_OMAP_HS=y
 # CONFIG_OMAP_HS_MMC2 is not set
-# CONFIG_OMAP_HS_MMC3 is not set
+CONFIG_OMAP_HS_MMC3=y
 # CONFIG_MMC_SPI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
 CONFIG_SWITCH=y
-# CONFIG_SWITCH_GPIO is not set
+CONFIG_SWITCH_GPIO=y
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1276,7 +1474,7 @@
 #
 # CONFIG_DMADEVICES is not set
 CONFIG_REGULATOR=y
-CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_DEBUG is not set
 # CONFIG_REGULATOR_FIXED_VOLTAGE is not set
 # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
 # CONFIG_REGULATOR_BQ24022 is not set
@@ -1310,7 +1508,20 @@
 # CBUS support
 #
 # CONFIG_CBUS is not set
-# CONFIG_MPU_BRIDGE is not set
+CONFIG_MPU_BRIDGE=y
+CONFIG_BRIDGE_DVFS=y
+CONFIG_BRIDGE_MEMPOOL_SIZE=0x600000
+# CONFIG_BRIDGE_DEBUG is not set
+
+#
+# Bridge Hacking
+#
+# CONFIG_BRIDGE_CHECK_ALIGN_128 is not set
+
+#
+# Bridge Notifications
+#
+# CONFIG_BRIDGE_NTFY_PWRERR is not set
 
 #
 # File systems
@@ -1379,7 +1590,16 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1517,8 +1737,9 @@
 # CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
 # CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
@@ -1534,7 +1755,10 @@
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
 
 #
 # Tracers
@@ -1547,6 +1771,7 @@
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_PRINTK_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
diff --git a/arch/arm/configs/zoom2_defconfig b/arch/arm/configs/zoom2_defconfig
index 2a09205..62a1f10 100644
--- a/arch/arm/configs/zoom2_defconfig
+++ b/arch/arm/configs/zoom2_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.29-omap1
-# Wed Aug 12 19:24:25 2009
+# Mon Feb 15 21:11:53 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -23,6 +23,8 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_OMAP_GPTIMER=y
+# CONFIG_OPROFILE_ARMV7 is not set
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -93,7 +95,10 @@
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
@@ -197,7 +202,7 @@
 CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_OMAP_MUX_WARNINGS=y
 CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MBOX_FWK is not set
+CONFIG_OMAP_MBOX_FWK=y
 CONFIG_OMAP_IOMMU=y
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
@@ -208,11 +213,14 @@
 # CONFIG_OMAP_LL_DEBUG_UART1 is not set
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_LL_DEBUG_UART_EXT=y
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
+CONFIG_OMAP_LL_DEBUG_NONE=y
 CONFIG_OMAP_SERIAL_WAKE=y
 # CONFIG_OMAP_PM_NONE is not set
 # CONFIG_OMAP_PM_NOOP is not set
 CONFIG_OMAP_PM_SRF=y
+CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND=y
+CONFIG_VOLTSCALE_VPFORCE=y
 CONFIG_ARCH_OMAP34XX=y
 CONFIG_ARCH_OMAP3430=y
 
@@ -222,6 +230,9 @@
 # CONFIG_MACH_NOKIA_RX51 is not set
 # CONFIG_MACH_OMAP_LDP is not set
 CONFIG_MACH_OMAP_ZOOM2=y
+# CONFIG_MACH_OMAP_ZOOM3 is not set
+# CONFIG_MACH_OMAP_3630SDP is not set
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
 CONFIG_WIFI_CONTROL_FUNC=y
 CONFIG_TIWLAN_SDIO=y
 CONFIG_TIWLAN_MMC_CONTROLLER=3
@@ -256,13 +267,17 @@
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
 # CONFIG_HAS_TLS_REG is not set
 # CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
 
 #
 # errata
 #
-# CONFIG_ARM_ERRATA_430973 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_451027=y
+CONFIG_ARM_ERRATUM_451034=y
 
 #
 # Bus support
@@ -301,6 +316,7 @@
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -328,9 +344,9 @@
 # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_FREQ_MIN_TICKS=10
 CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
 CONFIG_CPU_IDLE=y
@@ -349,7 +365,7 @@
 # CONFIG_FPE_FASTFPE is not set
 CONFIG_VFP=y
 CONFIG_VFPv3=y
-# CONFIG_NEON is not set
+CONFIG_NEON=y
 
 #
 # Userspace binary formats
@@ -505,7 +521,9 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
@@ -590,7 +608,8 @@
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
 # CONFIG_MTD_NAND_GPIO is not set
 CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_NAND_OMAP_HWECC=y
+CONFIG_MTD_NAND_OMAP_PREFETCH=y
+# CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
@@ -628,6 +647,9 @@
 # CONFIG_KERNEL_DEBUGGER_CORE is not set
 # CONFIG_UID_STAT is not set
 CONFIG_WL127X_RFKILL=y
+# CONFIG_APANIC is not set
+CONFIG_APANIC_PLABEL="kpanic"
+CONFIG_BUILD_TI_ST=y
 # CONFIG_C2PORT is not set
 
 #
@@ -637,6 +659,14 @@
 # CONFIG_EEPROM_AT25 is not set
 # CONFIG_EEPROM_LEGACY is not set
 # CONFIG_EEPROM_93CX6 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_TI_ST=m
+CONFIG_TI_ST_BT=m
+# CONFIG_TI_ST_FM is not set
+# CONFIG_TI_ST_GPS is not set
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -691,15 +721,34 @@
 # CONFIG_EQUALIZER is not set
 # CONFIG_TUN is not set
 # CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
-# CONFIG_SMSC911X is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
 # CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
@@ -790,7 +839,17 @@
 # CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
 # CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
 # CONFIG_TOUCHSCREEN_TSC2007 is not set
-# CONFIG_INPUT_MISC is not set
+CONFIG_INPUT_MISC=y
+# CONFIG_INPUT_ATI_REMOTE is not set
+# CONFIG_INPUT_ATI_REMOTE2 is not set
+# CONFIG_INPUT_KEYSPAN_REMOTE is not set
+# CONFIG_INPUT_POWERMATE is not set
+# CONFIG_INPUT_YEALINK is not set
+# CONFIG_INPUT_CM109 is not set
+# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
+CONFIG_INPUT_UINPUT=y
+# CONFIG_INPUT_GPIO is not set
+# CONFIG_INPUT_KEYCHORD is not set
 
 #
 # Hardware I/O ports
@@ -813,22 +872,20 @@
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_OMAP is not set
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_OMAP_DMA_UART1 is not set
+CONFIG_SERIAL_OMAP_DMA_UART2=y
+CONFIG_SERIAL_OMAP_UART2_RXDMA_TIMEOUT=1
+CONFIG_SERIAL_OMAP_UART2_RXDMA_BUFSIZE=4096
+# CONFIG_SERIAL_OMAP_DMA_UART3 is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
@@ -877,7 +934,7 @@
 # CONFIG_SENSORS_PCA9539 is not set
 # CONFIG_SENSORS_PCF8591 is not set
 CONFIG_TWL4030_MADC=y
-# CONFIG_TWL4030_POWEROFF is not set
+CONFIG_TWL4030_POWEROFF=y
 # CONFIG_SENSORS_MAX6875 is not set
 # CONFIG_SENSORS_TSL2550 is not set
 # CONFIG_SENSORS_PCA963X is not set
@@ -989,7 +1046,7 @@
 # CONFIG_HTC_PASIC3 is not set
 # CONFIG_TPS65010 is not set
 CONFIG_TWL4030_CORE=y
-# CONFIG_TWL4030_POWER is not set
+CONFIG_TWL4030_POWER=y
 # CONFIG_MFD_TMIO is not set
 # CONFIG_MFD_T7L66XB is not set
 # CONFIG_MFD_TC6387XB is not set
@@ -1031,8 +1088,6 @@
 CONFIG_VIDEO_V4L1=y
 CONFIG_VIDEOBUF_GEN=y
 CONFIG_VIDEOBUF_DMA_SG=y
-CONFIG_VIDEO_OMAP_VIDEOOUT=y
-# CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL is not set
 CONFIG_VIDEO_CAPTURE_DRIVERS=y
 # CONFIG_VIDEO_ADV_DEBUG is not set
 # CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
@@ -1110,13 +1165,13 @@
 # CONFIG_VIDEO_SAA5246A is not set
 # CONFIG_VIDEO_SAA5249 is not set
 CONFIG_VIDEO_OMAP3=y
-CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER=y
-CONFIG_VIDEO_OMAP34XX_ISP_RESIZER=y
 CONFIG_VIDEO_OMAP3_V4L2=y
 CONFIG_VIDEO_OMAP_VIDEOLIB=y
 CONFIG_VIDEO_OMAP_VIDEOOUT=y
 CONFIG_NTSC_M=y
 # CONFIG_PAL_BDGHI is not set
+CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER=y
+CONFIG_VIDEO_OMAP34XX_ISP_RESIZER=y
 # CONFIG_SOC_CAMERA is not set
 # CONFIG_V4L_USB_DRIVERS is not set
 # CONFIG_RADIO_ADAPTERS is not set
@@ -1154,7 +1209,6 @@
 # CONFIG_FB_VIRTUAL is not set
 # CONFIG_FB_METRONOME is not set
 # CONFIG_FB_MB862XX is not set
-CONFIG_FB_OMAP_LCD_WVGA=y
 # CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
 CONFIG_OMAP2_DSS=y
 CONFIG_OMAP2_DSS_VRAM_SIZE=4
@@ -1162,9 +1216,11 @@
 # CONFIG_OMAP2_DSS_RFBI is not set
 # CONFIG_OMAP2_DSS_VENC is not set
 # CONFIG_OMAP2_DSS_SDI is not set
-# CONFIG_OMAP2_DSS_DSI is not set
+CONFIG_OMAP2_DSS_DSI=y
+CONFIG_OMAP2_DSS_USE_DSI_PLL=y
+CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI=y
 # CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
-CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=0
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=3
 
 #
 # OMAP2/3 Display Device Drivers
@@ -1174,8 +1230,8 @@
 # CONFIG_PANEL_SHARP_LS037V7DW01 is not set
 # CONFIG_PANEL_N800 is not set
 CONFIG_PANEL_ZOOM2=y
-CONFIG_SIL9022=y
 # CONFIG_CTRL_BLIZZARD is not set
+CONFIG_SIL9022=y
 CONFIG_FB_OMAP2=y
 CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
 # CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
@@ -1213,6 +1269,9 @@
 CONFIG_SOUND=y
 # CONFIG_SOUND_OSS_CORE is not set
 CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
 # CONFIG_SND_SEQUENCER is not set
 # CONFIG_SND_MIXER_OSS is not set
 # CONFIG_SND_PCM_OSS is not set
@@ -1232,7 +1291,13 @@
 CONFIG_SND_USB=y
 # CONFIG_SND_USB_AUDIO is not set
 # CONFIG_SND_USB_CAIAQ is not set
-# CONFIG_SND_SOC is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_ZOOM2=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
 # CONFIG_SOUND_PRIME is not set
 CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
@@ -1276,14 +1341,14 @@
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 
 #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_OTG=y
@@ -1323,7 +1388,7 @@
 #
 # USB Device Class drivers
 #
-# CONFIG_USB_ACM is not set
+CONFIG_USB_ACM=m
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_WDM is not set
 # CONFIG_USB_TMC is not set
@@ -1335,7 +1400,19 @@
 #
 # see USB_STORAGE Help for more information
 #
-# CONFIG_USB_STORAGE is not set
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_DEBUG=y
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
 # CONFIG_USB_LIBUSUAL is not set
 
 #
@@ -1347,7 +1424,63 @@
 #
 # USB port drivers
 #
-# CONFIG_USB_SERIAL is not set
+CONFIG_USB_SERIAL=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
 
 #
 # USB Miscellaneous drivers
@@ -1396,14 +1529,17 @@
 # CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
-CONFIG_USB_ANDROID=y
+CONFIG_USB_ANDROID=m
 # CONFIG_USB_CDC_COMPOSITE is not set
 
 #
@@ -1424,7 +1560,7 @@
 #
 CONFIG_MMC_BLOCK=y
 CONFIG_MMC_BLOCK_BOUNCE=y
-CONFIG_MMC_BLOCK_PARANOID_RESUME=y
+# CONFIG_MMC_BLOCK_DEFERRED_RESUME is not set
 # CONFIG_SDIO_UART is not set
 # CONFIG_MMC_TEST is not set
 
@@ -1440,7 +1576,7 @@
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
 CONFIG_SWITCH=y
-# CONFIG_SWITCH_GPIO is not set
+CONFIG_SWITCH_GPIO=y
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1546,6 +1682,16 @@
 # CONFIG_BRIDGE_DEBUG is not set
 
 #
+# Bridge Hacking
+#
+# CONFIG_BRIDGE_CACHE_LINE_CHECK is not set
+
+#
+# Bridge Notifications
+#
+# CONFIG_BRIDGE_NTFY_PWRERR is not set
+
+#
 # File systems
 #
 CONFIG_EXT2_FS=y
@@ -1622,6 +1768,7 @@
 # CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
 # CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
 CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1759,6 +1906,7 @@
 # CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
 # CONFIG_DEBUG_KOBJECT is not set
 # CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_INFO=y
@@ -1776,7 +1924,10 @@
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
 
 #
 # Tracers
@@ -1789,6 +1940,7 @@
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_PRINTK_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
diff --git a/arch/arm/configs/zoom2_pm_defconfig b/arch/arm/configs/zoom3_defconfig
similarity index 68%
copy from arch/arm/configs/zoom2_pm_defconfig
copy to arch/arm/configs/zoom3_defconfig
index 28988a3..fb3a0ca 100644
--- a/arch/arm/configs/zoom2_pm_defconfig
+++ b/arch/arm/configs/zoom3_defconfig
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.29-omap1
-# Mon Aug  3 10:55:29 2009
+# Mon Feb 15 21:10:47 2010
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -23,6 +23,8 @@
 CONFIG_GENERIC_HWEIGHT=y
 CONFIG_GENERIC_CALIBRATE_DELAY=y
 CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_OPROFILE_OMAP_GPTIMER=y
+# CONFIG_OPROFILE_ARMV7 is not set
 CONFIG_VECTORS_BASE=0xffff0000
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
@@ -60,8 +62,7 @@
 CONFIG_USER_SCHED=y
 # CONFIG_CGROUP_SCHED is not set
 # CONFIG_CGROUPS is not set
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
 # CONFIG_RELAY is not set
 # CONFIG_NAMESPACES is not set
 CONFIG_BLK_DEV_INITRD=y
@@ -94,7 +95,10 @@
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
-# CONFIG_PROFILING is not set
+CONFIG_PROFILING=y
+CONFIG_TRACEPOINTS=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=y
 CONFIG_HAVE_OPROFILE=y
 # CONFIG_KPROBES is not set
 CONFIG_HAVE_KPROBES=y
@@ -108,7 +112,7 @@
 # CONFIG_MODULE_FORCE_LOAD is not set
 CONFIG_MODULE_UNLOAD=y
 # CONFIG_MODULE_FORCE_UNLOAD is not set
-CONFIG_MODVERSIONS=y
+# CONFIG_MODVERSIONS is not set
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
@@ -188,7 +192,7 @@
 # CONFIG_OMAP_DEBUG_POWERDOMAIN is not set
 # CONFIG_OMAP_DEBUG_CLOCKDOMAIN is not set
 CONFIG_OMAP_SMARTREFLEX=y
-# CONFIG_OMAP_SMARTREFLEX_TESTING is not set
+CONFIG_OMAP_SMARTREFLEX_TESTING=y
 CONFIG_OMAP_RESET_CLOCKS=y
 CONFIG_OMAP_BOOT_TAG=y
 CONFIG_OMAP_BOOT_REASON=y
@@ -198,8 +202,8 @@
 CONFIG_OMAP_MUX_DEBUG=y
 CONFIG_OMAP_MUX_WARNINGS=y
 CONFIG_OMAP_MCBSP=y
-# CONFIG_OMAP_MBOX_FWK is not set
-# CONFIG_OMAP_IOMMU is not set
+CONFIG_OMAP_MBOX_FWK=y
+CONFIG_OMAP_IOMMU=y
 # CONFIG_OMAP_MPU_TIMER is not set
 CONFIG_OMAP_32K_TIMER=y
 # CONFIG_OMAP3_DEBOBS is not set
@@ -209,11 +213,14 @@
 # CONFIG_OMAP_LL_DEBUG_UART1 is not set
 # CONFIG_OMAP_LL_DEBUG_UART2 is not set
 # CONFIG_OMAP_LL_DEBUG_UART3 is not set
-CONFIG_OMAP_LL_DEBUG_UART_EXT=y
+# CONFIG_OMAP_LL_DEBUG_UART_EXT is not set
+CONFIG_OMAP_LL_DEBUG_NONE=y
 CONFIG_OMAP_SERIAL_WAKE=y
 # CONFIG_OMAP_PM_NONE is not set
 # CONFIG_OMAP_PM_NOOP is not set
 CONFIG_OMAP_PM_SRF=y
+CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND=y
+CONFIG_VOLTSCALE_VPFORCE=y
 CONFIG_ARCH_OMAP34XX=y
 CONFIG_ARCH_OMAP3430=y
 
@@ -222,9 +229,13 @@
 #
 # CONFIG_MACH_NOKIA_RX51 is not set
 # CONFIG_MACH_OMAP_LDP is not set
-CONFIG_MACH_OMAP_ZOOM2=y
+# CONFIG_MACH_OMAP_ZOOM2 is not set
+CONFIG_MACH_OMAP_ZOOM3=y
+# CONFIG_MACH_OMAP_3630SDP is not set
+# CONFIG_L2CACHE_OMAP3_DISABLE is not set
 CONFIG_WIFI_CONTROL_FUNC=y
-# CONFIG_TIWLAN_SDIO is not set
+CONFIG_TIWLAN_SDIO=y
+CONFIG_TIWLAN_MMC_CONTROLLER=3
 # CONFIG_MACH_OMAP_3430SDP is not set
 # CONFIG_MACH_OMAP3EVM is not set
 # CONFIG_MACH_OMAP3_BEAGLE is not set
@@ -256,13 +267,17 @@
 # CONFIG_CPU_ICACHE_DISABLE is not set
 # CONFIG_CPU_DCACHE_DISABLE is not set
 # CONFIG_CPU_BPREDICT_DISABLE is not set
+# CONFIG_CPU_USER_L2_PLE_ACCESS is not set
 # CONFIG_HAS_TLS_REG is not set
 # CONFIG_OUTER_CACHE is not set
+CONFIG_ARM_L1_CACHE_SHIFT=6
 
 #
 # errata
 #
-# CONFIG_ARM_ERRATA_430973 is not set
+CONFIG_ARM_ERRATA_430973=y
+CONFIG_ARM_ERRATA_451027=y
+CONFIG_ARM_ERRATUM_451034=y
 
 #
 # Bus support
@@ -301,6 +316,7 @@
 CONFIG_ZONE_DMA_FLAG=0
 CONFIG_VIRT_TO_BUS=y
 CONFIG_UNEVICTABLE_LRU=y
+CONFIG_DEFAULT_MMAP_MIN_ADDR=4096
 # CONFIG_LEDS is not set
 CONFIG_ALIGNMENT_TRAP=y
 
@@ -328,9 +344,9 @@
 # CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
 CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
 # CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
-# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_USERSPACE=y
+CONFIG_CPU_FREQ_GOV_ONDEMAND=y
+CONFIG_CPU_FREQ_GOV_CONSERVATIVE=y
 CONFIG_CPU_FREQ_MIN_TICKS=10
 CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER=1000
 CONFIG_CPU_IDLE=y
@@ -357,7 +373,7 @@
 CONFIG_BINFMT_ELF=y
 # CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
 CONFIG_HAVE_AOUT=y
-CONFIG_BINFMT_AOUT=y
+# CONFIG_BINFMT_AOUT is not set
 CONFIG_BINFMT_MISC=y
 
 #
@@ -371,7 +387,15 @@
 CONFIG_SUSPEND=y
 # CONFIG_PM_TEST_SUSPEND is not set
 CONFIG_SUSPEND_FREEZER=y
-# CONFIG_WAKELOCK is not set
+CONFIG_HAS_WAKELOCK=y
+CONFIG_HAS_EARLYSUSPEND=y
+CONFIG_WAKELOCK=y
+CONFIG_WAKELOCK_STAT=y
+CONFIG_USER_WAKELOCK=y
+CONFIG_EARLYSUSPEND=y
+# CONFIG_NO_USER_SPACE_SCREEN_ACCESS_CONTROL is not set
+# CONFIG_CONSOLE_EARLYSUSPEND is not set
+CONFIG_FB_EARLYSUSPEND=y
 # CONFIG_APM_EMULATION is not set
 CONFIG_ARCH_SUSPEND_POSSIBLE=y
 CONFIG_NET=y
@@ -384,7 +408,7 @@
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
-# CONFIG_XFRM_USER is not set
+CONFIG_XFRM_USER=y
 # CONFIG_XFRM_SUB_POLICY is not set
 CONFIG_XFRM_MIGRATE=y
 # CONFIG_XFRM_STATISTICS is not set
@@ -392,8 +416,13 @@
 CONFIG_NET_KEY_MIGRATE=y
 CONFIG_INET=y
 CONFIG_IP_MULTICAST=y
-# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_ADVANCED_ROUTER=y
+CONFIG_ASK_IP_FIB_HASH=y
+# CONFIG_IP_FIB_TRIE is not set
 CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_MULTIPLE_TABLES is not set
+# CONFIG_IP_ROUTE_MULTIPATH is not set
+# CONFIG_IP_ROUTE_VERBOSE is not set
 CONFIG_IP_PNP=y
 CONFIG_IP_PNP_DHCP=y
 CONFIG_IP_PNP_BOOTP=y
@@ -421,7 +450,115 @@
 # CONFIG_IPV6 is not set
 CONFIG_ANDROID_PARANOID_NETWORK=y
 # CONFIG_NETWORK_SECMARK is not set
-# CONFIG_NETFILTER is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG is not set
+CONFIG_NF_CONNTRACK=y
+# CONFIG_NF_CT_ACCT is not set
+# CONFIG_NF_CONNTRACK_MARK is not set
+# CONFIG_NF_CONNTRACK_EVENTS is not set
+# CONFIG_NF_CT_PROTO_DCCP is not set
+# CONFIG_NF_CT_PROTO_SCTP is not set
+# CONFIG_NF_CT_PROTO_UDPLITE is not set
+# CONFIG_NF_CONNTRACK_AMANDA is not set
+CONFIG_NF_CONNTRACK_FTP=y
+CONFIG_NF_CONNTRACK_H323=y
+CONFIG_NF_CONNTRACK_IRC=y
+# CONFIG_NF_CONNTRACK_NETBIOS_NS is not set
+# CONFIG_NF_CONNTRACK_PPTP is not set
+# CONFIG_NF_CONNTRACK_SANE is not set
+CONFIG_NF_CONNTRACK_SIP=y
+CONFIG_NF_CONNTRACK_TFTP=y
+# CONFIG_NF_CT_NETLINK is not set
+# CONFIG_NETFILTER_TPROXY is not set
+CONFIG_NETFILTER_XTABLES=y
+CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y
+# CONFIG_NETFILTER_XT_TARGET_CONNMARK is not set
+# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
+# CONFIG_NETFILTER_XT_TARGET_MARK is not set
+# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_NOTRACK is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP is not set
+# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNBYTES is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNMARK is not set
+# CONFIG_NETFILTER_XT_MATCH_CONNTRACK is not set
+# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
+# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
+# CONFIG_NETFILTER_XT_MATCH_ESP is not set
+# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_HELPER is not set
+CONFIG_NETFILTER_XT_MATCH_IPRANGE=y
+# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
+# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
+CONFIG_NETFILTER_XT_MATCH_MAC=y
+# CONFIG_NETFILTER_XT_MATCH_MARK is not set
+CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT is not set
+# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
+# CONFIG_NETFILTER_XT_MATCH_STATE is not set
+# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
+# CONFIG_NETFILTER_XT_MATCH_STRING is not set
+# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
+# CONFIG_NETFILTER_XT_MATCH_TIME is not set
+# CONFIG_NETFILTER_XT_MATCH_U32 is not set
+# CONFIG_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+CONFIG_NF_DEFRAG_IPV4=y
+CONFIG_NF_CONNTRACK_IPV4=y
+CONFIG_NF_CONNTRACK_PROC_COMPAT=y
+# CONFIG_IP_NF_QUEUE is not set
+CONFIG_IP_NF_IPTABLES=y
+# CONFIG_IP_NF_MATCH_ADDRTYPE is not set
+# CONFIG_IP_NF_MATCH_AH is not set
+# CONFIG_IP_NF_MATCH_ECN is not set
+# CONFIG_IP_NF_MATCH_TTL is not set
+CONFIG_IP_NF_FILTER=y
+# CONFIG_IP_NF_TARGET_REJECT is not set
+# CONFIG_IP_NF_TARGET_LOG is not set
+# CONFIG_IP_NF_TARGET_ULOG is not set
+CONFIG_NF_NAT=y
+CONFIG_NF_NAT_NEEDED=y
+CONFIG_IP_NF_TARGET_MASQUERADE=y
+# CONFIG_IP_NF_TARGET_NETMAP is not set
+CONFIG_IP_NF_TARGET_REDIRECT=y
+# CONFIG_IP_NF_TARGET_IDLETIMER is not set
+# CONFIG_NF_NAT_SNMP_BASIC is not set
+CONFIG_NF_NAT_FTP=y
+CONFIG_NF_NAT_IRC=y
+CONFIG_NF_NAT_TFTP=y
+# CONFIG_NF_NAT_AMANDA is not set
+# CONFIG_NF_NAT_PPTP is not set
+CONFIG_NF_NAT_H323=y
+CONFIG_NF_NAT_SIP=y
+CONFIG_IP_NF_MANGLE=y
+# CONFIG_IP_NF_TARGET_CLUSTERIP is not set
+# CONFIG_IP_NF_TARGET_ECN is not set
+# CONFIG_IP_NF_TARGET_TTL is not set
+CONFIG_IP_NF_RAW=y
+CONFIG_IP_NF_ARPTABLES=y
+CONFIG_IP_NF_ARPFILTER=y
+CONFIG_IP_NF_ARP_MANGLE=y
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
@@ -436,7 +573,7 @@
 # CONFIG_X25 is not set
 # CONFIG_LAPB is not set
 # CONFIG_ECONET is not set
-# CONFIG_WAN_ROUTER is not set
+CONFIG_WAN_ROUTER=y
 # CONFIG_NET_SCHED is not set
 # CONFIG_DCB is not set
 
@@ -497,15 +634,16 @@
 CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
 CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
-# CONFIG_FW_LOADER is not set
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
 # CONFIG_DEBUG_DRIVER is not set
 # CONFIG_DEBUG_DEVRES is not set
 # CONFIG_SYS_HYPERVISOR is not set
 CONFIG_CONNECTOR=y
 CONFIG_PROC_EVENTS=y
 CONFIG_MTD=y
-CONFIG_MTD_DEBUG=y
-CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_DEBUG is not set
 CONFIG_MTD_CONCAT=y
 CONFIG_MTD_PARTITIONS=y
 # CONFIG_MTD_TESTS is not set
@@ -530,8 +668,10 @@
 #
 # RAM/ROM/Flash chip drivers
 #
-# CONFIG_MTD_CFI is not set
+CONFIG_MTD_CFI=y
 # CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_GEN_PROBE=y
+# CONFIG_MTD_CFI_ADV_OPTIONS is not set
 CONFIG_MTD_MAP_BANK_WIDTH_1=y
 CONFIG_MTD_MAP_BANK_WIDTH_2=y
 CONFIG_MTD_MAP_BANK_WIDTH_4=y
@@ -542,6 +682,10 @@
 CONFIG_MTD_CFI_I2=y
 # CONFIG_MTD_CFI_I4 is not set
 # CONFIG_MTD_CFI_I8 is not set
+CONFIG_MTD_CFI_INTELEXT=y
+# CONFIG_MTD_CFI_AMDSTD is not set
+# CONFIG_MTD_CFI_STAA is not set
+CONFIG_MTD_CFI_UTIL=y
 # CONFIG_MTD_RAM is not set
 # CONFIG_MTD_ROM is not set
 # CONFIG_MTD_ABSENT is not set
@@ -550,6 +694,9 @@
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PHYSMAP is not set
+# CONFIG_MTD_ARM_INTEGRATOR is not set
+CONFIG_MTD_OMAP_NOR=y
 # CONFIG_MTD_PLATRAM is not set
 
 #
@@ -574,7 +721,8 @@
 # CONFIG_MTD_NAND_MUSEUM_IDS is not set
 # CONFIG_MTD_NAND_GPIO is not set
 CONFIG_MTD_NAND_OMAP2=y
-CONFIG_MTD_NAND_OMAP_HWECC=y
+CONFIG_MTD_NAND_OMAP_PREFETCH=y
+# CONFIG_MTD_NAND_OMAP_PREFETCH_DMA is not set
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_NANDSIM is not set
@@ -600,7 +748,7 @@
 # CONFIG_BLK_DEV_UB is not set
 CONFIG_BLK_DEV_RAM=y
 CONFIG_BLK_DEV_RAM_COUNT=16
-CONFIG_BLK_DEV_RAM_SIZE=4096
+CONFIG_BLK_DEV_RAM_SIZE=16384
 # CONFIG_BLK_DEV_XIP is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
@@ -611,7 +759,10 @@
 # CONFIG_ENCLOSURE_SERVICES is not set
 # CONFIG_KERNEL_DEBUGGER_CORE is not set
 # CONFIG_UID_STAT is not set
-# CONFIG_WL127X_RFKILL is not set
+CONFIG_WL127X_RFKILL=y
+# CONFIG_APANIC is not set
+CONFIG_APANIC_PLABEL="kpanic"
+CONFIG_BUILD_TI_ST=y
 # CONFIG_C2PORT is not set
 
 #
@@ -621,6 +772,14 @@
 # CONFIG_EEPROM_AT25 is not set
 # CONFIG_EEPROM_LEGACY is not set
 # CONFIG_EEPROM_93CX6 is not set
+
+#
+# Texas Instruments shared transport line discipline
+#
+CONFIG_TI_ST=m
+CONFIG_TI_ST_BT=m
+CONFIG_TI_ST_FM=m
+CONFIG_TI_ST_GPS=m
 CONFIG_HAVE_IDE=y
 # CONFIG_IDE is not set
 
@@ -661,7 +820,10 @@
 # CONFIG_SCSI_ISCSI_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
 # CONFIG_SCSI_SRP_ATTRS is not set
-# CONFIG_SCSI_LOWLEVEL is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_DH is not set
 # CONFIG_ATA is not set
 # CONFIG_MD is not set
@@ -670,17 +832,36 @@
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
-CONFIG_TUN=y
+# CONFIG_TUN is not set
 # CONFIG_VETH is not set
-# CONFIG_PHYLIB is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
 # CONFIG_ENC28J60 is not set
-CONFIG_SMC911X=y
-# CONFIG_SMSC911X is not set
+# CONFIG_SMC911X is not set
+CONFIG_SMSC911X=y
 # CONFIG_DNET is not set
 # CONFIG_IBM_NEW_EMAC_ZMII is not set
 # CONFIG_IBM_NEW_EMAC_RGMII is not set
@@ -690,8 +871,8 @@
 # CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
 # CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
 # CONFIG_B44 is not set
-# CONFIG_NETDEV_1000 is not set
-# CONFIG_NETDEV_10000 is not set
+CONFIG_NETDEV_1000=y
+CONFIG_NETDEV_10000=y
 
 #
 # Wireless LAN
@@ -778,8 +959,8 @@
 # CONFIG_INPUT_POWERMATE is not set
 # CONFIG_INPUT_YEALINK is not set
 # CONFIG_INPUT_CM109 is not set
-CONFIG_INPUT_TWL4030_PWRBUTTON=y
-# CONFIG_INPUT_UINPUT is not set
+# CONFIG_INPUT_TWL4030_PWRBUTTON is not set
+CONFIG_INPUT_UINPUT=y
 # CONFIG_INPUT_GPIO is not set
 # CONFIG_INPUT_KEYCHORD is not set
 
@@ -804,22 +985,20 @@
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=y
-CONFIG_SERIAL_8250_CONSOLE=y
-CONFIG_SERIAL_8250_NR_UARTS=32
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-CONFIG_SERIAL_8250_EXTENDED=y
-CONFIG_SERIAL_8250_MANY_PORTS=y
-CONFIG_SERIAL_8250_SHARE_IRQ=y
-CONFIG_SERIAL_8250_DETECT_IRQ=y
-CONFIG_SERIAL_8250_RSA=y
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
 #
 CONFIG_SERIAL_CORE=y
 CONFIG_SERIAL_CORE_CONSOLE=y
-# CONFIG_SERIAL_OMAP is not set
+CONFIG_SERIAL_OMAP=y
+CONFIG_SERIAL_OMAP_CONSOLE=y
+# CONFIG_SERIAL_OMAP_DMA_UART1 is not set
+CONFIG_SERIAL_OMAP_DMA_UART2=y
+CONFIG_SERIAL_OMAP_UART2_RXDMA_TIMEOUT=1
+CONFIG_SERIAL_OMAP_UART2_RXDMA_BUFSIZE=4096
+# CONFIG_SERIAL_OMAP_DMA_UART3 is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
 # CONFIG_LEGACY_PTYS is not set
@@ -877,7 +1056,7 @@
 # CONFIG_I2C_DEBUG_BUS is not set
 # CONFIG_I2C_DEBUG_CHIP is not set
 CONFIG_SPI=y
-CONFIG_SPI_DEBUG=y
+# CONFIG_SPI_DEBUG is not set
 CONFIG_SPI_MASTER=y
 
 #
@@ -940,7 +1119,7 @@
 # CONFIG_W1_SLAVE_DS2431 is not set
 # CONFIG_W1_SLAVE_DS2433 is not set
 # CONFIG_W1_SLAVE_DS2760 is not set
-# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_W1_SLAVE_BQ27000=y
 CONFIG_POWER_SUPPLY=y
 # CONFIG_POWER_SUPPLY_DEBUG is not set
 # CONFIG_PDA_POWER is not set
@@ -951,7 +1130,7 @@
 # CONFIG_THERMAL is not set
 # CONFIG_THERMAL_HWMON is not set
 CONFIG_WATCHDOG=y
-# CONFIG_WATCHDOG_NOWAYOUT is not set
+CONFIG_WATCHDOG_NOWAYOUT=y
 
 #
 # Watchdog Device Drivers
@@ -997,24 +1176,186 @@
 #
 # Multimedia core support
 #
-# CONFIG_VIDEO_DEV is not set
+CONFIG_VIDEO_DEV=y
+CONFIG_VIDEO_V4L2_COMMON=y
+CONFIG_VIDEO_ALLOW_V4L1=y
+CONFIG_VIDEO_V4L1_COMPAT=y
 # CONFIG_DVB_CORE is not set
-# CONFIG_VIDEO_MEDIA is not set
+CONFIG_VIDEO_MEDIA=y
 
 #
 # Multimedia drivers
 #
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=y
+# CONFIG_MEDIA_TUNER_CUSTOMIZE is not set
+CONFIG_MEDIA_TUNER_SIMPLE=y
+CONFIG_MEDIA_TUNER_TDA8290=y
+CONFIG_MEDIA_TUNER_TDA9887=y
+CONFIG_MEDIA_TUNER_TEA5761=y
+CONFIG_MEDIA_TUNER_TEA5767=y
+CONFIG_MEDIA_TUNER_MT20XX=y
+CONFIG_MEDIA_TUNER_XC2028=y
+CONFIG_MEDIA_TUNER_XC5000=y
+CONFIG_VIDEO_V4L2=y
+CONFIG_VIDEO_V4L1=y
+CONFIG_VIDEOBUF_GEN=y
+CONFIG_VIDEOBUF_DMA_SG=y
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+# CONFIG_VIDEO_FIXED_MINOR_RANGES is not set
+# CONFIG_VIDEO_HELPER_CHIPS_AUTO is not set
+
+#
+# Encoders/decoders and other helper chips
+#
+
+#
+# Audio decoders
+#
+# CONFIG_VIDEO_TVAUDIO is not set
+# CONFIG_VIDEO_TDA7432 is not set
+# CONFIG_VIDEO_TDA9840 is not set
+# CONFIG_VIDEO_TDA9875 is not set
+# CONFIG_VIDEO_TEA6415C is not set
+# CONFIG_VIDEO_TEA6420 is not set
+# CONFIG_VIDEO_MSP3400 is not set
+# CONFIG_VIDEO_CS5345 is not set
+# CONFIG_VIDEO_CS53L32A is not set
+# CONFIG_VIDEO_M52790 is not set
+# CONFIG_VIDEO_TLV320AIC23B is not set
+# CONFIG_VIDEO_WM8775 is not set
+# CONFIG_VIDEO_WM8739 is not set
+# CONFIG_VIDEO_VP27SMPX is not set
+
+#
+# Video decoders
+#
+# CONFIG_VIDEO_BT819 is not set
+# CONFIG_VIDEO_BT856 is not set
+# CONFIG_VIDEO_BT866 is not set
+# CONFIG_VIDEO_KS0127 is not set
+# CONFIG_VIDEO_OV7670 is not set
+# CONFIG_VIDEO_TCM825X is not set
+CONFIG_VIDEO_IMX046=y
+CONFIG_VIDEO_LV8093=y
+# CONFIG_VIDEO_SAA7110 is not set
+# CONFIG_VIDEO_SAA7111 is not set
+# CONFIG_VIDEO_SAA7114 is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_SAA7191 is not set
+# CONFIG_VIDEO_TVP514X is not set
+# CONFIG_VIDEO_TVP5150 is not set
+# CONFIG_VIDEO_VPX3220 is not set
+
+#
+# Video and audio decoders
+#
+# CONFIG_VIDEO_CX25840 is not set
+
+#
+# MPEG video encoders
+#
+# CONFIG_VIDEO_CX2341X is not set
+
+#
+# Video encoders
+#
+# CONFIG_VIDEO_SAA7127 is not set
+# CONFIG_VIDEO_SAA7185 is not set
+# CONFIG_VIDEO_ADV7170 is not set
+# CONFIG_VIDEO_ADV7175 is not set
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+CONFIG_VIDEO_OMAP3=y
+CONFIG_VIDEO_OMAP3_V4L2=y
+CONFIG_VIDEO_OMAP_VIDEOLIB=y
+CONFIG_VIDEO_OMAP_VIDEOOUT=y
+CONFIG_NTSC_M=y
+# CONFIG_PAL_BDGHI is not set
+CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER=y
+CONFIG_VIDEO_OMAP34XX_ISP_RESIZER=y
+# CONFIG_SOC_CAMERA is not set
+# CONFIG_V4L_USB_DRIVERS is not set
+# CONFIG_RADIO_ADAPTERS is not set
 # CONFIG_DAB is not set
 
 #
 # Graphics support
 #
 # CONFIG_VGASTATE is not set
-# CONFIG_VIDEO_OUTPUT_CONTROL is not set
-# CONFIG_FB is not set
-# CONFIG_FB_OMAP_LCD_WVGA is not set
-# CONFIG_OMAP2_DSS is not set
-# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+CONFIG_VIDEO_OUTPUT_CONTROL=m
+CONFIG_FB=y
+CONFIG_FIRMWARE_EDID=y
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+CONFIG_FB_MODE_HELPERS=y
+CONFIG_FB_TILEBLITTING=y
+
+#
+# Frame buffer hardware drivers
+#
+# CONFIG_FB_UVESA is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+# CONFIG_FB_OMAP_BOOTLOADER_INIT is not set
+CONFIG_OMAP2_DSS=y
+CONFIG_OMAP2_DSS_VRAM_SIZE=4
+CONFIG_OMAP2_DSS_DEBUG_SUPPORT=y
+# CONFIG_OMAP2_DSS_RFBI is not set
+# CONFIG_OMAP2_DSS_VENC is not set
+# CONFIG_OMAP2_DSS_SDI is not set
+CONFIG_OMAP2_DSS_DSI=y
+# CONFIG_OMAP2_DSS_FAKE_VSYNC is not set
+CONFIG_OMAP2_DSS_MIN_FCK_PER_PCK=2
+
+#
+# OMAP2/3 Display Device Drivers
+#
+# CONFIG_PANEL_GENERIC is not set
+# CONFIG_PANEL_SAMSUNG_LTE430WQ_F0C is not set
+# CONFIG_PANEL_SHARP_LS037V7DW01 is not set
+# CONFIG_PANEL_N800 is not set
+CONFIG_PANEL_ZOOM2=y
+# CONFIG_CTRL_BLIZZARD is not set
+CONFIG_SIL9022=y
+CONFIG_FB_OMAP2=y
+CONFIG_FB_OMAP2_DEBUG_SUPPORT=y
+# CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE is not set
+CONFIG_FB_OMAP2_NUM_FBS=1
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_LCD_CLASS_DEVICE=y
+# CONFIG_LCD_LTV350QV is not set
+# CONFIG_LCD_ILI9320 is not set
+# CONFIG_LCD_TDO24M is not set
+# CONFIG_LCD_VGG2432A4 is not set
+CONFIG_LCD_PLATFORM=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_GENERIC=y
 
 #
 # Display device support
@@ -1026,22 +1367,99 @@
 #
 # CONFIG_VGA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
-# CONFIG_SOUND is not set
-# CONFIG_HID_SUPPORT is not set
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+# CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
+# CONFIG_FONTS is not set
+CONFIG_FONT_8x8=y
+CONFIG_FONT_8x16=y
+CONFIG_LOGO=y
+CONFIG_LOGO_LINUX_MONO=y
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_SOUND=y
+# CONFIG_SOUND_OSS_CORE is not set
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_JACK=y
+# CONFIG_SND_SEQUENCER is not set
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
+# CONFIG_SND_HRTIMER is not set
+# CONFIG_SND_DYNAMIC_MINORS is not set
+CONFIG_SND_SUPPORT_OLD_API=y
+CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+CONFIG_SND_DRIVERS=y
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+CONFIG_SND_ARM=y
+CONFIG_SND_SPI=y
+CONFIG_SND_USB=y
+# CONFIG_SND_USB_AUDIO is not set
+# CONFIG_SND_USB_CAIAQ is not set
+CONFIG_SND_SOC=y
+CONFIG_SND_OMAP_SOC=y
+CONFIG_SND_OMAP_SOC_MCBSP=y
+CONFIG_SND_OMAP_SOC_ZOOM2=y
+CONFIG_SND_SOC_I2C_AND_SPI=y
+# CONFIG_SND_SOC_ALL_CODECS is not set
+CONFIG_SND_SOC_TWL4030=y
+# CONFIG_SOUND_PRIME is not set
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_EZKEY is not set
+# CONFIG_HID_GYRATION is not set
+# CONFIG_HID_LOGITECH is not set
+# CONFIG_HID_MICROSOFT is not set
+# CONFIG_HID_MONTEREY is not set
+# CONFIG_HID_NTRIG is not set
+# CONFIG_HID_PANTHERLORD is not set
+# CONFIG_HID_PETALYNX is not set
+# CONFIG_HID_SAMSUNG is not set
+# CONFIG_HID_SONY is not set
+# CONFIG_HID_SUNPLUS is not set
+# CONFIG_GREENASIA_FF is not set
+# CONFIG_HID_TOPSEED is not set
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
 CONFIG_USB=y
-# CONFIG_USB_DEBUG is not set
-# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+CONFIG_USB_DEBUG=y
+CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
 
 #
 # Miscellaneous USB options
 #
 CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DEVICE_CLASS is not set
 # CONFIG_USB_DYNAMIC_MINORS is not set
 CONFIG_USB_SUSPEND=y
 CONFIG_USB_OTG=y
@@ -1081,7 +1499,7 @@
 #
 # USB Device Class drivers
 #
-# CONFIG_USB_ACM is not set
+CONFIG_USB_ACM=m
 # CONFIG_USB_PRINTER is not set
 # CONFIG_USB_WDM is not set
 # CONFIG_USB_TMC is not set
@@ -1093,8 +1511,8 @@
 #
 # see USB_STORAGE Help for more information
 #
-CONFIG_USB_STORAGE=y
-# CONFIG_USB_STORAGE_DEBUG is not set
+CONFIG_USB_STORAGE=m
+CONFIG_USB_STORAGE_DEBUG=y
 # CONFIG_USB_STORAGE_DATAFAB is not set
 # CONFIG_USB_STORAGE_FREECOM is not set
 # CONFIG_USB_STORAGE_ISD200 is not set
@@ -1117,7 +1535,63 @@
 #
 # USB port drivers
 #
-# CONFIG_USB_SERIAL is not set
+CONFIG_USB_SERIAL=m
+CONFIG_USB_EZUSB=y
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_CH341 is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_FUNSOFT is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_IUU is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+CONFIG_USB_SERIAL_KEYSPAN=m
+# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
+# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_MOS7720 is not set
+# CONFIG_USB_SERIAL_MOS7840 is not set
+# CONFIG_USB_SERIAL_MOTOROLA is not set
+# CONFIG_USB_SERIAL_NAVMAN is not set
+# CONFIG_USB_SERIAL_PL2303 is not set
+# CONFIG_USB_SERIAL_OTI6858 is not set
+# CONFIG_USB_SERIAL_SPCP8X5 is not set
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_SIEMENS_MPI is not set
+# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OPTION is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+# CONFIG_USB_SERIAL_OPTICON is not set
+# CONFIG_USB_SERIAL_DEBUG is not set
 
 #
 # USB Miscellaneous drivers
@@ -1144,9 +1618,9 @@
 # CONFIG_USB_ISIGHTFW is not set
 # CONFIG_USB_VST is not set
 CONFIG_USB_GADGET=y
-CONFIG_USB_GADGET_DEBUG=y
-CONFIG_USB_GADGET_DEBUG_FILES=y
-CONFIG_USB_GADGET_DEBUG_FS=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
 CONFIG_USB_GADGET_VBUS_DRAW=2
 CONFIG_USB_GADGET_SELECTED=y
 # CONFIG_USB_GADGET_AT91 is not set
@@ -1166,14 +1640,17 @@
 # CONFIG_USB_GADGET_GOKU is not set
 # CONFIG_USB_GADGET_DUMMY_HCD is not set
 CONFIG_USB_GADGET_DUALSPEED=y
-# CONFIG_USB_ZERO is not set
-# CONFIG_USB_ETH is not set
-# CONFIG_USB_GADGETFS is not set
-# CONFIG_USB_FILE_STORAGE is not set
-# CONFIG_USB_G_SERIAL is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ZERO_HNPTEST is not set
+CONFIG_USB_ETH=m
+CONFIG_USB_ETH_RNDIS=y
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
 # CONFIG_USB_MIDI_GADGET is not set
 # CONFIG_USB_G_PRINTER is not set
-CONFIG_USB_ANDROID=y
+CONFIG_USB_ANDROID=m
 # CONFIG_USB_CDC_COMPOSITE is not set
 
 #
@@ -1204,13 +1681,14 @@
 # CONFIG_MMC_SDHCI is not set
 CONFIG_MMC_OMAP_HS=y
 # CONFIG_OMAP_HS_MMC2 is not set
-# CONFIG_OMAP_HS_MMC3 is not set
+CONFIG_OMAP_HS_MMC3=y
+CONFIG_HC_Broken_eMMC_ZOOM2=y
 # CONFIG_MMC_SPI is not set
 # CONFIG_MEMSTICK is not set
 # CONFIG_ACCESSIBILITY is not set
 # CONFIG_NEW_LEDS is not set
 CONFIG_SWITCH=y
-# CONFIG_SWITCH_GPIO is not set
+CONFIG_SWITCH_GPIO=y
 CONFIG_RTC_LIB=y
 CONFIG_RTC_CLASS=y
 CONFIG_RTC_HCTOSYS=y
@@ -1276,7 +1754,7 @@
 #
 # CONFIG_DMADEVICES is not set
 CONFIG_REGULATOR=y
-CONFIG_REGULATOR_DEBUG=y
+# CONFIG_REGULATOR_DEBUG is not set
 # CONFIG_REGULATOR_FIXED_VOLTAGE is not set
 # CONFIG_REGULATOR_VIRTUAL_CONSUMER is not set
 # CONFIG_REGULATOR_BQ24022 is not set
@@ -1310,7 +1788,20 @@
 # CBUS support
 #
 # CONFIG_CBUS is not set
-# CONFIG_MPU_BRIDGE is not set
+CONFIG_MPU_BRIDGE=y
+CONFIG_BRIDGE_DVFS=y
+CONFIG_BRIDGE_MEMPOOL_SIZE=0x600000
+# CONFIG_BRIDGE_DEBUG is not set
+
+#
+# Bridge Hacking
+#
+# CONFIG_BRIDGE_CACHE_LINE_CHECK is not set
+
+#
+# Bridge Notifications
+#
+# CONFIG_BRIDGE_NTFY_PWRERR is not set
 
 #
 # File systems
@@ -1379,7 +1870,17 @@
 # CONFIG_BEFS_FS is not set
 # CONFIG_BFS_FS is not set
 # CONFIG_EFS_FS is not set
-# CONFIG_YAFFS_FS is not set
+CONFIG_YAFFS_FS=y
+CONFIG_YAFFS_YAFFS1=y
+# CONFIG_YAFFS_9BYTE_TAGS is not set
+# CONFIG_YAFFS_DOES_ECC is not set
+CONFIG_YAFFS_YAFFS2=y
+CONFIG_YAFFS_AUTO_YAFFS2=y
+# CONFIG_YAFFS_DISABLE_LAZY_LOAD is not set
+# CONFIG_YAFFS_DISABLE_WIDE_TNODES is not set
+# CONFIG_YAFFS_ALWAYS_CHECK_CHUNK_ERASED is not set
+CONFIG_YAFFS_SHORT_NAMES_IN_RAM=y
+# CONFIG_YAFFS_EMPTY_LOST_AND_FOUND is not set
 CONFIG_JFFS2_FS=y
 CONFIG_JFFS2_FS_DEBUG=0
 CONFIG_JFFS2_FS_WRITEBUFFER=y
@@ -1517,8 +2018,9 @@
 # CONFIG_LOCK_STAT is not set
 # CONFIG_DEBUG_SPINLOCK_SLEEP is not set
 # CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+CONFIG_STACKTRACE=y
 # CONFIG_DEBUG_KOBJECT is not set
-CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_DEBUG_INFO=y
 # CONFIG_DEBUG_VM is not set
 # CONFIG_DEBUG_WRITECOUNT is not set
@@ -1534,7 +2036,10 @@
 # CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
 # CONFIG_FAULT_INJECTION is not set
 # CONFIG_LATENCYTOP is not set
+CONFIG_NOP_TRACER=y
 CONFIG_HAVE_FUNCTION_TRACER=y
+CONFIG_RING_BUFFER=y
+CONFIG_TRACING=y
 
 #
 # Tracers
@@ -1547,6 +2052,7 @@
 # CONFIG_BOOT_TRACER is not set
 # CONFIG_TRACE_BRANCH_PROFILING is not set
 # CONFIG_STACK_TRACER is not set
+# CONFIG_FTRACE_STARTUP_TEST is not set
 # CONFIG_DYNAMIC_PRINTK_DEBUG is not set
 # CONFIG_SAMPLES is not set
 CONFIG_HAVE_ARCH_KGDB=y
@@ -1554,8 +2060,7 @@
 # CONFIG_DEBUG_USER is not set
 # CONFIG_DEBUG_ERRORS is not set
 # CONFIG_DEBUG_STACK_USAGE is not set
-CONFIG_DEBUG_LL=y
-# CONFIG_DEBUG_ICEDCC is not set
+# CONFIG_DEBUG_LL is not set
 
 #
 # Security options
diff --git a/arch/arm/include/asm/cache.h b/arch/arm/include/asm/cache.h
index cb7a9e9..66c160b 100644
--- a/arch/arm/include/asm/cache.h
+++ b/arch/arm/include/asm/cache.h
@@ -4,7 +4,23 @@
 #ifndef __ASMARM_CACHE_H
 #define __ASMARM_CACHE_H
 
-#define L1_CACHE_SHIFT		5
+#define L1_CACHE_SHIFT		CONFIG_ARM_L1_CACHE_SHIFT
 #define L1_CACHE_BYTES		(1 << L1_CACHE_SHIFT)
 
+/*
+ * Memory returned by kmalloc() may be used for DMA, so we must make
+ * sure that all such allocations are cache aligned. Otherwise,
+ * unrelated code may cause parts of the buffer to be read into the
+ * cache before the transfer is done, causing old data to be seen by
+ * the CPU.
+ */
+#define ARCH_KMALLOC_MINALIGN	L1_CACHE_BYTES
+
+/*
+ * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
+ */
+#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
+#define ARCH_SLAB_MINALIGN 8
+#endif
+
 #endif
diff --git a/arch/arm/include/asm/hwcap.h b/arch/arm/include/asm/hwcap.h
index bda489f..f7bd52b 100644
--- a/arch/arm/include/asm/hwcap.h
+++ b/arch/arm/include/asm/hwcap.h
@@ -17,6 +17,8 @@
 #define HWCAP_CRUNCH	1024
 #define HWCAP_THUMBEE	2048
 #define HWCAP_NEON	4096
+#define HWCAP_VFPv3	8192
+#define HWCAP_VFPv3D16	16384
 
 #if defined(__KERNEL__) && !defined(__ASSEMBLY__)
 /*
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index cbdadfe..d2a59cf 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -75,12 +75,6 @@
 extern void __iounmap(volatile void __iomem *addr);
 
 /*
- * external interface to remap single page with appropriate type
- */
-extern int ioremap_page(unsigned long virt, unsigned long phys,
-			unsigned int mtype);
-
-/*
  * Bad read/write accesses...
  */
 extern void __readwrite_bug(const char *fn);
diff --git a/arch/arm/include/asm/mach/map.h b/arch/arm/include/asm/mach/map.h
index 58cf91f..742c2aa 100644
--- a/arch/arm/include/asm/mach/map.h
+++ b/arch/arm/include/asm/mach/map.h
@@ -30,6 +30,14 @@
 
 #ifdef CONFIG_MMU
 extern void iotable_init(struct map_desc *, int);
+
+struct mem_type;
+extern const struct mem_type *get_mem_type(unsigned int type);
+/*
+ * external interface to remap single page with appropriate type
+ */
+extern int ioremap_page(unsigned long virt, unsigned long phys,
+			const struct mem_type *mtype);
 #else
 #define iotable_init(map,num)	do { } while (0)
 #endif
diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index f341c9d..1c75656 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -194,13 +194,6 @@
 	(((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \
 	 VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
 
-/*
- * With EABI on ARMv5 and above we must have 64-bit aligned slab pointers.
- */
-#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5)
-#define ARCH_SLAB_MINALIGN 8
-#endif
-
 #include <asm-generic/page.h>
 
 #endif
diff --git a/arch/arm/include/asm/ptrace.h b/arch/arm/include/asm/ptrace.h
index 7319261..236a06b 100644
--- a/arch/arm/include/asm/ptrace.h
+++ b/arch/arm/include/asm/ptrace.h
@@ -27,6 +27,8 @@
 /* PTRACE_SYSCALL is 24 */
 #define PTRACE_GETCRUNCHREGS	25
 #define PTRACE_SETCRUNCHREGS	26
+#define PTRACE_GETVFPREGS	27
+#define PTRACE_SETVFPREGS	28
 
 /*
  * PSR bits
diff --git a/arch/arm/include/asm/thread_info.h b/arch/arm/include/asm/thread_info.h
index 68b9ec8..b9dc8a8 100644
--- a/arch/arm/include/asm/thread_info.h
+++ b/arch/arm/include/asm/thread_info.h
@@ -113,6 +113,8 @@
 extern void iwmmxt_task_release(struct thread_info *);
 extern void iwmmxt_task_switch(struct thread_info *);
 
+extern void vfp_sync_state(struct thread_info *thread);
+
 #endif
 
 /*
diff --git a/arch/arm/include/asm/user.h b/arch/arm/include/asm/user.h
index 825c1e7..df95e05 100644
--- a/arch/arm/include/asm/user.h
+++ b/arch/arm/include/asm/user.h
@@ -81,4 +81,13 @@
 #define HOST_TEXT_START_ADDR (u.start_code)
 #define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG)
 
+/*
+ * User specific VFP registers. If only VFPv2 is present, registers 16 to 31
+ * are ignored by the ptrace system call.
+ */
+struct user_vfp {
+	unsigned long long fpregs[32];
+	unsigned long fpscr;
+};
+
 #endif /* _ARM_USER_H */
diff --git a/arch/arm/include/asm/vfpmacros.h b/arch/arm/include/asm/vfpmacros.h
index 422f3cc..934798b 100644
--- a/arch/arm/include/asm/vfpmacros.h
+++ b/arch/arm/include/asm/vfpmacros.h
@@ -32,6 +32,9 @@
 
 	@ write all the working registers out of the VFP
 	.macro	VFPFSTMIA, base, tmp
+#ifdef CONFIG_ARM_ERRATUM_451034
+	dmb
+#endif
 #if __LINUX_ARM_ARCH__ < 6
 	STC	p11, cr0, [\base],#33*4		    @ FSTMIAX \base!, {d0-d15}
 #else
diff --git a/arch/arm/kernel/entry-armv.S b/arch/arm/kernel/entry-armv.S
index 85040cf..4c482b1 100644
--- a/arch/arm/kernel/entry-armv.S
+++ b/arch/arm/kernel/entry-armv.S
@@ -154,6 +154,9 @@
 __dabt_svc:
 	svc_entry
 
+#ifdef CONFIG_ARM_ERRATA_451027
+        dmb
+#endif
 	@
 	@ get ready to re-enable interrupts if appropriate
 	@
diff --git a/arch/arm/kernel/entry-common.S b/arch/arm/kernel/entry-common.S
index 159d041..8f7fe18 100644
--- a/arch/arm/kernel/entry-common.S
+++ b/arch/arm/kernel/entry-common.S
@@ -69,6 +69,9 @@
 	/* perform architecture specific actions before user return */
 	arch_ret_to_user r1, lr
 
+#ifdef CONFIG_ARM_ERRATUM_451034
+	dmb
+#endif
 	@ slow_restore_user_regs
 	ldr	r1, [sp, #S_PSR]		@ get calling cpsr
 	ldr	lr, [sp, #S_PC]!		@ get pc
diff --git a/arch/arm/kernel/process.c b/arch/arm/kernel/process.c
index 994b4d3..f884b85 100644
--- a/arch/arm/kernel/process.c
+++ b/arch/arm/kernel/process.c
@@ -234,7 +234,7 @@
 		printk("%04lx ", (unsigned long)p & 0xffff);
 		for (j = 0; j < 8; j++) {
 			u32	data;
-			if (__get_user(data, p)) {
+			if (probe_kernel_address(p, data)) {
 				printk(" ********");
 			} else {
 				printk(" %08x", data);
diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
index df653ea..89882a1 100644
--- a/arch/arm/kernel/ptrace.c
+++ b/arch/arm/kernel/ptrace.c
@@ -653,6 +653,54 @@
 }
 #endif
 
+#ifdef CONFIG_VFP
+/*
+ * Get the child VFP state.
+ */
+static int ptrace_getvfpregs(struct task_struct *tsk, void __user *data)
+{
+	struct thread_info *thread = task_thread_info(tsk);
+	union vfp_state *vfp = &thread->vfpstate;
+	struct user_vfp __user *ufp = data;
+
+	vfp_sync_state(thread);
+
+	/* copy the floating point registers */
+	if (copy_to_user(&ufp->fpregs, &vfp->hard.fpregs,
+			 sizeof(vfp->hard.fpregs)))
+		return -EFAULT;
+
+	/* copy the status and control register */
+	if (put_user(vfp->hard.fpscr, &ufp->fpscr))
+		return -EFAULT;
+
+	return 0;
+}
+
+/*
+ * Set the child VFP state.
+ */
+static int ptrace_setvfpregs(struct task_struct *tsk, void __user *data)
+{
+	struct thread_info *thread = task_thread_info(tsk);
+	union vfp_state *vfp = &thread->vfpstate;
+	struct user_vfp __user *ufp = data;
+
+	vfp_sync_state(thread);
+
+	/* copy the floating point registers */
+	if (copy_from_user(&vfp->hard.fpregs, &ufp->fpregs,
+			   sizeof(vfp->hard.fpregs)))
+		return -EFAULT;
+
+	/* copy the status and control register */
+	if (get_user(vfp->hard.fpscr, &ufp->fpscr))
+		return -EFAULT;
+
+	return 0;
+}
+#endif
+
 long arch_ptrace(struct task_struct *child, long request, long addr, long data)
 {
 	int ret;
@@ -775,6 +823,16 @@
 			break;
 #endif
 
+#ifdef CONFIG_VFP
+		case PTRACE_GETVFPREGS:
+			ret = ptrace_getvfpregs(child, (void __user *)data);
+			break;
+
+		case PTRACE_SETVFPREGS:
+			ret = ptrace_setvfpregs(child, (void __user *)data);
+			break;
+#endif
+
 		default:
 			ret = ptrace_request(child, request, addr, data);
 			break;
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 68d6494..d301a53 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -780,6 +780,8 @@
 	"crunch",
 	"thumbee",
 	"neon",
+	"vfpv3",
+	"vfpv3d16",
 	NULL
 };
 
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index 13ad26a..921d02b 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -117,9 +117,23 @@
 	bool "OMAP3 ZOOM2 board"
 	depends on ARCH_OMAP3 && ARCH_OMAP34XX
 
+config MACH_OMAP_ZOOM3
+	bool "OMAP3 ZOOM3 board"
+	depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config MACH_OMAP_3630SDP
+	bool "OMAP3 3630 SDP board"
+	depends on ARCH_OMAP3 && ARCH_OMAP34XX
+
+config L2CACHE_OMAP3_DISABLE
+	bool "Disable level 2 cache in Aux cntrl reg"
+	depends on ARCH_OMAP3
+	help
+		Say Y here to disable L2 cache.
+
 config WIFI_CONTROL_FUNC
         bool "Enable WiFi control function abstraction"
-	depends on MACH_OMAP_ZOOM2
+	depends on MACH_OMAP_ZOOM2 || MACH_OMAP_ZOOM3
         help
           Enables Power/Reset/Carddetect function abstraction
 
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 3d6ee06..8cb7175 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -74,6 +74,13 @@
 					   board-ldp-flash.o \
 					   board-zoom2-camera.o \
 					   board-zoom2-wifi.o
+obj-$(CONFIG_MACH_OMAP_ZOOM3)		+= board-zoom2.o \
+					   mmc-twl4030.o \
+					   board-ldp-flash.o \
+					   board-zoom2-camera.o \
+					   board-zoom2-wifi.o
+obj-$(CONFIG_MACH_OMAP_3630SDP)		+= board-3630sdp.o \
+					   mmc-twl4030.o
 obj-$(CONFIG_MACH_OMAP_APOLLON)		+= board-apollon.o \
 					   board-apollon-mmc.o	\
 					   board-apollon-keys.o
@@ -105,3 +112,7 @@
 	obj-y				+= usb-ehci.o
 endif
 
+ifneq ($(CONFIG_USB_OHCI_HCD),)
+	obj-y				+= usb-ohci.o
+endif
+
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
index 76fdaef..cc59d04 100644
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ b/arch/arm/mach-omap2/board-3430sdp.c
@@ -42,7 +42,6 @@
 
 #include <mach/control.h>
 #include <mach/clock.h>
-
 #include "sdram-qimonda-hyb18m512160af-6.h"
 #include "mmc-twl4030.h"
 #include "pm.h"
@@ -424,8 +423,31 @@
 
 static void __init omap_3430sdp_init_irq(void)
 {
-	omap2_init_common_hw(hyb18m512160af6_sdrc_params, omap3_mpu_rate_table,
-			     omap3_dsp_rate_table, omap3_l3_rate_table);
+	switch (omap_rev_id()) {
+	case OMAP_3420:
+		omap2_init_common_hw(hyb18m512160af6_sdrc_params,
+		omap3_mpu_rate_table, omap3_dsp_rate_table_3420,
+		omap3_l3_rate_table);
+		break;
+
+	case OMAP_3430:
+		omap2_init_common_hw(hyb18m512160af6_sdrc_params,
+		omap3_mpu_rate_table, omap3_dsp_rate_table,
+		omap3_l3_rate_table);
+		break;
+
+	case OMAP_3440:
+		omap2_init_common_hw(hyb18m512160af6_sdrc_params,
+		omap3_mpu_rate_table, omap3_dsp_rate_table_3440,
+		omap3_l3_rate_table);
+		break;
+
+	default:
+		omap2_init_common_hw(hyb18m512160af6_sdrc_params,
+		omap3_mpu_rate_table, omap3_dsp_rate_table,
+		omap3_l3_rate_table);
+		break;
+		}
 	omap_init_irq();
 	omap_gpio_init();
 	sdp3430_init_smc91x();
@@ -777,7 +799,7 @@
 	.vpll2		= &sdp3430_vpll2,
 };
 
-static struct i2c_board_info __initdata sdp3430_i2c_boardinfo[] = {
+static struct i2c_board_info __initdata sdp3430_i2c1_boardinfo[] = {
 	{
 		I2C_BOARD_INFO("twl4030", 0x48),
 		.flags = I2C_CLIENT_WAKE,
@@ -786,13 +808,29 @@
 	},
 };
 
+/* I2C Address for ISP1301 Transceiver */
+#define ISP1301_I2C_ADDR1               0x2C
+#define ISP1301_I2C_ADDR2               0x2D
+
+static struct i2c_board_info __initdata sdp3430_i2c2_boardinfo[] = {
+	{
+		I2C_BOARD_INFO("isp1301_host", ISP1301_I2C_ADDR1),
+		.type           = "isp1301_host",
+	},
+	{
+		I2C_BOARD_INFO("isp1301_host", ISP1301_I2C_ADDR2),
+		.type           = "isp1301_host",
+	},
+};
+
 static int __init omap3430_i2c_init(void)
 {
 	/* i2c1 for PMIC only */
-	omap_register_i2c_bus(1, 2600, sdp3430_i2c_boardinfo,
-			ARRAY_SIZE(sdp3430_i2c_boardinfo));
-	/* i2c2 on camera connector (for sensor control) and optional isp1301 */
-	omap_register_i2c_bus(2, 400, NULL, 0);
+	omap_register_i2c_bus(1, 2600, sdp3430_i2c1_boardinfo,
+			ARRAY_SIZE(sdp3430_i2c1_boardinfo));
+	/* i2c2 optional isp1301 */
+	omap_register_i2c_bus(2, 100, sdp3430_i2c2_boardinfo,
+			ARRAY_SIZE(sdp3430_i2c2_boardinfo));
 	/* i2c3 on display connector (for DVI, tfp410) */
 	omap_register_i2c_bus(3, 400, NULL, 0);
 	return 0;
@@ -817,6 +855,7 @@
 	omap_serial_init();
 	usb_musb_init();
 	usb_ehci_init();
+	usb_ohci_init();
 	sdp3430_display_init();
 }
 
@@ -829,7 +868,7 @@
 MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
 	/* Maintainer: Syed Khasim - Texas Instruments Inc */
 	.phys_io	= 0x48000000,
-	.io_pg_offst	= ((0xd8000000) >> 18) & 0xfffc,
+	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap_3430sdp_map_io,
 	.init_irq	= omap_3430sdp_init_irq,
diff --git a/arch/arm/mach-omap2/board-3630sdp.c b/arch/arm/mach-omap2/board-3630sdp.c
new file mode 100644
index 0000000..3e20015
--- /dev/null
+++ b/arch/arm/mach-omap2/board-3630sdp.c
@@ -0,0 +1,963 @@
+/*
+ * linux/arch/arm/mach-omap2/board-sdp3630.c
+ *
+ * Copyright (C) 2009 Texas Instruments Inc.
+ * Harish Hanumanthappa <h-harish@ti.com>
+ *
+ * Modified from mach-omap2/board-zoom2.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 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/gpio_keys.h>
+#include <linux/workqueue.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/synaptics_i2c_rmi.h>
+#include <linux/spi/spi.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/interrupt.h>
+#include <linux/regulator/machine.h>
+#ifdef CONFIG_SIL9022
+#include <linux/sil9022.h>
+#endif
+#include <linux/switch.h>
+#include <mach/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <mach/board-zoom2.h>
+#include <mach/mcspi.h>
+#include <mach/gpio.h>
+#include <mach/board.h>
+#include <mach/common.h>
+#include <mach/gpmc.h>
+#include <mach/usb.h>
+#include <mach/mux.h>
+
+#include <asm/io.h>
+#include <asm/delay.h>
+#include <mach/control.h>
+
+#include <mach/display.h>
+#include <mach/hdq.h>
+
+#include "mmc-twl4030.h"
+#include "omap3-opp.h"
+#include "sdram-hynix-h8mbx00u0mer-0em.h"
+
+#include <media/v4l2-int-device.h>
+
+#ifdef CONFIG_PM
+#include <../drivers/media/video/omap/omap_voutdef.h>
+#endif
+
+#ifdef CONFIG_VIDEO_LV8093
+#include <media/lv8093.h>
+#define LV8093_PS_GPIO			7
+/* GPIO7 is connected to lens PS pin through inverter */
+#define LV8093_PWR_OFF			1
+#define LV8093_PWR_ON			(!LV8093_PWR_OFF)
+#endif
+
+#ifndef CONFIG_TWL4030_CORE
+#error "no power companion board defined!"
+#endif
+
+#ifdef CONFIG_WL127X_RFKILL
+#include <linux/wl127x-rfkill.h>
+#endif
+
+#define OMAP_SYNAPTICS_GPIO		163
+
+#define SDP3630_SMC91X_CS	3
+#define SDP3630_ETHR_SMC91X_GPIO 158
+
+#define TWL4030_MSECURE_GPIO	22
+
+static struct pin_config sdp3630_mux_pins[] = {
+/*
+ *		Name, reg-offset,
+ *		mux-mode | [active-mode | off-mode]
+ */
+
+/* McBSPs */
+MUX_CFG_34XX("MCBSP2_SLAVE", 0x13c /* FSX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP2_SLAVE", 0x13e /* CLKX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP2_SLAVE", 0x140 /* DR */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP2_SLAVE", 0x142 /* DX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x194 /* CLKS */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x172 /* FSX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x170 /* CLKX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x16e /* DR */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x16c /* DX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x172 /* FSX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x170 /* CLKX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x16e /* DR */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x16c /* DX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x172 /* FSX */,
+		OMAP34XX_MUX_MODE7)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x170 /* CLKX */,
+		OMAP34XX_MUX_MODE7)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x16e /* DR */,
+		OMAP34XX_MUX_MODE7)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x16c /* DX */,
+		OMAP34XX_MUX_MODE7)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x194 /* CLKS */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x18a /* FSX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x0b6 /* CLKX */,
+		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x0b8 /* DR */,
+		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_MASTER", 0x0ba /* DX */,
+		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP4_SLAVE", 0x18a /* FSX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_SLAVE", 0x0b6 /* CLKX */,
+		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_SLAVE", 0x0b8 /* DR */,
+		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT)
+MUX_CFG_34XX("MCBSP4_SLAVE", 0x0ba /* DX */,
+		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
+};
+
+static struct omap_mux_cfg sdp3630_mux_cfg = {
+		.pins	= sdp3630_mux_pins,
+		.size	= ARRAY_SIZE(sdp3630_mux_pins),
+};
+
+static struct resource sdp3630_smc91x_resources[] = {
+	[0] = {
+		.start	= OMAP34XX_ETHR_START,
+		.end	= OMAP34XX_ETHR_START + SZ_4K,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= 0,
+		.end	= 0,
+		.flags	= IORESOURCE_IRQ | IORESOURCE_IRQ_LOWLEVEL,
+	},
+};
+
+static struct platform_device sdp3630_smc91x_device = {
+	.name		= "smc91x",
+	.id		= -1,
+	.num_resources	= ARRAY_SIZE(sdp3630_smc91x_resources),
+	.resource	= sdp3630_smc91x_resources,
+};
+
+/* sdp3630 has Qwerty keyboard*/
+static int sdp3630_twl4030_keymap[] = {
+	KEY(0, 0, KEY_E),
+	KEY(1, 0, KEY_R),
+	KEY(2, 0, KEY_T),
+	KEY(3, 0, KEY_HOME),
+	KEY(6, 0, KEY_I),
+	KEY(7, 0, KEY_LEFTSHIFT),
+	KEY(0, 1, KEY_D),
+	KEY(1, 1, KEY_F),
+	KEY(2, 1, KEY_G),
+	KEY(3, 1, KEY_SEND),
+	KEY(6, 1, KEY_K),
+	KEY(7, 1, KEY_ENTER),
+	KEY(0, 2, KEY_X),
+	KEY(1, 2, KEY_C),
+	KEY(2, 2, KEY_V),
+	KEY(3, 2, KEY_END),
+	KEY(6, 2, KEY_DOT),
+	KEY(7, 2, KEY_CAPSLOCK),
+	KEY(0, 3, KEY_Z),
+	KEY(1, 3, KEY_KPPLUS),
+	KEY(2, 3, KEY_B),
+	KEY(3, 3, KEY_F1),
+	KEY(6, 3, KEY_O),
+	KEY(7, 3, KEY_SPACE),
+	KEY(0, 4, KEY_W),
+	KEY(1, 4, KEY_Y),
+	KEY(2, 4, KEY_U),
+	KEY(3, 4, KEY_F2),
+	KEY(4, 4, KEY_VOLUMEUP),
+	KEY(6, 4, KEY_L),
+	KEY(7, 4, KEY_LEFT),
+	KEY(0, 5, KEY_S),
+	KEY(1, 5, KEY_H),
+	KEY(2, 5, KEY_J),
+	KEY(3, 5, KEY_F3),
+	KEY(5, 5, KEY_VOLUMEDOWN),
+	KEY(6, 5, KEY_M),
+	KEY(4, 5, KEY_ENTER),
+	KEY(7, 5, KEY_RIGHT),
+	KEY(0, 6, KEY_Q),
+	KEY(1, 6, KEY_A),
+	KEY(2, 6, KEY_N),
+	KEY(3, 6, KEY_BACKSPACE),
+	KEY(6, 6, KEY_P),
+	KEY(7, 6, KEY_UP),
+	KEY(6, 7, KEY_SELECT),
+	KEY(7, 7, KEY_DOWN),
+	KEY(0, 7, KEY_PROG1),	/*MACRO 1 <User defined> */
+	KEY(1, 7, KEY_PROG2),	/*MACRO 2 <User defined> */
+	KEY(2, 7, KEY_PROG3),	/*MACRO 3 <User defined> */
+	KEY(3, 7, KEY_PROG4),	/*MACRO 4 <User defined> */
+	0
+};
+
+static struct twl4030_keypad_data sdp3630_kp_twl4030_data = {
+	.rows		= 8,
+	.cols		= 8,
+	.keymap		= sdp3630_twl4030_keymap,
+	.keymapsize	= ARRAY_SIZE(sdp3630_twl4030_keymap),
+	.rep		= 1,
+};
+
+static int __init msecure_init(void)
+{
+	int ret = 0;
+
+#ifdef CONFIG_RTC_DRV_TWL4030
+	/* 3430ES2.0 doesn't have msecure/gpio-22 line connected to T2 */
+	if (omap_type() == OMAP2_DEVICE_TYPE_GP &&
+			omap_rev() < OMAP3430_REV_ES2_0) {
+		void __iomem *msecure_pad_config_reg =
+			omap_ctrl_base_get() + 0xA3C;
+		int mux_mask = 0x04;
+		u16 tmp;
+
+		ret = gpio_request(TWL4030_MSECURE_GPIO, "msecure");
+		if (ret < 0) {
+			printk(KERN_ERR "msecure_init: can't"
+				"reserve GPIO:%d !\n", TWL4030_MSECURE_GPIO);
+			goto out;
+		}
+		/*
+		 * TWL4030 will be in secure mode if msecure line from OMAP
+		 * is low. Make msecure line high in order to change the
+		 * TWL4030 RTC time and calender registers.
+		 */
+
+		tmp = __raw_readw(msecure_pad_config_reg);
+		tmp &= 0xF8;	/* To enable mux mode 03/04 = GPIO_RTC */
+		tmp |= mux_mask;/* To enable mux mode 03/04 = GPIO_RTC */
+		__raw_writew(tmp, msecure_pad_config_reg);
+
+		gpio_direction_output(TWL4030_MSECURE_GPIO, 1);
+	}
+out:
+#endif
+	return ret;
+}
+
+static struct omap2_mcspi_device_config sdp3630_lcd_mcspi_config = {
+	.turbo_mode		= 0,
+	.single_channel		= 1,  /* 0: slave, 1: master */
+};
+
+static struct spi_board_info sdp3630_spi_board_info[] __initdata = {
+	[0] = {
+		.modalias		= "sdp3630_disp_spi",
+		.bus_num		= 1,
+		.chip_select		= 2,
+		.max_speed_hz		= 375000,
+		.controller_data 	= &sdp3630_lcd_mcspi_config,
+	},
+};
+
+#define LCD_PANEL_BACKLIGHT_GPIO 	(7 + OMAP_MAX_GPIO_LINES)
+
+#define LCD_PANEL_RESET_GPIO		55
+#define LCD_PANEL_QVGA_GPIO		56
+
+#define TV_PANEL_ENABLE_GPIO		95
+
+
+#define PM_RECEIVER			TWL4030_MODULE_PM_RECEIVER
+#define ENABLE_VAUX2_DEDICATED		0x09
+#define ENABLE_VAUX2_DEV_GRP		0x20
+
+#define ENABLE_VPLL2_DEDICATED          0x05
+#define ENABLE_VPLL2_DEV_GRP            0xE0
+#define TWL4030_VPLL2_DEV_GRP           0x33
+#define TWL4030_VPLL2_DEDICATED         0x36
+
+#define SIL9022_RESET_GPIO 		97
+
+#define t2_out(c, r, v) twl4030_i2c_write_u8(c, r, v)
+
+static int sdp3630_panel_power_enable(int enable)
+{
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				(enable) ? ENABLE_VPLL2_DEDICATED : 0,
+				TWL4030_VPLL2_DEDICATED);
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				(enable) ? ENABLE_VPLL2_DEV_GRP : 0,
+				TWL4030_VPLL2_DEV_GRP);
+	return 0;
+}
+
+static int sdp3630_panel_enable_lcd(struct omap_dss_device *dssdev)
+{
+	sdp3630_panel_power_enable(1);
+
+	gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 1);
+
+	return 0;
+}
+
+static void sdp3630_panel_disable_lcd(struct omap_dss_device *dssdev)
+{
+#ifndef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+	sdp3630_panel_power_enable(0);
+#endif
+
+	gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
+
+}
+
+static struct omap_dss_device sdp3630_lcd_device = {
+	.name = "lcd",
+	.driver_name = "sdp3630_panel",
+	.type = OMAP_DISPLAY_TYPE_DPI,
+	.phy.dpi.data_lines = 24,
+	.platform_enable = sdp3630_panel_enable_lcd,
+	.platform_disable = sdp3630_panel_disable_lcd,
+ };
+
+#ifdef CONFIG_SIL9022
+static void sdp3630_hdmi_reset_enable(int level)
+{
+	/* Set GPIO_97 to high to pull SiI9022 HDMI transmitter
+	 * out of reset and low to disable it.
+	 */
+	gpio_request(SIL9022_RESET_GPIO, "hdmi reset");
+	gpio_direction_output(SIL9022_RESET_GPIO, level);
+}
+
+static int sdp3630_panel_enable_hdmi(struct omap_dss_device *dssdev)
+{
+	sdp3630_panel_power_enable(1);
+	sdp3630_hdmi_reset_enable(1);
+
+	return 0;
+}
+
+static void sdp3630_panel_disable_hdmi(struct omap_dss_device *dssdev)
+{
+	sdp3630_hdmi_reset_enable(0);
+#ifndef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+	sdp3630_panel_power_enable(0);
+#endif
+}
+struct hdmi_platform_data sdp3630_hdmi_data = {
+#ifdef CONFIG_PM
+	.set_min_bus_tput = omap_pm_set_min_bus_tput,
+#endif
+};
+
+static struct omap_dss_device sdp3630_hdmi_device = {
+	.name = "hdmi",
+	.driver_name = "hdmi_panel",
+	.type = OMAP_DISPLAY_TYPE_HDMI,
+	.phy.dpi.data_lines = 24,
+	.platform_enable = sdp3630_panel_enable_hdmi,
+	.platform_disable = sdp3630_panel_disable_hdmi,
+	.dev		= {
+		.platform_data = &sdp3630_hdmi_data,
+	},
+};
+#endif
+
+
+static int sdp3630_panel_enable_tv(struct omap_dss_device *dssdev)
+{
+#define ENABLE_VDAC_DEDICATED           0x03
+#define ENABLE_VDAC_DEV_GRP             0x20
+
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+			ENABLE_VDAC_DEDICATED,
+			TWL4030_VDAC_DEDICATED);
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+			ENABLE_VDAC_DEV_GRP, TWL4030_VDAC_DEV_GRP);
+
+	return 0;
+}
+
+static void sdp3630_panel_disable_tv(struct omap_dss_device *dssdev)
+{
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x00,
+			TWL4030_VDAC_DEDICATED);
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x00,
+			TWL4030_VDAC_DEV_GRP);
+}
+static struct omap_dss_device sdp3630_tv_device = {
+	.name = "tv",
+	.driver_name = "venc",
+	.type = OMAP_DISPLAY_TYPE_VENC,
+	.phy.venc.type = OMAP_DSS_VENC_TYPE_COMPOSITE,
+	.platform_enable = sdp3630_panel_enable_tv,
+	.platform_disable = sdp3630_panel_disable_tv,
+};
+
+static struct omap_dss_device *sdp3630_dss_devices[] = {
+	&sdp3630_lcd_device,
+	&sdp3630_tv_device,
+#ifdef CONFIG_SIL9022
+	&sdp3630_hdmi_device,
+#endif
+};
+
+static struct omap_dss_board_info sdp3630_dss_data = {
+	.get_last_off_on_transaction_id = get_last_off_on_transaction_id,
+	.num_devices = ARRAY_SIZE(sdp3630_dss_devices),
+	.devices = sdp3630_dss_devices,
+	.default_device = &sdp3630_lcd_device,
+};
+
+static struct platform_device sdp3630_dss_device = {
+	.name          = "omapdss",
+	.id            = -1,
+	.dev            = {
+		.platform_data = &sdp3630_dss_data,
+	},
+};
+
+static struct regulator_consumer_supply sdp3630_vdda_dac_supply = {
+	.supply		= "vdda_dac",
+	.dev		= &sdp3630_dss_device.dev,
+};
+
+static struct regulator_consumer_supply sdp3630_vdds_dsi_supply = {
+	.supply		= "vdds_dsi",
+	.dev		= &sdp3630_dss_device.dev,
+};
+
+#ifdef CONFIG_FB_OMAP2
+static struct resource sdp3630_vout_resource[3 - CONFIG_FB_OMAP2_NUM_FBS] = {
+};
+#else
+static struct resource sdp3630_vout_resource[2] = {
+};
+#endif
+
+#ifdef CONFIG_PM
+struct vout_platform_data sdp3630_vout_data = {
+	.set_min_bus_tput = omap_pm_set_min_bus_tput,
+	.set_max_mpu_wakeup_lat =  omap_pm_set_max_mpu_wakeup_lat,
+	.set_vdd1_opp = omap_pm_set_min_mpu_freq,
+	.set_cpu_freq = omap_pm_cpu_set_freq,
+};
+#endif
+
+static struct platform_device sdp3630_vout_device = {
+	.name		= "omap_vout",
+	.num_resources	= ARRAY_SIZE(sdp3630_vout_resource),
+	.resource	= &sdp3630_vout_resource[0],
+	.id		= -1,
+#ifdef CONFIG_PM
+	.dev		= {
+		.platform_data = &sdp3630_vout_data,
+	}
+#else
+	.dev		= {
+		.platform_data = NULL,
+	}
+#endif
+};
+
+static struct gpio_switch_platform_data headset_switch_data = {
+	.name		= "h2w",
+	.gpio		= OMAP_MAX_GPIO_LINES + 2, /* TWL4030 GPIO_2 */
+};
+
+static struct platform_device headset_switch_device = {
+	.name		= "switch-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &headset_switch_data,
+	}
+};
+
+static struct platform_device *sdp3630_devices[] __initdata = {
+	&sdp3630_dss_device,
+	&sdp3630_smc91x_device,
+#if defined(CONFIG_HDQ_MASTER_OMAP) || defined(CONFIG_HDQ_MASTER_OMAP_MODULE)
+	&omap_hdq_device,
+#endif
+	&sdp3630_vout_device,
+	&headset_switch_device,
+};
+
+static inline void __init sdp3630_init_smc91x(void)
+{
+	int eth_cs;
+	unsigned long cs_mem_base;
+	int eth_gpio = 0;
+
+	eth_cs = SDP3630_SMC91X_CS;
+
+	if (gpmc_cs_request(eth_cs, SZ_16M, &cs_mem_base) < 0) {
+		printk(KERN_ERR "Failed to request GPMC mem for smc911x\n");
+		return;
+	}
+
+	sdp3630_smc91x_resources[0].start = cs_mem_base + 0x300;
+	sdp3630_smc91x_resources[0].end   = cs_mem_base + 0x30f;
+	udelay(100);
+
+	eth_gpio = SDP3630_ETHR_SMC91X_GPIO;
+
+	sdp3630_smc91x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+
+	if (gpio_request(eth_gpio, "smc91x irq") < 0) {
+		printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
+		       eth_gpio);
+		return;
+	}
+	gpio_direction_input(eth_gpio);
+}
+
+/* Quad UART (TL16CP754C) is on sdp3630 debug board */
+/* Map registers to GPMC CS3 */
+
+static void __init omap_sdp3630_init_irq(void)
+{
+	omap2_init_common_hw(h8mbx00u0mer0em_sdrc_params,
+		omap3630_mpu_rate_table, omap3630_dsp_rate_table,
+		omap3630_l3_rate_table);
+	/* Production board supports McBSP4 */
+	omap2_mux_register(&sdp3630_mux_cfg);
+	omap_init_irq();
+	omap_gpio_init();
+	sdp3630_init_smc91x();
+}
+
+static struct regulator_consumer_supply sdp3630_vmmc1_supply = {
+	.supply		= "vmmc",
+};
+
+static struct regulator_consumer_supply sdp3630_vsim_supply = {
+	.supply		= "vmmc_aux",
+};
+
+static struct regulator_consumer_supply sdp3630_vmmc2_supply = {
+	.supply		= "vmmc",
+};
+
+/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
+static struct regulator_init_data sdp3630_vmmc1 = {
+	.constraints = {
+		.min_uV			= 1850000,
+		.max_uV			= 3150000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = 1,
+	.consumer_supplies      = &sdp3630_vmmc1_supply,
+};
+
+/* VMMC2 for MMC2 card */
+static struct regulator_init_data sdp3630_vmmc2 = {
+	.constraints = {
+		.min_uV			= 1850000,
+		.max_uV			= 1850000,
+		.apply_uV		= true,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = 1,
+	.consumer_supplies      = &sdp3630_vmmc2_supply,
+};
+
+/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */
+static struct regulator_init_data sdp3630_vsim = {
+	.constraints = {
+		.min_uV			= 1800000,
+		.max_uV			= 3000000,
+		.valid_modes_mask	= REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask		= REGULATOR_CHANGE_VOLTAGE
+					| REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = 1,
+	.consumer_supplies      = &sdp3630_vsim_supply,
+};
+
+static struct regulator_init_data sdp3630_vdac = {
+	.constraints = {
+		.min_uV                 = 1800000,
+		.max_uV                 = 1800000,
+		.valid_modes_mask       = REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask         = REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = 1,
+	.consumer_supplies      = &sdp3630_vdda_dac_supply,
+};
+
+static struct regulator_init_data sdp3630_vdsi = {
+	.constraints = {
+		.min_uV                 = 1800000,
+		.max_uV                 = 1800000,
+		.valid_modes_mask       = REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask         = REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = 1,
+	.consumer_supplies      = &sdp3630_vdds_dsi_supply,
+};
+
+static struct twl4030_hsmmc_info mmc[] __initdata = {
+	{
+		.mmc		= 1,
+		.wires		= 4,
+		.gpio_wp	= -EINVAL,
+	},
+	{}      /* Terminator */
+};
+
+static int sdp3630_twl_gpio_setup(struct device *dev,
+		unsigned gpio, unsigned ngpio)
+{
+	/* gpio + 0 is "mmc0_cd" (input/IRQ),
+	 * gpio + 1 is "mmc1_cd" (input/IRQ)
+	 */
+	mmc[0].gpio_cd = gpio + 0;
+	mmc[1].gpio_cd = gpio + 1;
+	twl4030_mmc_init(mmc);
+
+	/* link regulators to MMC adapters ... we "know" the
+	 * regulators will be set up only *after* we return.
+	*/
+	sdp3630_vmmc1_supply.dev = mmc[0].dev;
+	sdp3630_vsim_supply.dev = mmc[0].dev;
+	sdp3630_vmmc2_supply.dev = mmc[1].dev;
+
+	return 0;
+}
+
+static struct omap_lcd_config sdp3630_lcd_config __initdata = {
+	.ctrl_name      = "internal",
+};
+
+static struct omap_uart_config sdp3630_uart_config __initdata = {
+	.enabled_uarts	= ((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3)),
+};
+
+static struct omap_board_config_kernel sdp3630_config[] __initdata = {
+	{ OMAP_TAG_UART,	&sdp3630_uart_config },
+	{ OMAP_TAG_LCD,         &sdp3630_lcd_config },
+};
+
+static int sdp3630_batt_table[] = {
+/* 0 C*/
+30800, 29500, 28300, 27100,
+26000, 24900, 23900, 22900, 22000, 21100, 20300, 19400, 18700, 17900,
+17200, 16500, 15900, 15300, 14700, 14100, 13600, 13100, 12600, 12100,
+11600, 11200, 10800, 10400, 10000, 9630,   9280,   8950,   8620,   8310,
+8020,   7730,   7460,   7200,   6950,   6710,   6470,   6250,   6040,   5830,
+5640,   5450,   5260,   5090,   4920,   4760,   4600,   4450,   4310,   4170,
+4040,   3910,   3790,   3670,   3550
+};
+
+static struct twl4030_bci_platform_data sdp3630_bci_data = {
+	.battery_tmp_tbl	= sdp3630_batt_table,
+	.tblsize		= ARRAY_SIZE(sdp3630_batt_table),
+	.twl4030_bci_charging_current	= 1100, /* 1.1A for sdp3630 */
+};
+
+static struct twl4030_usb_data sdp3630_usb_data = {
+	.usb_mode	= T2_USB_MODE_ULPI,
+};
+
+static struct twl4030_gpio_platform_data sdp3630_gpio_data = {
+	.gpio_base	= OMAP_MAX_GPIO_LINES,
+	.irq_base	= TWL4030_GPIO_IRQ_BASE,
+	.irq_end	= TWL4030_GPIO_IRQ_END,
+	.setup		= sdp3630_twl_gpio_setup,
+};
+
+static struct twl4030_madc_platform_data sdp3630_madc_data = {
+	.irq_line	= 1,
+};
+
+static struct twl4030_ins __initdata sleep_on_seq[] = {
+
+	/* Turn off HFCLKOUT */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_OFF), 2},
+	/* Turn OFF VDD1 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 2},
+	/* Turn OFF VDD2 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
+	/* Turn OFF VPLL1 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 2},
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+	.script	= sleep_on_seq,
+	.size	= ARRAY_SIZE(sleep_on_seq),
+	.flags	= TRITON_SLEEP_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p12_seq[] __initdata = {
+	/* Turn on HFCLKOUT */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+	/* Turn ON VDD1 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 2},
+	/* Turn ON VDD2 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 2},
+	/* Turn ON VPLL1 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p12_script __initdata = {
+	.script = wakeup_p12_seq,
+	.size   = ARRAY_SIZE(wakeup_p12_seq),
+	.flags  = TRITON_WAKEUP12_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p3_seq[] __initdata = {
+	{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p3_script __initdata = {
+	.script = wakeup_p3_seq,
+	.size   = ARRAY_SIZE(wakeup_p3_seq),
+	.flags  = TRITON_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_ins wrst_seq[] __initdata = {
+/*
+ * Reset twl4030.
+ * Reset VDD1 regulator.
+ * Reset VDD2 regulator.
+ * Reset VPLL1 regulator.
+ * Enable sysclk output.
+ * Reenable twl4030.
+ */
+	{MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
+	{MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
+	{MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
+	{MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
+	{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+	{MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wrst_script __initdata = {
+	.script = wrst_seq,
+	.size   = ARRAY_SIZE(wrst_seq),
+	.flags  = TRITON_WRST_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+	&sleep_on_script,
+	&wakeup_p12_script,
+	&wakeup_p3_script,
+	&wrst_script,
+};
+
+static struct twl4030_resconfig twl4030_rconfig[] = {
+	{ .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3, .type = -1,
+		.type2 = -1 },
+	{ .resource = RES_VDD1, .devgroup = DEV_GRP_P1, .type = -1,
+		.type2 = -1 },
+	{ .resource = RES_VDD2, .devgroup = DEV_GRP_P1, .type = -1,
+		.type2 = -1 },
+	{ 0, 0},
+};
+
+static struct twl4030_power_data sdp3630_t2scripts_data __initdata = {
+	.scripts	= twl4030_scripts,
+	.size		= ARRAY_SIZE(twl4030_scripts),
+	.resource_config = twl4030_rconfig,
+};
+
+static struct twl4030_platform_data sdp3630_twldata = {
+	.irq_base	= TWL4030_IRQ_BASE,
+	.irq_end	= TWL4030_IRQ_END,
+
+	/* platform_data for children goes here */
+	.bci		= &sdp3630_bci_data,
+	.madc		= &sdp3630_madc_data,
+	.usb		= &sdp3630_usb_data,
+	.gpio		= &sdp3630_gpio_data,
+	.keypad		= &sdp3630_kp_twl4030_data,
+	.power		= &sdp3630_t2scripts_data,
+	.vmmc1          = &sdp3630_vmmc1,
+	.vmmc2          = &sdp3630_vmmc2,
+	.vsim           = &sdp3630_vsim,
+	.vdac		= &sdp3630_vdac,
+	.vpll2		= &sdp3630_vdsi,
+};
+
+static struct i2c_board_info __initdata sdp3630_i2c_bus1_info[] = {
+	{
+		I2C_BOARD_INFO("twl4030", 0x48),
+		.flags = I2C_CLIENT_WAKE,
+		.irq = INT_34XX_SYS_NIRQ,
+		.platform_data = &sdp3630_twldata,
+	},
+};
+
+static void synaptics_dev_init(void)
+{
+	/* Set the ts_gpio pin mux */
+	omap_cfg_reg(H18_34XX_GPIO163);
+
+	if (gpio_request(OMAP_SYNAPTICS_GPIO, "touch") < 0) {
+		printk(KERN_ERR "can't get synaptics pen down GPIO\n");
+		return;
+	}
+	gpio_direction_input(OMAP_SYNAPTICS_GPIO);
+	omap_set_gpio_debounce(OMAP_SYNAPTICS_GPIO, 1);
+	omap_set_gpio_debounce_time(OMAP_SYNAPTICS_GPIO, 0xa);
+}
+
+static int synaptics_power(int power_state)
+{
+	/* TODO: synaptics is powered by vbatt */
+	return 0;
+}
+
+static struct synaptics_i2c_rmi_platform_data synaptics_platform_data[] = {
+	{
+		.version	= 0x0,
+		.power		= &synaptics_power,
+		.flags		= SYNAPTICS_SWAP_XY,
+		.irqflags	= IRQF_TRIGGER_LOW,
+	}
+};
+
+/* I2C Address for ISP1301 Transceiver */
+#define ISP1301_I2C_ADDR1               0x2C
+#define ISP1301_I2C_ADDR2               0x2D
+
+static struct i2c_board_info __initdata sdp3630_i2c_bus2_info[] = {
+	{
+		I2C_BOARD_INFO(SYNAPTICS_I2C_RMI_NAME,  0x20),
+		.platform_data = &synaptics_platform_data,
+		.irq = OMAP_GPIO_IRQ(OMAP_SYNAPTICS_GPIO),
+	},
+#ifdef CONFIG_VIDEO_LV8093
+	{
+		I2C_BOARD_INFO(LV8093_NAME,  LV8093_AF_I2C_ADDR),
+		.platform_data = &sdp3630_lv8093_platform_data,
+	},
+#endif
+	{
+		I2C_BOARD_INFO("isp1301_host", ISP1301_I2C_ADDR1),
+		.type           = "isp1301_host",
+	},
+	{
+		I2C_BOARD_INFO("isp1301_host", ISP1301_I2C_ADDR2),
+		.type           = "isp1301_host",
+	},
+};
+
+static struct i2c_board_info __initdata sdp3630_i2c_bus3_info[] = {
+#ifdef CONFIG_SIL9022
+	{
+		I2C_BOARD_INFO(SIL9022_DRV_NAME,  SI9022_I2CSLAVEADDRESS),
+	},
+#endif
+};
+
+
+static int __init omap_i2c_init(void)
+{
+	omap_register_i2c_bus(1, 100, sdp3630_i2c_bus1_info,
+			ARRAY_SIZE(sdp3630_i2c_bus1_info));
+	omap_register_i2c_bus(2, 100, sdp3630_i2c_bus2_info,
+			ARRAY_SIZE(sdp3630_i2c_bus2_info));
+	omap_register_i2c_bus(3, 400, sdp3630_i2c_bus3_info,
+			ARRAY_SIZE(sdp3630_i2c_bus3_info));
+	return 0;
+}
+
+/* usb1hs reset is routed to chip select pin of ISP1504
+ * on 750-2099-003(A) daughter card */
+static void config_usb1hs_gpio(void)
+{
+	omap_cfg_reg(D25_34XX_GPIO126);
+}
+
+/* Set GPIO56 to safemode (input only),
+ * this prevents a toggle on RCV pin of ISP1301
+ */
+static void config_usb3fs_gpio(void)
+{
+	omap_cfg_reg(R8_34XX_GPIO56_TRISTATE);
+}
+
+static void enable_board_wakeup_source(void)
+{
+	omap_cfg_reg(AF26_34XX_SYS_NIRQ);
+}
+
+static void __init omap_sdp3630_init(void)
+{
+	omap_i2c_init();
+	platform_add_devices(sdp3630_devices, ARRAY_SIZE(sdp3630_devices));
+	omap_board_config = sdp3630_config;
+	omap_board_config_size = ARRAY_SIZE(sdp3630_config);
+	spi_register_board_info(sdp3630_spi_board_info,
+				ARRAY_SIZE(sdp3630_spi_board_info));
+	synaptics_dev_init();
+	msecure_init();
+	omap_serial_init();
+	usb_musb_init();
+	config_usb1hs_gpio();
+	usb_ehci_init();
+	config_usb3fs_gpio();
+	usb_ohci_init();
+#ifdef CONFIG_SIL9022
+	config_hdmi_gpio();
+	sdp3630_hdmi_reset_enable(1);
+#endif
+	enable_board_wakeup_source();
+}
+
+static void __init omap_sdp3630_map_io(void)
+{
+	omap2_set_globals_343x();
+	omap2_map_common_io();
+}
+
+MACHINE_START(OMAP_3630SDP, "OMAP 3630SDP board")
+	.phys_io	= 0x48000000,
+	.io_pg_offst	= ((0xfa000000) >> 18) & 0xfffc,
+	.boot_params	= 0x80000100,
+	.map_io		= omap_sdp3630_map_io,
+	.init_irq	= omap_sdp3630_init_irq,
+	.init_machine	= omap_sdp3630_init,
+	.timer		= &omap_timer,
+MACHINE_END
diff --git a/arch/arm/mach-omap2/board-ldp-flash.c b/arch/arm/mach-omap2/board-ldp-flash.c
index bbc84df..feb5d4a 100644
--- a/arch/arm/mach-omap2/board-ldp-flash.c
+++ b/arch/arm/mach-omap2/board-ldp-flash.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/kernel.h>
+#include <linux/delay.h>
 #include <linux/platform_device.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
@@ -24,7 +25,7 @@
 #include <mach/gpmc.h>
 #include <mach/nand.h>
 
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
 #include <mach/board-zoom2.h>
 #else
 #include <mach/board-ldp.h>
@@ -65,6 +66,77 @@
 struct gpmc_freq_config freq_config[NO_GPMC_FREQ_SUPPORTED];
 #endif
 
+#define NAND_CMD_UNLOCK1	0x23
+#define NAND_CMD_UNLOCK2	0x24
+/**
+ * @brief platform specific unlock function
+ *
+ * @param mtd - mtd info
+ * @param ofs - offset to start unlock from
+ * @param len - length to unlock
+ *
+ * @return - unlock status
+ */
+static int omap_zoom2_nand_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
+{
+	int ret = 0;
+	int chipnr;
+	int status;
+	unsigned long page;
+	struct nand_chip *this = mtd->priv;
+	printk(KERN_INFO "nand_unlock: start: %08x, length: %d!\n",
+			(int)ofs, (int)len);
+
+	/* select the NAND device */
+	chipnr = (int)(ofs >> this->chip_shift);
+	this->select_chip(mtd, chipnr);
+	/* check the WP bit */
+	this->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
+	if ((this->read_byte(mtd) & 0x80) == 0) {
+		printk(KERN_ERR "nand_unlock: Device is write protected!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if ((ofs & (mtd->writesize - 1)) != 0) {
+		printk(KERN_ERR "nand_unlock: Start address must be"
+				"beginning of nand page!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	if (len == 0 || (len & (mtd->writesize - 1)) != 0) {
+		printk(KERN_ERR "nand_unlock: Length must be a multiple of "
+				"nand page size!\n");
+		ret = -EINVAL;
+		goto out;
+	}
+
+	/* submit address of first page to unlock */
+	page = (unsigned long)(ofs >> this->page_shift);
+	this->cmdfunc(mtd, NAND_CMD_UNLOCK1, -1, page & this->pagemask);
+
+	/* submit ADDRESS of LAST page to unlock */
+	page += (unsigned long)((ofs + len) >> this->page_shift) ;
+	this->cmdfunc(mtd, NAND_CMD_UNLOCK2, -1, page & this->pagemask);
+
+	/* call wait ready function */
+	status = this->waitfunc(mtd, this);
+	udelay(1000);
+	/* see if device thinks it succeeded */
+	if (status & 0x01) {
+		/* there was an error */
+		printk(KERN_ERR "nand_unlock: error status =0x%08x ", status);
+		ret = -EIO;
+		goto out;
+	}
+
+ out:
+	/* de-select the NAND device */
+	this->select_chip(mtd, -1);
+	return ret;
+}
+
 static struct mtd_partition ldp_nand_partitions[] = {
 	/* All the partition sizes are listed in terms of NAND block size */
 	{
@@ -89,6 +161,7 @@
 		.offset		= 0x0200000,
 		.size		= 0x1C00000,   /* 30M */
 	},
+#ifdef CONFIG_ANDROID
 	{
 		.name		= "system",
 		.offset		= 0x2000000,
@@ -104,8 +177,33 @@
 		.offset		= 0xE000000,
 		.size		= 0x2000000,    /* 32M */
  	},
+#endif
 };
 
+/*
+ * Unlock the nand partitions "system", "userdata", "cache" on Zoom2
+ * once CORE hits OFF mode.
+ */
+#if defined(CONFIG_ANDROID) && defined(CONFIG_MACH_OMAP_ZOOM2)
+static void zoom2_nand_unlock(struct mtd_info *mtd, struct device *dev)
+{
+	static int off_counter;
+
+	if (get_last_off_on_transaction_id(dev) != off_counter) {
+		int offset, size;
+
+		offset = ldp_nand_partitions[4].offset;
+		size = ldp_nand_partitions[4].size + ldp_nand_partitions[5].size
+				+ ldp_nand_partitions[6].size;
+		/* Unlock the partitions "system", "userdata" and "cache" */
+		omap_zoom2_nand_unlock(mtd, offset, size);
+		off_counter = get_last_off_on_transaction_id(dev);
+	}
+}
+#else
+#define zoom2_nand_unlock NULL
+#endif
+
 /* NAND chip access: 16 bit */
 static struct omap_nand_platform_data ldp_nand_data = {
 	.parts		= ldp_nand_partitions,
@@ -113,6 +211,9 @@
 	.nand_setup	= NULL,
 	.dma_channel	= -1,		/* disable DMA in OMAP NAND driver */
 	.dev_ready	= NULL,
+	.unlock		= omap_zoom2_nand_unlock,
+	.board_unlock	= zoom2_nand_unlock,
+	.ecc_opt	= 0x1,
 };
 
 static struct resource ldp_nand_resource = {
diff --git a/arch/arm/mach-omap2/board-zoom2-camera.c b/arch/arm/mach-omap2/board-zoom2-camera.c
index 349a25f..edfa809 100644
--- a/arch/arm/mach-omap2/board-zoom2-camera.c
+++ b/arch/arm/mach-omap2/board-zoom2-camera.c
@@ -12,13 +12,13 @@
  * published by the Free Software Foundation.
  */
 
-#ifdef CONFIG_TWL4030_CORE
-
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
 #include <linux/mm.h>
 
+#if defined(CONFIG_TWL4030_CORE) && defined(CONFIG_VIDEO_OMAP3)
+
 #include <linux/i2c/twl4030.h>
 
 #include <asm/io.h>
@@ -41,6 +41,10 @@
 #define VAUX_DEV_GRP_P1		0x20
 #define VAUX_DEV_GRP_NONE	0x00
 
+#define CAMZOOM2_USE_XCLKB  	1
+
+#define ISP_IMX046_MCLK		216000000
+
 /* Sensor specific GPIO signals */
 #define IMX046_RESET_GPIO  	98
 #define IMX046_STANDBY_GPIO	58
@@ -124,17 +128,15 @@
 
 static struct omap34xxcam_sensor_config imx046_hwc = {
 	.sensor_isp  = 0,
-	.xclk        = OMAP34XXCAM_XCLK_B,
 	.capture_mem = IMX046_BIGGEST_FRAME_BYTE_SIZE * 2,
 	.ival_default	= { 1, 10 },
 };
 
-static int imx046_sensor_set_prv_data(void *priv)
+static int imx046_sensor_set_prv_data(struct v4l2_int_device *s, void *priv)
 {
 	struct omap34xxcam_hw_config *hwc = priv;
 
-	hwc->u.sensor.xclk	= imx046_hwc.xclk;
-	hwc->u.sensor.sensor_isp = imx046_hwc.sensor_isp;
+	hwc->u.sensor		= imx046_hwc;
 	hwc->dev_index		= 2;
 	hwc->dev_minor		= 5;
 	hwc->dev_type		= OMAP34XXCAM_SLAVE_SENSOR;
@@ -150,7 +152,8 @@
 	.prestrobe 		= 0x0,
 	.shutter 		= 0x0,
 	.wenlog 		= ISPCCDC_CFG_WENLOG_AND,
-	.wait_hs_vs		= 2,
+	.wait_hs_vs		= 0,
+	.cam_mclk		= ISP_IMX046_MCLK,
 	.raw_fmt_in		= ISPCCDC_INPUT_FMT_RG_GB,
 	.u.csi.crc 		= 0x0,
 	.u.csi.mode 		= 0x0,
@@ -166,8 +169,10 @@
 };
 
 
-static int imx046_sensor_power_set(struct device *dev, enum v4l2_power power)
+static int imx046_sensor_power_set(struct v4l2_int_device *s, enum v4l2_power power)
 {
+	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+	struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
 	struct isp_csi2_lanes_cfg lanecfg;
 	struct isp_csi2_phy_cfg phyconfig;
 	static enum v4l2_power previous_power = V4L2_POWER_OFF;
@@ -181,9 +186,9 @@
 		/* Through-put requirement:
 		 * 3280 x 2464 x 2Bpp x 7.5fps x 3 memory ops = 355163 KByte/s
 		 */
-		omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 355163);
+		omap_pm_set_min_bus_tput(vdev->cam->isp, OCP_INITIATOR_AGENT, 355163);
 
-		isp_csi2_reset();
+		isp_csi2_reset(&isp->isp_csi2);
 
 		lanecfg.clk.pol = IMX046_CSI2_CLOCK_POLARITY;
 		lanecfg.clk.pos = IMX046_CSI2_CLOCK_LANE;
@@ -195,57 +200,57 @@
 		lanecfg.data[2].pos = 0;
 		lanecfg.data[3].pol = 0;
 		lanecfg.data[3].pos = 0;
-		isp_csi2_complexio_lanes_config(&lanecfg);
-		isp_csi2_complexio_lanes_update(true);
+		isp_csi2_complexio_lanes_config(&isp->isp_csi2, &lanecfg);
+		isp_csi2_complexio_lanes_update(&isp->isp_csi2, true);
 
-		isp_csi2_ctrl_config_ecc_enable(true);
+		isp_csi2_ctrl_config_ecc_enable(&isp->isp_csi2, true);
 
 		phyconfig.ths_term = IMX046_CSI2_PHY_THS_TERM;
 		phyconfig.ths_settle = IMX046_CSI2_PHY_THS_SETTLE;
 		phyconfig.tclk_term = IMX046_CSI2_PHY_TCLK_TERM;
 		phyconfig.tclk_miss = IMX046_CSI2_PHY_TCLK_MISS;
 		phyconfig.tclk_settle = IMX046_CSI2_PHY_TCLK_SETTLE;
-		isp_csi2_phy_config(&phyconfig);
-		isp_csi2_phy_update(true);
+		isp_csi2_phy_config(&isp->isp_csi2, &phyconfig);
+		isp_csi2_phy_update(&isp->isp_csi2, true);
 
-		isp_configure_interface(&imx046_if_config);
+		isp_configure_interface(vdev->cam->isp, &imx046_if_config);
 
-		if (previous_power == V4L2_POWER_OFF) {
-			/* Request and configure gpio pins */
-			if (gpio_request(IMX046_RESET_GPIO, "imx046_rst") != 0)
-				return -EIO;
+		/* Request and configure gpio pins */
+		if (gpio_request(IMX046_RESET_GPIO, "imx046_rst") != 0)
+			return -EIO;
 
-			/* nRESET is active LOW. set HIGH to release reset */
-			gpio_set_value(IMX046_RESET_GPIO, 1);
+		/* nRESET is active LOW. set HIGH to release reset */
+		gpio_set_value(IMX046_RESET_GPIO, 1);
 
-			/* set to output mode */
-			gpio_direction_output(IMX046_RESET_GPIO, true);
+		/* set to output mode */
+		gpio_direction_output(IMX046_RESET_GPIO, true);
 
-			/* turn on analog power */
-			twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-					VAUX_2_8_V, TWL4030_VAUX2_DEDICATED);
-			twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-					VAUX_DEV_GRP_P1, TWL4030_VAUX2_DEV_GRP);
+		/* turn on analog power */
+		twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				VAUX_2_8_V, TWL4030_VAUX2_DEDICATED);
+		twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				VAUX_DEV_GRP_P1, TWL4030_VAUX2_DEV_GRP);
 
-			twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-					VAUX_1_8_V, TWL4030_VAUX4_DEDICATED);
-			twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
-					VAUX_DEV_GRP_P1, TWL4030_VAUX4_DEV_GRP);
-			udelay(100);
+		twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				VAUX_1_8_V, TWL4030_VAUX4_DEDICATED);
+		twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				VAUX_DEV_GRP_P1, TWL4030_VAUX4_DEV_GRP);
+		udelay(100);
 
-			/* have to put sensor to reset to guarantee detection */
-			gpio_set_value(IMX046_RESET_GPIO, 0);
-			udelay(1500);
+		/* have to put sensor to reset to guarantee detection */
+		gpio_set_value(IMX046_RESET_GPIO, 0);
+		udelay(1500);
 
-			/* nRESET is active LOW. set HIGH to release reset */
-			gpio_set_value(IMX046_RESET_GPIO, 1);
-			udelay(300);
-		}
+		/* nRESET is active LOW. set HIGH to release reset */
+		gpio_set_value(IMX046_RESET_GPIO, 1);
+		udelay(300);
 		break;
 	case V4L2_POWER_OFF:
-		printk(KERN_DEBUG "imx046_sensor_power_set(OFF)\n");
+	case V4L2_POWER_STANDBY:
+		printk(KERN_DEBUG "imx046_sensor_power_set(%s)\n",
+			(power == V4L2_POWER_OFF) ? "OFF" : "STANDBY");
 		/* Power Down Sequence */
-		isp_csi2_complexio_power(ISP_CSI2_POWER_OFF);
+		isp_csi2_complexio_power(&isp->isp_csi2, ISP_CSI2_POWER_OFF);
 
 		twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
 				VAUX_DEV_GRP_NONE, TWL4030_VAUX4_DEV_GRP);
@@ -253,12 +258,11 @@
 				VAUX_DEV_GRP_NONE, TWL4030_VAUX2_DEV_GRP);
 		gpio_free(IMX046_RESET_GPIO);
 
-		omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 0);
-		break;
-	case V4L2_POWER_STANDBY:
-		printk(KERN_DEBUG "imx046_sensor_power_set(STANDBY)\n");
-		/*TODO*/
-		omap_pm_set_min_bus_tput(dev, OCP_INITIATOR_AGENT, 0);
+		omap_pm_set_min_bus_tput(vdev->cam->isp, OCP_INITIATOR_AGENT, 0);
+
+		/* Make sure not to disable the MCLK twice in a row */
+		if (previous_power == V4L2_POWER_ON)
+			isp_disable_mclk(isp);
 		break;
 	}
 
@@ -267,16 +271,76 @@
 	return err;
 }
 
+static u32 imx046_sensor_set_xclk(struct v4l2_int_device *s, u32 xclkfreq)
+{
+	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+
+	return isp_set_xclk(vdev->cam->isp, xclkfreq, CAMZOOM2_USE_XCLKB);
+}
+
+static int imx046_csi2_lane_count(struct v4l2_int_device *s, int count)
+{
+	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+	struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+	return isp_csi2_complexio_lanes_count(&isp->isp_csi2, count);
+}
+
+static int imx046_csi2_cfg_vp_out_ctrl(struct v4l2_int_device *s,
+				       u8 vp_out_ctrl)
+{
+	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+	struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+	return isp_csi2_ctrl_config_vp_out_ctrl(&isp->isp_csi2, vp_out_ctrl);
+}
+
+static int imx046_csi2_ctrl_update(struct v4l2_int_device *s, bool force_update)
+{
+	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+	struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+	return isp_csi2_ctrl_update(&isp->isp_csi2, force_update);
+}
+
+static int imx046_csi2_cfg_virtual_id(struct v4l2_int_device *s, u8 ctx, u8 id)
+{
+	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+	struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+	return isp_csi2_ctx_config_virtual_id(&isp->isp_csi2, ctx, id);
+}
+
+static int imx046_csi2_ctx_update(struct v4l2_int_device *s, u8 ctx,
+				  bool force_update)
+{
+	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+	struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+	return isp_csi2_ctx_update(&isp->isp_csi2, ctx, force_update);
+}
+
+static int imx046_csi2_calc_phy_cfg0(struct v4l2_int_device *s,
+				     u32 mipiclk, u32 lbound_hs_settle,
+				     u32 ubound_hs_settle)
+{
+	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
+	struct isp_device *isp = dev_get_drvdata(vdev->cam->isp);
+
+	return isp_csi2_calc_phy_cfg0(&isp->isp_csi2, mipiclk,
+				      lbound_hs_settle, ubound_hs_settle);
+}
+
 struct imx046_platform_data zoom2_imx046_platform_data = {
 	.power_set            = imx046_sensor_power_set,
 	.priv_data_set        = imx046_sensor_set_prv_data,
-	.set_xclk             = isp_set_xclk,
-	.csi2_lane_count      = isp_csi2_complexio_lanes_count,
-	.csi2_cfg_vp_out_ctrl = isp_csi2_ctrl_config_vp_out_ctrl,
-	.csi2_ctrl_update     = isp_csi2_ctrl_update,
-	.csi2_cfg_virtual_id  = isp_csi2_ctx_config_virtual_id,
-	.csi2_ctx_update      = isp_csi2_ctx_update,
-	.csi2_calc_phy_cfg0   = isp_csi2_calc_phy_cfg0,
+	.set_xclk             = imx046_sensor_set_xclk,
+	.csi2_lane_count      = imx046_csi2_lane_count,
+	.csi2_cfg_vp_out_ctrl = imx046_csi2_cfg_vp_out_ctrl,
+	.csi2_ctrl_update     = imx046_csi2_ctrl_update,
+	.csi2_cfg_virtual_id  = imx046_csi2_cfg_virtual_id,
+	.csi2_ctx_update      = imx046_csi2_ctx_update,
+	.csi2_calc_phy_cfg0   = imx046_csi2_calc_phy_cfg0,
 };
 #endif
 
@@ -295,8 +359,4 @@
 
 	cam_inited = 1;
 }
-#else
-void __init zoom2_cam_init(void)
-{
-}
 #endif
diff --git a/arch/arm/mach-omap2/board-zoom2.c b/arch/arm/mach-omap2/board-zoom2.c
index e97a65a..c5f1bb4 100644
--- a/arch/arm/mach-omap2/board-zoom2.c
+++ b/arch/arm/mach-omap2/board-zoom2.c
@@ -28,6 +28,8 @@
 #ifdef CONFIG_SIL9022
 #include <linux/sil9022.h>
 #endif
+#include <linux/switch.h>
+#include <linux/smsc911x.h>
 #include <mach/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/mach/arch.h>
@@ -54,18 +56,28 @@
 
 #include "mmc-twl4030.h"
 #include "omap3-opp.h"
+#include "sdram-hynix-h8mbx00u0mer-0em.h"
 #include "sdram-micron-mt46h32m32lf-6.h"
 
 #include <media/v4l2-int-device.h>
 
-#if defined(CONFIG_VIDEO_IMX046) || defined(CONFIG_VIDEO_IMX046_MODULE)
+#if (defined(CONFIG_VIDEO_IMX046) || defined(CONFIG_VIDEO_IMX046_MODULE)) && \
+    defined(CONFIG_VIDEO_OMAP3)
 #include <media/imx046.h>
 extern struct imx046_platform_data zoom2_imx046_platform_data;
 #endif
 
+#ifdef CONFIG_VIDEO_OMAP3
 extern void zoom2_cam_init(void);
+#else
+#define zoom2_cam_init()	NULL
+#endif
 
-#ifdef CONFIG_VIDEO_LV8093
+#ifdef CONFIG_PM
+#include <../drivers/media/video/omap/omap_voutdef.h>
+#endif
+
+#if defined(CONFIG_VIDEO_LV8093) && defined(CONFIG_VIDEO_OMAP3)
 #include <media/lv8093.h>
 extern struct imx046_platform_data zoom2_lv8093_platform_data;
 #define LV8093_PS_GPIO			7
@@ -92,6 +104,11 @@
 #define ENABLE_VAUX3_DEDICATED  0x03
 #define ENABLE_VAUX3_DEV_GRP  	0x20
 #define TWL4030_MSECURE_GPIO	22
+#define WL127X_BTEN_GPIO	109
+
+#define ZOOM2_EXT_QUART_PHYS 0x10000000
+#define ZOOM2_EXT_QUART_VIRT 0xfa400000
+#define ZOOM2_EXT_QUART_SIZE SZ_256
 
 static struct pin_config zoom2_mux_pins[] = {
 /*
@@ -110,29 +127,29 @@
 		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
 MUX_CFG_34XX("MCBSP3_MASTER", 0x194 /* CLKS */,
 		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
-MUX_CFG_34XX("MCBSP3_MASTER", 0x196 /* FSX */,
-		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
-MUX_CFG_34XX("MCBSP3_MASTER", 0x198 /* CLKX */,
-		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
-MUX_CFG_34XX("MCBSP3_MASTER", 0x192 /* DR */,
-		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
-MUX_CFG_34XX("MCBSP3_MASTER", 0x190 /* DX */,
-		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
-MUX_CFG_34XX("MCBSP3_SLAVE", 0x196 /* FSX */,
-		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
-MUX_CFG_34XX("MCBSP3_SLAVE", 0x198 /* CLKX */,
-		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
-MUX_CFG_34XX("MCBSP3_SLAVE", 0x192 /* DR */,
-		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_INPUT_PULLDOWN)
-MUX_CFG_34XX("MCBSP3_SLAVE", 0x190 /* DX */,
-		OMAP34XX_MUX_MODE2 | OMAP34XX_PIN_OUTPUT)
-MUX_CFG_34XX("MCBSP3_TRISTATE", 0x196 /* FSX */,
+MUX_CFG_34XX("MCBSP3_MASTER", 0x172 /* FSX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x170 /* CLKX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x16e /* DR */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_MASTER", 0x16c /* DX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x172 /* FSX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x170 /* CLKX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x16e /* DR */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLDOWN)
+MUX_CFG_34XX("MCBSP3_SLAVE", 0x16c /* DX */,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x172 /* FSX */,
 		OMAP34XX_MUX_MODE7)
-MUX_CFG_34XX("MCBSP3_TRISTATE", 0x198 /* CLKX */,
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x170 /* CLKX */,
 		OMAP34XX_MUX_MODE7)
-MUX_CFG_34XX("MCBSP3_TRISTATE", 0x192 /* DR */,
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x16e /* DR */,
 		OMAP34XX_MUX_MODE7)
-MUX_CFG_34XX("MCBSP3_TRISTATE", 0x190 /* DX */,
+MUX_CFG_34XX("MCBSP3_TRISTATE", 0x16c /* DX */,
 		OMAP34XX_MUX_MODE7)
 MUX_CFG_34XX("MCBSP4_MASTER", 0x194 /* CLKS */,
 		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT)
@@ -159,7 +176,7 @@
 		.size	= ARRAY_SIZE(zoom2_mux_pins),
 };
 
-static struct resource zoom2_smc911x_resources[] = {
+static struct resource zoom2_smsc911x_resources[] = {
 	[0] = {
 		.start	= OMAP34XX_ETHR_START,
 		.end	= OMAP34XX_ETHR_START + SZ_4K,
@@ -172,11 +189,21 @@
 	},
 };
 
-static struct platform_device zoom2_smc911x_device = {
-	.name		= "smc911x",
+static struct smsc911x_platform_config zoom_smsc911x_config = {
+        .irq_polarity   = SMSC911X_IRQ_POLARITY_ACTIVE_LOW,
+        .irq_type       = SMSC911X_IRQ_TYPE_OPEN_DRAIN,
+        .flags          = SMSC911X_USE_32BIT,
+        .phy_interface  = PHY_INTERFACE_MODE_MII,
+};
+
+static struct platform_device zoom2_smsc911x_device = {
+	.name		= "smsc911x",
 	.id		= -1,
-	.num_resources	= ARRAY_SIZE(zoom2_smc911x_resources),
-	.resource	= zoom2_smc911x_resources,
+	.num_resources	= ARRAY_SIZE(zoom2_smsc911x_resources),
+	.resource	= zoom2_smsc911x_resources,
+	.dev		= {
+		.platform_data = &zoom_smsc911x_config,
+	}
 };
 
 #ifdef CONFIG_WL127X_RFKILL
@@ -192,6 +219,15 @@
 };
 #endif
 
+/* GPIOS need to be in order of BT, FM and GPS
+ * provide -1 is Not applicable for chip */
+static int gpios[] = {109, 161, -1};
+static struct platform_device zoom_btfmgps_device = {
+       .name           = "kim", /* named after init manager for ST */
+       .id             = -1,
+       .dev.platform_data = &gpios,
+};
+
 /* Zoom2 has Qwerty keyboard*/
 static int zoom2_twl4030_keymap[] = {
 	KEY(0, 0, KEY_E),
@@ -308,8 +344,7 @@
 	},
 };
 
-#define LCD_PANEL_BACKLIGHT_GPIO 	(15 + OMAP_MAX_GPIO_LINES)
-#define LCD_PANEL_ENABLE_GPIO 		(7 + OMAP_MAX_GPIO_LINES)
+#define LCD_PANEL_BACKLIGHT_GPIO 	(7 + OMAP_MAX_GPIO_LINES)
 
 #define LCD_PANEL_RESET_GPIO		55
 #define LCD_PANEL_QVGA_GPIO		56
@@ -336,18 +371,19 @@
 {
 	unsigned char lcd_panel_reset_gpio;
 
-	omap_cfg_reg(AF21_34XX_GPIO8);
+	if (!cpu_is_omap3630())
+		omap_cfg_reg(AF21_34XX_GPIO8);
 	omap_cfg_reg(B23_34XX_GPIO167);
 	omap_cfg_reg(AB1_34XX_McSPI1_CS2);
 	omap_cfg_reg(A24_34XX_GPIO94);
 
-	if (omap_rev() > OMAP3430_REV_ES3_0) {
-		/* Production Zoom2 Board:
-		 * GPIO-96 is the LCD_RESET_GPIO
-		 */
-		omap_cfg_reg(C25_34XX_GPIO96);
-		lcd_panel_reset_gpio = 96;
-	} else {
+	/* Production Zoom2 Board:
+	 * GPIO-96 is the LCD_RESET_GPIO
+	 */
+	omap_cfg_reg(C25_34XX_GPIO96);
+	lcd_panel_reset_gpio = 96;
+
+	if (cpu_is_omap34xx() && (omap_rev() <= OMAP3430_REV_ES3_0)) {
 		/* Pilot Zoom2 board
 		 * GPIO-55 is the LCD_RESET_GPIO
 		 */
@@ -357,14 +393,12 @@
 
 	gpio_request(lcd_panel_reset_gpio, "lcd reset");
 	gpio_request(LCD_PANEL_QVGA_GPIO, "lcd qvga");
-	gpio_request(LCD_PANEL_ENABLE_GPIO, "lcd panel");
 	gpio_request(LCD_PANEL_BACKLIGHT_GPIO, "lcd backlight");
 	
 	gpio_request( TV_PANEL_ENABLE_GPIO, "tv panel");
 
 	gpio_direction_output(LCD_PANEL_QVGA_GPIO, 0);
 	gpio_direction_output(lcd_panel_reset_gpio, 0);
-	gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
 	gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
 
 	gpio_direction_output(TV_PANEL_ENABLE_GPIO, 0);
@@ -387,7 +421,6 @@
 {
 	zoom2_panel_power_enable(1);
 
-	gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 1);
 	gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 1);
 
 	return 0;
@@ -395,9 +428,10 @@
 
 static void zoom2_panel_disable_lcd(struct omap_dss_device *dssdev)
 {
+#ifndef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
 	zoom2_panel_power_enable(0);
+#endif
 
-	gpio_direction_output(LCD_PANEL_ENABLE_GPIO, 0);
 	gpio_direction_output(LCD_PANEL_BACKLIGHT_GPIO, 0);
 
 }
@@ -432,8 +466,15 @@
 static void zoom2_panel_disable_hdmi(struct omap_dss_device *dssdev)
 {
 	zoom2_hdmi_reset_enable(0);
+#ifndef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
 	zoom2_panel_power_enable(0);
+#endif
 }
+struct hdmi_platform_data zoom2_hdmi_data = {
+#ifdef CONFIG_PM
+	.set_min_bus_tput = omap_pm_set_min_bus_tput,
+#endif
+};
 
 static struct omap_dss_device zoom2_hdmi_device = {
 	.name = "hdmi",
@@ -442,6 +483,9 @@
 	.phy.dpi.data_lines = 24,
 	.platform_enable = zoom2_panel_enable_hdmi,
 	.platform_disable = zoom2_panel_disable_hdmi,
+	.dev		= {
+		.platform_data = &zoom2_hdmi_data,
+	},
 };
 #endif
 
@@ -485,6 +529,7 @@
 };
 
 static struct omap_dss_board_info zoom2_dss_data = {
+	.get_last_off_on_transaction_id = get_last_off_on_transaction_id,
 	.num_devices = ARRAY_SIZE(zoom2_dss_devices),
 	.devices = zoom2_dss_devices,
 	.default_device = &zoom2_lcd_device,
@@ -503,6 +548,11 @@
 	.dev		= &zoom2_dss_device.dev,
 };
 
+static struct regulator_consumer_supply zoom2_vdds_dsi_supply = {
+	.supply		= "vdds_dsi",
+	.dev		= &zoom2_dss_device.dev,
+};
+
 #ifdef CONFIG_FB_OMAP2
 static struct resource zoom2_vout_resource[3 - CONFIG_FB_OMAP2_NUM_FBS] = {
 };
@@ -511,16 +561,47 @@
 };
 #endif
 
+#ifdef CONFIG_PM
+struct vout_platform_data zoom2_vout_data = {
+	.set_min_bus_tput = omap_pm_set_min_bus_tput,
+	.set_max_mpu_wakeup_lat =  omap_pm_set_max_mpu_wakeup_lat,
+	.set_vdd1_opp = omap_pm_set_min_mpu_freq,
+	.set_cpu_freq = omap_pm_cpu_set_freq,
+};
+#endif
+
 static struct platform_device zoom2_vout_device = {
 	.name		= "omap_vout",
 	.num_resources	= ARRAY_SIZE(zoom2_vout_resource),
 	.resource	= &zoom2_vout_resource[0],
 	.id		= -1,
+#ifdef CONFIG_PM
+	.dev		= {
+		.platform_data = &zoom2_vout_data,
+	}
+#else
+	.dev		= {
+		.platform_data = NULL,
+	}
+#endif
+};
+
+static struct gpio_switch_platform_data headset_switch_data = {
+	.name		= "h2w",
+	.gpio		= OMAP_MAX_GPIO_LINES + 2, /* TWL4030 GPIO_2 */
+};
+
+static struct platform_device headset_switch_device = {
+	.name		= "switch-gpio",
+	.id		= -1,
+	.dev		= {
+		.platform_data = &headset_switch_data,
+	}
 };
 
 static struct platform_device *zoom2_devices[] __initdata = {
 	&zoom2_dss_device,
-	&zoom2_smc911x_device,
+	&zoom2_smsc911x_device,
 #ifdef CONFIG_WL127X_RFKILL
 	&zoom2_wl127x_device,
 #endif
@@ -528,6 +609,8 @@
 	&omap_hdq_device,
 #endif
 	&zoom2_vout_device,
+	&headset_switch_device,
+	&zoom_btfmgps_device,
 };
 
 static inline void __init zoom2_init_smc911x(void)
@@ -543,13 +626,13 @@
 		return;
 	}
 
-	zoom2_smc911x_resources[0].start = cs_mem_base + 0x0;
-	zoom2_smc911x_resources[0].end   = cs_mem_base + 0xf;
+	zoom2_smsc911x_resources[0].start = cs_mem_base + 0x0;
+	zoom2_smsc911x_resources[0].end   = cs_mem_base + 0xf;
 	udelay(100);
 
 	eth_gpio = LDP_SMC911X_GPIO;
 
-	zoom2_smc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
+	zoom2_smsc911x_resources[1].start = OMAP_GPIO_IRQ(eth_gpio);
 
 	if (gpio_request(eth_gpio, "smc911x irq") < 0) {
 		printk(KERN_ERR "Failed to request GPIO%d for smc911x IRQ\n",
@@ -585,9 +668,51 @@
 
 static void __init omap_zoom2_init_irq(void)
 {
-	omap2_init_common_hw(mt46h32m32lf6_sdrc_params, omap3_mpu_rate_table,
-			     omap3_dsp_rate_table, omap3_l3_rate_table);
-	omap2_mux_register(&zoom2_mux_cfg);
+	if (cpu_is_omap3630()) {
+		omap2_init_common_hw(h8mbx00u0mer0em_sdrc_params,
+		omap3630_mpu_rate_table, omap3630_dsp_rate_table,
+		omap3630_l3_rate_table);
+	} else {
+		switch (omap_rev_id()) {
+		case OMAP_3420:
+			omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+			omap3_mpu_rate_table, omap3_dsp_rate_table_3420,
+			omap3_l3_rate_table);
+			break;
+
+		case OMAP_3430:
+			omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+			omap3_mpu_rate_table, omap3_dsp_rate_table,
+			omap3_l3_rate_table);
+			break;
+
+		case OMAP_3440:
+			omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+			omap3_mpu_rate_table, omap3_dsp_rate_table_3440,
+			omap3_l3_rate_table);
+			break;
+
+		default:
+			omap2_init_common_hw(mt46h32m32lf6_sdrc_params,
+			omap3_mpu_rate_table, omap3_dsp_rate_table,
+			omap3_l3_rate_table);
+			break;
+		}
+	}
+
+	/* Set Mcbsp only for Producton units */
+	/* Else you will see white screen on beta boards */
+
+	if (cpu_is_omap3630() || (omap_rev() > OMAP3430_REV_ES3_0)) {
+		/* Production board supports McBSP4 */
+		omap2_mux_register(&zoom2_mux_cfg);
+	} else {
+		/* McBSP4_CLK is linked to LCD_RESET line
+		 * on Pre-Production zoom2's
+		 * Hence a white screen seen
+		 */
+		printk(KERN_WARNING "Issue: McBSP4 not supported on this baord");
+	}
 	omap_init_irq();
 	omap_gpio_init();
 	zoom2_init_smc911x();
@@ -663,17 +788,32 @@
 	.consumer_supplies      = &zoom2_vdda_dac_supply,
 };
 
+static struct regulator_init_data zoom2_vdsi = {
+	.constraints = {
+		.min_uV                 = 1800000,
+		.max_uV                 = 1800000,
+		.valid_modes_mask       = REGULATOR_MODE_NORMAL
+					| REGULATOR_MODE_STANDBY,
+		.valid_ops_mask         = REGULATOR_CHANGE_MODE
+					| REGULATOR_CHANGE_STATUS,
+	},
+	.num_consumer_supplies  = 1,
+	.consumer_supplies      = &zoom2_vdds_dsi_supply,
+};
+
 static struct twl4030_hsmmc_info mmc[] __initdata = {
 	{
 		.mmc		= 1,
 		.wires		= 4,
 		.gpio_wp	= -EINVAL,
 	},
+#ifdef CONFIG_OMAP_HS_MMC2
 	{
 		.mmc		= 2,
-		.wires		= 4,
+		.wires		= 8,
 		.gpio_wp	= -EINVAL,
 	},
+#endif
 	{
 		.mmc		= 3,
 		.wires		= 4,
@@ -747,6 +887,97 @@
 	.irq_line	= 1,
 };
 
+static struct twl4030_ins __initdata sleep_on_seq[] = {
+
+	/* Turn off HFCLKOUT */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_OFF), 2},
+	/* Turn OFF VDD1 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_OFF), 2},
+	/* Turn OFF VDD2 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_OFF), 2},
+	/* Turn OFF VPLL1 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_OFF), 2},
+};
+
+static struct twl4030_script sleep_on_script __initdata = {
+	.script	= sleep_on_seq,
+	.size	= ARRAY_SIZE(sleep_on_seq),
+	.flags	= TRITON_SLEEP_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p12_seq[] __initdata = {
+	/* Turn on HFCLKOUT */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+	/* Turn ON VDD1 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_ACTIVE), 2},
+	/* Turn ON VDD2 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_ACTIVE), 2},
+	/* Turn ON VPLL1 */
+	{MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p12_script __initdata = {
+	.script = wakeup_p12_seq,
+	.size   = ARRAY_SIZE(wakeup_p12_seq),
+	.flags  = TRITON_WAKEUP12_SCRIPT,
+};
+
+static struct twl4030_ins wakeup_p3_seq[] __initdata = {
+	{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wakeup_p3_script __initdata = {
+	.script = wakeup_p3_seq,
+	.size   = ARRAY_SIZE(wakeup_p3_seq),
+	.flags  = TRITON_WAKEUP3_SCRIPT,
+};
+
+static struct twl4030_ins wrst_seq[] __initdata = {
+/*
+ * Reset twl4030.
+ * Reset VDD1 regulator.
+ * Reset VDD2 regulator.
+ * Reset VPLL1 regulator.
+ * Enable sysclk output.
+ * Reenable twl4030.
+ */
+	{MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_OFF), 2},
+	{MSG_SINGULAR(DEV_GRP_P1, 0xf, RES_STATE_WRST), 15},
+	{MSG_SINGULAR(DEV_GRP_P1, 0x10, RES_STATE_WRST), 15},
+	{MSG_SINGULAR(DEV_GRP_P1, 0x7, RES_STATE_WRST), 0x60},
+	{MSG_SINGULAR(DEV_GRP_P1, 0x19, RES_STATE_ACTIVE), 2},
+	{MSG_SINGULAR(DEV_GRP_NULL, 0x1b, RES_STATE_ACTIVE), 2},
+};
+
+static struct twl4030_script wrst_script __initdata = {
+	.script = wrst_seq,
+	.size   = ARRAY_SIZE(wrst_seq),
+	.flags  = TRITON_WRST_SCRIPT,
+};
+
+static struct twl4030_script *twl4030_scripts[] __initdata = {
+	&sleep_on_script,
+	&wakeup_p12_script,
+	&wakeup_p3_script,
+	&wrst_script,
+};
+
+static struct twl4030_resconfig twl4030_rconfig[] = {
+	{ .resource = RES_HFCLKOUT, .devgroup = DEV_GRP_P3, .type = -1,
+		.type2 = -1 },
+	{ .resource = RES_VDD1, .devgroup = DEV_GRP_P1, .type = -1,
+		.type2 = -1 },
+	{ .resource = RES_VDD2, .devgroup = DEV_GRP_P1, .type = -1,
+		.type2 = -1 },
+	{ 0, 0},
+};
+
+static struct twl4030_power_data zoom2_t2scripts_data __initdata = {
+	.scripts	= twl4030_scripts,
+	.size		= ARRAY_SIZE(twl4030_scripts),
+	.resource_config = twl4030_rconfig,
+};
+
 static struct twl4030_platform_data zoom2_twldata = {
 	.irq_base	= TWL4030_IRQ_BASE,
 	.irq_end	= TWL4030_IRQ_END,
@@ -757,10 +988,12 @@
 	.usb		= &zoom2_usb_data,
 	.gpio		= &zoom2_gpio_data,
 	.keypad		= &zoom2_kp_twl4030_data,
+	.power		= &zoom2_t2scripts_data,
 	.vmmc1          = &zoom2_vmmc1,
 	.vmmc2          = &zoom2_vmmc2,
 	.vsim           = &zoom2_vsim,
 	.vdac		= &zoom2_vdac,
+	.vpll2		= &zoom2_vdsi,
 };
 
 static struct i2c_board_info __initdata zoom2_i2c_bus1_info[] = {
@@ -807,13 +1040,14 @@
 		.platform_data = &synaptics_platform_data,
 		.irq = OMAP_GPIO_IRQ(OMAP_SYNAPTICS_GPIO),
 	},
-#if defined(CONFIG_VIDEO_IMX046) || defined(CONFIG_VIDEO_IMX046_MODULE)
+#if (defined(CONFIG_VIDEO_IMX046) || defined(CONFIG_VIDEO_IMX046_MODULE)) && \
+    defined(CONFIG_VIDEO_OMAP3)
 	{
 		I2C_BOARD_INFO("imx046", IMX046_I2C_ADDR),
 		.platform_data = &zoom2_imx046_platform_data,
 	},
 #endif
-#ifdef CONFIG_VIDEO_LV8093
+#if defined(CONFIG_VIDEO_LV8093) && defined(CONFIG_VIDEO_OMAP3)
 	{
 		I2C_BOARD_INFO(LV8093_NAME,  LV8093_AF_I2C_ADDR),
 		.platform_data = &zoom2_lv8093_platform_data,
@@ -832,6 +1066,30 @@
 
 static int __init omap_i2c_init(void)
 {
+
+/* Disable OMAP 3630 internal pull-ups for I2Ci */
+	if (cpu_is_omap3630()) {
+
+		u32 prog_io;
+
+		prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
+		/* Program (bit 19)=1 to disable internal pull-up on I2C1 */
+		prog_io |= OMAP3630_PRG_I2C1_PULLUPRESX;
+		/* Program (bit 0)=1 to disable internal pull-up on I2C2 */
+		prog_io |= OMAP3630_PRG_I2C2_PULLUPRESX;
+		omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
+
+		prog_io = omap_ctrl_readl(OMAP36XX_CONTROL_PROG_IO2);
+		/* Program (bit 7)=1 to disable internal pull-up on I2C3 */
+		prog_io |= OMAP3630_PRG_I2C3_PULLUPRESX;
+		omap_ctrl_writel(prog_io, OMAP36XX_CONTROL_PROG_IO2);
+
+		prog_io = omap_ctrl_readl(OMAP36XX_CONTROL_PROG_IO_WKUP1);
+		/* Program (bit 5)=1 to disable internal pull-up on I2C4(SR) */
+		prog_io |= OMAP3630_PRG_SR_PULLUPRESX;
+		omap_ctrl_writel(prog_io, OMAP36XX_CONTROL_PROG_IO_WKUP1);
+	}
+
 	omap_register_i2c_bus(1, 100, zoom2_i2c_bus1_info,
 			ARRAY_SIZE(zoom2_i2c_bus1_info));
 	omap_register_i2c_bus(2, 100, zoom2_i2c_bus2_info,
@@ -848,6 +1106,12 @@
 	omap_cfg_reg(W21_34XX_GPIO162);
 }
 
+static void config_bt_gpio(void)
+{
+	/* configure BT_EN gpio */
+	omap_cfg_reg(B25_34XX_GPIO109);
+}
+
 static void enable_board_wakeup_source(void)
 {
 	omap_cfg_reg(AF26_34XX_SYS_NIRQ);
@@ -859,9 +1123,37 @@
 	omap_cfg_reg(C27_34XX_CAM_PCLK);
 }
 
+static void config_mux_mcbsp3(void)
+{
+	/*Mux setting for GPIO164 McBSP3*/
+	omap_cfg_reg(H19_34XX_GPIO164_OUT);
+}
+static int __init wl127x_vio_leakage_fix(void)
+{
+	int ret = 0;
+
+	ret = gpio_request(WL127X_BTEN_GPIO, "wl127x_bten");
+	if (ret < 0) {
+		printk(KERN_ERR "wl127x_bten gpio_%d request fail",
+						WL127X_BTEN_GPIO);
+		goto fail;
+	}
+
+	gpio_direction_output(WL127X_BTEN_GPIO, 1);
+	mdelay(10);
+	gpio_direction_output(WL127X_BTEN_GPIO, 0);
+	udelay(64);
+
+	gpio_free(WL127X_BTEN_GPIO);
+fail:
+	return ret;
+}
+
 static void __init omap_zoom2_init(void)
 {
 	omap_i2c_init();
+	/* Fix to prevent VIO leakage on wl127x */
+	wl127x_vio_leakage_fix();
 	platform_add_devices(zoom2_devices, ARRAY_SIZE(zoom2_devices));
 	omap_board_config = zoom2_config;
 	omap_board_config_size = ARRAY_SIZE(zoom2_config);
@@ -874,8 +1166,10 @@
 	omap_serial_init();
 	usb_musb_init();
 	config_wlan_gpio();
+	config_bt_gpio();
 	zoom2_cam_init();
 	zoom2_lcd_tv_panel_init();
+	config_mux_mcbsp3();
 #ifdef CONFIG_SIL9022
 	config_hdmi_gpio();
 	zoom2_hdmi_reset_enable(1);
@@ -885,9 +1179,9 @@
 
 static struct map_desc zoom2_io_desc[] __initdata = {
 	{
-		.virtual	= ZOOM2_QUART_VIRT,
+		.virtual	= ZOOM2_EXT_QUART_VIRT,
 		.pfn		= __phys_to_pfn(ZOOM2_QUART_PHYS),
-		.length		= ZOOM2_QUART_SIZE,
+		.length		= ZOOM2_EXT_QUART_SIZE,
 		.type		= MT_DEVICE
 	},
 };
@@ -899,12 +1193,16 @@
 	omap2_map_common_io();
 }
 
+#ifdef CONFIG_MACH_OMAP_ZOOM3
+MACHINE_START(OMAP_ZOOM3, "OMAP ZOOM3 board")
+#else
 MACHINE_START(OMAP_ZOOM2, "OMAP ZOOM2 board")
+#endif
 	/* phys_io is only used for DEBUG_LL early printing.  The Zoom2's
 	 * console is on an external quad UART sitting at address 0x10000000
 	 */
-	.phys_io	= 0x10000000,
-	.io_pg_offst	= ((0xfb000000) >> 18) & 0xfffc,
+	.phys_io	= ZOOM2_EXT_QUART_PHYS,
+	.io_pg_offst	= ((ZOOM2_EXT_QUART_VIRT) >> 18) & 0xfffc,
 	.boot_params	= 0x80000100,
 	.map_io		= omap_zoom2_map_io,
 	.init_irq	= omap_zoom2_init_irq,
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 672cfb6..f377a2e 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -448,6 +448,41 @@
 	return 0;
 }
 
+/** omap3_pwrdn_bug_clk_enable - enable clocks suffering from PWRDN bug
+ * @clk: DPLL output struct clk
+ *
+ * 3630 only: dpll3_m3_ck, dpll4_m2_ck, dpll4_m3_ck, dpll4_m4_ck, dpll4_m5_ck
+ * & dpll4_m6_ck dividers get lost after their respective PWRDN bits are set.
+ * Any write to the corresponding CM_CLKSEL register will refresh the
+ * dividers.  Only x2 clocks are affected, so it is safe to trust the parent
+ * clock information to refresh the CM_CLKSEL registers.
+ */
+int omap3_pwrdn_bug_clk_enable(struct clk *clk)
+{
+	u32 v;
+
+	v = _omap2_clk_read_reg(clk->enable_reg, clk);
+	if (clk->flags & INVERT_ENABLE)
+		v &= ~(1 << clk->enable_bit);
+	else
+		v |= (1 << clk->enable_bit);
+	_omap2_clk_write_reg(v, clk->enable_reg, clk);
+	v = _omap2_clk_read_reg(clk->enable_reg, clk); /* OCP barrier */
+
+	omap2_clk_wait_ready(clk);
+
+	v = __raw_readl(OMAP34XX_CM_REGADDR(clk->parent->prcm_mod,
+				clk->parent->clksel_reg));
+	v += (1 << clk->parent->clksel_shift);
+	__raw_writel(v, OMAP34XX_CM_REGADDR(clk->parent->prcm_mod,
+				clk->parent->clksel_reg));
+	v -= (1 << clk->parent->clksel_shift);
+	__raw_writel(v, OMAP34XX_CM_REGADDR(clk->parent->prcm_mod,
+				clk->parent->clksel_reg));
+
+	return 0;
+}
+
 /* Disables clock without considering parent dependencies or use count */
 static void _omap2_clk_disable(struct clk *clk)
 {
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 4964aad..f06add5 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -47,6 +47,7 @@
 int omap2_dpll_set_rate_tolerance(struct clk *clk, unsigned int tolerance);
 long omap2_dpll_round_rate(struct clk *clk, unsigned long target_rate);
 struct clk *omap2_clk_get_parent(struct clk *clk);
+int omap3_pwrdn_bug_clk_enable(struct clk *clk);
 
 #ifdef CONFIG_OMAP_RESET_CLOCKS
 void omap2_clk_disable_unused(struct clk *clk);
@@ -72,7 +73,7 @@
 			   const char *name);
 void omap2_clk_prepare_for_reboot(void);
 
-extern void omap3_lock_dpll5();
+extern void omap3_lock_dpll5(void);
 extern u8 cpu_mask;
 
 /* clksel_rate data common to 24xx/343x */
diff --git a/arch/arm/mach-omap2/clock34xx.c b/arch/arm/mach-omap2/clock34xx.c
index 35cf4b3..c3e3535 100644
--- a/arch/arm/mach-omap2/clock34xx.c
+++ b/arch/arm/mach-omap2/clock34xx.c
@@ -28,6 +28,7 @@
 #include <linux/bitops.h>
 #include <linux/err.h>
 #include <linux/cpufreq.h>
+#include <linux/i2c/twl4030.h>
 
 #include <mach/clock.h>
 #include <mach/sram.h>
@@ -62,7 +63,7 @@
  * SDRC_MPURATE_LOOPS: Number of MPU loops to execute at
  * 2^MPURATE_BASE_SHIFT MHz for SDRC to stabilize
  */
-#define SDRC_MPURATE_LOOPS		96
+#define SDRC_MPURATE_LOOPS		24
 
 /**
  * omap3_dpll_recalc - recalculate DPLL rate
@@ -311,7 +312,7 @@
 }
 
 /**
- * omap3_noncore_dpll_enable - instruct a DPLL to enter bypass or lock mode
+ * omap3_noncore_dpll_disable - instruct a DPLL to enter bypass or lock mode
  * @clk: pointer to a DPLL struct clk
  *
  * Instructs a non-CORE DPLL to enable, e.g., to enter bypass or lock.
@@ -332,8 +333,34 @@
 	_omap3_noncore_dpll_stop(clk);
 }
 
+/* OMAP3630 j-type DPLL4 compensation variables */
+void lookup_dco_sddiv(struct clk *clk, u8 *dco, u8 *sd_div, u16 m, u8 n)
+{
+	unsigned long fint, clkinp, sd; /* watch out for overflow */
+	int mod1, mod2;
 
-/* Non-CORE DPLL rate set code */
+	++n; /* always n+1 below */
+	clkinp = clk->parent->rate;
+	fint = (clkinp / n) * m;
+
+	if (fint < 1000000000)
+		*dco = 2;
+	else
+		*dco = 4;
+	/*
+	* target sigma-delta to near 250MHz
+	* sd = ceil[(m/(n+1)) * (clkinp_MHz / 250)]
+	*/
+	clkinp /= 100000; /* shift from MHz to 10*Hz for 38.4 and 19.2*/
+	mod1 = (clkinp * m) % (250 * n);
+	sd = (clkinp * m) / (250 * n);
+	mod2 = sd % 10;
+	sd /= 10;
+
+	if (mod1 + mod2)
+		++sd;
+	*sd_div = sd;
+}
 
 /*
  * omap3_noncore_dpll_program - set non-core DPLL M,N values directly
@@ -383,6 +410,13 @@
 	v &= ~(dd->mult_mask | dd->div1_mask);
 	v |= m << __ffs(dd->mult_mask);
 	v |= (n - 1) << __ffs(dd->div1_mask);
+	if (dd->jtype) {
+		u8 dco, sd_div;
+		lookup_dco_sddiv(clk, &dco, &sd_div, m, n);
+		v &= ~(dd->dco_sel_mask | dd->sd_div_mask);
+		v |=  dco << __ffs(dd->dco_sel_mask);
+		v |=  sd_div << __ffs(dd->sd_div_mask);
+	}
 	cm_write_mod_reg(v, clk->prcm_mod, dd->mult_div1_reg);
 
 	/* We let the clock framework set the other output dividers later */
@@ -644,7 +678,7 @@
 
 	v = cm_read_mod_reg(pclk->prcm_mod, dd->control_reg) & dd->enable_mask;
 	v >>= __ffs(dd->enable_mask);
-	if (v == OMAP3XXX_EN_DPLL_LOCKED)
+	if (v == OMAP3XXX_EN_DPLL_LOCKED && (!dd->jtype))
 		rate *= 2;
 
 	if (rate_storage == CURRENT_RATE)
@@ -662,7 +696,7 @@
 #if defined(CONFIG_ARCH_OMAP3)
 
 #ifdef CONFIG_CPU_FREQ
-static struct cpufreq_frequency_table freq_table[MAX_VDD1_OPP+1];
+static struct cpufreq_frequency_table freq_table[VDD1_OPP6+1];
 
 void omap2_clk_init_cpufreq_table(struct cpufreq_frequency_table **table)
 {
@@ -672,8 +706,7 @@
 	if (!mpu_opps)
 		return;
 
-	/* Avoid registering the 120% Overdrive with CPUFreq */
-	prcm = mpu_opps + MAX_VDD1_OPP - 1;
+	prcm = mpu_opps + MAX_VDD1_OPP;
 	for (; prcm->rate; prcm--) {
 		freq_table[i].index = i;
 		freq_table[i].frequency = prcm->rate / 1000;
@@ -714,6 +747,8 @@
  */
 void omap2_clk_prepare_for_reboot(void)
 {
+	int err = 0;
+
 	/* REVISIT: Not ready for 343x */
 #if 0
 	u32 rate;
@@ -724,9 +759,21 @@
 	rate = clk_get_rate(sclk);
 	clk_set_rate(vclk, rate);
 #endif
+
+	/*
+	 * PRCM on OMAP3 will drive SYS_OFFMODE low during DPLL3 warm reset.
+	 * This causes Gaia sleep script to execute, usually killing VDD1 and
+	 * VDD2 while code is running.  WA is to disable the sleep script
+	 * before warm reset.
+	 */
+#ifdef CONFIG_TWL4030_POWER
+	err = twl4030_remove_script(TRITON_SLEEP_SCRIPT);
+	if (err)
+		pr_err("twl4030: error trying to disable sleep script!\n");
+#endif
 }
 
-void omap3_lock_dpll5()
+void omap3_lock_dpll5(void)
 {
 	struct clk *dpll5_clk;
 	struct clk *dpll5_m2_clk;
@@ -807,13 +854,46 @@
 			cpu_mask |= RATE_IN_3430ES2;
 			cpu_clkflg |= CLOCK_IN_OMAP3430ES2;
 		}
-	}
+		if (cpu_is_omap3630()) {
+			dpll4_ck.dpll_data->jtype = 1;
+			dpll4_dd.mult_mask =
+				OMAP3430_PERIPH_DPLL_36XX_MULT_MASK;
 
+			dpll3_m3x2_ck.enable =
+				&omap3_pwrdn_bug_clk_enable;
+			dpll4_m2x2_ck.enable =
+				&omap3_pwrdn_bug_clk_enable;
+			dpll4_m3x2_ck.enable =
+				&omap3_pwrdn_bug_clk_enable;
+			dpll4_m4x2_ck.enable =
+				&omap3_pwrdn_bug_clk_enable;
+			dpll4_m5x2_ck.enable =
+				&omap3_pwrdn_bug_clk_enable;
+			dpll4_m6x2_ck.enable =
+				&omap3_pwrdn_bug_clk_enable;
+
+			cpu_clkflg |= CLOCK_IN_OMAP363X;
+			cpu_mask |= RATE_IN_363X;
+
+			omap_96m_alwon_fck.parent = &omap_192m_alwon_ck;
+			omap_96m_alwon_fck.init = &omap2_init_clksel_parent;
+			omap_96m_alwon_fck.clksel_reg = CM_CLKSEL;
+			omap_96m_alwon_fck.prcm_mod = CORE_MOD;
+			omap_96m_alwon_fck.clksel_mask =
+				OMAP3630_CLKSEL_96M_MASK;
+			omap_96m_alwon_fck.clksel = omap_96m_alwon_fck_clksel;
+			omap_96m_alwon_fck.recalc = &omap2_clksel_recalc;
+			}
+	}
 	clk_init(&omap2_clk_functions);
 
 	for (clkp = onchip_34xx_clks;
 	     clkp < onchip_34xx_clks + ARRAY_SIZE(onchip_34xx_clks);
 	     clkp++) {
+		if (cpu_is_omap3630()) {
+			if ((*clkp)->flags & CLOCK_IN_OMAP363X)
+				(*clkp)->clksel_mask = (*clkp)->clksel_mask2;
+		}
 		if ((*clkp)->flags & cpu_clkflg)
 			clk_register(*clkp);
 	}
diff --git a/arch/arm/mach-omap2/clock34xx.h b/arch/arm/mach-omap2/clock34xx.h
index f00bdf7..dca19ad 100644
--- a/arch/arm/mach-omap2/clock34xx.h
+++ b/arch/arm/mach-omap2/clock34xx.h
@@ -253,6 +253,22 @@
 	{ .div = 14, .val = 14, .flags = RATE_IN_343X },
 	{ .div = 15, .val = 15, .flags = RATE_IN_343X },
 	{ .div = 16, .val = 16, .flags = RATE_IN_343X },
+	{ .div = 17, .val = 17, .flags = RATE_IN_343X },
+	{ .div = 18, .val = 18, .flags = RATE_IN_343X },
+	{ .div = 19, .val = 19, .flags = RATE_IN_343X },
+	{ .div = 20, .val = 20, .flags = RATE_IN_343X },
+	{ .div = 21, .val = 21, .flags = RATE_IN_343X },
+	{ .div = 22, .val = 22, .flags = RATE_IN_343X },
+	{ .div = 23, .val = 23, .flags = RATE_IN_343X },
+	{ .div = 24, .val = 24, .flags = RATE_IN_343X },
+	{ .div = 25, .val = 25, .flags = RATE_IN_343X },
+	{ .div = 26, .val = 26, .flags = RATE_IN_343X },
+	{ .div = 27, .val = 27, .flags = RATE_IN_343X },
+	{ .div = 28, .val = 28, .flags = RATE_IN_343X },
+	{ .div = 29, .val = 29, .flags = RATE_IN_343X },
+	{ .div = 30, .val = 30, .flags = RATE_IN_343X },
+	{ .div = 31, .val = 31, .flags = RATE_IN_343X },
+	{ .div = 32, .val = 32, .flags = RATE_IN_343X },
 	{ .div = 0 }
 };
 
@@ -514,6 +530,7 @@
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= CM_CLKSEL1,
 	.clksel_mask	= OMAP3430_DIV_DPLL3_MASK,
+	.clksel_shift	= OMAP3430_DIV_DPLL3_SHIFT,
 	.clksel		= div16_dpll3_clksel,
 	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
 	.clkdm		= { .name = "dpll3_clkdm" },
@@ -592,6 +609,7 @@
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= OMAP3430_CM_CLKSEL3,
 	.clksel_mask	= OMAP3430_DIV_96M_MASK,
+	.clksel_shift	= OMAP3430_DIV_96M_SHIFT,
 	.clksel		= div16_dpll4_clksel,
 	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
 	.clkdm		= { .name = "dpll4_clkdm" },
@@ -616,6 +634,27 @@
  * 96M_ALWON_FCLK (called "omap_96m_alwon_fck" below) and
  * CM_96K_(F)CLK.
  */
+
+static struct clk omap_192m_alwon_ck = {
+	.name		= "omap_192m_alwon_ck",
+	.parent		= &dpll4_m2x2_ck,
+	.flags		= CLOCK_IN_OMAP363X | PARENT_CONTROLS_CLOCK,
+	.clkdm		= { .name = "prm_clkdm" },
+	.recalc		= &followparent_recalc,
+   };
+
+static const struct clksel_rate omap_96m_alwon_fck_rates[] = {
+	{ .div = 1, .val = 1, .flags = RATE_IN_363X },
+	{ .div = 2, .val = 2, .flags = RATE_IN_363X | DEFAULT_RATE },
+	{ .div = 0 }
+};
+
+static const struct clksel omap_96m_alwon_fck_clksel[] = {
+	{ .parent = &omap_192m_alwon_ck, .rates = omap_96m_alwon_fck_rates },
+	{ .parent = NULL }
+};
+
+
 static struct clk omap_96m_alwon_fck = {
 	.name		= "omap_96m_alwon_fck",
 	.parent		= &dpll4_m2x2_ck,
@@ -669,8 +708,11 @@
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= CM_CLKSEL,
 	.clksel_mask	= OMAP3430_CLKSEL_TV_MASK,
+	.clksel_mask2 = OMAP3630_CLKSEL_TV_MASK,
+	.clksel_shift = OMAP3430_CLKSEL_TV_SHIFT,
 	.clksel		= div16_dpll4_clksel,
-	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK
+					| CLOCK_IN_OMAP363X,
 	.clkdm		= { .name = "dpll4_clkdm" },
 	.recalc		= &omap2_clksel_recalc,
 };
@@ -761,8 +803,11 @@
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= CM_CLKSEL,
 	.clksel_mask	= OMAP3430_CLKSEL_DSS1_MASK,
+	.clksel_mask2	= OMAP3630_CLKSEL_DSS1_MASK,
+	.clksel_shift	= OMAP3430_CLKSEL_DSS1_SHIFT,
 	.clksel		= div16_dpll4_clksel,
-	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK
+					| CLOCK_IN_OMAP363X,
 	.clkdm		= { .name = "dpll4_clkdm" },
 	.recalc		= &omap2_clksel_recalc,
 	.set_rate	= &omap2_clksel_set_rate,
@@ -789,10 +834,15 @@
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= CM_CLKSEL,
 	.clksel_mask	= OMAP3430_CLKSEL_CAM_MASK,
+	.clksel_mask2	= OMAP3630_CLKSEL_CAM_MASK,
+	.clksel_shift	= OMAP3430_CLKSEL_CAM_SHIFT,
 	.clksel		= div16_dpll4_clksel,
-	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK
+					| CLOCK_IN_OMAP363X,
 	.clkdm		= { .name = "dpll4_clkdm" },
 	.recalc		= &omap2_clksel_recalc,
+	.set_rate	= &omap2_clksel_set_rate,
+	.round_rate	= &omap2_clksel_round_rate,
 };
 
 /* The PWRDN bit is apparently only available on 3430ES2 and above */
@@ -815,8 +865,11 @@
 	.init		= &omap2_init_clksel_parent,
 	.clksel_reg	= CM_CLKSEL1,
 	.clksel_mask	= OMAP3430_DIV_DPLL4_MASK,
+	.clksel_mask2	= OMAP3630_DIV_DPLL4_MASK,
+	.clksel_shift	= OMAP3430_DIV_DPLL4_SHIFT,
 	.clksel		= div16_dpll4_clksel,
-	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK,
+	.flags		= CLOCK_IN_OMAP343X | PARENT_CONTROLS_CLOCK
+					| CLOCK_IN_OMAP363X,
 	.clkdm		= { .name = "dpll4_clkdm" },
 	.recalc		= &omap2_clksel_recalc,
 };
@@ -1204,12 +1257,24 @@
 /* SGX power domain - 3430ES2 only */
 
 static const struct clksel_rate sgx_core_rates[] = {
+	{ .div = 2, .val = 5, .flags = RATE_IN_363X },
 	{ .div = 3, .val = 0, .flags = RATE_IN_343X | DEFAULT_RATE },
 	{ .div = 4, .val = 1, .flags = RATE_IN_343X },
 	{ .div = 6, .val = 2, .flags = RATE_IN_343X },
 	{ .div = 0 },
 };
 
+static const struct clksel_rate sgx_192m_rates[] = {
+	{ .div = 1,  .val = 4, .flags = RATE_IN_363X | DEFAULT_RATE },
+	{ .div = 0 },
+};
+
+static const struct clksel_rate sgx_corex2_rates[] = {
+	{ .div = 3, .val = 6, .flags = RATE_IN_363X | DEFAULT_RATE },
+	{ .div = 5, .val = 7, .flags = RATE_IN_363X },
+	{ .div = 0 },
+};
+
 static const struct clksel_rate sgx_96m_rates[] = {
 	{ .div = 1,  .val = 3, .flags = RATE_IN_343X | DEFAULT_RATE },
 	{ .div = 0 },
@@ -1218,6 +1283,9 @@
 static const struct clksel sgx_clksel[] = {
 	{ .parent = &core_ck,	 .rates = sgx_core_rates },
 	{ .parent = &cm_96m_fck, .rates = sgx_96m_rates },
+	{ .parent = &omap_192m_alwon_ck, .rates = sgx_192m_rates },
+	{ .parent = &corex2_fck, .rates = sgx_corex2_rates },
+
 	{ .parent = NULL },
 };
 
@@ -1233,6 +1301,8 @@
 	.flags		= CLOCK_IN_OMAP3430ES2,
 	.clkdm		= { .name = "sgx_clkdm" },
 	.recalc		= &omap2_clksel_recalc,
+	.set_rate	= &omap2_clksel_set_rate,
+	.round_rate	= &omap2_clksel_round_rate,
 };
 
 static struct clk sgx_ick = {
@@ -3368,6 +3438,7 @@
 	&dpll3_m3x2_ck,
 	&emu_core_alwon_ck,
 	&dpll4_ck,
+	&omap_192m_alwon_ck,
 	&omap_96m_alwon_fck,
 	&omap_96m_fck,
 	&cm_96m_fck,
diff --git a/arch/arm/mach-omap2/clockdomain.c b/arch/arm/mach-omap2/clockdomain.c
index fa55b6f..fc1e65e 100644
--- a/arch/arm/mach-omap2/clockdomain.c
+++ b/arch/arm/mach-omap2/clockdomain.c
@@ -134,6 +134,37 @@
 }
 
 
+/*
+ * _omap2_clkdm_set_hwsup - set the hwsup idle transition bit
+ * @clkdm: struct clockdomain *
+ * @enable: int 0 to disable, 1 to enable
+ *
+ * Internal helper for actually switching the bit that controls hwsup
+ * idle transitions for clkdm.
+ */
+static void _omap2_clkdm_set_hwsup(struct clockdomain *clkdm, int enable)
+{
+	u32 v;
+
+	if (cpu_is_omap24xx()) {
+		if (enable)
+			v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
+		else
+			v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
+	} else if (cpu_is_omap34xx()) {
+		if (enable)
+			v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
+		else
+			v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
+	} else {
+		BUG();
+	}
+
+	cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
+			    v << __ffs(clkdm->clktrctrl_mask),
+			    clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
+}
+
 static struct clockdomain *_clkdm_lookup(const char *name)
 {
 	struct clockdomain *clkdm, *temp_clkdm;
@@ -452,7 +483,6 @@
  */
 void omap2_clkdm_allow_idle(struct clockdomain *clkdm)
 {
-	u32 v;
 
 	if (!clkdm)
 		return;
@@ -468,20 +498,7 @@
 
 	if (atomic_read(&clkdm->usecount) > 0)
 		_clkdm_add_autodeps(clkdm);
-
-	if (cpu_is_omap24xx())
-		v = OMAP24XX_CLKSTCTRL_ENABLE_AUTO;
-	else if (cpu_is_omap34xx())
-		v = OMAP34XX_CLKSTCTRL_ENABLE_AUTO;
-	else
-		BUG();
-
-
-	cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
-			    v << __ffs(clkdm->clktrctrl_mask),
-			    clkdm->pwrdm.ptr->prcm_offs,
-			    CM_CLKSTCTRL);
-
+	_omap2_clkdm_set_hwsup(clkdm, 1);
 	pwrdm_clkdm_state_switch(clkdm);
 }
 
@@ -496,7 +513,6 @@
  */
 void omap2_clkdm_deny_idle(struct clockdomain *clkdm)
 {
-	u32 v;
 
 	if (!clkdm)
 		return;
@@ -510,17 +526,7 @@
 	pr_debug("clockdomain: disabling automatic idle transitions for %s\n",
 		 clkdm->name);
 
-	if (cpu_is_omap24xx())
-		v = OMAP24XX_CLKSTCTRL_DISABLE_AUTO;
-	else if (cpu_is_omap34xx())
-		v = OMAP34XX_CLKSTCTRL_DISABLE_AUTO;
-	else
-		BUG();
-
-	cm_rmw_mod_reg_bits(clkdm->clktrctrl_mask,
-			    v << __ffs(clkdm->clktrctrl_mask),
-			    clkdm->pwrdm.ptr->prcm_offs, CM_CLKSTCTRL);
-
+	_omap2_clkdm_set_hwsup(clkdm, 0);
 	if (atomic_read(&clkdm->usecount) > 0)
 		_clkdm_del_autodeps(clkdm);
 }
@@ -565,11 +571,14 @@
 	v = omap2_clkdm_clktrctrl_read(clkdm);
 
 	if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
-	    (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+	    (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
+		/* Disable HW transitions when we are changing deps */
+		_omap2_clkdm_set_hwsup(clkdm, 0);
 		_clkdm_add_autodeps(clkdm);
-	else
+		_omap2_clkdm_set_hwsup(clkdm, 1);
+		} else {
 		omap2_clkdm_wakeup(clkdm);
-
+		}
 	pwrdm_wait_transition(clkdm->pwrdm.ptr);
 	pwrdm_clkdm_state_switch(clkdm);
 
@@ -619,11 +628,14 @@
 	v = omap2_clkdm_clktrctrl_read(clkdm);
 
 	if ((cpu_is_omap34xx() && v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ||
-	    (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO))
+	    (cpu_is_omap24xx() && v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO)) {
+		/*Disable HW transitions when we are changing deps */
+		_omap2_clkdm_set_hwsup(clkdm, 0);
 		_clkdm_del_autodeps(clkdm);
-	else
+		 _omap2_clkdm_set_hwsup(clkdm, 1);
+		} else {
 		omap2_clkdm_sleep(clkdm);
-
+		}
 	pwrdm_clkdm_state_switch(clkdm);
 
 	return 0;
diff --git a/arch/arm/mach-omap2/cm-regbits-34xx.h b/arch/arm/mach-omap2/cm-regbits-34xx.h
index 6923deb..159cb3e 100644
--- a/arch/arm/mach-omap2/cm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/cm-regbits-34xx.h
@@ -81,7 +81,7 @@
 
 /* CM_CLKSEL1_PLL_IVA2 */
 #define OMAP3430_IVA2_CLK_SRC_SHIFT			19
-#define OMAP3430_IVA2_CLK_SRC_MASK			(0x3 << 19)
+#define OMAP3430_IVA2_CLK_SRC_MASK			(0x7 << 19)
 #define OMAP3430_IVA2_DPLL_MULT_SHIFT			8
 #define OMAP3430_IVA2_DPLL_MULT_MASK			(0x7ff << 8)
 #define OMAP3430_IVA2_DPLL_DIV_SHIFT			0
@@ -126,7 +126,7 @@
 
 /* CM_CLKSEL1_PLL_MPU */
 #define OMAP3430_MPU_CLK_SRC_SHIFT			19
-#define OMAP3430_MPU_CLK_SRC_MASK			(0x3 << 19)
+#define OMAP3430_MPU_CLK_SRC_MASK			(0x7 << 19)
 #define OMAP3430_MPU_DPLL_MULT_SHIFT			8
 #define OMAP3430_MPU_DPLL_MULT_MASK			(0x7ff << 8)
 #define OMAP3430_MPU_DPLL_DIV_SHIFT			0
@@ -336,6 +336,8 @@
 #define OMAP3430_CLKSEL_L4_MASK				(0x3 << 2)
 #define OMAP3430_CLKSEL_L3_SHIFT			0
 #define OMAP3430_CLKSEL_L3_MASK				(0x3 << 0)
+#define OMAP3630_CLKSEL_96M_SHIFT			12
+#define OMAP3630_CLKSEL_96M_MASK			(0x3 << 12)
 
 /* CM_CLKSTCTRL_CORE */
 #define OMAP3430ES1_CLKTRCTRL_D2D_SHIFT			4
@@ -517,8 +519,13 @@
 /* CM_CLKSEL2_PLL */
 #define OMAP3430_PERIPH_DPLL_MULT_SHIFT			8
 #define OMAP3430_PERIPH_DPLL_MULT_MASK			(0x7ff << 8)
+#define OMAP3430_PERIPH_DPLL_36XX_MULT_MASK		(0xfff << 8)
 #define OMAP3430_PERIPH_DPLL_DIV_SHIFT			0
 #define OMAP3430_PERIPH_DPLL_DIV_MASK			(0x7f << 0)
+#define OMAP3630_PERIPH_DPLL_DCO_SEL_SHIFT		21
+#define OMAP3630_PERIPH_DPLL_DCO_SEL_MASK		(0x7 << 21)
+#define OMAP3630_PERIPH_DPLL_SD_DIV_SHIFT		24
+#define OMAP3630_PERIPH_DPLL_SD_DIV_MASK		(0xff << 24)
 
 /* CM_CLKSEL3_PLL */
 #define OMAP3430_DIV_96M_SHIFT				0
@@ -569,8 +576,10 @@
 /* CM_CLKSEL_DSS */
 #define OMAP3430_CLKSEL_TV_SHIFT			8
 #define OMAP3430_CLKSEL_TV_MASK				(0x1f << 8)
+#define OMAP3630_CLKSEL_TV_MASK				(0x3f << 8)
 #define OMAP3430_CLKSEL_DSS1_SHIFT			0
 #define OMAP3430_CLKSEL_DSS1_MASK			(0x1f << 0)
+#define OMAP3630_CLKSEL_DSS1_MASK			(0x3f << 0)
 
 /* CM_SLEEPDEP_DSS specific bits */
 
@@ -598,6 +607,7 @@
 /* CM_CLKSEL_CAM */
 #define OMAP3430_CLKSEL_CAM_SHIFT			0
 #define OMAP3430_CLKSEL_CAM_MASK			(0x1f << 0)
+#define OMAP3630_CLKSEL_CAM_MASK			(0x3f << 0)
 
 /* CM_SLEEPDEP_CAM specific bits */
 
@@ -693,8 +703,10 @@
 /* CM_CLKSEL1_EMU */
 #define OMAP3430_DIV_DPLL4_SHIFT			24
 #define OMAP3430_DIV_DPLL4_MASK				(0x1f << 24)
+#define OMAP3630_DIV_DPLL4_MASK				(0x3f << 24)
 #define OMAP3430_DIV_DPLL3_SHIFT			16
 #define OMAP3430_DIV_DPLL3_MASK				(0x1f << 16)
+#define OMAP3630_DIV_DPLL3_MASK				(0x3f << 16)
 #define OMAP3430_CLKSEL_TRACECLK_SHIFT			11
 #define OMAP3430_CLKSEL_TRACECLK_MASK			(0x7 << 11)
 #define OMAP3430_CLKSEL_PCLK_SHIFT			8
diff --git a/arch/arm/mach-omap2/control.c b/arch/arm/mach-omap2/control.c
index c9407c0..4219314 100644
--- a/arch/arm/mach-omap2/control.c
+++ b/arch/arm/mach-omap2/control.c
@@ -209,8 +209,7 @@
 
 	/* Populate the Scratchpad contents */
 	scratchpad_contents.boot_config_ptr = 0x0;
-	if (omap_rev() != OMAP3430_REV_ES3_0 &&
-					omap_rev() != OMAP3430_REV_ES3_1)
+	if (omap_rev() < OMAP3430_REV_ES3_0)
 		scratchpad_contents.public_restore_ptr =
 			virt_to_phys(get_restore_pointer());
 	else
@@ -331,6 +330,27 @@
 		sizeof(sdrc_block_contents), &arm_context_addr, 4);
 }
 
+void omap3_scratchpad_dpll4autoidle(int enable)
+{
+	void * __iomem scratchpad_address;
+	struct omap3_scratchpad_prcm_block prcm_block_contents;
+
+	scratchpad_address = OMAP2_IO_ADDRESS(OMAP343X_SCRATCHPAD);
+
+	memcpy_fromio(&prcm_block_contents, scratchpad_address + 0x2C,
+		sizeof(prcm_block_contents));
+	if (enable)
+		prcm_block_contents.cm_autoidle_pll |=
+			(1 << OMAP3430_AUTO_PERIPH_DPLL_SHIFT);
+	else
+		prcm_block_contents.cm_autoidle_pll &=
+			~OMAP3430_AUTO_PERIPH_DPLL_MASK;
+
+	memcpy_toio(scratchpad_address + 0x2C, &prcm_block_contents,
+		sizeof(prcm_block_contents));
+
+}
+
 void omap3_control_save_context(void)
 {
 	control_context.sysconfig = omap_ctrl_readl(OMAP2_CONTROL_SYSCONFIG);
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index 6ac2c66..6086837 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -35,14 +35,17 @@
 
 #ifdef CONFIG_CPU_IDLE
 
-#define OMAP3_MAX_STATES 7
+#define OMAP3_MAX_STATES 9
 #define OMAP3_STATE_C1 0 /* C1 - MPU WFI + Core active */
-#define OMAP3_STATE_C2 1 /* C2 - MPU WFI + Core inactive */
+#define OMAP3_STATE_C2 1 /* C2 - MPU inactive + Core inactive */
 #define OMAP3_STATE_C3 2 /* C3 - MPU CSWR + Core inactive */
-#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core iactive */
-#define OMAP3_STATE_C5 4 /* C5 - MPU RET + Core RET */
-#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core RET */
-#define OMAP3_STATE_C7 6 /* C7 - MPU OFF + Core OFF */
+#define OMAP3_STATE_C4 3 /* C4 - MPU OFF + Core inactive */
+#define OMAP3_STATE_C5 4 /* C5 - MPU CSWR + Core CSWR */
+#define OMAP3_STATE_C6 5 /* C6 - MPU OFF + Core CSWR */
+#define OMAP3_STATE_C7 6 /* C7 - MPU OSWR + CORE OSWR */
+#define OMAP3_STATE_C8 7 /* C8 - MPU OFF + CORE OSWR */
+#define OMAP3_STATE_C9 8 /* C9 - MPU OFF + CORE OFF */
+
 
 struct omap3_processor_cx {
 	u8 valid;
@@ -51,13 +54,19 @@
 	u32 wakeup_latency;
 	u32 mpu_state;
 	u32 core_state;
+	u32 mpu_logicl1_ret_state;
+	u32 mpu_l2cache_ret_state;
+	u32 core_logic_state;
+	u32 core_mem1_ret_state;
+	u32 core_mem2_ret_state;
 	u32 threshold;
 	u32 flags;
 };
 
 struct omap3_processor_cx omap3_power_states[OMAP3_MAX_STATES];
 struct omap3_processor_cx current_cx_state;
-struct powerdomain *mpu_pd, *core_pd, *per_pd;
+struct powerdomain *mpu_pd, *core_pd, *per_pd, *iva2_pd;
+struct powerdomain *sgx_pd, *usb_pd, *cam_pd, *dss_pd;
 
 static int omap3_idle_bm_check(void)
 {
@@ -66,19 +75,13 @@
 	return 0;
 }
 
-static int _cpuidle_allow_idle(struct powerdomain *pwrdm,
-				struct clockdomain *clkdm)
+static int pwrdm_get_idle_state(struct powerdomain *pwrdm)
 {
-	omap2_clkdm_allow_idle(clkdm);
-	return 0;
+	if (pwrdm_can_idle(pwrdm))
+		return pwrdm_read_next_pwrst(pwrdm);
+	return PWRDM_POWER_ON;
 }
 
-static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
-				struct clockdomain *clkdm)
-{
-	omap2_clkdm_deny_idle(clkdm);
-	return 0;
-}
 
 /**
  * omap3_enter_idle - Programs OMAP3 to enter the specified state
@@ -94,7 +97,11 @@
 	struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
 	struct timespec ts_preidle, ts_postidle, ts_idle;
 	u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
-
+	u32 mpu_logicl1_ret_state = cx->mpu_logicl1_ret_state;
+	u32 mpu_l2cache_ret_state = cx->mpu_l2cache_ret_state;
+	u32 core_logic_state = cx->core_logic_state;
+	u32 core_mem1_ret_state = cx->core_mem1_ret_state;
+	u32 core_mem2_ret_state = cx->core_mem2_ret_state;
 	current_cx_state = *cx;
 
 	/* Used to keep track of the total time in idle */
@@ -103,31 +110,45 @@
 	local_irq_disable();
 	local_fiq_disable();
 
-	if (!enable_off_mode) {
-		if (mpu_state < PWRDM_POWER_RET)
-			mpu_state = PWRDM_POWER_RET;
-		if (core_state < PWRDM_POWER_RET)
-			core_state = PWRDM_POWER_RET;
+
+	if (!enable_oswr_ret) {
+		if (mpu_logicl1_ret_state == PWRDM_POWER_OFF)
+			mpu_logicl1_ret_state = PWRDM_POWER_RET;
+		if (mpu_l2cache_ret_state == PWRDM_POWER_OFF)
+			mpu_l2cache_ret_state = PWRDM_POWER_RET;
+		if (core_logic_state == PWRDM_POWER_OFF)
+			core_logic_state = PWRDM_POWER_RET;
+		if (core_mem1_ret_state == PWRDM_POWER_OFF)
+			core_mem1_ret_state = PWRDM_POWER_RET;
+		if (core_mem2_ret_state == PWRDM_POWER_OFF)
+			core_mem2_ret_state = PWRDM_POWER_RET;
 	}
 
+	if (mpu_logicl1_ret_state != 0xFF)
+		pwrdm_set_logic_retst(mpu_pd, mpu_logicl1_ret_state);
+
+	if (mpu_l2cache_ret_state != 0xFF)
+		pwrdm_set_mem_retst(mpu_pd, 0, mpu_l2cache_ret_state);
+
+	if (core_logic_state != 0xFF)
+		pwrdm_set_logic_retst(core_pd, core_logic_state);
+
+	if (core_mem1_ret_state != 0xFF)
+		pwrdm_set_mem_retst(core_pd, 0, core_mem1_ret_state);
+
+	if (core_mem2_ret_state != 0xFF)
+		pwrdm_set_mem_retst(core_pd, 1, core_mem2_ret_state);
+
 	pwrdm_set_next_pwrst(mpu_pd, mpu_state);
 	pwrdm_set_next_pwrst(core_pd, core_state);
 
 	if (omap_irq_pending() || need_resched())
 		goto return_sleep_time;
 
-	if (cx->type == OMAP3_STATE_C1) {
-		pwrdm_for_each_clkdm(mpu_pd, _cpuidle_deny_idle);
-		pwrdm_for_each_clkdm(core_pd, _cpuidle_deny_idle);
-	}
 
 	/* Execute ARM wfi */
 	omap_sram_idle();
 
-	if (cx->type == OMAP3_STATE_C1) {
-		pwrdm_for_each_clkdm(mpu_pd, _cpuidle_allow_idle);
-		pwrdm_for_each_clkdm(core_pd, _cpuidle_allow_idle);
-	}
 
 return_sleep_time:
 	getnstimeofday(&ts_postidle);
@@ -136,9 +157,8 @@
 	local_irq_enable();
 	local_fiq_enable();
 
-	return (u32)timespec_to_ns(&ts_idle)/1000;
+	return ts_idle.tv_nsec/NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
 }
-
 /**
  * omap3_enter_idle_bm - Checks for any bus activity
  * @dev: cpuidle device
@@ -153,13 +173,90 @@
 {
 	struct cpuidle_state *new_state = state;
 
-	if ((state->flags & CPUIDLE_FLAG_CHECK_BM) && omap3_idle_bm_check()) {
-		BUG_ON(!dev->safe_state);
-		new_state = dev->safe_state;
-	}
+	u32 per_state = 0, saved_per_state = 0, cam_state, usb_state;
+	u32 iva2_state, sgx_state, dss_state, new_core_state;
+	struct omap3_processor_cx *cx;
+	int ret;
 
+	if (state->flags & CPUIDLE_FLAG_CHECK_BM) {
+		if (omap3_idle_bm_check()) {
+			BUG_ON(!dev->safe_state);
+			new_state = dev->safe_state;
+			goto select_state;
+		}
+		cx = cpuidle_get_statedata(state);
+		new_core_state = cx->core_state;
+
+		/* Check if CORE is active, if yes, fallback to inactive */
+		if (!pwrdm_can_idle(core_pd))
+			new_core_state = PWRDM_POWER_INACTIVE;
+
+		/*
+		 * Prevent idle completely if CAM is active.
+		 * CAM does not have wakeup capability in OMAP3.
+		 */
+		cam_state = pwrdm_get_idle_state(cam_pd);
+		if (cam_state == PWRDM_POWER_ON) {
+			new_state = dev->safe_state;
+			goto select_state;
+		}
+
+		/*
+		 * Check if PER can idle or not. If we are not likely
+		 * to idle, deny PER off. This prevents unnecessary
+		 * context save/restore.
+		 */
+		saved_per_state = pwrdm_read_next_pwrst(per_pd);
+		if (pwrdm_can_idle(per_pd)) {
+			per_state = saved_per_state;
+			/*
+			 * Prevent PER off if CORE is active as this
+			 * would disable PER wakeups completely
+			 */
+			if (per_state == PWRDM_POWER_OFF &&
+			    new_core_state > PWRDM_POWER_RET)
+				per_state = PWRDM_POWER_RET;
+
+		} else if (saved_per_state == PWRDM_POWER_OFF)
+			per_state = PWRDM_POWER_RET;
+
+		/*
+		 * If we are attempting CORE off, check if any other
+		 * powerdomains are at retention or higher. CORE off causes
+		 * chipwide reset which would reset these domains also.
+		 */
+		if (new_core_state == PWRDM_POWER_OFF) {
+			dss_state = pwrdm_get_idle_state(dss_pd);
+			iva2_state = pwrdm_get_idle_state(iva2_pd);
+			sgx_state = pwrdm_get_idle_state(sgx_pd);
+			usb_state = pwrdm_get_idle_state(usb_pd);
+
+			if (cam_state > PWRDM_POWER_OFF ||
+			    dss_state > PWRDM_POWER_OFF ||
+			    iva2_state > PWRDM_POWER_OFF ||
+			    per_state > PWRDM_POWER_OFF ||
+			    sgx_state > PWRDM_POWER_OFF ||
+			    usb_state > PWRDM_POWER_OFF)
+				new_core_state = PWRDM_POWER_RET;
+		}
+		/* Fallback to new target core state */
+		while (cx->core_state > new_core_state) {
+			state--;
+			cx = cpuidle_get_statedata(state);
+		}
+		new_state = state;
+		/* Are we changing PER target state? */
+		if (per_state != saved_per_state)
+			pwrdm_set_next_pwrst(per_pd, per_state);
+
+	}
+select_state:
 	dev->last_state = new_state;
-	return omap3_enter_idle(dev, new_state);
+	ret = omap3_enter_idle(dev, new_state);
+	/* Restore potentially tampered PER state */
+	if (per_state != saved_per_state)
+		pwrdm_set_next_pwrst(per_pd, saved_per_state);
+	return ret;
 }
 
 DEFINE_PER_CPU(struct cpuidle_device, omap3_idle_dev);
@@ -168,15 +265,29 @@
  *
  * Below is the desciption of each C state.
  * 	C1 . MPU WFI + Core active
- *	C2 . MPU WFI + Core inactive
+ *	C2 . MPU inactive + Core inactive
  *	C3 . MPU CSWR + Core inactive
  *	C4 . MPU OFF + Core inactive
  *	C5 . MPU CSWR + Core CSWR
  *	C6 . MPU OFF + Core CSWR
- *	C7 . MPU OFF + Core OFF
+ *	C7 . MPU OSWR + Core OSWR
+ *	C8 . MPU OFF + Core OSWR
+ *	C9 . MPU OFF + Core OFF
  */
 void omap_init_power_states(void)
 {
+	int i;
+	struct omap3_processor_cx *cx;
+
+	for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
+		cx = &omap3_power_states[i];
+		cx->mpu_logicl1_ret_state = 0xFF;
+		cx->mpu_l2cache_ret_state = 0xFF;
+		cx->core_logic_state = 0xFF;
+		cx->core_mem1_ret_state = 0xFF;
+		cx->core_mem2_ret_state = 0xFF;
+	}
+
 	/* C1 . MPU WFI + Core active */
 	omap3_power_states[OMAP3_STATE_C1].valid = 1;
 	omap3_power_states[OMAP3_STATE_C1].type = OMAP3_STATE_C1;
@@ -193,9 +304,10 @@
 	omap3_power_states[OMAP3_STATE_C2].sleep_latency = 0;
 	omap3_power_states[OMAP3_STATE_C2].wakeup_latency = 18;
 	omap3_power_states[OMAP3_STATE_C2].threshold = 20;
-	omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_ON;
-	omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_ON;
-	omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID;
+	omap3_power_states[OMAP3_STATE_C2].mpu_state = PWRDM_POWER_INACTIVE;
+	omap3_power_states[OMAP3_STATE_C2].core_state = PWRDM_POWER_INACTIVE;
+	omap3_power_states[OMAP3_STATE_C2].flags = CPUIDLE_FLAG_TIME_VALID |
+				CPUIDLE_FLAG_CHECK_BM;
 
 	/* C3 . MPU CSWR + Core inactive */
 	omap3_power_states[OMAP3_STATE_C3].valid = 1;
@@ -203,8 +315,16 @@
 	omap3_power_states[OMAP3_STATE_C3].sleep_latency = 150;
 	omap3_power_states[OMAP3_STATE_C3].wakeup_latency = 260;
 	omap3_power_states[OMAP3_STATE_C3].threshold = 500;
+#ifdef CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND
+	omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_INACTIVE;
+#else
 	omap3_power_states[OMAP3_STATE_C3].mpu_state = PWRDM_POWER_RET;
+#endif
 	omap3_power_states[OMAP3_STATE_C3].core_state = PWRDM_POWER_INACTIVE;
+	omap3_power_states[OMAP3_STATE_C3].mpu_logicl1_ret_state =
+				PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C3].mpu_l2cache_ret_state =
+				PWRDM_POWER_RET;
 	omap3_power_states[OMAP3_STATE_C3].flags = CPUIDLE_FLAG_TIME_VALID |
 				CPUIDLE_FLAG_CHECK_BM;
 
@@ -225,8 +345,21 @@
 	omap3_power_states[OMAP3_STATE_C5].sleep_latency = 310;
 	omap3_power_states[OMAP3_STATE_C5].wakeup_latency = 2850;
 	omap3_power_states[OMAP3_STATE_C5].threshold = 5000;
+#ifdef CONFIG_OMAP3_MPU_L2_CACHE_WORKAROUND
+	omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_INACTIVE;
+#else
 	omap3_power_states[OMAP3_STATE_C5].mpu_state = PWRDM_POWER_RET;
+#endif
 	omap3_power_states[OMAP3_STATE_C5].core_state = PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C5].mpu_logicl1_ret_state =
+				PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C5].mpu_l2cache_ret_state =
+				PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C5].core_logic_state = PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C5].core_mem1_ret_state =
+				PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C5].core_mem2_ret_state =
+				PWRDM_POWER_RET;
 	omap3_power_states[OMAP3_STATE_C5].flags = CPUIDLE_FLAG_TIME_VALID |
 				CPUIDLE_FLAG_CHECK_BM;
 
@@ -238,20 +371,87 @@
 	omap3_power_states[OMAP3_STATE_C6].threshold = 10000;
 	omap3_power_states[OMAP3_STATE_C6].mpu_state = PWRDM_POWER_OFF;
 	omap3_power_states[OMAP3_STATE_C6].core_state = PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C6].core_logic_state = PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C6].core_mem1_ret_state =
+				PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C6].core_mem2_ret_state =
+				PWRDM_POWER_RET;
 	omap3_power_states[OMAP3_STATE_C6].flags = CPUIDLE_FLAG_TIME_VALID |
 				CPUIDLE_FLAG_CHECK_BM;
 
-	/* C7 . MPU OFF + Core OFF */
+	/* C7 . MPU OSWR + Core OSWR */
 	omap3_power_states[OMAP3_STATE_C7].valid = 1;
 	omap3_power_states[OMAP3_STATE_C7].type = OMAP3_STATE_C7;
-	omap3_power_states[OMAP3_STATE_C7].sleep_latency = 10000;
-	omap3_power_states[OMAP3_STATE_C7].wakeup_latency = 30000;
-	omap3_power_states[OMAP3_STATE_C7].threshold = 300000;
-	omap3_power_states[OMAP3_STATE_C7].mpu_state = PWRDM_POWER_OFF;
-	omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C7].sleep_latency = 4000;
+	omap3_power_states[OMAP3_STATE_C7].wakeup_latency = 9000;
+	omap3_power_states[OMAP3_STATE_C7].threshold = 18000;
+	omap3_power_states[OMAP3_STATE_C7].mpu_state = PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C7].core_state = PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C7].mpu_logicl1_ret_state =
+				PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C7].mpu_l2cache_ret_state =
+				PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C7].core_logic_state = PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C7].core_mem1_ret_state =
+				PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C7].core_mem2_ret_state =
+				PWRDM_POWER_OFF;
 	omap3_power_states[OMAP3_STATE_C7].flags = CPUIDLE_FLAG_TIME_VALID |
 				CPUIDLE_FLAG_CHECK_BM;
+
+	/* C8 . MPU OFF + Core OSWR */
+	omap3_power_states[OMAP3_STATE_C8].valid = 1;
+	omap3_power_states[OMAP3_STATE_C8].type = OMAP3_STATE_C7;
+	omap3_power_states[OMAP3_STATE_C8].sleep_latency = 8000;
+	omap3_power_states[OMAP3_STATE_C8].wakeup_latency = 25000;
+	omap3_power_states[OMAP3_STATE_C8].threshold = 250000;
+	omap3_power_states[OMAP3_STATE_C8].mpu_state = PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C8].core_state = PWRDM_POWER_RET;
+	omap3_power_states[OMAP3_STATE_C8].core_logic_state = PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C8].core_mem1_ret_state =
+				PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C8].core_mem2_ret_state =
+				PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C8].flags = CPUIDLE_FLAG_TIME_VALID |
+				CPUIDLE_FLAG_CHECK_BM;
+
+	/* C9 . MPU OFF + Core OFF */
+	omap3_power_states[OMAP3_STATE_C9].valid = 1;
+	omap3_power_states[OMAP3_STATE_C9].type = OMAP3_STATE_C7;
+	omap3_power_states[OMAP3_STATE_C9].sleep_latency = 10000;
+	omap3_power_states[OMAP3_STATE_C9].wakeup_latency = 30000;
+	omap3_power_states[OMAP3_STATE_C9].threshold = 300000;
+	omap3_power_states[OMAP3_STATE_C9].mpu_state = PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C9].core_state = PWRDM_POWER_OFF;
+	omap3_power_states[OMAP3_STATE_C9].flags = CPUIDLE_FLAG_TIME_VALID |
+				CPUIDLE_FLAG_CHECK_BM;
+
 }
+/**
+ * omap3_cpuidle_update_states - Update the cpuidle states.
+ *
+ * Currently, this function toggles the validity of idle states based upon
+ * the flag 'enable_off_mode'. When the flag is set all states are valid.
+ * Else, states leading to OFF state set to be invalid.
+ */
+void omap3_cpuidle_update_states(void)
+{
+	int i;
+
+	for (i = OMAP3_STATE_C1; i < OMAP3_MAX_STATES; i++) {
+		if (enable_off_mode) {
+			omap3_power_states[i].valid = 1;
+		} else {
+			if ((omap3_power_states[i].mpu_state
+					== PWRDM_POWER_OFF)
+			|| (omap3_power_states[i].core_state
+					== PWRDM_POWER_RET))
+				omap3_power_states[i].valid = 0;
+			}
+		}
+}
+
+
 
 struct cpuidle_driver omap3_idle_driver = {
 	.name = 	"omap3_idle",
@@ -274,6 +474,11 @@
 	mpu_pd = pwrdm_lookup("mpu_pwrdm");
 	core_pd = pwrdm_lookup("core_pwrdm");
 	per_pd = pwrdm_lookup("per_pwrdm");
+	iva2_pd = pwrdm_lookup("iva2_pwrdm");
+	sgx_pd = pwrdm_lookup("sgx_pwrdm");
+	usb_pd = pwrdm_lookup("usbhost_pwrdm");
+	cam_pd = pwrdm_lookup("cam_pwrdm");
+	dss_pd = pwrdm_lookup("dss_pwrdm");
 
 	omap_init_power_states();
 	cpuidle_register_driver(&omap3_idle_driver);
@@ -302,6 +507,8 @@
 		return -EINVAL;
 	dev->state_count = count;
 
+	omap3_cpuidle_update_states();
+
 	if (cpuidle_register_device(dev)) {
 		printk(KERN_ERR "%s: CPUidle register device failed\n",
 		       __func__);
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index f816b56..937d3ec 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -113,6 +113,11 @@
 		.flags		= IORESOURCE_MEM,
 	},
 	{
+		.start 		= OMAP3430_ISP_CSI2PHY2_BASE,
+		.end 		= OMAP3430_ISP_CSI2PHY2_END,
+		.flags 		= IORESOURCE_MEM,
+	},
+	{
 		.start		= INT_34XX_CAM_IRQ,
 		.flags		= IORESOURCE_IRQ,
 	}
@@ -545,19 +550,24 @@
 		}
 	}
 
-	if (cpu_is_omap3430()) {
+	if (cpu_is_omap3430() || cpu_is_omap3630()) {
 		u32 dev_conf = 0, v_shift = 0;
 		if (controller_nr == 0) {
 			omap_cfg_reg(N28_3430_MMC1_CLK);
 			omap_cfg_reg(M27_3430_MMC1_CMD);
 			omap_cfg_reg(N27_3430_MMC1_DAT0);
-			omap_cfg_reg(N26_3430_MMC1_DAT1);
-			omap_cfg_reg(N25_3430_MMC1_DAT2);
-			omap_cfg_reg(P28_3430_MMC1_DAT3);
-			omap_cfg_reg(P27_3430_MMC1_DAT4);
-			omap_cfg_reg(P26_3430_MMC1_DAT5);
-			omap_cfg_reg(R27_3430_MMC1_DAT6);
-			omap_cfg_reg(R25_3430_MMC1_DAT7);
+			if (mmc_controller->slots[0].wires == 4 ||
+				mmc_controller->slots[0].wires == 8) {
+				omap_cfg_reg(N26_3430_MMC1_DAT1);
+				omap_cfg_reg(N25_3430_MMC1_DAT2);
+				omap_cfg_reg(P28_3430_MMC1_DAT3);
+			}
+			if (mmc_controller->slots[0].wires == 8) {
+				omap_cfg_reg(P27_3430_MMC1_DAT4);
+				omap_cfg_reg(P26_3430_MMC1_DAT5);
+				omap_cfg_reg(R27_3430_MMC1_DAT6);
+				omap_cfg_reg(R25_3430_MMC1_DAT7);
+			}
 			dev_conf = OMAP2_CONTROL_DEVCONF0;
 			v_shift = OMAP2_MMCSDIO1ADPCLKISEL;
 		}
@@ -566,9 +576,18 @@
 			omap_cfg_reg(AE2_3430_MMC2_CLK);
 			omap_cfg_reg(AG5_3430_MMC2_CMD);
 			omap_cfg_reg(AH5_3430_MMC2_DAT0);
-			omap_cfg_reg(AH4_3430_MMC2_DAT1);
-			omap_cfg_reg(AG4_3430_MMC2_DAT2);
-			omap_cfg_reg(AF4_3430_MMC2_DAT3);
+			if (mmc_controller->slots[0].wires == 4 ||
+				mmc_controller->slots[0].wires == 8) {
+				omap_cfg_reg(AH4_3430_MMC2_DAT1);
+				omap_cfg_reg(AG4_3430_MMC2_DAT2);
+				omap_cfg_reg(AF4_3430_MMC2_DAT3);
+			}
+			if (mmc_controller->slots[0].wires == 8) {
+				omap_cfg_reg(AE4_3430_MMC2_DAT4);
+				omap_cfg_reg(AH3_3430_MMC2_DAT5);
+				omap_cfg_reg(AF3_3430_MMC2_DAT6);
+				omap_cfg_reg(AE3_3430_MMC2_DAT7);
+			}
 			dev_conf = OMAP343X_CONTROL_DEVCONF1;
 			v_shift = OMAP2_MMCSDIO2ADPCLKISEL;
 		}
@@ -577,9 +596,12 @@
 			omap_cfg_reg(AF10_3430_MMC3_CLK);
 			omap_cfg_reg(AC3_3430_MMC3_CMD);
 			omap_cfg_reg(AE11_3430_MMC3_DAT0);
-			omap_cfg_reg(AH9_3430_MMC3_DAT1);
-			omap_cfg_reg(AF13_3430_MMC3_DAT2);
-			omap_cfg_reg(AE13_3430_MMC3_DAT3);
+			if (mmc_controller->slots[0].wires == 4 ||
+				mmc_controller->slots[0].wires == 8) {
+				omap_cfg_reg(AH9_3430_MMC3_DAT1);
+				omap_cfg_reg(AF13_3430_MMC3_DAT2);
+				omap_cfg_reg(AE13_3430_MMC3_DAT3);
+			}
 		}
 
 		/*
@@ -619,7 +641,7 @@
 			irq = INT_24XX_MMC2_IRQ;
 			break;
 		case 2:
-			if (!cpu_is_omap34xx())
+			if (!(cpu_is_omap34xx() || cpu_is_omap3630()))
 				return;
 			base = OMAP3_MMC3_BASE;
 			irq = INT_34XX_MMC3_IRQ;
diff --git a/arch/arm/mach-omap2/gpmc.c b/arch/arm/mach-omap2/gpmc.c
index 9458869..7982cc3 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/arch/arm/mach-omap2/gpmc.c
@@ -54,6 +54,11 @@
 #define GPMC_CHUNK_SHIFT	24		/* 16 MB */
 #define GPMC_SECTION_SHIFT	28		/* 128 MB */
 
+#define PREFETCH_FIFOTHRESHOLD	(0x40 << 8)
+#define CS_NUM_SHIFT		24
+#define ENABLE_PREFETCH		(0x1 << 7)
+#define DMA_MPU_MODE		2
+
 /* Structure to save gpmc cs context */
 struct gpmc_cs_config {
 	u32 config1;
@@ -411,6 +416,63 @@
 }
 EXPORT_SYMBOL(gpmc_cs_free);
 
+/**
+ * gpmc_prefetch_enable - configures and starts prefetch transfer
+ * @cs: nand cs (chip select) number
+ * @dma_mode: dma mode enable (1) or disable (0)
+ * @u32_count: number of bytes to be transferred
+ * @is_write: prefetch read(0) or write post(1) mode
+ */
+int gpmc_prefetch_enable(int cs, int dma_mode,
+				unsigned int u32_count, int is_write)
+{
+	uint32_t prefetch_config1;
+
+	if (!(gpmc_read_reg(GPMC_PREFETCH_CONTROL))) {
+		/* Set the amount of bytes to be prefetched */
+		gpmc_write_reg(GPMC_PREFETCH_CONFIG2, u32_count);
+
+		/* Set dma/mpu mode, the prefetch read / post write and
+		 * enable the engine. Set which cs is has requested for.
+		 */
+		prefetch_config1 = ((cs << CS_NUM_SHIFT) |
+					PREFETCH_FIFOTHRESHOLD |
+					ENABLE_PREFETCH |
+					(dma_mode << DMA_MPU_MODE) |
+					(0x1 & is_write));
+		gpmc_write_reg(GPMC_PREFETCH_CONFIG1, prefetch_config1);
+	} else {
+		return -EBUSY;
+	}
+	/*  Start the prefetch engine */
+	gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x1);
+
+	return 0;
+}
+EXPORT_SYMBOL(gpmc_prefetch_enable);
+
+/**
+ * gpmc_prefetch_reset - disables and stops the prefetch engine
+ */
+void gpmc_prefetch_reset(void)
+{
+	/* Stop the PFPW engine */
+	gpmc_write_reg(GPMC_PREFETCH_CONTROL, 0x0);
+
+	/* Reset/disable the PFPW engine */
+	gpmc_write_reg(GPMC_PREFETCH_CONFIG1, 0x0);
+}
+EXPORT_SYMBOL(gpmc_prefetch_reset);
+
+/**
+ * gpmc_prefetch_status - reads prefetch status of engine
+ */
+int  gpmc_prefetch_status(void)
+{
+	return gpmc_read_reg(GPMC_PREFETCH_STATUS);
+}
+EXPORT_SYMBOL(gpmc_prefetch_status);
+
 static void __init gpmc_mem_init(void)
 {
 	int cs;
diff --git a/arch/arm/mach-omap2/id.c b/arch/arm/mach-omap2/id.c
index 32ceaa6..6424b23 100644
--- a/arch/arm/mach-omap2/id.c
+++ b/arch/arm/mach-omap2/id.c
@@ -23,8 +23,9 @@
 #include <mach/cpu.h>
 
 static struct omap_chip_id omap_chip;
-static unsigned int omap_revision;
 
+static unsigned int omap_revision, omap_revision_id;
+static char *rev_name = "ES1.0                         ";
 
 unsigned int omap_rev(void)
 {
@@ -32,6 +33,12 @@
 }
 EXPORT_SYMBOL(omap_rev);
 
+unsigned int omap_rev_id(void)
+{
+	return omap_revision_id;
+}
+EXPORT_SYMBOL(omap_rev_id);
+
 /**
  * omap_chip_is - test whether currently running OMAP matches a chip type
  * @oc: omap_chip_t to test against
@@ -157,7 +164,6 @@
 	u32 cpuid, idcode;
 	u16 hawkeye;
 	u8 rev;
-	char *rev_name = "ES1.0";
 
 	/*
 	 * We cannot access revision registers on ES1.0.
@@ -180,7 +186,9 @@
 	hawkeye = (idcode >> 12) & 0xffff;
 	rev = (idcode >> 28) & 0xff;
 
-	if (hawkeye == 0xb7ae) {
+	switch (hawkeye) {
+	case 0xb7ae:
+		/* Handle 34xx/35xx devices */
 		switch (rev) {
 		case 0:
 			omap_revision = OMAP3430_REV_ES2_0;
@@ -203,6 +211,21 @@
 			omap_revision = OMAP3430_REV_ES3_1;
 			rev_name = "Unknown revision\n";
 		}
+		break;
+	case 0xb891:
+		/* Handle 36xx devices */
+		switch (rev) {
+		case 0:
+			omap_revision = OMAP3630_REV_ES1_0;
+			break;
+		default:
+			/* Use the latest known revision as default */
+			omap_revision = OMAP3630_REV_ES1_0;
+		}
+		break;
+	default:
+		/* Unknown default to latest silicon rev as default*/
+		omap_revision = OMAP3630_REV_ES1_0;
 	}
 
 out:
@@ -246,6 +269,8 @@
 			omap_chip.oc |= CHIP_IS_OMAP3430ES3_0;
 		else if (omap_rev() == OMAP3430_REV_ES3_1)
 			omap_chip.oc |= CHIP_IS_OMAP3430ES3_1;
+		else if (omap_rev() == OMAP3630_REV_ES1_0)
+				omap_chip.oc |= CHIP_IS_OMAP3630ES1;
 	} else {
 		pr_err("Uninitialized omap_chip, please fix!\n");
 	}
@@ -268,3 +293,74 @@
 	else
 		tap_prod_id = 0x0208;
 }
+
+void __init omap_l2cache_enable(void)
+{
+	u32 l2_val;
+
+	asm volatile("mrc p15, 0, %0, c1, c0, 1":"=r" (l2_val));
+	if ((l2_val & 0x2) == 0) {
+		printk(KERN_WARNING "L2 CACHE is not enabled in bootloader\n"
+				"Enable the L2 Cache here\n");
+#ifndef CONFIG_L2CACHE_OMAP3_DISABLE
+		l2_val |= 0x2;
+		asm volatile("mcr p15, 0, %0, c1, c0, 1"::"r" (l2_val));
+#endif
+	} else
+		printk(KERN_WARNING "L2 CACHE is enabled in bootloader\n");
+}
+
+/*
+  * Get OMAP chip version details from bootargs
+ */
+int  omap34xx_get_omap_version(char *str)
+{
+	unsigned int rev_id;
+	if (get_option(&str, &rev_id) == 1)	{
+		switch (rev_id) {
+		case 3420:
+			omap_revision_id = OMAP_3420;
+			omap_revision = OMAP3430_REV_ES3_1;
+			omap_chip.oc |= CHIP_IS_OMAP3430ES3_1;
+			rev_name = "ES3.1";
+			break;
+		case 3430:
+			omap_revision_id = OMAP_3430;
+			omap_revision = OMAP3430_REV_ES3_1;
+			omap_chip.oc |= CHIP_IS_OMAP3430ES3_1;
+			rev_name = "ES3.1";
+			break;
+		case 3440:
+			omap_revision_id = OMAP_3440;
+			omap_revision = OMAP3430_REV_ES3_1_1;
+			omap_chip.oc |= CHIP_IS_OMAP3430ES3_1_1;
+			rev_name = "ES3.1.1";
+			break;
+		case 3630:
+			omap_revision_id = OMAP_3630;
+			omap_chip.oc |= CHIP_IS_OMAP3630ES1;
+			omap_revision = OMAP3630_REV_ES1_0;
+			break;
+		case 3630800:
+			omap_revision_id = OMAP_3630_800;
+			omap_chip.oc |= CHIP_IS_OMAP3630ES1;
+			omap_revision = OMAP3630_REV_ES1_0;
+			break;
+		case 36301000:
+			omap_revision_id = OMAP_3630_1000;
+			omap_chip.oc |= CHIP_IS_OMAP3630ES1;
+			omap_revision = OMAP3630_REV_ES1_0;
+			break;
+		default:
+			pr_err("OMAP revision unknown, please fix!\n");
+			return 1;
+		}
+		pr_info("OMAP%04x %s\n", omap_rev() >> 16, rev_name);
+		pr_info("OMAP Version is OMAP%04d\n", rev_id);
+	}
+
+	return 1;
+}
+
+__setup("omap_version=", omap34xx_get_omap_version);
+
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 1241d60..142d18e 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -175,6 +175,8 @@
 
 void __init omap2_map_common_io(void)
 {
+	omap_l2cache_enable();
+
 #if defined(CONFIG_ARCH_OMAP2420)
 	iotable_init(omap24xx_io_desc, ARRAY_SIZE(omap24xx_io_desc));
 	iotable_init(omap242x_io_desc, ARRAY_SIZE(omap242x_io_desc));
diff --git a/arch/arm/mach-omap2/iommu2.c b/arch/arm/mach-omap2/iommu2.c
index 88a44f1..4a0e1cd 100644
--- a/arch/arm/mach-omap2/iommu2.c
+++ b/arch/arm/mach-omap2/iommu2.c
@@ -17,10 +17,7 @@
 #include <linux/module.h>
 #include <linux/stringify.h>
 
-#include <asm/io.h>
-
 #include <mach/iommu.h>
-#include <mach/iommu2.h>
 
 /*
  * omap2 architecture specific register bit definitions
@@ -82,7 +79,7 @@
 		l = iommu_read_reg(obj, MMU_SYSSTATUS);
 		if (l & MMU_SYS_RESETDONE)
 			break;
-	} while (time_after(jiffies, timeout));
+	} while (!time_after(jiffies, timeout));
 
 	if (!(l & MMU_SYS_RESETDONE)) {
 		dev_err(obj->dev, "can't take mmu out of reset\n");
@@ -220,10 +217,19 @@
 }
 
 #define pr_reg(name)							\
-	p += sprintf(p, "%20s: %08x\n",					\
-		     __stringify(name), iommu_read_reg(obj, MMU_##name));
+	do {								\
+		ssize_t bytes;						\
+		const char *str = "%20s: %08x\n";			\
+		const int maxcol = 32;					\
+		bytes = snprintf(p, maxcol, str, __stringify(name),	\
+				 iommu_read_reg(obj, MMU_##name));	\
+		p += bytes;						\
+		len -= bytes;						\
+		if (len < maxcol)					\
+			goto out;					\
+	} while (0)
 
-static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf)
+static ssize_t omap2_iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len)
 {
 	char *p = buf;
 
@@ -245,7 +251,7 @@
 	pr_reg(READ_CAM);
 	pr_reg(READ_RAM);
 	pr_reg(EMU_FAULT_AD);
-
+out:
 	return p - buf;
 }
 
diff --git a/arch/arm/mach-omap2/irq.c b/arch/arm/mach-omap2/irq.c
index 700fc3d..f349a96 100644
--- a/arch/arm/mach-omap2/irq.c
+++ b/arch/arm/mach-omap2/irq.c
@@ -192,6 +192,17 @@
 
 	return 0;
 }
+void omap3_intc_autoidle(int enable)
+{
+	u32 read_val;
+
+	read_val = intc_bank_read_reg(&irq_banks[0], INTC_SYSCONFIG);
+	if (!enable)
+		read_val &= ~0x1;
+	else
+		read_val |= 0x1;
+	intc_bank_write_reg(read_val, &irq_banks[0], INTC_SYSCONFIG);
+}
 
 void __init omap_init_irq(void)
 {
@@ -272,4 +283,11 @@
 	}
 	/* MIRs are saved and restore with other PRCM registers */
 }
+
+void omap3_intc_suspend(void)
+{
+	/* A pending interrupt would prevent OMAP from entering suspend */
+	omap_ack_irq(0);
+}
+
 #endif /* CONFIG_ARCH_OMAP3 */
diff --git a/arch/arm/mach-omap2/mailbox.c b/arch/arm/mach-omap2/mailbox.c
index a23fbb8..bc80a5a 100644
--- a/arch/arm/mach-omap2/mailbox.c
+++ b/arch/arm/mach-omap2/mailbox.c
@@ -177,6 +177,9 @@
 	u32 bit = (irq == IRQ_TX) ? p->notfull_bit : p->newmsg_bit;
 
 	mbox_write_reg(bit, p->irqstatus);
+
+	/* Flush posted writes to avoid spurious IRQ */
+	mbox_read_reg(p->irqstatus);
 }
 
 static int omap2_mbox_is_irq(struct omap_mbox *mbox,
diff --git a/arch/arm/mach-omap2/mmc-twl4030.c b/arch/arm/mach-omap2/mmc-twl4030.c
index 898a805..9e6e089 100644
--- a/arch/arm/mach-omap2/mmc-twl4030.c
+++ b/arch/arm/mach-omap2/mmc-twl4030.c
@@ -29,6 +29,7 @@
 #endif
 
 #include "mmc-twl4030.h"
+#include <mach/omap-pm.h>
 
 
 #if defined(CONFIG_REGULATOR) && \
@@ -236,7 +237,7 @@
 static int twl_mmc1_set_power(struct device *dev, int slot, int power_on,
 				int vdd)
 {
-	u32 reg;
+	u32 reg, prog_io;
 	int ret = 0;
 	struct twl_mmc_controller *c = &hsmmc[0];
 	struct omap_mmc_platform_data *mmc = dev->platform_data;
@@ -268,34 +269,38 @@
 		}
 
 		reg = omap_ctrl_readl(control_pbias_offset);
-		reg |= OMAP2_PBIASSPEEDCTRL0;
+		if (cpu_is_omap3630()) {
+			/* Set MMC I/O to 52Mhz */
+			prog_io = omap_ctrl_readl(OMAP343X_CONTROL_PROG_IO1);
+			prog_io |= OMAP3630_PRG_SDMMC1_SPEEDCTRL;
+			omap_ctrl_writel(prog_io, OMAP343X_CONTROL_PROG_IO1);
+		} else {
+			reg |= OMAP2_PBIASSPEEDCTRL0;
+		}
 		reg &= ~OMAP2_PBIASLITEPWRDNZ0;
 		omap_ctrl_writel(reg, control_pbias_offset);
 
-		ret = mmc_regulator_set_ocr(c->vcc, vdd);
-
-		/* 100ms delay required for PBIAS configuration */
-		msleep(100);
 		reg = omap_ctrl_readl(control_pbias_offset);
-		reg |= (OMAP2_PBIASLITEPWRDNZ0 | OMAP2_PBIASSPEEDCTRL0);
 		if ((1 << vdd) <= MMC_VDD_165_195)
 			reg &= ~OMAP2_PBIASLITEVMODE0;
 		else
 			reg |= OMAP2_PBIASLITEVMODE0;
 		omap_ctrl_writel(reg, control_pbias_offset);
+
+		mmc_regulator_set_ocr(c->vcc, vdd);
+
+		/* 400uS required for VDDS to stable */
+		udelay(400);
+
+		reg = omap_ctrl_readl(control_pbias_offset);
+		reg |= OMAP2_PBIASLITEPWRDNZ0;
+		omap_ctrl_writel(reg, control_pbias_offset);
 	} else {
 		reg = omap_ctrl_readl(control_pbias_offset);
 		reg &= ~OMAP2_PBIASLITEPWRDNZ0;
 		omap_ctrl_writel(reg, control_pbias_offset);
 
 		ret = mmc_regulator_set_ocr(c->vcc, 0);
-
-		/* 100ms delay required for PBIAS configuration */
-		msleep(100);
-		reg = omap_ctrl_readl(control_pbias_offset);
-		reg |= (OMAP2_PBIASSPEEDCTRL0 | OMAP2_PBIASLITEPWRDNZ0 |
-			OMAP2_PBIASLITEVMODE0);
-		omap_ctrl_writel(reg, control_pbias_offset);
 	}
 
 	return ret;
@@ -413,6 +418,15 @@
 		mmc->dma_mask = 0xffffffff;
 		mmc->init = twl_mmc_late_init;
 		mmc->context_loss = get_last_off_on_transaction_id;
+		mmc->set_vdd1_opp = omap_pm_set_min_mpu_freq;
+		if (cpu_is_omap3630()) {
+			mmc->max_vdd1_opp = 600000000;
+			mmc->min_vdd1_opp = 150000000;
+		} else if (cpu_is_omap3430()) {
+			mmc->max_vdd1_opp = 500000000;
+			mmc->min_vdd1_opp = 125000000;
+		} else
+			mmc->set_vdd1_opp = NULL;
 
 		/* note: twl4030 card detect GPIOs can disable VMMCx ... */
 		if (gpio_is_valid(c->gpio_cd)) {
diff --git a/arch/arm/mach-omap2/mux.c b/arch/arm/mach-omap2/mux.c
index 69bf44b..ada9895 100644
--- a/arch/arm/mach-omap2/mux.c
+++ b/arch/arm/mach-omap2/mux.c
@@ -526,6 +526,8 @@
 		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
 MUX_CFG_34XX("B24_34XX_GPIO101_OUT", 0x11A,
 		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("B25_34XX_GPIO109", 0x12A,
+		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
 MUX_CFG_34XX("B26_34XX_GPIO111", 0x12e,
 		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
 MUX_CFG_34XX("AG4_34XX_GPIO134_OUT", 0x160,
@@ -549,7 +551,7 @@
 MUX_CFG_34XX("AA21_34XX_GPIO157_OUT", 0x18e,
 		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
 MUX_CFG_34XX("W21_34XX_GPIO162", 0x198,
-		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
+		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT)
 MUX_CFG_34XX("H18_34XX_GPIO163", 0x19a,
                 OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_INPUT_PULLUP)
 MUX_CFG_34XX("H19_34XX_GPIO164_OUT", 0x19c,
@@ -612,6 +614,14 @@
 		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
 MUX_CFG_34XX("AF4_3430_MMC2_DAT3", 0x162,
 		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE4_3430_MMC2_DAT4", 0x164,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AH3_3430_MMC2_DAT5", 0x166,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AF3_3430_MMC2_DAT6", 0x168,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
+MUX_CFG_34XX("AE3_3430_MMC2_DAT7", 0x16A,
+		OMAP34XX_MUX_MODE0 | OMAP34XX_PIN_INPUT_PULLUP)
 
 /* MMC3 */
 MUX_CFG_34XX("AF10_3430_MMC3_CLK", 0x5d8,
@@ -738,6 +748,10 @@
 MUX_CFG_34XX("AF26_34XX_SYS_NIRQ", 0x1E0,
 		OMAP3_WAKEUP_EN | OMAP34XX_PIN_INPUT_PULLUP |
 		OMAP34XX_MUX_MODE0)
+MUX_CFG_34XX("D25_34XX_GPIO126", 0x132,
+		OMAP34XX_MUX_MODE4 | OMAP34XX_PIN_OUTPUT)
+MUX_CFG_34XX("R8_34XX_GPIO56_TRISTATE", 0x0b8,
+		OMAP34XX_MUX_MODE7)
 };
 
 #define OMAP34XX_PINS_SZ	ARRAY_SIZE(omap34xx_pins)
diff --git a/arch/arm/mach-omap2/omap3-iommu.c b/arch/arm/mach-omap2/omap3-iommu.c
index b732519..6abc217 100644
--- a/arch/arm/mach-omap2/omap3-iommu.c
+++ b/arch/arm/mach-omap2/omap3-iommu.c
@@ -11,71 +11,70 @@
  */
 
 #include <linux/platform_device.h>
-#include <linux/io.h>
 
 #include <mach/iommu.h>
 
-#define OMAP3_MMU1_BASE	0x480bd400
-#define OMAP3_MMU2_BASE	0x5d000000
-#define OMAP3_MMU1_IRQ	24
-#define OMAP3_MMU2_IRQ	28
-
-static struct resource omap3_iommu_res[] = {
-	{ /* Camera ISP MMU */
-		.start		= OMAP3_MMU1_BASE,
-		.end		= OMAP3_MMU1_BASE + MMU_REG_SIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= OMAP3_MMU1_IRQ,
-		.flags		= IORESOURCE_IRQ,
-	},
-	{ /* IVA2.2 MMU */
-		.start		= OMAP3_MMU2_BASE,
-		.end		= OMAP3_MMU2_BASE + MMU_REG_SIZE - 1,
-		.flags		= IORESOURCE_MEM,
-	},
-	{
-		.start		= OMAP3_MMU2_IRQ,
-		.flags		= IORESOURCE_IRQ,
-	},
+struct iommu_device {
+	resource_size_t base;
+	int irq;
+	struct iommu_platform_data pdata;
+	struct resource res[2];
 };
-#define NR_IOMMU_RES (ARRAY_SIZE(omap3_iommu_res) / 2)
 
-static const struct iommu_platform_data omap3_iommu_pdata[] __initconst = {
+static struct iommu_device devices[] = {
 	{
-		.name = "isp",
-		.nr_tlb_entries = 8,
-		.clk_name = "cam_ick",
+		.base = 0x480bd400,
+		.irq = 24,
+		.pdata = {
+			.name = "isp",
+			.nr_tlb_entries = 8,
+			.clk_name = "cam_ick",
+		},
 	},
 #if defined(CONFIG_MPU_BRIDGE_IOMMU)
 	{
-		.name = "iva2",
-		.nr_tlb_entries = 32,
-		.clk_name = "iva2_ck",
+		.base = 0x5d000000,
+		.irq = 28,
+		.pdata = {
+			.name = "iva2",
+			.nr_tlb_entries = 32,
+			.clk_name = "iva2_ck",
+		},
 	},
 #endif
 };
-#define NR_IOMMU_DEVICES ARRAY_SIZE(omap3_iommu_pdata)
+#define NR_IOMMU_DEVICES ARRAY_SIZE(devices)
 
 static struct platform_device *omap3_iommu_pdev[NR_IOMMU_DEVICES];
 
 static int __init omap3_iommu_init(void)
 {
 	int i, err;
+	struct resource res[] = {
+		{ .flags = IORESOURCE_MEM },
+		{ .flags = IORESOURCE_IRQ },
+	};
 
 	for (i = 0; i < NR_IOMMU_DEVICES; i++) {
 		struct platform_device *pdev;
+		const struct iommu_device *d = &devices[i];
 
-		pdev = platform_device_alloc("omap-iommu", i + 1);
-		if (!pdev)
+		pdev = platform_device_alloc("omap-iommu", i);
+		if (!pdev) {
+			err = -ENOMEM;
 			goto err_out;
-		err = platform_device_add_resources(pdev,
-				    &omap3_iommu_res[2 * i], NR_IOMMU_RES);
+		}
+
+		res[0].start = d->base;
+		res[0].end = d->base + MMU_REG_SIZE - 1;
+		res[1].start = res[1].end = d->irq;
+
+		err = platform_device_add_resources(pdev, res,
+						    ARRAY_SIZE(res));
 		if (err)
 			goto err_out;
-		err = platform_device_add_data(pdev, &omap3_iommu_pdata[i],
-					       sizeof(omap3_iommu_pdata[0]));
+		err = platform_device_add_data(pdev, &d->pdata,
+					       sizeof(d->pdata));
 		if (err)
 			goto err_out;
 		err = platform_device_add(pdev);
diff --git a/arch/arm/mach-omap2/omap3-opp.h b/arch/arm/mach-omap2/omap3-opp.h
index 3c9a582..5046a51 100644
--- a/arch/arm/mach-omap2/omap3-opp.h
+++ b/arch/arm/mach-omap2/omap3-opp.h
@@ -4,22 +4,70 @@
 #include <mach/omap-pm.h>
 
 /* MPU speeds */
+#define S1000M	1000000000
+#define S800M	800000000
+#define S720M   720000000
 #define S600M   600000000
 #define S550M   550000000
+#define S520M   520000000
 #define S500M   500000000
+#define S300M	300000000
 #define S250M   250000000
+#define S150M	150000000
 #define S125M   125000000
 
 /* DSP speeds */
+#define S875M   875000000
+#define S760M   760000000
+#define S660M   660000000
+#define S520M	520000000
 #define S430M   430000000
 #define S400M   400000000
 #define S360M   360000000
+#define S260M	260000000
 #define S180M   180000000
+#define S130M	130000000
 #define S90M    90000000
 
 /* L3 speeds */
+#define S50M	50000000
 #define S83M    83000000
+#define S100M	100000000
 #define S166M   166000000
+#define S200M	200000000
+
+static struct omap_opp omap3630_mpu_rate_table[] = {
+	{0, 0, 0},
+	/*OPP1 (OPP50) - 0.93mV*/
+	{S300M, VDD1_OPP1, 0x1b},
+	/*OPP2 (OPP100) - 1.1V*/
+	{S600M, VDD1_OPP2, 0x28},
+	/*OPP3 (OPP130) - 1.26V*/
+	{S800M, VDD1_OPP3, 0x35},
+	/*OPP4 (OPP-1G) - 1.35V*/
+	{S1000M, VDD1_OPP4, 0x3C},
+
+};
+
+static struct omap_opp omap3630_l3_rate_table[] = {
+	{0, 0, 0},
+	/*OPP1 (OPP50) - 0.93V*/
+	{S100M, VDD2_OPP1, 0x1b},
+	/*OPP2 (OPP100) - 1.1375V*/
+	{S200M, VDD2_OPP2, 0x2b},
+};
+
+static struct omap_opp omap3630_dsp_rate_table[] = {
+	{0, 0, 0},
+	/*OPP1 (OPP50) - 0.93V*/
+	{S260M, VDD1_OPP1, 0x1b},
+	/*OPP2 (OPP100) - 1.1V*/
+	{S520M, VDD1_OPP2, 0x28},
+	/*OPP3 (OPP130) - 1.26V*/
+	{S660M, VDD1_OPP3, 0x35},
+	/*OPP4 (OPP-1G) - 1.35V*/
+	{S800M, VDD1_OPP4, 0x3C},
+};
 
 static struct omap_opp omap3_mpu_rate_table[] = {
 	{0, 0, 0},
@@ -33,6 +81,8 @@
 	{S550M, VDD1_OPP4, 0x36},
 	/*OPP5*/
 	{S600M, VDD1_OPP5, 0x3C},
+	/*OPP6*/
+	{S720M, VDD1_OPP6, 0x3C},
 };
 
 static struct omap_opp omap3_l3_rate_table[] = {
@@ -45,6 +95,22 @@
 	{S166M, VDD2_OPP3, 0x2C},
 };
 
+/* iva rate table for 3420 */
+static struct omap_opp omap3_dsp_rate_table_3420[] = {
+	{0, 0, 0},
+	/*OPP1*/
+	{S90M, VDD1_OPP1, 0x1E},
+	/*OPP2*/
+	{S180M, VDD1_OPP2, 0x26},
+	/*OPP3*/
+	{S360M, VDD1_OPP3, 0x30},
+	/*OPP4*/
+	{S360M, VDD1_OPP4, 0x36},
+	/*OPP5*/
+	{S360M, VDD1_OPP5, 0x36},
+};
+
+/* iva rate table for 3430 */
 static struct omap_opp omap3_dsp_rate_table[] = {
 	{0, 0, 0},
 	/*OPP1*/
@@ -54,9 +120,26 @@
 	/*OPP3*/
 	{S360M, VDD1_OPP3, 0x30},
 	/*OPP4*/
-	{S400M, VDD1_OPP4, 0x36},
+	{S430M, VDD1_OPP4, 0x36},
 	/*OPP5*/
 	{S430M, VDD1_OPP5, 0x3C},
 };
 
+/* iva rate table for 3430 */
+static struct omap_opp omap3_dsp_rate_table_3440[] = {
+	{0, 0, 0},
+	/*OPP1*/
+	{S90M, VDD1_OPP1, 0x1E},
+	/*OPP2*/
+	{S180M, VDD1_OPP2, 0x26},
+	/*OPP3*/
+	{S360M, VDD1_OPP3, 0x30},
+	/*OPP4*/
+	{S430M, VDD1_OPP4, 0x36},
+	/*OPP5*/
+	{S430M, VDD1_OPP5, 0x3C},
+	/*OPP6*/
+	{S520M, VDD1_OPP6, 0x3C},
+};
+
 #endif
diff --git a/arch/arm/mach-omap2/omapdev-common.h b/arch/arm/mach-omap2/omapdev-common.h
index a2d4855..e5233f5 100644
--- a/arch/arm/mach-omap2/omapdev-common.h
+++ b/arch/arm/mach-omap2/omapdev-common.h
@@ -204,6 +204,7 @@
 	&modem_intc_3xxx_omapdev,
 	&sms_3xxx_omapdev,
 	&gpmc_3xxx_omapdev,
+	&nand_3xxx_omapdev,
 	&sdrc_3xxx_omapdev,
 	&ocm_ram_3xxx_omapdev,
 	&ocm_rom_3xxx_omapdev,
diff --git a/arch/arm/mach-omap2/omapdev3xxx.h b/arch/arm/mach-omap2/omapdev3xxx.h
index f6970d8..0c77ce4 100644
--- a/arch/arm/mach-omap2/omapdev3xxx.h
+++ b/arch/arm/mach-omap2/omapdev3xxx.h
@@ -105,6 +105,14 @@
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
 
+static struct omapdev nand_3xxx_omapdev = {
+	.name		= "nand_omapdev",
+	.pwrdm		= { .name = "core_pwrdm" },
+	.pdev_name	= "omap2-nand",
+	.pdev_id	= 0,
+	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+};
+
 static struct omapdev sdrc_3xxx_omapdev = {
 	.name		= "sdrc_omapdev",
 	.pwrdm		= { .name = "core_pwrdm" },
@@ -663,7 +671,7 @@
 
 static struct omapdev usbotg_3xxx_omapdev = {
 	.name		= "usbotg_omapdev",
-	.pwrdm		= { .name = "usbhost_pwrdm" },
+	.pwrdm		= { .name = "core_pwrdm" },
 	.pdev_name	= "musb_hdrc",
 	.pdev_id	= -1,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
@@ -682,7 +690,7 @@
 static struct omapdev dsi_3xxx_omapdev = {
 	.name		= "dsi_omapdev",
 	.pwrdm		= { .name = "dss_pwrdm" },
-	.pdev_name	= "omapfb",
+	.pdev_name	= "omapdss",
 	.pdev_id	= -1,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
@@ -690,7 +698,7 @@
 static struct omapdev dsi_phy_3xxx_omapdev = {
 	.name		= "dsi_phy_omapdev",
 	.pwrdm		= { .name = "dss_pwrdm" },
-	.pdev_name	= "omapfb",
+	.pdev_name	= "omapdss",
 	.pdev_id	= -1,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
@@ -698,7 +706,7 @@
 static struct omapdev dsi_pll_3xxx_omapdev = {
 	.name		= "dsi_pll_omapdev",
 	.pwrdm		= { .name = "dss_pwrdm" },
-	.pdev_name	= "omapfb",
+	.pdev_name	= "omapdss",
 	.pdev_id	= -1,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
@@ -706,7 +714,7 @@
 static struct omapdev dss_3xxx_omapdev = {
 	.name		= "dss_omapdev",
 	.pwrdm		= { .name = "dss_pwrdm" },
-	.pdev_name	= "omapfb",
+	.pdev_name	= "omapdss",
 	.pdev_id	= -1,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
@@ -714,7 +722,7 @@
 static struct omapdev dispc_3xxx_omapdev = {
 	.name		= "dispc_omapdev",
 	.pwrdm		= { .name = "dss_pwrdm" },
-	.pdev_name	= "omapfb",
+	.pdev_name	= "omapdss",
 	.pdev_id	= -1,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
@@ -722,7 +730,7 @@
 static struct omapdev rfbi_3xxx_omapdev = {
 	.name		= "rfbi_omapdev",
 	.pwrdm		= { .name = "dss_pwrdm" },
-	.pdev_name	= "omapfb",
+	.pdev_name	= "omapdss",
 	.pdev_id	= -1,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
@@ -730,7 +738,7 @@
 static struct omapdev venc_3xxx_omapdev = {
 	.name		= "venc_omapdev",
 	.pwrdm		= { .name = "dss_pwrdm" },
-	.pdev_name	= "omapfb",
+	.pdev_name	= "omapdss",
 	.pdev_id	= -1,
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 };
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index 993498b..3797b2a 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -382,6 +382,9 @@
 	for (i = 0; i < 4; i++)
 		seq_printf(s, ",%s:%d", pwrdm_state_names[i],
 			pwrdm->state_counter[i]);
+	seq_printf(s, ",RET-LOGIC-OFF:%d,RET-MEM-OFF:%d",
+			pwrdm->ret_logic_off_counter,
+			pwrdm->ret_mem_off_counter);
 
 	seq_printf(s, "\n");
 
@@ -539,7 +542,7 @@
 	(void) debugfs_create_file("time", S_IRUGO,
 		d, (void *)DEBUG_FILE_TIMERS, &debug_fops);
 
-	pwrdm_for_each(pwrdms_setup, (void *)d);
+	pwrdm_for_each_nolock(pwrdms_setup, (void *)d);
 
 	pm_dbg_dir = debugfs_create_dir("registers", d);
 	if (IS_ERR(pm_dbg_dir))
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index d07b722..b2d6638 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -37,17 +37,23 @@
 
 #include "prm-regbits-34xx.h"
 #include "pm.h"
+#include <mach/omap-pm.h>
 
 unsigned short enable_dyn_sleep;
 unsigned short enable_off_mode;
 EXPORT_SYMBOL(enable_off_mode);
+unsigned short enable_oswr_ret;
+EXPORT_SYMBOL(enable_oswr_ret);
 unsigned short voltage_off_while_idle;
 unsigned short wakeup_timer_seconds;
+unsigned long max_dsp_frequency;
 atomic_t sleep_block = ATOMIC_INIT(0);
 
 static ssize_t idle_show(struct kobject *, struct kobj_attribute *, char *);
 static ssize_t idle_store(struct kobject *k, struct kobj_attribute *,
 			  const char *buf, size_t n);
+static ssize_t vdd_max_dsp_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf);
 
 static struct kobj_attribute sleep_while_idle_attr =
 	__ATTR(sleep_while_idle, 0644, idle_show, idle_store);
@@ -55,23 +61,30 @@
 static struct kobj_attribute enable_off_mode_attr =
 	__ATTR(enable_off_mode, 0644, idle_show, idle_store);
 
+static struct kobj_attribute enable_oswr_ret_attr =
+	__ATTR(enable_oswr_ret, 0644, idle_show, idle_store);
+
 static struct kobj_attribute voltage_off_while_idle_attr =
 	__ATTR(voltage_off_while_idle, 0644, idle_show, idle_store);
 
+static struct kobj_attribute max_dsp_frequency_attr =
+	__ATTR(max_dsp_frequency, 0644, vdd_max_dsp_show, NULL);
 #ifdef CONFIG_OMAP_PM_SRF
 static ssize_t vdd_opp_show(struct kobject *, struct kobj_attribute *, char *);
 static ssize_t vdd_opp_store(struct kobject *k, struct kobj_attribute *,
 			  const char *buf, size_t n);
+static ssize_t vdd_opp_lock_store(struct kobject *k, struct kobj_attribute *,
+			  const char *buf, size_t n);
+
 static struct kobj_attribute vdd1_opp_attr =
 	__ATTR(vdd1_opp, 0644, vdd_opp_show, vdd_opp_store);
 
 static struct kobj_attribute vdd2_opp_attr =
 	__ATTR(vdd2_opp, 0644, vdd_opp_show, vdd_opp_store);
 static struct kobj_attribute vdd1_lock_attr =
-	__ATTR(vdd1_lock, 0644, vdd_opp_show, vdd_opp_store);
+	__ATTR(vdd1_lock, 0644, vdd_opp_show, vdd_opp_lock_store);
 static struct kobj_attribute vdd2_lock_attr =
-	__ATTR(vdd2_lock, 0644, vdd_opp_show, vdd_opp_store);
-
+	__ATTR(vdd2_lock, 0644, vdd_opp_show, vdd_opp_lock_store);
 #endif
 
 static struct kobj_attribute wakeup_timer_seconds_attr =
@@ -84,6 +97,8 @@
 		return sprintf(buf, "%hu\n", enable_dyn_sleep);
 	else if (attr == &enable_off_mode_attr)
 		return sprintf(buf, "%hu\n", enable_off_mode);
+	else if (attr == &enable_oswr_ret_attr)
+		return sprintf(buf, "%hu\n", enable_oswr_ret);
 	else if (attr == &voltage_off_while_idle_attr)
 		return sprintf(buf, "%hu\n", voltage_off_while_idle);
 	else if (attr == &wakeup_timer_seconds_attr)
@@ -107,6 +122,8 @@
 	} else if (attr == &enable_off_mode_attr) {
 		enable_off_mode = value;
 		omap3_pm_off_mode_enable(enable_off_mode);
+	} else if (attr == &enable_oswr_ret_attr) {
+		enable_oswr_ret = value;
 	} else if (attr == &wakeup_timer_seconds_attr) {
 		wakeup_timer_seconds = value;
 	} else if (attr == &voltage_off_while_idle_attr) {
@@ -128,18 +145,19 @@
 #include <mach/omap34xx.h>
 static int vdd1_locked;
 static int vdd2_locked;
+static struct device sysfs_cpufreq_dev;
 
 static ssize_t vdd_opp_show(struct kobject *kobj, struct kobj_attribute *attr,
 			 char *buf)
 {
 	if (attr == &vdd1_opp_attr)
-		return sprintf(buf, "%hu\n", resource_get_level("vdd1_opp"));
+		return sprintf(buf, "%u\n", resource_get_level("vdd1_opp"));
 	else if (attr == &vdd2_opp_attr)
-		return sprintf(buf, "%hu\n", resource_get_level("vdd2_opp"));
+		return sprintf(buf, "%u\n", resource_get_level("vdd2_opp"));
 	else if (attr == &vdd1_lock_attr)
-		return sprintf(buf, "%hu\n", resource_get_opp_lock(VDD1_OPP));
+		return sprintf(buf, "%u\n", resource_get_opp_lock(VDD1_OPP));
 	else if (attr == &vdd2_lock_attr)
-		return sprintf(buf, "%hu\n", resource_get_opp_lock(VDD2_OPP));
+		return sprintf(buf, "%u\n", resource_get_opp_lock(VDD2_OPP));
 	else
 		return -EINVAL;
 }
@@ -148,6 +166,42 @@
 			  const char *buf, size_t n)
 {
 	unsigned short value;
+	struct omap_opp *opp_table;
+
+	if (sscanf(buf, "%hu", &value) != 1)
+		return -EINVAL;
+
+	if (attr == &vdd1_opp_attr) {
+		if (value < MIN_VDD1_OPP || value > MAX_VDD1_OPP) {
+			printk(KERN_ERR "vdd_opp_store: Invalid value\n");
+			return -EINVAL;
+		}
+		opp_table = omap_get_mpu_rate_table();
+		omap_pm_set_min_mpu_freq(&sysfs_cpufreq_dev,
+					opp_table[value].rate);
+	} else if (attr == &vdd2_opp_attr) {
+		if (value < MIN_VDD2_OPP || (value > MAX_VDD2_OPP)) {
+			printk(KERN_ERR "vdd_opp_store: Invalid value\n");
+			return -EINVAL;
+		}
+		if (value == VDD2_OPP2)
+			omap_pm_set_min_bus_tput(&sysfs_cpufreq_dev,
+					OCP_INITIATOR_AGENT, 83*1000*4);
+		else if (value == VDD2_OPP3)
+			omap_pm_set_min_bus_tput(&sysfs_cpufreq_dev,
+					OCP_INITIATOR_AGENT, 166*1000*4);
+
+	} else {
+		return -EINVAL;
+	}
+	return n;
+}
+
+
+static ssize_t vdd_opp_lock_store(struct kobject *kobj,
+	struct kobj_attribute *attr, const char *buf, size_t n)
+{
+	unsigned short value;
 	int flags = 0;
 
 	if (sscanf(buf, "%hu", &value) != 1)
@@ -166,6 +220,11 @@
 		if (vdd1_locked == 0 && value != 0) {
 			resource_lock_opp(VDD1_OPP);
 			vdd1_locked = 1;
+			if (value < MIN_VDD1_OPP || value > MAX_VDD1_OPP) {
+				printk(KERN_ERR "vdd_opp_store: Invalid value\n");
+				return -EINVAL;
+				}
+		resource_set_opp_level(VDD1_OPP, value, flags);
 		}
 	} else if (attr == &vdd2_lock_attr) {
 		flags = OPP_IGNORE_LOCK;
@@ -179,26 +238,27 @@
 		if (vdd2_locked == 0 && value != 0) {
 			resource_lock_opp(VDD2_OPP);
 			vdd2_locked = 1;
+			if (value < MIN_VDD2_OPP || value > MAX_VDD2_OPP) {
+				printk(KERN_ERR "vdd_opp_store: Invalid value\n");
+				return -EINVAL;
+			}
+			resource_set_opp_level(VDD2_OPP, value, flags);
 		}
-	}
-
-	if (attr == &vdd1_opp_attr) {
-		if (value < 1 || value > 5) {
-			printk(KERN_ERR "vdd_opp_store: Invalid value\n");
-			return -EINVAL;
-		}
-		resource_set_opp_level(VDD1_OPP, value, flags);
-	} else if (attr == &vdd2_opp_attr) {
-		if (value < 1 || value > 3) {
-			printk(KERN_ERR "vdd_opp_store: Invalid value\n");
-			return -EINVAL;
-		}
-		resource_set_opp_level(VDD2_OPP, value, flags);
-	} else {
+	}  else {
 		return -EINVAL;
 	}
 	return n;
 }
+
+static ssize_t vdd_max_dsp_show(struct kobject *kobj,
+				struct kobj_attribute *attr, char *buf)
+{
+	struct omap_opp *dsp_rate;
+	if (attr == &max_dsp_frequency_attr) {
+		dsp_rate = omap_get_dsp_rate_table();
+	return sprintf(buf, "%ld\n", dsp_rate[MAX_VDD1_OPP].rate);
+		}
+}
 #endif
 
 void omap2_block_sleep(void)
@@ -254,9 +314,21 @@
 		return error;
 	}
 	error = sysfs_create_file(power_kobj,
+				&enable_oswr_ret_attr.attr);
+	if (error) {
+		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+		return error;
+	}
+	error = sysfs_create_file(power_kobj,
 				  &wakeup_timer_seconds_attr.attr);
 	if (error)
 		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
+	error = sysfs_create_file(power_kobj,
+				  &max_dsp_frequency_attr.attr);
+	if (error)
+		printk(KERN_ERR "sysfs_create_file failed: %d\n", error);
+
 #ifdef CONFIG_OMAP_PM_SRF
 	error = sysfs_create_file(power_kobj,
 				  &vdd1_opp_attr.attr);
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 9e112b3..53d5666 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -25,6 +25,7 @@
 
 extern unsigned short enable_dyn_sleep;
 extern unsigned short enable_off_mode;
+extern unsigned short enable_oswr_ret;
 extern unsigned short voltage_off_while_idle;
 extern atomic_t sleep_block;
 extern void *omap3_secure_ram_storage;
@@ -33,12 +34,18 @@
 extern struct omap_dm_timer *gptimer_wakeup;
 
 #ifdef CONFIG_ARCH_OMAP3
-struct prm_setup_vc {
+struct prm_setup_times_vc {
 	u16 clksetup;
 	u16 voltsetup_time1;
 	u16 voltsetup_time2;
-	u16 voltoffset;
 	u16 voltsetup2;
+	u16 voltsetup1;
+};
+
+struct prm_setup_vc {
+	struct prm_setup_times_vc *setup_times;
+	struct prm_setup_times_vc *setup_times_off;
+	u16 voltoffset;
 /* PRM_VC_CMD_VAL_0 specific bits */
 	u16 vdd0_on;
 	u16 vdd0_onlp;
@@ -56,7 +63,6 @@
 	u32 vdd_ch_conf;
 	u32 vdd_i2c_cfg;
 };
-
 extern void omap3_pm_off_mode_enable(int);
 extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm);
 extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state);
@@ -107,6 +113,7 @@
 static inline void omap2_allow_sleep(void) { }
 #endif
 
+extern void omap3_cpuidle_update_states(void);
 extern unsigned int omap24xx_idle_loop_suspend_sz;
 extern unsigned int omap34xx_suspend_sz;
 extern unsigned int save_secure_ram_context_sz;
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 1ca6815..156c8d7 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -27,8 +27,10 @@
 #include <linux/list.h>
 #include <linux/err.h>
 #include <linux/clk.h>
+#include <linux/reboot.h>
 
 #include <mach/gpio.h>
+#include <mach/cpu.h>
 #include <mach/sram.h>
 #include <mach/prcm.h>
 #include <mach/clockdomain.h>
@@ -43,6 +45,7 @@
 #include <mach/gpmc.h>
 #include <mach/dma.h>
 #include <mach/dmtimer.h>
+#include <mach/usb.h>
 
 #include <asm/tlbflush.h>
 
@@ -56,14 +59,21 @@
 #include "pm.h"
 #include "smartreflex.h"
 #include "sdrc.h"
+#include <mach/omap-pm.h>
+#include "../vfp/vfp.h"
 
 static int regset_save_on_suspend;
 
+/* Function pointer need to be called from idle and suspend/resume path */
+static int (*core_off_notification)(bool);
+
 /* Scratchpad offsets */
 #define OMAP343X_TABLE_ADDRESS_OFFSET	   0x31
 #define OMAP343X_TABLE_VALUE_OFFSET	   0x30
 #define OMAP343X_CONTROL_REG_VALUE_OFFSET  0x32
 
+#define VP_TRANXDONE_TIMEOUT	62
+
 struct power_state {
 	struct powerdomain *pwrdm;
 	u32 next_state;
@@ -81,14 +91,19 @@
 
 static struct powerdomain *mpu_pwrdm, *neon_pwrdm;
 static struct powerdomain *core_pwrdm, *per_pwrdm;
-static struct powerdomain *cam_pwrdm;
+static struct powerdomain *wkup_pwrdm;
 
-static struct prm_setup_vc prm_setup = {
+static struct prm_setup_times_vc prm_setup_times_default = {
 	.clksetup = 0xff,
 	.voltsetup_time1 = 0xfff,
 	.voltsetup_time2 = 0xfff,
-	.voltoffset = 0xff,
 	.voltsetup2 = 0xff,
+};
+
+static struct prm_setup_vc prm_setup_default = {
+	.setup_times = &prm_setup_times_default,
+	.setup_times_off = NULL,
+	.voltoffset = 0xff,
 	.vdd0_on = 0x30,
 	.vdd0_onlp = 0x1e,
 	.vdd0_ret = 0x1e,
@@ -105,14 +120,26 @@
 	.vdd_cmd_ra = (R_VDD2_SR_CONTROL << OMAP3430_VOLRA1_SHIFT) |
 			(R_VDD1_SR_CONTROL << OMAP3430_VOLRA0_SHIFT),
 	.vdd_ch_conf = OMAP3430_CMD1 | OMAP3430_RAV1,
-	.vdd_i2c_cfg = OMAP3430_MCODE_SHIFT | OMAP3430_HSEN | OMAP3430_SREN,
+	.vdd_i2c_cfg = OMAP3430_MCODE_SHIFT | OMAP3430_HSEN ,
 };
 
+static struct prm_setup_vc *prm_setup = &prm_setup_default;
+
 static inline void omap3_per_save_context(void)
 {
 	omap3_gpio_save_context();
 }
 
+static void prm_program_setup_times(struct prm_setup_times_vc *times)
+{
+	prm_write_mod_reg(times->voltsetup1, OMAP3430_GR_MOD,
+			OMAP3_PRM_VOLTSETUP1_OFFSET);
+	prm_write_mod_reg(times->voltsetup2, OMAP3430_GR_MOD,
+			OMAP3_PRM_VOLTSETUP2_OFFSET);
+	prm_write_mod_reg(times->clksetup, OMAP3430_GR_MOD,
+			OMAP3_PRM_CLKSETUP_OFFSET);
+}
+
 static inline void omap3_per_restore_context(void)
 {
 	omap3_gpio_restore_context();
@@ -147,31 +174,48 @@
 		prm_clear_mod_reg_bits(OMAP3430_EN_IO_CHAIN, WKUP_MOD, PM_WKEN);
 }
 
-static void omap3_core_save_context(void)
+static void omap3_core_save_context(int core_state)
 {
-	u32 control_padconf_off;
-	/* Save the padconf registers */
-	control_padconf_off =
-	omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF);
-	control_padconf_off |= START_PADCONF_SAVE;
-	omap_ctrl_writel(control_padconf_off, OMAP343X_CONTROL_PADCONF_OFF);
-	/* wait for the save to complete */
-	while (!omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
-			& PADCONF_SAVE_DONE)
-		;
+	if (core_state == PWRDM_POWER_OFF) {
+		u32 control_padconf_off;
+		/* Save the padconf registers */
+		control_padconf_off =
+			omap_ctrl_readl(OMAP343X_CONTROL_PADCONF_OFF);
+		control_padconf_off |= START_PADCONF_SAVE;
+		omap_ctrl_writel(control_padconf_off,
+				OMAP343X_CONTROL_PADCONF_OFF);
+		/* Due to Silicon Bug on context restore it is found
+		 * that the CONTROL_PAD_CONF_ETK14 register is not saved into
+		 * scratch pad memory sometimes. To rectify it delay acess by Mpu
+		 * for 300us for scm to finish saving task
+		 */
+		udelay(300);
+		/* wait for the save to complete */
+		while (!(omap_ctrl_readl(OMAP343X_CONTROL_GENERAL_PURPOSE_STATUS)
+				& PADCONF_SAVE_DONE))
+			;
+		/* Save the system control module context,
+		 * padconf already save above
+		 */
+		omap3_control_save_context();
+	}
+
 	/* Save the Interrupt controller context */
 	omap3_intc_save_context();
 	/* Save the GPMC context */
 	omap3_gpmc_save_context();
-	/* Save the system control module context, padconf already save above*/
-	omap3_control_save_context();
 	omap_dma_global_context_save();
 }
 
-static void omap3_core_restore_context(void)
+static void omap3_core_restore_context(int core_state)
 {
-	/* Restore the control module context, padconf restored by h/w */
-	omap3_control_restore_context();
+	if (core_state == PWRDM_POWER_OFF)
+
+		/* Restore the control module context,
+		 * padconf restored by h/w
+		 */
+		omap3_control_restore_context();
+
 	/* Restore the GPMC context */
 	omap3_gpmc_restore_context();
 	/* Restore the interrupt controller context */
@@ -219,7 +263,7 @@
  * that any peripheral wake-up events occurring while attempting to
  * clear the PM_WKST_x are detected and cleared.
  */
-static void prcm_clear_mod_irqs(s16 module, u8 regs)
+static int prcm_clear_mod_irqs(s16 module, u8 regs)
 {
 	u32 wkst, fclk, iclk, clken;
 	u16 wkst_off = (regs == 3) ? OMAP3430ES2_PM_WKST3 : PM_WKST1;
@@ -227,6 +271,7 @@
 	u16 iclk_off = (regs == 3) ? CM_ICLKEN3 : CM_ICLKEN1;
 	u16 grpsel_off = (regs == 3) ?
 		OMAP3430ES2_PM_MPUGRPSEL3 : OMAP3430_PM_MPUGRPSEL;
+	int c = 0;
 
 	wkst = prm_read_mod_reg(module, wkst_off);
 	wkst &= prm_read_mod_reg(module, grpsel_off);
@@ -245,11 +290,27 @@
 			cm_set_mod_reg_bits(clken, module, fclk_off);
 			prm_write_mod_reg(wkst, module, wkst_off);
 			wkst = prm_read_mod_reg(module, wkst_off);
+			c++;
 		}
 		cm_write_mod_reg(iclk, module, iclk_off);
 		cm_write_mod_reg(fclk, module, fclk_off);
 	}
+	return c;
 }
+static int _prcm_int_handle_wakeup(void)
+{
+	int c;
+
+	c = prcm_clear_mod_irqs(WKUP_MOD, 1);
+	c += prcm_clear_mod_irqs(CORE_MOD, 1);
+	c += prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
+	if (omap_rev() > OMAP3430_REV_ES1_0) {
+		c += prcm_clear_mod_irqs(CORE_MOD, 3);
+		c += prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
+	}
+
+	return c;
+ }
 
 /*
  * PRCM Interrupt Handler
@@ -271,18 +332,36 @@
 static irqreturn_t prcm_interrupt_handler (int irq, void *dev_id)
 {
 	u32 irqstatus_mpu;
+	int c = 0;
 
 	do {
-		prcm_clear_mod_irqs(WKUP_MOD, 1);
-		prcm_clear_mod_irqs(CORE_MOD, 1);
-		prcm_clear_mod_irqs(OMAP3430_PER_MOD, 1);
-		if (omap_rev() > OMAP3430_REV_ES1_0) {
-			prcm_clear_mod_irqs(CORE_MOD, 3);
-			prcm_clear_mod_irqs(OMAP3430ES2_USBHOST_MOD, 1);
-		}
-
 		irqstatus_mpu = prm_read_mod_reg(OCP_MOD,
 					OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+		if (irqstatus_mpu & (OMAP3430_WKUP_ST | OMAP3430_IO_ST)) {
+			c = _prcm_int_handle_wakeup();
+
+			/*
+			 * Is the MPU PRCM interrupt handler racing with the
+			 * IVA2 PRCM interrupt handler ?
+			 */
+			WARN(c == 0, "prcm: WARNING: PRCM indicated MPU wakeup "
+			     "but no wakeup sources are marked\n");
+		 } else if (irqstatus_mpu & (OMAP3430_VP1_ST | OMAP3430_VP2_ST |
+				OMAP3430_VC_ST)) {
+			/* Clear all the VP1/2 and VC status flag here */
+			prm_write_mod_reg((irqstatus_mpu &
+					(OMAP3430_VP1_ST |
+					 OMAP3430_VP2_ST |
+					 OMAP3430_VC_ST)), OCP_MOD,
+					 OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+
+		} else {
+
+			/* XXX we need to expand our PRCM interrupt handler */
+			WARN(1, "prcm: WARNING: PRCM interrupt received, but "
+			     "no code to handle it (%08x)\n", irqstatus_mpu);
+		}
+
 		prm_write_mod_reg(irqstatus_mpu, OCP_MOD,
 					OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
 
@@ -330,9 +409,9 @@
 	int mpu_next_state = PWRDM_POWER_ON;
 	int per_next_state = PWRDM_POWER_ON;
 	int core_next_state = PWRDM_POWER_ON;
-	int core_prev_state, per_prev_state;
+	int mpu_prev_state, core_prev_state, per_prev_state;
+	int mpu_logic_state, mpu_mem_state, core_logic_state, core_mem_state;
 	u32 sdrc_pwr = 0;
-	int per_state_modified = 0;
 
 	if (!_omap_sram_idle)
 		return;
@@ -343,12 +422,26 @@
 	pwrdm_clear_all_prev_pwrst(per_pwrdm);
 
 	mpu_next_state = pwrdm_read_next_pwrst(mpu_pwrdm);
+	mpu_logic_state = pwrdm_read_next_logic_pwrst(mpu_pwrdm);
+	mpu_mem_state = pwrdm_read_next_mem_pwrst(mpu_pwrdm, 0);
+
 	switch (mpu_next_state) {
+	case PWRDM_POWER_INACTIVE:
 	case PWRDM_POWER_ON:
-	case PWRDM_POWER_RET:
 		/* No need to save context */
 		save_state = 0;
 		break;
+	case PWRDM_POWER_RET:
+		if (!mpu_logic_state && !mpu_mem_state)
+			save_state = 3;
+		else if (!mpu_mem_state)
+			save_state = 2;
+		else if (!mpu_logic_state)
+			save_state = 1;
+		else
+			/* No need to save context */
+			save_state = 0;
+		break;
 	case PWRDM_POWER_OFF:
 		save_state = 3;
 		break;
@@ -361,46 +454,85 @@
 	pwrdm_pre_transition();
 
 	/* NEON control */
-	if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON)
+	if (pwrdm_read_pwrst(neon_pwrdm) == PWRDM_POWER_ON) {
+		if (mpu_next_state == PWRDM_POWER_OFF)
+			vfp_pm_save_context();
 		pwrdm_set_next_pwrst(neon_pwrdm, mpu_next_state);
+		}
 
 	/* PER */
 	per_next_state = pwrdm_read_next_pwrst(per_pwrdm);
 	core_next_state = pwrdm_read_next_pwrst(core_pwrdm);
-	if (per_next_state < PWRDM_POWER_ON) {
-		omap_uart_prepare_idle(2);
-		omap2_gpio_prepare_for_idle(per_next_state);
-		if (per_next_state == PWRDM_POWER_OFF) {
-			if (core_next_state == PWRDM_POWER_ON) {
-				per_next_state = PWRDM_POWER_RET;
-				pwrdm_set_next_pwrst(per_pwrdm, per_next_state);
-				per_state_modified = 1;
-			} else
-				omap3_per_save_context();
-		}
-	}
+	core_logic_state = pwrdm_read_next_logic_pwrst(core_pwrdm);
+	core_mem_state = pwrdm_read_next_mem_pwrst(core_pwrdm, 0) |
+				pwrdm_read_next_mem_pwrst(core_pwrdm, 1);
 
-	if (pwrdm_read_pwrst(cam_pwrdm) == PWRDM_POWER_ON)
-		omap2_clkdm_deny_idle(mpu_pwrdm->pwrdm_clkdms[0]);
+	if (per_next_state < PWRDM_POWER_ON) {
+		omap_uart_prepare_idle(2, per_next_state);
+		omap2_gpio_prepare_for_idle(per_next_state);
+		if (per_next_state == PWRDM_POWER_OFF)
+			omap3_per_save_context();
+	} else
+		omap_uart_prepare_idle(2, per_next_state);
+
 
 	/* CORE */
 	if (core_next_state < PWRDM_POWER_ON) {
 		/* Disable smartreflex before entering WFI */
 		disable_smartreflex(SR1);
 		disable_smartreflex(SR2);
-		omap_uart_prepare_idle(0);
-		omap_uart_prepare_idle(1);
+		omap_uart_prepare_idle(0, core_next_state & core_logic_state);
+		omap_uart_prepare_idle(1, core_next_state & core_logic_state);
 		if (core_next_state == PWRDM_POWER_OFF) {
 			prm_set_mod_reg_bits(OMAP3430_AUTO_OFF,
 					     OMAP3430_GR_MOD,
 					     OMAP3_PRM_VOLTCTRL_OFFSET);
-			omap3_core_save_context();
+			omap3_core_save_context(PWRDM_POWER_OFF);
 			omap3_prcm_save_context();
-		}
+			if (core_off_notification != NULL)
+				core_off_notification(PRCM_ENTER_OFF);
+		} else if ((core_next_state == PWRDM_POWER_RET) &&
+				(core_logic_state == PWRDM_POWER_OFF) &&
+				(core_mem_state == PWRDM_POWER_OFF)) {
+			omap3_core_save_context(PWRDM_POWER_RET);
+			omap3_prcm_save_context();
+			if (prm_setup->setup_times_off != NULL)
+				prm_program_setup_times(
+						prm_setup->setup_times_off);
+			/*
+			 * This is a hack. Currently OSWR does not
+			 * work if rom code restores DPLL4 to non
+			 * auto idle mode.
+			 * ROM restore takes 20mS longer if PER/DPLL4
+			 * idle is enabled before OFF.So it is typically
+			 * not enabled. Since OSWR hangs if it is not enabled
+			 * enable it for OSWR alone. Later in the restore path
+			 * it is disabled again
+			 */
+
+			omap3_scratchpad_dpll4autoidle(1);
+			prm_set_mod_reg_bits(OMAP3430_AUTO_RET,
+						OMAP3430_GR_MOD,
+						OMAP3_PRM_VOLTCTRL_OFFSET);
+		} else if (core_next_state == PWRDM_POWER_RET) {
+			prm_set_mod_reg_bits(OMAP3430_AUTO_RET,
+						OMAP3430_GR_MOD,
+						OMAP3_PRM_VOLTCTRL_OFFSET);
+	}
+
 		/* Enable IO-PAD and IO-CHAIN wakeups */
 		prm_set_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
 		omap3_enable_io_chain();
+	} else {
+		omap_uart_prepare_idle(0, core_next_state & core_logic_state);
+		omap_uart_prepare_idle(1, core_next_state & core_logic_state);
 	}
+	/*
+	 * Disable INTC autoidle as it can cause interrupt controller
+	 * to enter unknown state with right combination of sleep / wakeup
+	 * transitions
+	 */
+	omap3_intc_autoidle(0);
 
 	/*
 	* On EMU/HS devices ROM code restores a SRDC value
@@ -430,47 +562,85 @@
 	    core_next_state == PWRDM_POWER_OFF)
 		sdrc_write_reg(sdrc_pwr, SDRC_POWER);
 
-	/* Restore table entry modified during MMU restoration */
-	if (pwrdm_read_prev_pwrst(mpu_pwrdm) == PWRDM_POWER_OFF)
-		restore_table_entry();
+	mpu_prev_state = pwrdm_read_prev_pwrst(mpu_pwrdm);
 
+	/* Restore table entry modified during MMU restoration */
+	if (((mpu_prev_state == PWRDM_POWER_RET) &&
+			(pwrdm_read_prev_logic_pwrst(mpu_pwrdm) ==
+			 PWRDM_POWER_OFF)) ||
+			(mpu_prev_state == PWRDM_POWER_OFF))
+		restore_table_entry();
 
 	/* CORE */
 	if (core_next_state < PWRDM_POWER_ON) {
 		core_prev_state = pwrdm_read_prev_pwrst(core_pwrdm);
-		if (core_prev_state == PWRDM_POWER_OFF) {
-			omap3_core_restore_context();
+		if ((core_prev_state == PWRDM_POWER_OFF) ||
+				(core_prev_state == PWRDM_POWER_RET &&
+				 pwrdm_read_prev_logic_pwrst(core_pwrdm) ==
+				 PWRDM_POWER_OFF)) {
+			omap3_core_restore_context(core_prev_state);
 			omap3_prcm_restore_context();
 			omap3_sram_restore_context();
 			omap2_sms_restore_context();
+
+			if (core_off_notification != NULL)
+				core_off_notification(PRCM_EXIT_OFF);
+			/*
+			 * For OSWR to work we put PER DPLL in auto
+			 * idle mode in scratchpad. Clear it so that
+			 * next time if a OFF is attempted the ROM restore
+			 * does nt take long
+			 */
+			if (core_prev_state == PWRDM_POWER_RET)
+				omap3_scratchpad_dpll4autoidle(0);
+			/*
+			 * Errata 1.164 fix : OTG autoidle can prevent
+			 * sleep
+			 */
+			usb_musb_disable_autoidle();
+
 		}
 		omap_uart_resume_idle(0);
 		omap_uart_resume_idle(1);
-		if (core_next_state == PWRDM_POWER_OFF)
+		if (core_next_state == PWRDM_POWER_OFF) {
 			prm_clear_mod_reg_bits(OMAP3430_AUTO_OFF,
 					       OMAP3430_GR_MOD,
 					       OMAP3_PRM_VOLTCTRL_OFFSET);
+			if (prm_setup->setup_times_off != NULL)
+				prm_program_setup_times(prm_setup->setup_times);
+		}
 		/* Enable smartreflex after WFI */
 		enable_smartreflex(SR1);
 		enable_smartreflex(SR2);
+	} else {
+		omap_uart_resume_idle(0);
+		omap_uart_resume_idle(1);
 	}
+	/* Re-enable interrupt controller autoidle */
+	omap3_intc_autoidle(1);
 
 	/* PER */
 	if (per_next_state < PWRDM_POWER_ON) {
-		per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
+		if (per_next_state == PWRDM_POWER_OFF) {
+			/*
+			 * Reading the prev-state takes long time (11us@OPP2),
+			 * only do it, if we really tried to put PER in OFF
+			 */
+			per_prev_state = pwrdm_read_prev_pwrst(per_pwrdm);
 		if (per_prev_state == PWRDM_POWER_OFF) {
-			omap3_per_restore_context();
-			omap3_gpio_restore_pad_context(0);
-		} else if (per_next_state == PWRDM_POWER_OFF)
-			omap3_gpio_restore_pad_context(1);
+				omap3_per_restore_context();
+				omap3_gpio_restore_pad_context(0);
+			} else if (per_next_state == PWRDM_POWER_OFF) {
+				omap3_gpio_restore_pad_context(1);
+			}
+		}
 		omap2_gpio_resume_after_idle();
 		omap_uart_resume_idle(2);
-		if (per_state_modified)
-			pwrdm_set_next_pwrst(per_pwrdm, PWRDM_POWER_OFF);
-	}
+	} else
+		omap_uart_resume_idle(2);
 
 	/* Disable IO-PAD and IO-CHAIN wakeup */
-	if (core_next_state < PWRDM_POWER_ON) {
+	if (core_next_state <= PWRDM_POWER_ON) {
 		prm_clear_mod_reg_bits(OMAP3430_EN_IO, WKUP_MOD, PM_WKEN);
 		omap3_disable_io_chain();
 	}
@@ -478,7 +648,6 @@
 
 	pwrdm_post_transition();
 
-	omap2_clkdm_allow_idle(mpu_pwrdm->pwrdm_clkdms[0]);
 }
 
 int omap3_can_sleep(void)
@@ -514,6 +683,17 @@
 	if (cur_state == state)
 		return ret;
 
+	/*
+	 * check if bridge has hibernated? if yes then just return success
+	 * If OFF mode is not enabled, sleep switch is performed for IVA which is not
+	 * necessary.
+	 * REVISIT: Bridge has to set powerstate based on enable_off_mode state.
+	 */
+	if (!strcmp(pwrdm->name, "iva2_pwrdm")) {
+		/* if (cur_state == PWRDM_POWER_OFF) */
+			return 0;
+	}
+
 	if (pwrdm_read_pwrst(pwrdm) < PWRDM_POWER_ON) {
 		omap2_clkdm_wakeup(pwrdm->pwrdm_clkdms[0]);
 		sleep_switch = 1;
@@ -528,7 +708,6 @@
 	}
 
 	if (sleep_switch) {
-		omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
 		pwrdm_wait_transition(pwrdm);
 		pwrdm_state_switch(pwrdm);
 	}
@@ -602,7 +781,7 @@
 	}
 
 	omap_uart_prepare_suspend();
-
+	omap3_intc_suspend();
 	regset_save_on_suspend = 1;
 	omap_sram_idle();
 	regset_save_on_suspend = 0;
@@ -653,8 +832,7 @@
 static int omap3_pm_begin(suspend_state_t state)
 {
 	suspend_state = state;
-	omap_uart_enable_irqs(0);
-	return 0;
+	return omap_uart_enable_irqs(0);
 }
 
 static void omap3_pm_end(void)
@@ -724,6 +902,23 @@
 
 static void __init prcm_setup_regs(void)
 {
+	u32 cm_clksel1_mpu, cm_clksel1_iva2;
+
+	/*set Bypass clock dividers for MPU and IVA */
+	cm_clksel1_mpu = cm_read_mod_reg(MPU_MOD, CM_CLKSEL1);
+	cm_clksel1_iva2 = cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSEL1);
+	if (cpu_is_omap3630()) {
+		cm_clksel1_iva2 = (cm_clksel1_iva2 & ~(OMAP3430_IVA2_CLK_SRC_MASK)) |
+					(0x2 << OMAP3430_IVA2_CLK_SRC_SHIFT);
+		cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+					(0x1 << OMAP3430_MPU_CLK_SRC_SHIFT);
+	} else if (cpu_is_omap34xx()) {
+		cm_clksel1_iva2 = (cm_clksel1_iva2 & ~(OMAP3430_IVA2_CLK_SRC_MASK)) |
+					(0x4 << OMAP3430_IVA2_CLK_SRC_SHIFT);
+		cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+					(0x2 << OMAP3430_MPU_CLK_SRC_SHIFT);
+		}
+
 	/* reset modem */
 	prm_write_mod_reg(OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RSTPWRON |
 			  OMAP3430_RM_RSTCTRL_CORE_MODEM_SW_RST,
@@ -735,6 +930,11 @@
 	prm_write_mod_reg(0, OMAP3430_IVA2_MOD, PM_WKDEP);
 	prm_write_mod_reg(0, MPU_MOD, PM_WKDEP);
 	prm_write_mod_reg(0, OMAP3430_DSS_MOD, PM_WKDEP);
+
+	/* Enable PM_WKEN to support DSS LPR */
+	prm_write_mod_reg(OMAP3430_PM_WKEN_DSS_EN_DSS,
+				OMAP3430_DSS_MOD, PM_WKEN);
+
 	prm_write_mod_reg(0, OMAP3430_NEON_MOD, PM_WKDEP);
 	prm_write_mod_reg(0, OMAP3430_CAM_MOD, PM_WKDEP);
 	prm_write_mod_reg(0, OMAP3430_PER_MOD, PM_WKDEP);
@@ -845,6 +1045,8 @@
 			CM_AUTOIDLE);
 	}
 
+	omap_ctrl_writel(OMAP3430_AUTOIDLE, OMAP2_CONTROL_SYSCONFIG);
+
 	/*
 	 * Set all plls to autoidle. This is needed until autoidle is
 	 * enabled by clockfw
@@ -906,6 +1108,26 @@
 	omap3_iva_idle();
 }
 
+/* Function to register smc notification  used in driver code */
+void pm_register_sleep_notification(u32 domain_id, int (*notification)(bool))
+{
+	if (core_off_notification == NULL)
+		core_off_notification = notification;
+	else
+		printk(KERN_ERR "This function is already registered\n");
+}
+EXPORT_SYMBOL(pm_register_sleep_notification);
+
+/* Function to unregister smc notification used in driver code */
+void pm_unregister_sleep_notification(u32 domain_id, int (*notification)(bool))
+{
+	if (core_off_notification != NULL)
+		core_off_notification = NULL;
+	else
+		printk(KERN_ERR "This function is already unregistered\n");
+}
+EXPORT_SYMBOL(pm_unregister_sleep_notification);
+
 void omap3_pm_off_mode_enable(int enable)
 {
 	struct power_state *pwrst;
@@ -916,6 +1138,8 @@
 	else
 		state = PWRDM_POWER_RET;
 
+	omap3_cpuidle_update_states();
+
 #ifdef CONFIG_OMAP_PM_SRF
 	resource_lock_opp(VDD1_OPP);
 	resource_lock_opp(VDD2_OPP);
@@ -954,26 +1178,147 @@
 	return -EINVAL;
 }
 
+static void omap3_init_prm_setup_times(struct prm_setup_times_vc *conf)
+{
+	if (conf == NULL)
+		return;
+
+	conf->voltsetup1 =
+		(conf->voltsetup_time2 << OMAP3430_SETUP_TIME2_SHIFT) |
+		(conf->voltsetup_time1 << OMAP3430_SETUP_TIME1_SHIFT);
+}
+
+#ifdef CONFIG_VOLTSCALE_VPFORCE
+/* Voltage Scale using vp force update */
+static int voltagescale_vpforceupdate(u32 target_opp, u32 current_opp,
+					u8 target_vsel, u8 current_vsel)
+{
+	u32 vdd, target_opp_no, current_opp_no;
+	u32 t2_smps_delay = 0;
+	u32 t2_smps_steps = 0;
+	u32 vpconfig, vp_config_offs, vp_tranxdone_st;
+	int timeout = 0;
+
+	vdd = get_vdd(target_opp);
+	target_opp_no = get_opp_no(target_opp);
+	current_opp_no = get_opp_no(current_opp);
+	t2_smps_steps = abs(target_vsel - current_vsel);
+
+	if (vdd == VDD1_OPP) {
+		vp_config_offs = OMAP3_PRM_VP1_CONFIG_OFFSET;
+		vp_tranxdone_st = OMAP3430_VP1_TRANXDONE_ST;
+		vpconfig = target_vsel << OMAP3430_INITVOLTAGE_SHIFT |
+				((target_opp_no < VDD1_OPP3)
+				? PRM_VP1_CONFIG_ERRORGAIN_OPPLOW
+				: PRM_VP1_CONFIG_ERRORGAIN_OPPHIGH);
+		prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+				(target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
+				OMAP3430_GR_MOD,
+				OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
+	} else if (vdd == VDD2_OPP) {
+		vp_config_offs = OMAP3_PRM_VP2_CONFIG_OFFSET;
+		vp_tranxdone_st = OMAP3430_VP2_TRANXDONE_ST;
+		vpconfig = target_vsel << OMAP3430_INITVOLTAGE_SHIFT |
+				((target_opp_no < VDD2_OPP3)
+				? PRM_VP2_CONFIG_ERRORGAIN_OPPLOW
+				: PRM_VP2_CONFIG_ERRORGAIN_OPPHIGH);
+		prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+				(target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
+				OMAP3430_GR_MOD,
+				OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
+	} else {
+		pr_warning("Wrong VDD passed.VDD %d does not exist\n", vdd);
+		return -1;
+	}
+	/* Clear all pending TransactionDone interrupt/status */
+	while (timeout < VP_TRANXDONE_TIMEOUT) {
+		prm_write_mod_reg(vp_tranxdone_st, OCP_MOD,
+			OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+		if (!(prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET)
+					& vp_tranxdone_st))
+			break;
+
+		udelay(1);
+		timeout++;
+	}
+	if (timeout == VP_TRANXDONE_TIMEOUT)
+		pr_warning("VP1:TRANXDONE timeout exceeded still\
+			going ahead with voltage changed\n");
+
+	/* Configuring for vpforceupdate */
+	prm_rmw_mod_reg_bits(OMAP3430_ERRORGAIN_MASK |
+			OMAP3430_INITVOLTAGE_MASK | OMAP3430_INITVDD |
+			OMAP3430_FORCEUPDATE, vpconfig, OMAP3430_GR_MOD,
+			vp_config_offs);
+	/* Initialize VP voltage */
+	prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+			vp_config_offs);
+	/* Force update of voltage */
+	prm_set_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD,
+			vp_config_offs);
+	timeout = 0;
+	/* Wait for TransactionDone */
+	while ((timeout < VP_TRANXDONE_TIMEOUT) &&
+			(!(prm_read_mod_reg(OCP_MOD,
+			OMAP2_PRM_IRQSTATUS_MPU_OFFSET) &
+			vp_tranxdone_st))) {
+		udelay(1);
+		timeout++;
+	}
+
+	if (timeout == VP_TRANXDONE_TIMEOUT)
+		pr_warning("VP1:TRANXDONE timeout exceeded going ahead with\
+			 the t2 smps wait\n");
+
+	/* Wait for voltage to settle with SW wait-loop */
+	t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2;
+	udelay(t2_smps_delay);
+
+	timeout = 0;
+	/* Clear all pending TransactionDone interrupt/status */
+	 while (timeout < VP_TRANXDONE_TIMEOUT) {
+		prm_write_mod_reg(vp_tranxdone_st, OCP_MOD,
+			OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+		if (!(prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET)
+					& vp_tranxdone_st))
+			break;
+
+		udelay(1);
+		timeout++;
+	}
+	if (timeout == VP_TRANXDONE_TIMEOUT)
+		pr_warning("VP1:TRANXDONE timeout exceeded\n");
+
+	/* Clear INITVDD bit */
+	prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+			vp_config_offs);
+
+	/* Clear force bit */
+	prm_clear_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD,
+			vp_config_offs);
+	return 0;
+}
+#endif
+
+/* Scale voltage using vcbypass or vpforceupdate */
+int omap_scale_voltage(u32 target_opp, u32 current_opp,
+				u8 target_vsel, u8 current_vsel)
+{
+	#if defined(CONFIG_VOLTSCALE_VPFORCE)
+		return voltagescale_vpforceupdate(target_opp, current_opp,
+					target_vsel, current_vsel);
+	#elif defined(CONFIG_OMAP_SMARTREFLEX)
+		return sr_voltagescale_vcbypass(target_opp, current_opp,
+					target_vsel, current_vsel);
+	#else
+		return 0;
+	#endif
+}
+EXPORT_SYMBOL(omap_scale_voltage);
+
 void omap3_set_prm_setup_vc(struct prm_setup_vc *setup_vc)
 {
-	prm_setup.clksetup = setup_vc->clksetup;
-	prm_setup.voltsetup_time1 = setup_vc->voltsetup_time1;
-	prm_setup.voltsetup_time2 = setup_vc->voltsetup_time2;
-	prm_setup.voltoffset = setup_vc->voltoffset;
-	prm_setup.voltsetup2 = setup_vc->voltsetup2;
-	prm_setup.vdd0_on = setup_vc->vdd0_on;
-	prm_setup.vdd0_onlp = setup_vc->vdd0_onlp;
-	prm_setup.vdd0_ret = setup_vc->vdd0_ret;
-	prm_setup.vdd0_off = setup_vc->vdd0_off;
-	prm_setup.vdd1_on = setup_vc->vdd1_on;
-	prm_setup.vdd1_onlp = setup_vc->vdd1_onlp;
-	prm_setup.vdd1_ret = setup_vc->vdd1_ret;
-	prm_setup.vdd1_off = setup_vc->vdd1_off;
-	prm_setup.i2c_slave_ra = setup_vc->i2c_slave_ra;
-	prm_setup.vdd_vol_ra = setup_vc->vdd_vol_ra;
-	prm_setup.vdd_cmd_ra = setup_vc->vdd_cmd_ra;
-	prm_setup.vdd_ch_conf = setup_vc->vdd_ch_conf;
-	prm_setup.vdd_i2c_cfg = setup_vc->vdd_i2c_cfg;
+	prm_setup = setup_vc;
 }
 
 static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
@@ -983,7 +1328,7 @@
 	if (!pwrdm->pwrsts)
 		return 0;
 
-	pwrst = kmalloc(sizeof(struct power_state), GFP_KERNEL);
+	pwrst = kmalloc(sizeof(struct power_state), GFP_ATOMIC);
 	if (!pwrst)
 		return -ENOMEM;
 	pwrst->pwrdm = pwrdm;
@@ -1020,6 +1365,49 @@
 				save_secure_ram_context_sz);
 }
 
+#ifdef CONFIG_OMAP_PM_SRF
+static void set_opps_max(void)
+{
+	resource_set_opp_level(VDD2_OPP, MAX_VDD2_OPP, OPP_IGNORE_LOCK);
+	resource_set_opp_level(VDD1_OPP, MAX_VDD1_OPP, OPP_IGNORE_LOCK);
+	return;
+}
+#else
+static void set_opps_max(void)
+{
+	return;
+}
+#endif
+
+static int prcm_prepare_reboot(struct notifier_block *this, unsigned long code,
+					void *x)
+{
+	if ((code == SYS_DOWN) || (code == SYS_HALT) ||
+		(code == SYS_POWER_OFF)) {
+		set_opps_max();
+	}
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block prcm_notifier = {
+	.notifier_call	= prcm_prepare_reboot,
+	.next		= NULL,
+	.priority	= INT_MAX,
+};
+
+static int panic_prepare_reboot(struct notifier_block *this,
+					unsigned long code, void *x)
+{
+	set_opps_max();
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block prcm_panic_notifier = {
+	.notifier_call	= panic_prepare_reboot,
+	.next		= NULL,
+	.priority	= INT_MAX,
+};
+
 int __init omap3_pm_init(void)
 {
 	struct power_state *pwrst, *tmp;
@@ -1057,7 +1445,7 @@
 	neon_pwrdm = pwrdm_lookup("neon_pwrdm");
 	per_pwrdm = pwrdm_lookup("per_pwrdm");
 	core_pwrdm = pwrdm_lookup("core_pwrdm");
-	cam_pwrdm = pwrdm_lookup("cam_pwrdm");
+	wkup_pwrdm = pwrdm_lookup("wkup_pwrdm");
 
 	omap_push_sram_idle();
 
@@ -1077,6 +1465,14 @@
 	 * http://marc.info/?l=linux-omap&m=121852150710062&w=2
 	*/
 	pwrdm_add_wkdep(per_pwrdm, core_pwrdm);
+	/*
+	 * A part of the fix for errata 1.158.
+	 * GPIO pad spurious transition (glitch/spike) upon wakeup
+	 * from SYSTEM OFF mode. The remaining fix is in:
+	 * omap3_gpio_save_context, omap3_gpio_restore_context.
+	 */
+	if (omap_rev() <= OMAP3430_REV_ES3_1)
+		pwrdm_add_wkdep(per_pwrdm, wkup_pwrdm);
 
 	if (omap_type() != OMAP2_DEVICE_TYPE_GP) {
 		omap3_secure_ram_storage =
@@ -1097,6 +1493,9 @@
 	}
 
 	omap3_save_scratchpad_contents();
+	register_reboot_notifier(&prcm_notifier);
+	atomic_notifier_chain_register(&panic_notifier_list,
+					&prcm_panic_notifier);
 err1:
 	return ret;
 err2:
@@ -1144,32 +1543,32 @@
 
 static void __init configure_vc(void)
 {
-	prm_write_mod_reg(prm_setup.i2c_slave_ra, OMAP3430_GR_MOD,
+	prm_write_mod_reg(prm_setup->i2c_slave_ra, OMAP3430_GR_MOD,
 				OMAP3_PRM_VC_SMPS_SA_OFFSET);
-	prm_write_mod_reg(prm_setup.vdd_vol_ra, OMAP3430_GR_MOD,
+	prm_write_mod_reg(prm_setup->vdd_vol_ra, OMAP3430_GR_MOD,
 				OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET);
 
 	/* Only set if power_ic has different voltage and cmd addrs */
-	if (prm_setup.vdd_vol_ra != prm_setup.vdd_cmd_ra)
-		prm_write_mod_reg(prm_setup.vdd_cmd_ra, OMAP3430_GR_MOD,
+	if (prm_setup->vdd_vol_ra != prm_setup->vdd_cmd_ra)
+		prm_write_mod_reg(prm_setup->vdd_cmd_ra, OMAP3430_GR_MOD,
 				OMAP3_PRM_VC_SMPS_CMD_RA_OFFSET);
 
-	prm_write_mod_reg((prm_setup.vdd0_on << OMAP3430_VC_CMD_ON_SHIFT) |
-		(prm_setup.vdd0_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
-		(prm_setup.vdd0_ret << OMAP3430_VC_CMD_RET_SHIFT) |
-		(prm_setup.vdd0_off << OMAP3430_VC_CMD_OFF_SHIFT),
+	prm_write_mod_reg((prm_setup->vdd0_on << OMAP3430_VC_CMD_ON_SHIFT) |
+		(prm_setup->vdd0_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
+		(prm_setup->vdd0_ret << OMAP3430_VC_CMD_RET_SHIFT) |
+		(prm_setup->vdd0_off << OMAP3430_VC_CMD_OFF_SHIFT),
 		OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_0_OFFSET);
 
-	prm_write_mod_reg((prm_setup.vdd1_on << OMAP3430_VC_CMD_ON_SHIFT) |
-		(prm_setup.vdd1_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
-		(prm_setup.vdd1_ret << OMAP3430_VC_CMD_RET_SHIFT) |
-		(prm_setup.vdd1_off << OMAP3430_VC_CMD_OFF_SHIFT),
+	prm_write_mod_reg((prm_setup->vdd1_on << OMAP3430_VC_CMD_ON_SHIFT) |
+		(prm_setup->vdd1_onlp << OMAP3430_VC_CMD_ONLP_SHIFT) |
+		(prm_setup->vdd1_ret << OMAP3430_VC_CMD_RET_SHIFT) |
+		(prm_setup->vdd1_off << OMAP3430_VC_CMD_OFF_SHIFT),
 		OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_1_OFFSET);
 
-	prm_write_mod_reg(prm_setup.vdd_ch_conf, OMAP3430_GR_MOD,
+	prm_write_mod_reg(prm_setup->vdd_ch_conf, OMAP3430_GR_MOD,
 				OMAP3_PRM_VC_CH_CONF_OFFSET);
 
-	prm_write_mod_reg(prm_setup.vdd_i2c_cfg, OMAP3430_GR_MOD,
+	prm_write_mod_reg(prm_setup->vdd_i2c_cfg, OMAP3430_GR_MOD,
 				OMAP3_PRM_VC_I2C_CFG_OFFSET);
 
 	/* Setup value for voltctrl */
@@ -1177,18 +1576,11 @@
 			  OMAP3430_GR_MOD, OMAP3_PRM_VOLTCTRL_OFFSET);
 
 	/* Write setup times */
-	prm_write_mod_reg(prm_setup.clksetup, OMAP3430_GR_MOD,
-			OMAP3_PRM_CLKSETUP_OFFSET);
-	prm_write_mod_reg((prm_setup.voltsetup_time2 <<
-			OMAP3430_SETUP_TIME2_SHIFT) |
-			(prm_setup.voltsetup_time1 <<
-			OMAP3430_SETUP_TIME1_SHIFT),
-			OMAP3430_GR_MOD, OMAP3_PRM_VOLTSETUP1_OFFSET);
-
-	prm_write_mod_reg(prm_setup.voltoffset, OMAP3430_GR_MOD,
+	omap3_init_prm_setup_times(prm_setup->setup_times);
+	omap3_init_prm_setup_times(prm_setup->setup_times_off);
+	prm_program_setup_times(prm_setup->setup_times);
+	prm_write_mod_reg(prm_setup->voltoffset, OMAP3430_GR_MOD,
 			OMAP3_PRM_VOLTOFFSET_OFFSET);
-	prm_write_mod_reg(prm_setup.voltsetup2, OMAP3430_GR_MOD,
-			OMAP3_PRM_VOLTSETUP2_OFFSET);
 
 	pm_dbg_regset_init(1);
 }
diff --git a/arch/arm/mach-omap2/powerdomain.c b/arch/arm/mach-omap2/powerdomain.c
index 7aa64a8..ad47e3d 100644
--- a/arch/arm/mach-omap2/powerdomain.c
+++ b/arch/arm/mach-omap2/powerdomain.c
@@ -112,8 +112,8 @@
 static int _pwrdm_state_switch(struct powerdomain *pwrdm, int flag)
 {
 
-	int prev;
-	int state;
+	u8  prev;
+	u8  state;
 
 	if (pwrdm == NULL)
 		return -EINVAL;
@@ -128,6 +128,16 @@
 		prev = pwrdm_read_prev_pwrst(pwrdm);
 		if (pwrdm->state != prev)
 			pwrdm->state_counter[prev]++;
+		if (prev == PWRDM_POWER_RET) {
+			if ((pwrdm->pwrsts_logic_ret == PWRSTS_OFF_RET) &&
+					(pwrdm_read_prev_logic_pwrst(pwrdm) ==
+					PWRDM_POWER_OFF))
+				pwrdm->ret_logic_off_counter++;
+			if ((pwrdm->pwrsts_mem_ret[0] == PWRSTS_OFF_RET) &&
+					(pwrdm_read_prev_mem_pwrst(pwrdm, 0) ==
+					PWRDM_POWER_OFF))
+				pwrdm->ret_mem_off_counter++;
+		}
 		break;
 	default:
 		return -EINVAL;
@@ -159,12 +169,20 @@
 static __init void _pwrdm_setup(struct powerdomain *pwrdm)
 {
 	int i;
+	int state;
 
 	for (i = 0; i < 4; i++)
 		pwrdm->state_counter[i] = 0;
+	pwrdm->ret_logic_off_counter = 0;
+	pwrdm->ret_mem_off_counter = 0;
 
 	pwrdm_wait_transition(pwrdm);
-	pwrdm->state = pwrdm_read_pwrst(pwrdm);
+	state = pwrdm_read_pwrst(pwrdm);
+	if (state < 0) {
+		pr_err("powerdomain: invalid state for %s\n", pwrdm->name);
+		return;
+	}
+	pwrdm->state = state;
 	pwrdm->state_counter[pwrdm->state] = 1;
 
 }
@@ -221,6 +239,7 @@
 	pr_debug("powerdomain: registered %s\n", pwrdm->name);
 	ret = 0;
 
+	pwrdm->next_state = -1;
 pr_unlock:
 	write_unlock_irqrestore(&pwrdm_rwlock, flags);
 
@@ -273,35 +292,49 @@
 }
 
 /**
- * pwrdm_for_each - call function on each registered clockdomain
+ * pwrdm_for_each_nolock - call function on each registered clockdomain
  * @fn: callback function *
  *
  * Call the supplied function for each registered powerdomain.  The
  * callback function can return anything but 0 to bail out early from
- * the iterator.  The callback function is called with the pwrdm_rwlock
- * held for reading, so no powerdomain structure manipulation
- * functions should be called from the callback, although hardware
- * powerdomain control functions are fine.  Returns the last return
- * value of the callback function, which should be 0 for success or
- * anything else to indicate failure; or -EINVAL if the function
- * pointer is null.
+ * the iterator.Returns the last return value of the callback function, which
+ * should be 0 for success or anything else to indicate failure; or -EINVAL
+ * if the function pointer is null.
  */
-int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
 			void *user)
 {
 	struct powerdomain *temp_pwrdm;
-	unsigned long flags;
 	int ret = 0;
 
 	if (!fn)
 		return -EINVAL;
 
-	read_lock_irqsave(&pwrdm_rwlock, flags);
 	list_for_each_entry(temp_pwrdm, &pwrdm_list, node) {
 		ret = (*fn)(temp_pwrdm, user);
 		if (ret)
 			break;
 	}
+
+	return ret;
+}
+/**
+ * pwrdm_for_each - call function on each registered clockdomain
+ * @fn: callback function
+ *
+ * This function is the same as 'pwrdm_for_each_nolock()', but keeps the
+ * &pwrdm_rwlock locked for reading, so no powerdomain structure manipulation
+ * functions should be called from the callback, although hardware powerdomain
+ * control functions are fine.
+ */
+int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
+			void *user)
+{
+	unsigned long flags;
+	int ret;
+
+	read_lock_irqsave(&pwrdm_rwlock, flags);
+	ret = pwrdm_for_each_nolock(fn, user);
 	read_unlock_irqrestore(&pwrdm_rwlock, flags);
 
 	return ret;
@@ -686,19 +719,37 @@
  */
 int pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst)
 {
+	u8 prg_pwrst;
+
 	if (!pwrdm)
 		return -EINVAL;
 
+	if (pwrdm->next_state == pwrst)
+		return 0;
+
 	if (!(pwrdm->pwrsts & (1 << pwrst)))
 		return -EINVAL;
 
 	pr_debug("powerdomain: setting next powerstate for %s to %0x\n",
 		 pwrdm->name, pwrst);
 
+	/* INACTIVE is reserved, so we program pwrdm as ON */
+	if (pwrst == PWRDM_POWER_INACTIVE)
+		prg_pwrst = PWRDM_POWER_ON;
+	else
+		prg_pwrst = pwrst;
+
 	prm_rmw_mod_reg_bits(OMAP_POWERSTATE_MASK,
-			     (pwrst << OMAP_POWERSTATE_SHIFT),
+			     (prg_pwrst << OMAP_POWERSTATE_SHIFT),
 			     pwrdm->prcm_offs, PM_PWSTCTRL);
 
+	/* If next state is ON, prevent idle */
+	if (pwrst == PWRDM_POWER_ON)
+		omap2_clkdm_deny_idle(pwrdm->pwrdm_clkdms[0]);
+	else
+		omap2_clkdm_allow_idle(pwrdm->pwrdm_clkdms[0]);
+	pwrdm->next_state = pwrst;
+
 	return 0;
 }
 
@@ -715,6 +766,9 @@
 	if (!pwrdm)
 		return -EINVAL;
 
+	if (pwrdm->next_state > -1)
+		return pwrdm->next_state;
+
 	return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL,
 					OMAP_POWERSTATE_MASK);
 }
@@ -951,6 +1005,29 @@
 }
 
 /**
+ * pwrdm_read_next_logic_pwrst - get next powerdomain logic power state
+ * @pwrdm: struct powerdomain * to get next logic power state
+ *
+ * Return the powerdomain pwrdm's logic power state.  Returns -EINVAL
+ * if the powerdomain pointer is null or returns the next logic
+ * power state upon success.
+ */
+int pwrdm_read_next_logic_pwrst(struct powerdomain *pwrdm)
+{
+	if (!pwrdm)
+		return -EINVAL;
+
+	/*
+	 * The register bit names below may not correspond to the
+	 * actual names of the bits in each powerdomain's register,
+	 * but the type of value returned is the same for each
+	 * powerdomain.
+	 */
+	return prm_read_mod_bits_shift(pwrdm->prcm_offs, PM_PWSTCTRL,
+					OMAP3430_LOGICSTATEST);
+}
+
+/**
  * pwrdm_read_mem_pwrst - get current memory bank power state
  * @pwrdm: struct powerdomain * to get current memory bank power state
  * @bank: memory bank number (0-3)
@@ -1017,6 +1094,16 @@
 	if (pwrdm->banks < (bank + 1))
 		return -EEXIST;
 
+#ifdef CONFIG_ARCH_OMAP3430
+	/*
+	 * In 3430, for MPU domain bank 0 status bits
+	 * are displayed in the position of bank1 status bits
+	 * in PREPWST  . So the hack. Think of a cleaner
+	 * way of doing this
+	 */
+	if (!strcmp("mpu_pwrdm", pwrdm->name))
+		bank = 1;
+#endif
 	/*
 	 * The register bit names below may not correspond to the
 	 * actual names of the bits in each powerdomain's register,
@@ -1046,6 +1133,54 @@
 }
 
 /**
+ * pwrdm_read_next_mem_pwrst - get next memory bank power state
+ * @pwrdm: struct powerdomain * to get mext memory bank power state
+ * @bank: memory bank number (0-3)
+ *
+ * Return the powerdomain pwrdm's next memory power state for bank
+ * x.  Returns -EINVAL if the powerdomain pointer is null, -EEXIST if
+ * the target memory bank does not exist or is not controllable, or
+ * returns the next memory power state upon success.
+ */
+int pwrdm_read_next_mem_pwrst(struct powerdomain *pwrdm, u8 bank)
+{
+	u32 m;
+
+	if (!pwrdm)
+		return -EINVAL;
+
+	if (pwrdm->banks < (bank + 1))
+		return -EEXIST;
+
+	/*
+	 * The register bit names below may not correspond to the
+	 * actual names of the bits in each powerdomain's register,
+	 * but the type of value returned is the same for each
+	 * powerdomain.
+	 */
+	switch (bank) {
+	case 0:
+		m = OMAP3430_SHAREDL1CACHEFLATRETSTATE;
+		break;
+	case 1:
+		m = OMAP3430_L1FLATMEMRETSTATE;
+		break;
+	case 2:
+		m = OMAP3430_SHAREDL2CACHEFLATRETSTATE;
+		break;
+	case 3:
+		m = OMAP3430_SHAREDL2CACHEFLATRETSTATE;
+		break;
+	default:
+		WARN_ON(1); /* should never happen */
+		return -EEXIST;
+	}
+
+	return prm_read_mod_bits_shift(pwrdm->prcm_offs,
+					PM_PWSTCTRL, m);
+}
+
+/**
  * pwrdm_clear_all_prev_pwrst - clear previous powerstate register for a pwrdm
  * @pwrdm: struct powerdomain * to clear
  *
@@ -1180,6 +1315,29 @@
 	return 0;
 }
 
+/**
+ * pwrdm_can_idle - check if the powerdomain can enter idle
+ * @pwrdm: struct powerdomain * the powerdomain to check status of
+ *
+ * Does a functional clock check for the powerdomain and returns 1 if the
+ * powerdomain can enter idle, 0 if not.
+ */
+int pwrdm_can_idle(struct powerdomain *pwrdm)
+{
+	int i;
+	const int fclk_regs[] = { CM_FCLKEN, OMAP3430ES2_CM_FCLKEN3 };
+
+	if (!pwrdm)
+		return -EINVAL;
+
+	for (i = 0; i < pwrdm->fclk_reg_amt; i++)
+		if (cm_read_mod_reg(pwrdm->prcm_offs, fclk_regs[i]) &
+				(0xffffffff ^ pwrdm->fclk_masks[i]))
+			return 0;
+	return 1;
+}
+
+
 int pwrdm_state_switch(struct powerdomain *pwrdm)
 {
 	return _pwrdm_state_switch(pwrdm, PWRDM_STATE_NOW);
diff --git a/arch/arm/mach-omap2/powerdomains34xx.h b/arch/arm/mach-omap2/powerdomains34xx.h
index 87e8111..c376efa 100644
--- a/arch/arm/mach-omap2/powerdomains34xx.h
+++ b/arch/arm/mach-omap2/powerdomains34xx.h
@@ -165,7 +165,7 @@
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 	.dep_bit	  = OMAP3430_PM_WKDEP_MPU_EN_IVA2_SHIFT,
 	.wkdep_srcs	  = iva2_wkdeps,
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.banks		  = 4,
 	.pwrsts_mem_ret	  = {
@@ -180,6 +180,7 @@
 		[2] = PWRSTS_OFF_ON,
 		[3] = PWRDM_POWER_ON,
 	},
+	.fclk_reg_amt	  = 1,
 };
 
 static struct powerdomain mpu_34xx_pwrdm = {
@@ -188,7 +189,7 @@
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 	.dep_bit	  = OMAP3430_EN_MPU_SHIFT,
 	.wkdep_srcs	  = mpu_34xx_wkdeps,
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
@@ -206,7 +207,8 @@
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1 |
 					   CHIP_IS_OMAP3430ES2 |
 					   CHIP_IS_OMAP3430ES3_0),
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
+	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.dep_bit	  = OMAP3430_EN_CORE_SHIFT,
 	.banks		  = 2,
 	.pwrsts_mem_ret	  = {
@@ -214,8 +216,8 @@
 		[1] = PWRSTS_OFF_RET,	 /* MEM2RETSTATE */
 	},
 	.pwrsts_mem_on	  = {
-		[0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
-		[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+		[0] = PWRSTS_OFF_RET_INA_ON, /* MEM1ONSTATE */
+		[1] = PWRSTS_OFF_RET_INA_ON, /* MEM2ONSTATE */
 	},
 };
 
@@ -224,7 +226,8 @@
 	.name		  = "core_pwrdm",
 	.prcm_offs	  = CORE_MOD,
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES3_1),
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
+	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.dep_bit	  = OMAP3430_EN_CORE_SHIFT,
 	.flags		  = PWRDM_HAS_HDWR_SAR, /* for USBTLL only */
 	.banks		  = 2,
@@ -233,9 +236,15 @@
 		[1] = PWRSTS_OFF_RET,	 /* MEM2RETSTATE */
 	},
 	.pwrsts_mem_on	  = {
-		[0] = PWRSTS_OFF_RET_ON, /* MEM1ONSTATE */
-		[1] = PWRSTS_OFF_RET_ON, /* MEM2ONSTATE */
+		[0] = PWRSTS_OFF_RET_INA_ON, /* MEM1ONSTATE */
+		[1] = PWRSTS_OFF_RET_INA_ON, /* MEM2ONSTATE */
 	},
+	.fclk_reg_amt	  = 2,
+	.fclk_masks	  = {
+		[0] = OMAP3430_EN_UART2 | OMAP3430_EN_UART1,
+		[1] = 0,
+	},
+
 };
 
 /* Another case of bit name collisions between several registers: EN_DSS */
@@ -246,7 +255,7 @@
 	.dep_bit	  = OMAP3430_PM_WKDEP_MPU_EN_DSS_SHIFT,
 	.wkdep_srcs	  = cam_dss_wkdeps,
 	.sleepdep_srcs	  = dss_per_usbhost_sleepdeps,
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
 	.pwrsts_logic_ret = PWRDM_POWER_RET,
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
@@ -255,6 +264,7 @@
 	.pwrsts_mem_on	  = {
 		[0] = PWRDM_POWER_ON,  /* MEMONSTATE */
 	},
+	.fclk_reg_amt	  = 1,
 };
 
 /*
@@ -278,6 +288,7 @@
 	.pwrsts_mem_on	  = {
 		[0] = PWRDM_POWER_ON,  /* MEMONSTATE */
 	},
+	.fclk_reg_amt	  = 1,
 };
 
 static struct powerdomain cam_pwrdm = {
@@ -286,7 +297,7 @@
 	.prcm_offs	  = OMAP3430_CAM_MOD,
 	.wkdep_srcs	  = cam_dss_wkdeps,
 	.sleepdep_srcs	  = cam_gfx_sleepdeps,
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
 	.pwrsts_logic_ret = PWRDM_POWER_RET,
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
@@ -295,6 +306,7 @@
 	.pwrsts_mem_on	  = {
 		[0] = PWRDM_POWER_ON,  /* MEMONSTATE */
 	},
+	.fclk_reg_amt	  = 1,
 };
 
 static struct powerdomain per_pwrdm = {
@@ -304,7 +316,7 @@
 	.dep_bit	  = OMAP3430_EN_PER_SHIFT,
 	.wkdep_srcs	  = per_usbhost_wkdeps,
 	.sleepdep_srcs	  = dss_per_usbhost_sleepdeps,
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
 	.pwrsts_logic_ret = PWRSTS_OFF_RET,
 	.banks		  = 1,
 	.pwrsts_mem_ret	  = {
@@ -313,6 +325,10 @@
 	.pwrsts_mem_on	  = {
 		[0] = PWRDM_POWER_ON,  /* MEMONSTATE */
 	},
+	.fclk_reg_amt	  = 1,
+	.fclk_masks	  = {
+		[0] = OMAP3430_EN_UART3,
+	},
 };
 
 static struct powerdomain emu_pwrdm = {
@@ -326,7 +342,7 @@
 	.prcm_offs	  = OMAP3430_NEON_MOD,
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
 	.wkdep_srcs	  = neon_wkdeps,
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
 	.pwrsts_logic_ret = PWRDM_POWER_RET,
 };
 
@@ -336,7 +352,7 @@
 	.omap_chip	  = OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
 	.wkdep_srcs	  = per_usbhost_wkdeps,
 	.sleepdep_srcs	  = dss_per_usbhost_sleepdeps,
-	.pwrsts		  = PWRSTS_OFF_RET_ON,
+	.pwrsts		  = PWRSTS_OFF_RET_INA_ON,
 	.pwrsts_logic_ret = PWRDM_POWER_RET,
 	/*
 	 * REVISIT: Enabling usb host save and restore mechanism seems to
@@ -353,6 +369,7 @@
 	.pwrsts_mem_on	  = {
 		[0] = PWRDM_POWER_ON,  /* MEMONSTATE */
 	},
+	.fclk_reg_amt	  = 1,
 };
 
 static struct powerdomain dpll1_pwrdm = {
diff --git a/arch/arm/mach-omap2/prcm.c b/arch/arm/mach-omap2/prcm.c
index 3f2520d..6b21032 100644
--- a/arch/arm/mach-omap2/prcm.c
+++ b/arch/arm/mach-omap2/prcm.c
@@ -26,7 +26,9 @@
 #include <mach/prcm.h>
 #include <mach/irqs.h>
 #include <mach/control.h>
+#include <mach/sram.h>
 
+#include "sdrc.h"
 #include "clock.h"
 #include "cm.h"
 #include "prm.h"
@@ -129,11 +131,13 @@
 void omap_prcm_arch_reset(char mode)
 {
 	s16 prcm_offs;
+
 	omap2_clk_prepare_for_reboot();
 
-	if (cpu_is_omap24xx())
+	if (cpu_is_omap24xx()) {
 		prcm_offs = WKUP_MOD;
-	else if (cpu_is_omap34xx()) {
+		prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, RM_RSTCTRL);
+	} else if (cpu_is_omap34xx()) {
 		u32 l;
 
 		prcm_offs = OMAP3430_GR_MOD;
@@ -144,10 +148,11 @@
 		 * cf. OMAP34xx TRM, Initialization / Software Booting
 		 * Configuration. */
 		omap_writel(l, OMAP343X_SCRATCHPAD + 4);
+
+		omap3_configure_core_dpll_warmreset();
+
 	} else
 		WARN_ON(1);
-
-	prm_set_mod_reg_bits(OMAP_RST_DPLL3, prcm_offs, RM_RSTCTRL);
 }
 
 static inline u32 __omap_prcm_read(void __iomem *base, s16 module, u16 reg)
@@ -237,7 +242,6 @@
 	prcm_context.cm_sysconfig = __raw_readl(OMAP3430_CM_SYSCONFIG);
 	prcm_context.sgx_cm_clksel =
 			 cm_read_mod_reg(OMAP3430ES2_SGX_MOD, CM_CLKSEL);
-	prcm_context.wkup_cm_clksel = cm_read_mod_reg(WKUP_MOD, CM_CLKSEL);
 	prcm_context.dss_cm_clksel =
 			 cm_read_mod_reg(OMAP3430_DSS_MOD, CM_CLKSEL);
 	prcm_context.cam_cm_clksel =
@@ -254,8 +258,6 @@
 			cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL4);
 	prcm_context.pll_cm_clksel5 =
 			 cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKSEL5);
-	prcm_context.pll_cm_clken =
-			cm_read_mod_reg(PLL_MOD, CM_CLKEN);
 	prcm_context.pll_cm_clken2 =
 			cm_read_mod_reg(PLL_MOD, OMAP3430ES2_CM_CLKEN2);
 	prcm_context.cm_polctrl = __raw_readl(OMAP3430_CM_POLCTRL);
@@ -301,8 +303,6 @@
 			 cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_AUTOIDLE2);
 	prcm_context.mpu_cm_autoidle2 =
 			 cm_read_mod_reg(MPU_MOD, CM_AUTOIDLE2);
-	prcm_context.pll_cm_autoidle =
-			 cm_read_mod_reg(PLL_MOD, CM_AUTOIDLE);
 	prcm_context.iva2_cm_clkstctrl =
 			 cm_read_mod_reg(OMAP3430_IVA2_MOD, CM_CLKSTCTRL);
 	prcm_context.mpu_cm_clkstctrl =
@@ -394,7 +394,6 @@
 	__raw_writel(prcm_context.cm_sysconfig, OMAP3430_CM_SYSCONFIG);
 	cm_write_mod_reg(prcm_context.sgx_cm_clksel, OMAP3430ES2_SGX_MOD,
 					 CM_CLKSEL);
-	cm_write_mod_reg(prcm_context.wkup_cm_clksel, WKUP_MOD, CM_CLKSEL);
 	cm_write_mod_reg(prcm_context.dss_cm_clksel, OMAP3430_DSS_MOD,
 					 CM_CLKSEL);
 	cm_write_mod_reg(prcm_context.cam_cm_clksel, OMAP3430_CAM_MOD,
@@ -411,7 +410,6 @@
 					OMAP3430ES2_CM_CLKSEL4);
 	cm_write_mod_reg(prcm_context.pll_cm_clksel5, PLL_MOD,
 					 OMAP3430ES2_CM_CLKSEL5);
-	cm_write_mod_reg(prcm_context.pll_cm_clken, PLL_MOD, CM_CLKEN);
 	cm_write_mod_reg(prcm_context.pll_cm_clken2, PLL_MOD,
 					OMAP3430ES2_CM_CLKEN2);
 	__raw_writel(prcm_context.cm_polctrl, OMAP3430_CM_POLCTRL);
@@ -450,7 +448,6 @@
 	cm_write_mod_reg(prcm_context.iva2_cm_autiidle2, OMAP3430_IVA2_MOD,
 					CM_AUTOIDLE2);
 	cm_write_mod_reg(prcm_context.mpu_cm_autoidle2, MPU_MOD, CM_AUTOIDLE2);
-	cm_write_mod_reg(prcm_context.pll_cm_autoidle, PLL_MOD, CM_AUTOIDLE);
 	cm_write_mod_reg(prcm_context.iva2_cm_clkstctrl, OMAP3430_IVA2_MOD,
 					CM_CLKSTCTRL);
 	cm_write_mod_reg(prcm_context.mpu_cm_clkstctrl, MPU_MOD, CM_CLKSTCTRL);
diff --git a/arch/arm/mach-omap2/prm-regbits-34xx.h b/arch/arm/mach-omap2/prm-regbits-34xx.h
index d4ea370..8ae9fe5 100644
--- a/arch/arm/mach-omap2/prm-regbits-34xx.h
+++ b/arch/arm/mach-omap2/prm-regbits-34xx.h
@@ -243,6 +243,23 @@
 #define OMAP3430_EVGENON_ST				(1 << 2)
 #define OMAP3430_FS_USB_WKUP_ST				(1 << 1)
 
+#define OMAP3430_VP1_ST	(OMAP3430_VP1_OPPCHANGEDONE_ST |	\
+				 OMAP3430_VP1_MINVDD_ST	|		\
+				 OMAP3430_VP1_MAXVDD_ST |		\
+				 OMAP3430_VP1_NOSMPSACK_ST |		\
+				 OMAP3430_VP1_EQVALUE_ST |		\
+				 OMAP3430_VP1_TRANXDONE_ST)
+
+#define OMAP3430_VP2_ST	(OMAP3430_VP2_OPPCHANGEDONE_ST |	\
+				 OMAP3430_VP2_MINVDD_ST |		\
+				 OMAP3430_VP2_MAXVDD_ST |		\
+				 OMAP3430_VP2_NOSMPSACK_ST |		\
+				 OMAP3430_VP2_EQVALUE_ST |		\
+				  OMAP3430_VP2_TRANXDONE_ST)
+
+#define OMAP3430_VC_ST		(OMAP3430_VC_SAERR_ST |		\
+				 OMAP3430_VC_RAERR_ST |		\
+				 OMAP3430_VC_TIMEOUTERR_ST)
 /* PRM_IRQENABLE_MPU specific bits */
 #define OMAP3430ES2_SND_PERIPH_DPLL_RECAL_EN_SHIFT		25
 #define OMAP3430ES2_SND_PERIPH_DPLL_RECAL_EN			(1 << 25)
diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c
index 68616f0..238129c 100644
--- a/arch/arm/mach-omap2/resource34xx.c
+++ b/arch/arm/mach-omap2/resource34xx.c
@@ -38,7 +38,7 @@
 void init_latency(struct shared_resource *resp)
 {
 	resp->no_of_users = 0;
-	resp->curr_level = RES_DEFAULTLEVEL;
+	resp->curr_level = RES_LATENCY_DEFAULTLEVEL;
 	*((u8 *)resp->resource_data) = 0;
 	return;
 }
@@ -62,7 +62,7 @@
 		resp->curr_level = latency;
 
 	pm_qos_req_added = resp->resource_data;
-	if (latency == RES_DEFAULTLEVEL)
+	if (latency == RES_LATENCY_DEFAULTLEVEL)
 		/* No more users left, remove the pm_qos_req if present */
 		if (*pm_qos_req_added) {
 			pm_qos_remove_requirement(PM_QOS_CPU_DMA_LATENCY,
@@ -237,9 +237,29 @@
 {
 	int ret = 0, l3_div;
 	int *curr_opp;
+	u32 cm_clksel1_mpu;
 
 	lock_scratchpad_sem();
 	if (res == VDD1_OPP) {
+		if (target_level == VDD1_OPP1) {
+			cm_clksel1_mpu = cm_read_mod_reg(MPU_MOD, CM_CLKSEL1);
+			if (cpu_is_omap3630())
+				cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+							(0x2 << OMAP3430_MPU_CLK_SRC_SHIFT);
+			else if (cpu_is_omap34xx())
+				cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+							(0x4 << OMAP3430_MPU_CLK_SRC_SHIFT);
+			cm_write_mod_reg(cm_clksel1_mpu, MPU_MOD, CM_CLKSEL1);
+		} else if ((current_level == VDD1_OPP1) && (target_level != VDD1_OPP1)) {
+			cm_clksel1_mpu = cm_read_mod_reg(MPU_MOD, CM_CLKSEL1);
+			if (cpu_is_omap3630())
+				cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+							(0x1 << OMAP3430_MPU_CLK_SRC_SHIFT);
+			else if (cpu_is_omap34xx())
+				cm_clksel1_mpu = (cm_clksel1_mpu & ~(OMAP3430_MPU_CLK_SRC_MASK)) |
+							(0x2 << OMAP3430_MPU_CLK_SRC_SHIFT);
+			cm_write_mod_reg(cm_clksel1_mpu, MPU_MOD, CM_CLKSEL1);
+		}
 		curr_opp = &curr_vdd1_opp;
 		clk_set_rate(dpll1_clk, mpu_opps[target_level].rate);
 		clk_set_rate(dpll2_clk, dsp_opps[target_level].rate);
@@ -273,29 +293,31 @@
 		int current_level)
 {
 	int i, ret = 0, raise;
-#ifdef CONFIG_OMAP_SMARTREFLEX
 	unsigned long t_opp, c_opp;
 
 	t_opp = ID_VDD(res) | ID_OPP_NO(opp[target_level].opp_id);
 	c_opp = ID_VDD(res) | ID_OPP_NO(opp[current_level].opp_id);
-#endif
+	/* Sanity check of the OPP params before attempting to set */
+	if (!opp[target_level].rate || !opp[target_level].vsel)
+		return -EINVAL;
 	if (target_level > current_level)
 		raise = 1;
 	else
 		raise = 0;
 
+	disable_smartreflex(res);
+
 	for (i = 0; i < 2; i++) {
 		if (i == raise)
 			ret = program_opp_freq(res, target_level,
 					current_level);
-#ifdef CONFIG_OMAP_SMARTREFLEX
 		else
-			sr_voltagescale_vcbypass(t_opp, c_opp,
+			omap_scale_voltage(t_opp, c_opp,
 				opp[target_level].vsel,
 				opp[current_level].vsel);
-#endif
 	}
 
+	enable_smartreflex(res);
 	return ret;
 }
 
@@ -362,17 +384,18 @@
 	int ind;
 
 	if (resp == vdd1_resp) {
-		if (target_level < 3)
+		if (target_level < VDD1_THRESHOLD)
 			resource_release("vdd2_opp", &vdd2_dev);
 
 		resource_set_opp_level(VDD1_OPP, target_level, 0);
 		/*
 		 * For VDD1 OPP3 and above, make sure the interconnect
-		 * is at 100Mhz or above.
-		 * throughput in KiB/s for 100 Mhz = 100 * 1000 * 4.
+		 * is strictly above 100Mhz.
+		 * throughput in KiB/s for 200 Mhz = 200 * 1000 * 4.
 		 */
-		if (target_level >= 3)
-			resource_request("vdd2_opp", &vdd2_dev, 400000);
+		if (target_level >= VDD1_THRESHOLD)
+			resource_request("vdd2_opp", &vdd2_dev,
+				4 * l3_opps[omap_pm_get_max_vdd2_opp()].rate/1000);
 
 	} else if (resp == vdd2_resp) {
 		tput = target_level;
@@ -380,7 +403,7 @@
 		/* Convert the tput in KiB/s to Bus frequency in MHz */
 		req_l3_freq = (tput * 1000)/4;
 
-		for (ind = 2; ind <= MAX_VDD2_OPP; ind++)
+		for (ind = MIN_VDD2_OPP; ind <= MAX_VDD2_OPP; ind++)
 			if ((l3_opps + ind)->rate >= req_l3_freq) {
 				target_level = ind;
 				break;
diff --git a/arch/arm/mach-omap2/resource34xx.h b/arch/arm/mach-omap2/resource34xx.h
index 5b5618a..ac6476e 100644
--- a/arch/arm/mach-omap2/resource34xx.h
+++ b/arch/arm/mach-omap2/resource34xx.h
@@ -28,7 +28,7 @@
 #include <mach/omap-pm.h>
 #include <mach/omap34xx.h>
 
-extern int sr_voltagescale_vcbypass(u32 t_opp, u32 c_opp, u8 t_vsel, u8 c_vsel);
+extern int omap_scale_voltage(u32 t_opp, u32 c_opp, u8 t_vsel, u8 c_vsel);
 extern void lock_scratchpad_sem();
 extern void unlock_scratchpad_sem();
 
@@ -49,6 +49,7 @@
 static struct shared_resource mpu_latency = {
 	.name 		= "mpu_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags		= RES_TYPE_LATENCY,
 	.resource_data  = &mpu_qos_req_added,
 	.ops 		= &lat_res_ops,
 };
@@ -56,6 +57,7 @@
 static struct shared_resource core_latency = {
 	.name 		= "core_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags		= RES_TYPE_LATENCY,
 	.resource_data	= &core_qos_req_added,
 	.ops 		= &lat_res_ops,
 };
@@ -91,6 +93,7 @@
 static struct shared_resource core_pwrdm_latency = {
 	.name		= "core_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data	= &core_qos_req_added,
 	.ops		= &lat_res_ops,
 };
@@ -106,6 +109,7 @@
 static struct shared_resource iva2_pwrdm_latency = {
 	.name		= "iva2_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data	= &iva2_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -129,6 +133,7 @@
 static struct shared_resource gfx_pwrdm_latency = {
 	.name		= "gfx_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430ES1),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data	= &gfx_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -136,6 +141,7 @@
 static struct shared_resource sgx_pwrdm_latency = {
 	.name 		= "sgx_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data  = &sgx_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -151,6 +157,7 @@
 static struct shared_resource dss_pwrdm_latency = {
 	.name		= "dss_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data	= &dss_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -166,6 +173,7 @@
 static struct shared_resource cam_pwrdm_latency = {
 	.name		= "cam_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data	= &cam_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -181,6 +189,7 @@
 static struct shared_resource per_pwrdm_latency = {
 	.name		= "per_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data	= &per_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -196,6 +205,7 @@
 static struct shared_resource neon_pwrdm_latency = {
 	.name		= "neon_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data	= &neon_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -211,6 +221,7 @@
 static struct shared_resource usbhost_pwrdm_latency = {
 	.name		= "usbhost_pwrdm_latency",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_GE_OMAP3430ES2),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data  = &usbhost_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -226,6 +237,7 @@
 static struct shared_resource emu_pwrdm_latency = {
 	.name           = "emu_pwrdm",
 	.omap_chip	= OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_LATENCY,
 	.resource_data  = &emu_pwrdm_lat_db,
 	.ops		= &pd_lat_res_ops,
 };
@@ -251,6 +263,7 @@
 static struct shared_resource vdd1_opp = {
 	.name           = "vdd1_opp",
 	.omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_PERFORMANCE,
 	.ops            = &opp_res_ops,
 };
 
@@ -264,6 +277,7 @@
 static struct shared_resource vdd2_opp = {
 	.name           = "vdd2_opp",
 	.omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_PERFORMANCE,
 	.resource_data  = &l3_throughput_db,
 	.ops            = &opp_res_ops,
 };
@@ -279,6 +293,7 @@
 static struct shared_resource mpu_freq = {
 	.name           = "mpu_freq",
 	.omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_PERFORMANCE,
 	.resource_data  = &linked_res,
 	.ops            = &freq_res_ops,
 };
@@ -286,6 +301,7 @@
 static struct shared_resource dsp_freq = {
 	.name           = "dsp_freq",
 	.omap_chip      = OMAP_CHIP_INIT(CHIP_IS_OMAP3430),
+	.flags          = RES_TYPE_PERFORMANCE,
 	.resource_data  = &linked_res,
 	.ops            = &freq_res_ops,
 };
diff --git a/arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h b/arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h
new file mode 100644
index 0000000..adef6b9
--- /dev/null
+++ b/arch/arm/mach-omap2/sdram-hynix-h8mbx00u0mer-0em.h
@@ -0,0 +1,55 @@
+/*
+ * SDRC register values for the Hynix H8MBX00U0MER-0EM
+ *
+ * Copyright (C) 2008-2009 Texas Instruments, Inc.
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Nicole Chalhoub / Vincent Bour
+ *
+ * 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.
+ */
+
+#ifndef ARCH_ARM_MACH_OMAP2_SDRAM_HYNIX_H8MBX00U0MER0EM
+#define ARCH_ARM_MACH_OMAP2_SDRAM_HYNIX_H8MBX00U0MER0EM
+
+#include <mach/sdrc.h>
+
+/* Hynix H8MBX00U0MER-0EM */
+static struct omap_sdrc_params h8mbx00u0mer0em_sdrc_params[] = {
+	[0] = {
+		.rate        = 200000000,
+		.actim_ctrla = 0xa2e1b4c6,
+		.actim_ctrlb = 0x0002131c,
+		.rfr_ctrl    = 0x0005e601,
+		.mr          = 0x00000032,
+	},
+	[1] = {
+		.rate        = 166000000,
+		.actim_ctrla = 0x629db4c6,
+		.actim_ctrlb = 0x00012214,
+		.rfr_ctrl    = 0x0004dc01,
+		.mr          = 0x00000032,
+	},
+	[2] = {
+		.rate        = 100000000,
+		.actim_ctrla = 0x51912284,
+		.actim_ctrlb = 0x0002120e,
+		.rfr_ctrl    = 0x0002d101,
+		.mr          = 0x00000022,
+	},
+	[3] = {
+		.rate        = 83000000,
+		.actim_ctrla = 0x31512283,
+		.actim_ctrlb = 0x0001220a,
+		.rfr_ctrl    = 0x00025501,
+		.mr          = 0x00000022,
+	},
+	[4] = {
+		.rate        = 0
+	},
+};
+
+#endif
+
diff --git a/arch/arm/mach-omap2/sdrc.h b/arch/arm/mach-omap2/sdrc.h
index 1a8bbd0..3af2ff9 100644
--- a/arch/arm/mach-omap2/sdrc.h
+++ b/arch/arm/mach-omap2/sdrc.h
@@ -50,7 +50,8 @@
 #else
 #define OMAP242X_SDRC_REGADDR(reg)	IO_ADDRESS(OMAP2420_SDRC_BASE + (reg))
 #define OMAP243X_SDRC_REGADDR(reg)	IO_ADDRESS(OMAP243X_SDRC_BASE + (reg))
-#define OMAP34XX_SDRC_REGADDR(reg)	IO_ADDRESS(OMAP343X_SDRC_BASE + (reg))
+#define OMAP34XX_SDRC_REGADDR(reg)	L3_IO_ADDRESS	\
+						(OMAP343X_SDRC_BASE + (reg))
 #endif	/* __ASSEMBLER__ */
 
 #endif
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index 9d59eb1..b4a97d3 100755
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -21,6 +21,7 @@
 #include <linux/clk.h>
 #ifdef CONFIG_SERIAL_OMAP
 #include <linux/platform_device.h>
+#include <mach/omap-serial.h>
 #endif
 #include <linux/io.h>
 #include <linux/wakelock.h>
@@ -48,6 +49,10 @@
 	u32 wk_mask;
 	u32 padconf;
 
+	u32 rts_padconf;
+	int rts_override;
+	u16 rts_padvalue;
+
 	struct clk *ick;
 	struct clk *fck;
 	int clocked;
@@ -55,6 +60,7 @@
 	struct plat_serial8250_port *p;
 	struct list_head node;
 
+	int use_dma;
 #if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
 	int context_valid;
 
@@ -65,6 +71,7 @@
 	u16 sysc;
 	u16 scr;
 	u16 wer;
+	u16 mcr;
 #endif
 };
 
@@ -79,8 +86,6 @@
 		wake_lock_timeout(&omap_serial_wakelock, 10*HZ);
 }
 
-
-
 static struct plat_serial8250_port serial_platform_data[] = {
 	{
 		.membase	= IO_ADDRESS(OMAP_UART1_BASE),
@@ -111,7 +116,7 @@
 		.pm		= omap_serial_pm,
 	},
 #define QUART_CLK (1843200)
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
 	{
 		.membase	= ZOOM2_QUART_VIRT,
 		.mapbase        = 0x10000000,
@@ -162,7 +167,7 @@
 	}
 };
 
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
 static struct resource omap2_quaduart_resources[] = {
 	{
 		.start		= 0x10000000,
@@ -195,7 +200,7 @@
 	.resource		= omap2_uart3_resources,
 };
 
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
 static struct platform_device quaduart_device = {
 
 	.name			= "omap-uart",
@@ -209,7 +214,7 @@
 	&uart1_device,
 	&uart2_device,
 	&uart3_device,
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
 	&quaduart_device
 #endif
 };
@@ -262,9 +267,6 @@
 	u16 lcr = 0;
 	struct plat_serial8250_port *p = uart->p;
 
-	if (!enable_off_mode)
-		return;
-
 	lcr = serial_read_reg(p, UART_LCR);
 	serial_write_reg(p, UART_LCR, 0xBF);
 	uart->dll = serial_read_reg(p, UART_DLL);
@@ -275,6 +277,10 @@
 	uart->scr = serial_read_reg(p, UART_OMAP_SCR);
 	uart->wer = serial_read_reg(p, UART_OMAP_WER);
 
+	serial_write_reg(p, UART_LCR, 0x80);
+	uart->mcr = serial_read_reg(p, UART_MCR);
+	serial_write_reg(p, UART_LCR, lcr);
+
 	uart->context_valid = 1;
 }
 
@@ -283,9 +289,6 @@
 	u16 efr = 0;
 	struct plat_serial8250_port *p = uart->p;
 
-	if (!enable_off_mode)
-		return;
-
 	if (!uart->context_valid)
 		return;
 
@@ -302,7 +305,14 @@
 	serial_write_reg(p, UART_DLM, uart->dlh);
 	serial_write_reg(p, UART_LCR, 0x0); /* Operational mode */
 	serial_write_reg(p, UART_IER, uart->ier);
-	serial_write_reg(p, UART_FCR, 0xA1);
+	if (uart->use_dma)
+		serial_write_reg(p, UART_FCR, 0x59);
+	else
+		serial_write_reg(p, UART_FCR, 0x51);
+
+	serial_write_reg(p, UART_LCR, 0x80);
+	serial_write_reg(p, UART_MCR, uart->mcr);
+
 	serial_write_reg(p, UART_LCR, 0xBF); /* Config B mode */
 	serial_write_reg(p, UART_EFR, efr);
 	serial_write_reg(p, UART_LCR, UART_LCR_WLEN8);
@@ -323,21 +333,41 @@
 	u16 sysc;
 
 	sysc = serial_read_reg(p, UART_OMAP_SYSC) & 0x7;
-	if (enable)
-		sysc |= 0x2 << 3;
-	else
-		sysc |= 0x1 << 3;
-
+	if (enable) {
+		/* Errata 2.15: Force idle if in DMA mode */
+		sysc |= uart->use_dma ? 0x0 : (0x2 << 3);
+	} else {
+			sysc |= 0x1 << 3;
+	}
 	serial_write_reg(p, UART_OMAP_SYSC, sysc);
 }
 
+static inline void omap_uart_disable_rtspullup(struct omap_uart_state *uart)
+{
+	if (!uart->rts_padconf || !uart->rts_override)
+		return;
+	omap_ctrl_writew(uart->rts_padvalue, uart->rts_padconf);
+	uart->rts_override = 0;
+}
+
+static inline void omap_uart_enable_rtspullup(struct omap_uart_state *uart)
+{
+	if (!uart->rts_padconf || uart->rts_override)
+		return;
+
+	uart->rts_padvalue = omap_ctrl_readw(uart->rts_padconf);
+	omap_ctrl_writew(0x118 | 0x7, uart->rts_padconf);
+	uart->rts_override = 1;
+}
+
 static inline void omap_uart_restore(struct omap_uart_state *uart)
 {
 	omap_uart_enable_clocks(uart);
 	omap_uart_restore_context(uart);
 }
 
-static inline void omap_uart_disable_clocks(struct omap_uart_state *uart)
+static inline void omap_uart_disable_clocks(struct omap_uart_state *uart,
+							int power_state)
 {
 	if (!uart->clocked)
 		return;
@@ -345,7 +375,9 @@
 	if (uart->num == 3)
 		return;
 
-	omap_uart_save_context(uart);
+	if (power_state == PWRDM_POWER_OFF)
+		omap_uart_save_context(uart);
+
 	uart->clocked = 0;
 	clk_disable(uart->ick);
 	clk_disable(uart->fck);
@@ -377,16 +409,27 @@
 {
 	struct omap_uart_state *uart = (struct omap_uart_state *)data;
 
+#ifdef CONFIG_SERIAL_OMAP
+	/* check if the uart port is active
+	 * if port is active then dont allow
+	 * sleep.
+	 */
+	if (omap_uart_active(uart->num)) {
+		omap_uart_block_sleep(uart);
+		return;
+	}
+#endif
 	omap_uart_allow_sleep(uart);
 }
 
-void omap_uart_prepare_idle(int num)
+void omap_uart_prepare_idle(int num, int power_state)
 {
 	struct omap_uart_state *uart;
 
 	list_for_each_entry(uart, &uart_list, node) {
 		if (num == uart->num && uart->can_sleep) {
-			omap_uart_disable_clocks(uart);
+			omap_uart_enable_rtspullup(uart);
+			omap_uart_disable_clocks(uart, power_state);
 			return;
 		}
 	}
@@ -399,6 +442,7 @@
 	list_for_each_entry(uart, &uart_list, node) {
 		if (num == uart->num) {
 			omap_uart_restore(uart);
+			omap_uart_disable_rtspullup(uart);
 
 			/* Check for IO pad wakeup */
 			if (cpu_is_omap34xx() && uart->padconf) {
@@ -426,6 +470,29 @@
 	}
 }
 
+int uart_in_dma_mode(int num)
+{
+	int using_dma = 0;
+	switch (num) {
+	case 0:
+		#ifdef CONFIG_SERIAL_OMAP_DMA_UART1
+		using_dma = 1;
+		#endif
+		break;
+	case 1:
+		#ifdef CONFIG_SERIAL_OMAP_DMA_UART2
+		using_dma = 1;
+		#endif
+		break;
+	case 2:
+		#ifdef CONFIG_SERIAL_OMAP_DMA_UART3
+		using_dma = 1;
+		#endif
+		break;
+	}
+	return using_dma;
+}
+
 int omap_uart_can_sleep(void)
 {
 	struct omap_uart_state *uart;
@@ -467,9 +534,46 @@
 
 static u32 sleep_timeout = DEFAULT_TIMEOUT;
 
-static void omap_uart_idle_init(struct omap_uart_state *uart)
+static void omap_uart_wakeup_enable(struct omap_uart_state *uart)
 {
 	u32 v;
+	/* Set wake-enable bit */
+	if (uart->wk_en && uart->wk_mask) {
+		v = __raw_readl(uart->wk_en);
+		v |= uart->wk_mask;
+		__raw_writel(v, uart->wk_en);
+	}
+
+	/* Ensure IOPAD wake-enables are set */
+	if (cpu_is_omap34xx() && uart->padconf) {
+		u16 v;
+
+		v = omap_ctrl_readw(uart->padconf);
+		v |= OMAP3_PADCONF_WAKEUPENABLE0;
+		omap_ctrl_writew(v, uart->padconf);
+	}
+}
+
+
+static void omap_uart_rtspad_init(struct omap_uart_state *uart)
+{
+	if (!cpu_is_omap34xx())
+		return;
+	switch (uart->num) {
+	case 0:
+		uart->rts_padconf = 0x17e;
+		break;
+	case 1:
+		uart->rts_padconf = 0x176;
+		break;
+	default:
+		uart->rts_padconf = 0;
+		break;
+	}
+}
+
+static void omap_uart_idle_init(struct omap_uart_state *uart)
+{
 	struct plat_serial8250_port *p = uart->p;
 	int ret, irq_flags = 0;
 
@@ -538,21 +642,18 @@
 		uart->padconf = 0;
 	}
 
-	/* Set wake-enable bit */
-	if (uart->wk_en && uart->wk_mask) {
-		v = __raw_readl(uart->wk_en);
-		v |= uart->wk_mask;
-		__raw_writel(v, uart->wk_en);
-	}
+#ifdef CONFIG_SERIAL_OMAP
+	/* use rx as wakeup source only for uart3,
+	 * uart1,2 will wakeup using CTS PIN
+	 * This is supported by omap-serial
+	 * driver
+	 */
+	if (uart->num == 2 || uart->num == 3)
+		omap_uart_wakeup_enable(uart);
 
-	/* Ensure IOPAD wake-enables are set */
-	if (cpu_is_omap34xx() && uart->padconf) {
-		u16 v;
-
-		v = omap_ctrl_readw(uart->padconf);
-		v |= OMAP3_PADCONF_WAKEUPENABLE0;
-		omap_ctrl_writew(v, uart->padconf);
-	}
+#elif CONFIG_SERIAL_8250
+		omap_uart_wakeup_enable(uart);
+#endif
 
 	p->flags |= UPF_SHARE_IRQ;
 
@@ -567,18 +668,24 @@
 	WARN_ON(ret);
 }
 
-void omap_uart_enable_irqs(int enable)
+int omap_uart_enable_irqs(int enable)
 {
-	int ret;
+	int ret = 0;
 	struct omap_uart_state *uart;
 
 	list_for_each_entry(uart, &uart_list, node) {
-		if (enable)
-			ret = request_irq(uart->p->irq, omap_uart_interrupt,
-				IRQF_SHARED, "serial idle", (void *)uart);
-		else
+		if (enable) {
+			int irq_flags = 0;
+			if (uart->p->flags & UPF_SHARE_IRQ)
+				irq_flags |= IRQF_SHARED;
+			if (uart->p->flags & UPF_TRIGGER_HIGH)
+				irq_flags |= IRQF_TRIGGER_HIGH;
+			ret += request_irq(uart->p->irq, omap_uart_interrupt,
+				irq_flags, "serial idle", (void *)uart);
+		} else
 			free_irq(uart->p->irq, (void *)uart);
 	}
+	return ret;
 }
 
 static ssize_t sleep_timeout_show(struct kobject *kobj,
@@ -674,8 +781,11 @@
 		uart->p = p;
 		list_add(&uart->node, &uart_list);
 
+		uart->use_dma = uart_in_dma_mode(i);
+
 		omap_uart_enable_clocks(uart);
 		omap_uart_reset(uart);
+		omap_uart_rtspad_init(uart);
 		omap_uart_idle_init(uart);
 	}
 }
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index aedcf94..8796620 100644
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -39,7 +39,7 @@
 #define PM_PREPWSTST_MPU_V	OMAP34XX_PRM_REGADDR(MPU_MOD, \
 				OMAP3430_PM_PREPWSTST)
 #define CM_IDLEST1_CORE_V	OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST1)
-#define SDRC_SCRATCHPAD_SEM_V	0xd800291C
+#define SDRC_SCRATCHPAD_SEM_V	IO_ADDRESS(L4_34XX_BASE + 0x291C)
 
 /*
  * This is the physical address of the register as specified
@@ -260,8 +260,12 @@
 	and     r2, r2, #0x3
 	cmp     r2, #0x0	@ Check if target power state was OFF or RET
         moveq   r9, #0x3        @ MPU OFF => L1 and L2 lost
+	beq	restore_from_off
+	cmp	r2, #0x1
+	moveq	r9, #0x3
 	movne	r9, #0x1	@ Only L1 and L2 lost => avoid L2 invalidation
 	bne	logic_l1_restore
+restore_from_off:
 	ldr	r0, control_stat
 	ldr	r1, [r0]
 	and	r1, #0x700
@@ -277,12 +281,14 @@
 	mcr	p15, 0, r0, c7, c10, 5	@ data memory barrier
 	.word	0xE1600071		@ call SMI monitor (smi #1)
 	/* Write to Aux control register to set some bits */
+	ldr	r4, scratchpad_base
+	ldr	r3, [r4, #0xBC]	@ r3 points to the location which has the value
+				@ to be written to Aux Control
 	mov	r0, #42		@ set service ID for PPA
 	mov	r12, r0		@ copy secure Service ID in r12
 	mov	r1, #0		@ set task id for ROM code in r1
 	mov	r2, #4		@ set some flags in r2, r6
 	mov	r6, #0xff
-	adr	r3, write_aux_control_params	@ r3 points to parameters
 	mcr	p15, 0, r0, c7, c10, 4	@ data write barrier
 	mcr	p15, 0, r0, c7, c10, 5	@ data memory barrier
 	.word	0xE1600071		@ call SMI monitor (smi #1)
@@ -290,14 +296,14 @@
 	b	logic_l1_restore
 l2_inv_api_params:
 	.word   0x1, 0x00
-write_aux_control_params:
-	.word   0x1, 0x72
 l2_inv_gp:
 	/* Execute smi to invalidate L2 cache */
 	mov r12, #0x1                         @ set up to invalide L2
 smi:    .word 0xE1600070		@ Call SMI monitor (smieq)
+	ldr	r4, scratchpad_base
+	ldr	r3, [r4, #0xBC]
+	ldr	r0, [r3]
 	/* Write to Aux control register to set some bits */
-	mov	r0, #0x72
 	mov	r12, #0x3
 	.word 0xE1600070	@ Call SMI monitor (smieq)
 logic_l1_restore:
@@ -306,8 +312,7 @@
 	 * and flush branch target cache */
 	mcr	p15, 0, r1, c7, c5, 0
 
-	ldr	r4, scratchpad_base
-	ldr	r3, [r4,#0xBC]
+	add	r3, r3, #0x4
 	ldmia	r3!, {r4-r6}
 	mov	sp, r4
 	msr	spsr_cxsf, r5
@@ -328,7 +333,12 @@
 	/* data fault status Register */
 	MCR p15, 0, r9, c5, c0, 0
 
+#ifdef CONFIG_CPU_USER_L2_PLE_ACCESS
+	ldmia  r3!,{r4-r9}
+#else
 	ldmia  r3!,{r4-r8}
+#endif
+
 	/* instruction fault status Register */
 	MCR p15, 0, r4, c5, c0, 1
 	/*Data Auxiliary Fault Status Register */
@@ -339,6 +349,12 @@
 	MCR p15, 0, r7, c6, c0, 0
 	/*Instruction Fault Address Register*/
 	MCR p15, 0, r8, c6, c0, 2
+
+#ifdef CONFIG_CPU_USER_L2_PLE_ACCESS
+	/* PLE User Accessibility Register */
+	MCR p15, 0, r9, c11, c1, 0
+#endif
+
 	ldmia  r3!,{r4-r7}
 
 	/* user r/w thread and process ID */
@@ -424,6 +440,10 @@
 save_context_wfi:
 	/*b	save_context_wfi*/	@ enable to debug save code
 	mov	r8, r0 /* Store SDRAM address in r8 */
+	/* Save AUXCR register */
+	mrc 	p15, 0, r4, c1, c0, 1
+	str	r4, [r8]
+	add	r8, r8, #0x4
         /* Check what that target sleep state is:stored in r1*/
         /* 1 - Only L1 and logic lost */
         /* 2 - Only L2 lost */
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
old mode 100644
new mode 100755
index 15e8e14..eae0aa5
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -36,7 +36,26 @@
 #include "smartreflex.h"
 #include "prm-regbits-34xx.h"
 
-#define MAX_TRIES 100
+/* The timeout values have been measured using 32Khz timer
+ * for rover codebase by Nishant Menon. It is found to be
+ * working for Zoom2 also. Should get proper timeout values
+ * from h/w team. The SR disbale time out value 3472 was found
+ * to be insufficient on zoom2 where we get occasional timeouts.
+ * Increasing it to a safer value.
+*/
+#define SR_DISABLE_TIMEOUT	10000
+#define VP_TRANXDONE_TIMEOUT	62
+#define VP_IDLE_TIMEOUT		3472
+
+#define INTC_MIR0               0x48200084
+#define INTC_MIR_CLEAR0         0x48200088
+#define INTC_MIR_SET0           0x4820008C
+#define INTC_SR1		(0x1 << 18)
+#define INTC_SR2		(0x1 << 19)
+#define ERRCONFIG_STATUS_MASK	(ERRCONFIG_VPBOUNDINTST | \
+		 ERRCONFIG_MCUBOUNDINTST | ERRCONFIG_MCUDISACKINTST)
+
+
 
 struct omap_sr {
 	int		srid;
@@ -46,7 +65,7 @@
 	u32		clk_length;
 	u32		req_opp_no;
 	u32		opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue;
-	u32		opp5_nvalue;
+	u32		opp5_nvalue, opp6_nvalue;
 	u32		senp_mod, senn_mod;
 	void __iomem	*srbase_addr;
 	void __iomem	*vpbase_addr;
@@ -68,6 +87,8 @@
 					u32 value)
 {
 	u32 reg_val;
+	if (offset == ERRCONFIG)
+		mask |= ERRCONFIG_STATUS_MASK;
 
 	reg_val = __raw_readl(SR_REGADDR(offset));
 	reg_val &= ~mask;
@@ -88,6 +109,10 @@
 		return -1;
 	}
 
+	if (cpu_is_omap3630())
+		sr_modify_reg(sr, ERRCONFIG, SR_IDLEMODE_MASK,
+				SR_SMART_IDLE);
+	else
 	/* set fclk- active , iclk- idle */
 	sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
 		      SR_CLKACTIVITY_IOFF_FON);
@@ -97,6 +122,10 @@
 
 static void sr_clk_disable(struct omap_sr *sr)
 {
+	if (cpu_is_omap3630())
+		sr_modify_reg(sr, ERRCONFIG, SR_IDLEMODE_MASK,
+		SR_FORCE_IDLE);
+	else
 	/* set fclk, iclk- idle */
 	sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
 		      SR_CLKACTIVITY_IOFF_FOFF);
@@ -150,6 +179,31 @@
 		(rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
 }
 
+void sr_calculate_rg(u32 rfuse, u32 gain_fuse, u32 delta_nt,
+					u32 *rnsen, u32 *sengain)
+{
+	u32 nadj;
+	nadj = ((1 << (gain_fuse + 8)) / rfuse) + delta_nt;
+	cal_reciprocal(nadj, sengain, rnsen);
+}
+
+/* extrapolate OPP6  nvalues from OPP5 value */
+static u32 calculate_opp_nvalue(u32 opp5_nvalue, u32 delta_p, u32 delta_n)
+{
+	u32 sen_pgain_fuse, sen_ngain_fuse, sen_prn_fuse, sen_nrn_fuse;
+	u32 sen_nrn, sen_ngain, sen_prn, sen_pgain;
+	sen_pgain_fuse = (opp5_nvalue & 0x00F0000) >> 0x14;
+	sen_ngain_fuse = (opp5_nvalue & 0x000F0000) >> 0x10;
+	sen_prn_fuse = (opp5_nvalue & 0x0000FF00) >> 0x08;
+	sen_nrn_fuse = (opp5_nvalue & 0x000000FF);
+	sr_calculate_rg(sen_nrn_fuse, sen_ngain_fuse, delta_n, &sen_nrn,
+					&sen_ngain);
+	sr_calculate_rg(sen_prn_fuse, sen_pgain_fuse, delta_p, &sen_prn,
+					&sen_pgain);
+	return  (sen_pgain << 0x14) | (sen_ngain << 0x10)
+			| (sen_prn << 0x08) | (sen_nrn);
+}
+
 /* determine the current OPP from the frequency
  * we need to give this function last element of OPP rate table
  * and the frequency
@@ -234,6 +288,10 @@
 					OMAP343X_CONTROL_FUSE_OPP2_VDD1);
 		sr->opp1_nvalue = omap_ctrl_readl(
 					OMAP343X_CONTROL_FUSE_OPP1_VDD1);
+		if (sr->opp5_nvalue) {
+			sr->opp6_nvalue = calculate_opp_nvalue(sr->opp5_nvalue,
+			227, 379);
+		}
 	} else if (sr->srid == SR2) {
 		sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
 					OMAP343X_SR2_SENNENABLE_MASK) >>
@@ -256,22 +314,54 @@
 static void sr_set_testing_nvalues(struct omap_sr *sr)
 {
 	if (sr->srid == SR1) {
+		if (cpu_is_omap3630()) {
+			sr->senp_mod = 0x1;
+			sr->senn_mod = 0x1;
+
+			/* calculate nvalues for each opp */
+			sr->opp1_nvalue = cal_test_nvalue(557, 470);
+			sr->opp2_nvalue = cal_test_nvalue(997, 844);
+			sr->opp3_nvalue = cal_test_nvalue(1556, 1330);
+			sr->opp4_nvalue = cal_test_nvalue(1728, 1480);
+		} else {
 		sr->senp_mod = 0x03;	/* SenN-M5 enabled */
 		sr->senn_mod = 0x03;
 
 		/* calculate nvalues for each opp */
-		sr->opp5_nvalue = cal_test_nvalue(0xacd + 0x330, 0x848 + 0x330);
-		sr->opp4_nvalue = cal_test_nvalue(0x964 + 0x2a0, 0x727 + 0x2a0);
-		sr->opp3_nvalue = cal_test_nvalue(0x85b + 0x200, 0x655 + 0x200);
-		sr->opp2_nvalue = cal_test_nvalue(0x506 + 0x1a0, 0x3be + 0x1a0);
-		sr->opp1_nvalue = cal_test_nvalue(0x373 + 0x100, 0x28c + 0x100);
+			sr->opp1_nvalue = cal_test_nvalue(0x373 + 0x100,
+							0x28c + 0x100);
+			sr->opp2_nvalue = cal_test_nvalue(0x506 + 0x1a0,
+							0x3be + 0x1a0);
+			sr->opp3_nvalue = cal_test_nvalue(0x85b + 0x200,
+							0x655 + 0x200);
+			sr->opp4_nvalue = cal_test_nvalue(0x964 + 0x2a0,
+							0x727 + 0x2a0);
+			sr->opp5_nvalue = cal_test_nvalue(0xacd + 0x330,
+							0x848 + 0x330);
+		}
+		if (sr->opp5_nvalue) {
+			sr->opp6_nvalue = calculate_opp_nvalue(sr->opp5_nvalue,
+			227, 379);
+		}
 	} else if (sr->srid == SR2) {
-		sr->senp_mod = 0x03;
-		sr->senn_mod = 0x03;
+		if (cpu_is_omap3630()) {
+			sr->senp_mod = 0x1;
+			sr->senn_mod = 0x1;
 
-		sr->opp3_nvalue = cal_test_nvalue(0x76f + 0x200, 0x579 + 0x200);
-		sr->opp2_nvalue = cal_test_nvalue(0x4f5 + 0x1c0, 0x390 + 0x1c0);
-		sr->opp1_nvalue = cal_test_nvalue(0x359, 0x25d);
+			sr->opp1_nvalue = cal_test_nvalue(556, 468);
+			sr->opp2_nvalue = cal_test_nvalue(1099, 933);
+
+		} else {
+			sr->senp_mod = 0x03;
+			sr->senn_mod = 0x03;
+
+			sr->opp1_nvalue = cal_test_nvalue(0x359, 0x25d);
+			sr->opp2_nvalue = cal_test_nvalue(0x4f5 + 0x1c0,
+							0x390 + 0x1c0);
+			sr->opp3_nvalue = cal_test_nvalue(0x76f + 0x200,
+							0x579 + 0x200);
+		}
+
 	}
 
 }
@@ -292,17 +382,20 @@
 
 	if (srid == SR1) {
 		target_opp_no = get_vdd1_opp();
-		if (!target_opp_no)
+		if (!target_opp_no) {
 			/* Assume Nominal OPP as current OPP unknown */
 			vsel = mpu_opps[VDD1_OPP3].vsel;
+			target_opp_no = VDD1_OPP3;
+		}
 		else
 			vsel = mpu_opps[target_opp_no].vsel;
 
 		vpconfig = PRM_VP1_CONFIG_ERROROFFSET |
-			PRM_VP1_CONFIG_ERRORGAIN |
-			PRM_VP1_CONFIG_TIMEOUTEN |
-			vsel << OMAP3430_INITVOLTAGE_SHIFT;
-
+			OMAP3430_TIMEOUTEN |
+			vsel << OMAP3430_INITVOLTAGE_SHIFT |
+			((target_opp_no < VDD1_OPP3)
+					? PRM_VP1_CONFIG_ERRORGAIN_OPPLOW
+					: PRM_VP1_CONFIG_ERRORGAIN_OPPHIGH);
 		prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD,
 					OMAP3_PRM_VP1_CONFIG_OFFSET);
 		prm_write_mod_reg(PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN |
@@ -322,11 +415,11 @@
 					OMAP3_PRM_VP1_VLIMITTO_OFFSET);
 
 		/* Trigger initVDD value copy to voltage processor */
-		prm_set_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+		prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
 				     OMAP3_PRM_VP1_CONFIG_OFFSET);
 
 		/* Clear initVDD copy trigger bit */
-		prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+		prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
 				       OMAP3_PRM_VP1_CONFIG_OFFSET);
 
 		/* Force update of voltage */
@@ -338,17 +431,20 @@
 
 	} else if (srid == SR2) {
 		target_opp_no = get_vdd2_opp();
-		if (!target_opp_no)
+		if (!target_opp_no) {
 			/* Assume Nominal OPP */
 			vsel = l3_opps[VDD2_OPP3].vsel;
+			target_opp_no = VDD2_OPP3;
+		}
 		else
 			vsel = l3_opps[target_opp_no].vsel;
 
 		vpconfig = PRM_VP2_CONFIG_ERROROFFSET |
-			PRM_VP2_CONFIG_ERRORGAIN |
-			PRM_VP2_CONFIG_TIMEOUTEN |
-			vsel << OMAP3430_INITVOLTAGE_SHIFT;
-
+			OMAP3430_TIMEOUTEN |
+			vsel << OMAP3430_INITVOLTAGE_SHIFT |
+			((target_opp_no < VDD2_OPP3)
+					? PRM_VP2_CONFIG_ERRORGAIN_OPPLOW
+					: PRM_VP2_CONFIG_ERRORGAIN_OPPHIGH);
 		prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD,
 					OMAP3_PRM_VP2_CONFIG_OFFSET);
 		prm_write_mod_reg(PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN |
@@ -368,11 +464,11 @@
 					OMAP3_PRM_VP2_VLIMITTO_OFFSET);
 
 		/* Trigger initVDD value copy to voltage processor */
-		prm_set_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+		prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
 				     OMAP3_PRM_VP2_CONFIG_OFFSET);
 
 		/* Clear initVDD copy trigger bit */
-		prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD,
+		prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
 				       OMAP3_PRM_VP2_CONFIG_OFFSET);
 
 		/* Force update of voltage */
@@ -385,7 +481,7 @@
 	}
 }
 
-static void sr_configure(struct omap_sr *sr)
+static void sr_configure(struct omap_sr *sr, u32 target_opp)
 {
 	u32 sr_config;
 	u32 senp_en , senn_en;
@@ -396,38 +492,78 @@
 	senp_en = sr->senp_mod;
 	senn_en = sr->senn_mod;
 	if (sr->srid == SR1) {
-		sr_config = SR1_SRCONFIG_ACCUMDATA |
+		if (cpu_is_omap3630()) {
+			sr_config = SR1_SRCONFIG_ACCUMDATA |
 			(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
 			SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
-			SRCONFIG_MINMAXAVG_EN |
+			(senn_en << SRCONFIG_SENNENABLE_SHIFT_36XX) |
+			(senp_en << SRCONFIG_SENPENABLE_SHIFT_36XX);
+
+			sr_write_reg(sr, SRCONFIG, sr_config);
+			sr_write_reg(sr, AVGWEIGHT,
+				SR1_AVGWEIGHT_SENPAVGWEIGHT |
+				SR1_AVGWEIGHT_SENNAVGWEIGHT);
+
+			sr_modify_reg(sr, ERRCONFIG_36XX, (SR_ERRWEIGHT_MASK |
+			SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+			(SR1_ERRWEIGHT | SR1_ERRMAXLIMIT |
+			((target_opp < VDD1_OPP3) ? SR1_ERRMINLIMIT_OPPLOW
+			: SR1_ERRMINLIMIT_OPPHIGH)));
+		} else {
+			sr_config = SR1_SRCONFIG_ACCUMDATA |
+			(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+			SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
 			(senn_en << SRCONFIG_SENNENABLE_SHIFT) |
 			(senp_en << SRCONFIG_SENPENABLE_SHIFT) |
 			SRCONFIG_DELAYCTRL;
 
-		sr_write_reg(sr, SRCONFIG, sr_config);
-		sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT |
+			sr_write_reg(sr, SRCONFIG, sr_config);
+			sr_write_reg(sr, AVGWEIGHT,
+					SR1_AVGWEIGHT_SENPAVGWEIGHT |
 					SR1_AVGWEIGHT_SENNAVGWEIGHT);
 
-		sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
+			sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
 			SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
-			(SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | SR1_ERRMINLIMIT));
-
+			(SR1_ERRWEIGHT | SR1_ERRMAXLIMIT |
+			((target_opp < VDD1_OPP3) ? SR1_ERRMINLIMIT_OPPLOW
+			: SR1_ERRMINLIMIT_OPPHIGH)));
+		}
 	} else if (sr->srid == SR2) {
-		sr_config = SR2_SRCONFIG_ACCUMDATA |
+		if (cpu_is_omap3630()) {
+			sr_config = SR2_SRCONFIG_ACCUMDATA |
 			(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
 			SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
-			SRCONFIG_MINMAXAVG_EN |
+			(senn_en << SRCONFIG_SENNENABLE_SHIFT_36XX) |
+			(senp_en << SRCONFIG_SENPENABLE_SHIFT_36XX);
+
+			sr_write_reg(sr, SRCONFIG, sr_config);
+			sr_write_reg(sr, AVGWEIGHT,
+					SR2_AVGWEIGHT_SENPAVGWEIGHT |
+					SR2_AVGWEIGHT_SENNAVGWEIGHT);
+			sr_modify_reg(sr, ERRCONFIG_36XX, (SR_ERRWEIGHT_MASK |
+			SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
+			(SR2_ERRWEIGHT | SR2_ERRMAXLIMIT |
+			((target_opp < VDD2_OPP3) ? SR2_ERRMINLIMIT_OPPLOW
+			: SR2_ERRMINLIMIT_OPPHIGH)));
+
+		} else {
+			sr_config = SR2_SRCONFIG_ACCUMDATA |
+			(sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
+			SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
 			(senn_en << SRCONFIG_SENNENABLE_SHIFT) |
 			(senp_en << SRCONFIG_SENPENABLE_SHIFT) |
 			SRCONFIG_DELAYCTRL;
 
-		sr_write_reg(sr, SRCONFIG, sr_config);
-		sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT |
+			sr_write_reg(sr, SRCONFIG, sr_config);
+			sr_write_reg(sr, AVGWEIGHT,
+					SR2_AVGWEIGHT_SENPAVGWEIGHT |
 					SR2_AVGWEIGHT_SENNAVGWEIGHT);
-		sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
+			sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
 			SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
-			(SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT));
-
+			(SR2_ERRWEIGHT | SR2_ERRMAXLIMIT |
+			((target_opp < VDD2_OPP3) ? SR2_ERRMINLIMIT_OPPLOW
+			: SR2_ERRMINLIMIT_OPPHIGH)));
+		}
 	}
 	sr->is_sr_reset = 0;
 }
@@ -515,6 +651,9 @@
 
 	if (sr->srid == SR1) {
 		switch (target_opp_no) {
+		case 6:
+			nvalue_reciprocal = sr->opp6_nvalue;
+			break;
 		case 5:
 			nvalue_reciprocal = sr->opp5_nvalue;
 			break;
@@ -552,20 +691,27 @@
 	}
 
 	if (nvalue_reciprocal == 0) {
-		pr_notice("OPP%d doesn't support SmartReflex\n",
+		pr_notice("OPP%d doesn't support SmartReflex \n",
 								target_opp_no);
 		return false;
 	}
 
 	sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
-
+	if (cpu_is_omap3630()) {
+		/* Enable the interrupt */
+		sr_modify_reg(sr, ERRCONFIG_36XX,
+				(ERRCONFIG_VPBOUNDINTEN_36XX |
+				ERRCONFIG_VPBOUNDINTST_36XX),
+				(ERRCONFIG_VPBOUNDINTEN_36XX |
+				ERRCONFIG_VPBOUNDINTST_36XX));
+	} else {
 	/* Enable the interrupt */
 	sr_modify_reg(sr, ERRCONFIG,
 			(ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST |
 			ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST),
 			(ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST |
 			ERRCONFIG_MCUBOUNDINTEN | ERRCONFIG_MCUBOUNDINTST));
-
+	}
 	if (sr->srid == SR1) {
 		/* set/latch init voltage */
 		v = prm_read_mod_reg(OMAP3430_GR_MOD,
@@ -582,7 +728,7 @@
 		prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
 				       OMAP3_PRM_VP1_CONFIG_OFFSET);
 		/* Enable VP1 */
-		prm_set_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+		prm_set_mod_reg_bits(OMAP3430_VPENABLE, OMAP3430_GR_MOD,
 				     OMAP3_PRM_VP1_CONFIG_OFFSET);
 	} else if (sr->srid == SR2) {
 		/* set/latch init voltage */
@@ -600,7 +746,7 @@
 		prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
 				       OMAP3_PRM_VP2_CONFIG_OFFSET);
 		/* Enable VP2 */
-		prm_set_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD,
+		prm_set_mod_reg_bits(OMAP3430_VPENABLE, OMAP3430_GR_MOD,
 				     OMAP3_PRM_VP2_CONFIG_OFFSET);
 	}
 
@@ -609,45 +755,145 @@
 	return true;
 }
 
-static void sr_disable(struct omap_sr *sr)
+static int vp_disable(struct omap_sr *sr)
 {
-	u32 i = 0;
+	u32 vp_config_offs, vp_status_offs, vp_tranxdone_st;
+	int timeout = 0;
+
+	if (sr->srid == SR1) {
+		vp_config_offs = OMAP3_PRM_VP1_CONFIG_OFFSET;
+		vp_status_offs = OMAP3_PRM_VP1_STATUS_OFFSET;
+		vp_tranxdone_st = OMAP3430_VP1_TRANXDONE_ST;
+	} else if (sr->srid == SR2) {
+		vp_config_offs = OMAP3_PRM_VP2_CONFIG_OFFSET;
+		vp_status_offs = OMAP3_PRM_VP2_STATUS_OFFSET;
+		vp_tranxdone_st = OMAP3430_VP2_TRANXDONE_ST;
+	} else {
+		pr_warning("Wrong SR id. SR %d does not exost\n", sr->srid);
+		return -1;
+	}
+
+	while (timeout < VP_TRANXDONE_TIMEOUT) {
+		prm_write_mod_reg(vp_tranxdone_st, OCP_MOD,
+				  OMAP2_PRM_IRQSTATUS_MPU_OFFSET);
+		if (!(prm_read_mod_reg(OCP_MOD, OMAP2_PRM_IRQSTATUS_MPU_OFFSET)
+						& vp_tranxdone_st))
+			break;
+
+		udelay(1);
+		timeout++;
+	}
+
+	if (timeout == VP_TRANXDONE_TIMEOUT)
+		pr_warning("VP:TRANXDONE timeout exceeded still going ahead\
+					with disabling VP%d\n", sr->srid);
+
+	/* Disable VP */
+	prm_clear_mod_reg_bits(OMAP3430_VPENABLE, OMAP3430_GR_MOD,
+			       vp_config_offs);
+
+	/* Wait for VP to be in IDLE - typical latency < 1 microsecond */
+	timeout = 0;
+	while (timeout < VP_IDLE_TIMEOUT &&
+	       !(prm_read_mod_reg(OMAP3430_GR_MOD, vp_status_offs) &
+		 OMAP3430_VPINIDLE)) {
+		udelay(1);
+		timeout++;
+	}
+	if (timeout == VP_IDLE_TIMEOUT)
+		pr_warning("VP%d not idle timedout\n", sr->srid);
+	return 0;
+}
+
+
+static int sr_disable(struct omap_sr *sr)
+{
+	int c = 0;
+	u32 sr_int_status = 0;
+
+	/*Disable VP before disabling SR */
+	if (vp_disable(sr))
+		return -1;
 
 	sr->is_sr_reset = 1;
+	/* Check to see if SR is already disabled.
+	 * If so do nothing and return
+	 */
+	if (!(sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE))
+		return 0;
+
+	/*Check if SR interrupt is enabled at INTC level */
+	if (sr->srid == SR1)
+		sr_int_status = omap_readl(INTC_MIR0) & INTC_SR1;
+	else if (sr->srid == SR2)
+		sr_int_status = omap_readl(INTC_MIR0) & INTC_SR2;
+
+	/* Mask the SR1 or SR2 interrupt at INTC level if unmasked
+	 * so that the isr is not called. If this step is
+	 * is not done random spurious SR1/SR2 interrupts or
+	 * system suspend not working due to spurious interrupts
+	 * can be ovbserved.
+	 */
+	if (!sr_int_status) {
+		if (sr->srid == SR1)
+			omap_writel(INTC_SR1, INTC_MIR_SET0);
+		if (sr->srid == SR2)
+			omap_writel(INTC_SR2, INTC_MIR_SET0);
+		/* DSB is essential as none of the memory is
+		 * Strongly ordered
+		 */
+		dsb();
+	}
+	/* Enable MCUDisableAcknowledge interrupt, Disable VPBOUND interrupt
+	 * and Clean VPBOUNT interrupt status
+	 */
+	if (cpu_is_omap3430())
+		sr_modify_reg(sr, ERRCONFIG,
+			ERRCONFIG_MCUDISACKINTEN | ERRCONFIG_VPBOUNDINTEN,
+			ERRCONFIG_MCUDISACKINTEN | ERRCONFIG_VPBOUNDINTST);
 
 	/* SRCONFIG - disable SR */
 	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE);
 
-	if (sr->srid == SR1) {
-		/* Wait for VP idle before disabling VP */
-		while ((!prm_read_mod_reg(OMAP3430_GR_MOD,
-					OMAP3_PRM_VP1_STATUS_OFFSET))
-					&& i++ < MAX_TRIES)
+	/* Wait for SR to be disabled.
+	 * wait until ERRCONFIG.MCUDISACKINTST = 1
+	 * Typical latency is < 1us.
+	 */
+	if (cpu_is_omap3430()) {
+		while ((c < SR_DISABLE_TIMEOUT) &&
+			(!(sr_read_reg(sr, ERRCONFIG) &
+				ERRCONFIG_MCUDISACKINTST))) {
 			udelay(1);
+			c++;
+		}
+		if (c == SR_DISABLE_TIMEOUT)
+			pr_warning("SR%d not disabled\n", sr->srid);
 
-		if (i >= MAX_TRIES)
-			pr_warning("VP1 not idle, still going ahead with \
-							VP1 disable\n");
 
-		/* Disable VP1 */
-		prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD,
-					OMAP3_PRM_VP1_CONFIG_OFFSET);
-
-	} else if (sr->srid == SR2) {
-		/* Wait for VP idle before disabling VP */
-		while ((!prm_read_mod_reg(OMAP3430_GR_MOD,
-					OMAP3_PRM_VP2_STATUS_OFFSET))
-					&& i++ < MAX_TRIES)
-			udelay(1);
-
-		if (i >= MAX_TRIES)
-			pr_warning("VP2 not idle, still going ahead with \
-							 VP2 disable\n");
-
-		/* Disable VP2 */
-		prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD,
-					OMAP3_PRM_VP2_CONFIG_OFFSET);
+		/* Disable MCUDisableAcknowledge interrupt &
+		 * clear pending interrupt Also enable VPBOUND interrrupt
+		 */
+		sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN,
+			ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_MCUDISACKINTST);
 	}
+
+	/* DSB is essential as none of the memory is Strongly ordered */
+	dsb();
+	/* Wait till ERRCONFIG_MCUDISACKINTST is cleared before unmasking
+	 * SR interrupts. Else we can have spurious interrupts
+	 */
+	if (cpu_is_omap3430())
+		while (sr_read_reg(sr, ERRCONFIG) & ERRCONFIG_MCUDISACKINTST)
+			;
+
+	if (!sr_int_status) {
+		/* Unmask the SR interrrupts if previously unmasked*/
+		if (sr->srid == SR1)
+			omap_writel(INTC_SR1, INTC_MIR_CLEAR0);
+		if (sr->srid == SR2)
+			omap_writel(INTC_SR2, INTC_MIR_CLEAR0);
+	}
+	return 0;
 }
 
 static void change_ret_volt(struct omap_sr *sr, u32 val)
@@ -731,13 +977,16 @@
 		return;
 
 	if (sr->is_sr_reset == 1) {
-		sr_clk_enable(sr);
-		sr_configure(sr);
+		if (sr_clk_enable(sr))
+			return;
+		sr_configure(sr, target_opp_no);
 	}
 
-	if (sr->is_autocomp_active == 1)
+	if (sr->is_autocomp_active == 1) {
 		pr_warning("SR%d: VDD autocomp is already active\n",
 									srid);
+		return;
+	}
 
 	sr->is_autocomp_active = 1;
 	if (!sr_enable(sr, target_opp_no)) {
@@ -761,7 +1010,8 @@
 		return -EINVAL;
 
 	if (sr->is_autocomp_active == 1) {
-		sr_disable(sr);
+		if (sr_disable(sr))
+			pr_warning("Problems in SR Disable!!!!\n");
 		sr_clk_disable(sr);
 		sr->is_autocomp_active = 0;
 		/* Reset the volatage for current OPP */
@@ -788,7 +1038,8 @@
 	if (sr->is_autocomp_active == 1) {
 		if (sr->is_sr_reset == 1) {
 			/* Enable SR clks */
-			sr_clk_enable(sr);
+			if (sr_clk_enable(sr))
+				return;
 
 			if (srid == SR1)
 				target_opp_no = get_vdd1_opp();
@@ -800,7 +1051,7 @@
 						 Cannot configure SR\n");
 			}
 
-			sr_configure(sr);
+			sr_configure(sr, target_opp_no);
 
 			if (!sr_enable(sr, target_opp_no))
 				sr_clk_disable(sr);
@@ -810,8 +1061,6 @@
 
 void disable_smartreflex(int srid)
 {
-	u32 i = 0;
-
 	struct omap_sr *sr = NULL;
 
 	if (srid == SR1)
@@ -823,45 +1072,10 @@
 
 	if (sr->is_autocomp_active == 1) {
 		if (sr->is_sr_reset == 0) {
-
-			sr->is_sr_reset = 1;
-			/* SRCONFIG - disable SR */
-			sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
-							~SRCONFIG_SRENABLE);
-
-			/* Disable SR clk */
+			if (sr_disable(sr))
+				pr_warning("Problems in SR Disable!!!!\n");
+			 /* Disable SR clk */
 			sr_clk_disable(sr);
-			if (sr->srid == SR1) {
-				/* Wait for VP idle before disabling VP */
-				while ((!prm_read_mod_reg(OMAP3430_GR_MOD,
-						OMAP3_PRM_VP1_STATUS_OFFSET))
-						&& i++ < MAX_TRIES)
-					udelay(1);
-
-				if (i >= MAX_TRIES)
-					pr_warning("VP1 not idle, still going \
-						ahead with VP1 disable\n");
-
-				/* Disable VP1 */
-				prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE,
-						OMAP3430_GR_MOD,
-						OMAP3_PRM_VP1_CONFIG_OFFSET);
-			} else if (sr->srid == SR2) {
-				/* Wait for VP idle before disabling VP */
-				while ((!prm_read_mod_reg(OMAP3430_GR_MOD,
-						OMAP3_PRM_VP2_STATUS_OFFSET))
-						&& i++ < MAX_TRIES)
-					udelay(1);
-
-				if (i >= MAX_TRIES)
-					pr_warning("VP2 not idle, still going \
-						 ahead with VP2 disable\n");
-
-				/* Disable VP2 */
-				prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE,
-						OMAP3430_GR_MOD,
-						OMAP3_PRM_VP2_CONFIG_OFFSET);
-			}
 			/* Reset the volatage for current OPP */
 			sr_reset_voltage(srid);
 		}
@@ -877,13 +1091,13 @@
 int sr_voltagescale_vcbypass(u32 target_opp, u32 current_opp,
 					u8 target_vsel, u8 current_vsel)
 {
-	int sr_status = 0;
 	u32 vdd, target_opp_no, current_opp_no;
 	u32 vc_bypass_value;
 	u32 reg_addr = 0;
 	u32 loop_cnt = 0, retries_cnt = 0;
 	u32 t2_smps_steps = 0;
 	u32 t2_smps_delay = 0;
+	u32 error_gain;
 
 	if (omap3_volscale_vcbypass_fun)
 		return omap3_volscale_vcbypass_fun(target_opp, current_opp,
@@ -894,9 +1108,12 @@
 	current_opp_no = get_opp_no(current_opp);
 
 	if (vdd == VDD1_OPP) {
-		sr_status = sr_stop_vddautocomap(SR1);
 		t2_smps_steps = abs(target_vsel - current_vsel);
-
+		error_gain = ((target_opp_no < VDD1_OPP3)
+				? PRM_VP1_CONFIG_ERRORGAIN_OPPLOW
+				: PRM_VP1_CONFIG_ERRORGAIN_OPPHIGH);
+		prm_rmw_mod_reg_bits(OMAP3430_ERRORGAIN_MASK, error_gain,
+				OMAP3430_GR_MOD, OMAP3_PRM_VP1_CONFIG_OFFSET);
 		prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
 				(target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
 				OMAP3430_GR_MOD,
@@ -904,9 +1121,12 @@
 		reg_addr = R_VDD1_SR_CONTROL;
 
 	} else if (vdd == VDD2_OPP) {
-		sr_status = sr_stop_vddautocomap(SR2);
 		t2_smps_steps =  abs(target_vsel - current_vsel);
-
+		error_gain = ((target_opp_no < VDD2_OPP3)
+				? PRM_VP2_CONFIG_ERRORGAIN_OPPLOW
+				: PRM_VP2_CONFIG_ERRORGAIN_OPPHIGH);
+		prm_rmw_mod_reg_bits(OMAP3430_ERRORGAIN_MASK, error_gain,
+				OMAP3430_GR_MOD, OMAP3_PRM_VP2_CONFIG_OFFSET);
 		prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
 				(target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
 				OMAP3430_GR_MOD,
@@ -947,13 +1167,6 @@
 	t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2;
 	udelay(t2_smps_delay);
 
-	if (sr_status) {
-		if (vdd == VDD1_OPP)
-			sr_start_vddautocomap(SR1, target_opp_no);
-		else if (vdd == VDD2_OPP)
-			sr_start_vddautocomap(SR2, target_opp_no);
-	}
-
 	return 0;
 }
 
@@ -1048,8 +1261,15 @@
 	if (dev_id == &sr2)
 		try_change_ret_volt(dev_id, &vp2_volt);
 
-	sr_modify_reg(dev_id, ERRCONFIG, ERRCONFIG_MCUBOUNDINTST,
-			ERRCONFIG_MCUBOUNDINTST);
+	if (cpu_is_omap34xx()) {
+		sr_modify_reg(dev_id, ERRCONFIG, ERRCONFIG_MCUBOUNDINTST,
+				ERRCONFIG_MCUBOUNDINTST);
+
+		/* Flush posted writes to avoid spurious IRQ */
+		sr_read_reg(dev_id, ERRCONFIG);
+	} else if (cpu_is_omap3630())
+		/* Flush posted writes to avoid spurious IRQ */
+		sr_read_reg(dev_id, ERRCONFIG_36XX);
 
 	return IRQ_HANDLED;
 }
@@ -1058,6 +1278,7 @@
 {
 	int ret = 0;
 	u8 RdReg;
+	u32 current_opp_no;
 
 	/* Exit if OPP tables are not defined */
         if (!(mpu_opps && l3_opps)) {
@@ -1126,6 +1347,27 @@
 	if (ret)
 		pr_err("sysfs_create_file failed: %d\n", ret);
 
+	/* Enable SR only for 3430 for now */
+	if (!cpu_is_omap3630()) {
+		if (sr1.opp3_nvalue) {
+			current_opp_no = get_vdd1_opp();
+			if (!current_opp_no) {
+				pr_err("omap3_sr_init: Current VDD1 opp unknown\n");
+				return -EINVAL;
+			}
+			sr_start_vddautocomap(SR1, current_opp_no);
+		}
+		if (sr2.opp3_nvalue) {
+			current_opp_no = get_vdd2_opp();
+			if (!current_opp_no) {
+				pr_err("omap3_sr_init: Current VDD2 opp unknown\n");
+				return -EINVAL;
+			}
+			sr_start_vddautocomap(SR2, current_opp_no);
+			pr_info("SmartReflex: enabling autocompensation\n");
+		}
+	}
+
 	return 0;
 
 	/*
diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
index 7d1c470..1987740 100644
--- a/arch/arm/mach-omap2/smartreflex.h
+++ b/arch/arm/mach-omap2/smartreflex.h
@@ -29,6 +29,8 @@
 #define NVALUERECIPROCAL	0x1C
 #define SENERROR	0x20
 #define ERRCONFIG	0x24
+#define SENERROR_36XX   0x34
+#define ERRCONFIG_36XX  0x38
 
 /* SR Modules */
 #define SR1		1
@@ -48,48 +50,42 @@
 
 /* PRM_VP1_CONFIG */
 #define PRM_VP1_CONFIG_ERROROFFSET	(0x00 << 24)
-#define PRM_VP1_CONFIG_ERRORGAIN	(0x20 << 16)
+#define PRM_VP1_CONFIG_ERRORGAIN_OPPLOW		(0x0C << 16)
+#define PRM_VP1_CONFIG_ERRORGAIN_OPPHIGH	(0x18 << 16)
 
 #define PRM_VP1_CONFIG_INITVOLTAGE	(0x30 << 8) /* 1.2 volt */
-#define PRM_VP1_CONFIG_TIMEOUTEN	BIT(3)
-#define PRM_VP1_CONFIG_INITVDD		BIT(2)
-#define PRM_VP1_CONFIG_FORCEUPDATE	BIT(1)
-#define PRM_VP1_CONFIG_VPENABLE		BIT(0)
 
 /* PRM_VP1_VSTEPMIN */
-#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN	(0x01F4 << 8)
+#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN	(0x3C << 8)
 #define PRM_VP1_VSTEPMIN_VSTEPMIN		BIT(0)
 
 /* PRM_VP1_VSTEPMAX */
-#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX	(0x01F4 << 8)
+#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX	(0x3C << 8)
 #define PRM_VP1_VSTEPMAX_VSTEPMAX		(0x04 << 0)
 
 /* PRM_VP1_VLIMITTO */
-#define PRM_VP1_VLIMITTO_VDDMAX		(0x3C << 24)
-#define PRM_VP1_VLIMITTO_VDDMIN		(0x0 << 16)
+#define PRM_VP1_VLIMITTO_VDDMAX		(0x44 << 24)
+#define PRM_VP1_VLIMITTO_VDDMIN		(0x14 << 16)
 #define PRM_VP1_VLIMITTO_TIMEOUT	(0xFFFF << 0)
 
 /* PRM_VP2_CONFIG */
 #define PRM_VP2_CONFIG_ERROROFFSET	(0x00 << 24)
-#define PRM_VP2_CONFIG_ERRORGAIN	(0x20 << 16)
+#define PRM_VP2_CONFIG_ERRORGAIN_OPPLOW         (0x0C << 16)
+#define PRM_VP2_CONFIG_ERRORGAIN_OPPHIGH        (0x18 << 16)
 
 #define PRM_VP2_CONFIG_INITVOLTAGE	(0x30 << 8) /* 1.2 volt */
-#define PRM_VP2_CONFIG_TIMEOUTEN	BIT(3)
-#define PRM_VP2_CONFIG_INITVDD		BIT(2)
-#define PRM_VP2_CONFIG_FORCEUPDATE	BIT(1)
-#define PRM_VP2_CONFIG_VPENABLE		BIT(0)
 
 /* PRM_VP2_VSTEPMIN */
-#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN	(0x01F4 << 8)
+#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN	(0x3C << 8)
 #define PRM_VP2_VSTEPMIN_VSTEPMIN		BIT(0)
 
 /* PRM_VP2_VSTEPMAX */
-#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX	(0x01F4 << 8)
+#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX	(0x3C << 8)
 #define PRM_VP2_VSTEPMAX_VSTEPMAX		(0x04 << 0)
 
 /* PRM_VP2_VLIMITTO */
-#define PRM_VP2_VLIMITTO_VDDMAX		(0x2C << 24)
-#define PRM_VP2_VLIMITTO_VDDMIN		(0x0 << 16)
+#define PRM_VP2_VLIMITTO_VDDMAX		(0x42 << 24)
+#define PRM_VP2_VLIMITTO_VDDMIN		(0x18 << 16)
 #define PRM_VP2_VLIMITTO_TIMEOUT	(0xFFFF << 0)
 
 /* SRCONFIG */
@@ -105,6 +101,8 @@
 #define SRCONFIG_SRCLKLENGTH_SHIFT	12
 #define SRCONFIG_SENNENABLE_SHIFT	5
 #define SRCONFIG_SENPENABLE_SHIFT	3
+#define SRCONFIG_SENNENABLE_SHIFT_36XX	1
+#define SRCONFIG_SENPENABLE_SHIFT_36XX	0
 
 #define SRCONFIG_SRENABLE		BIT(11)
 #define SRCONFIG_SENENABLE		BIT(10)
@@ -136,19 +134,32 @@
 #define SR_CLKACTIVITY_IOFF_FOFF	(0x00 << 20)
 #define SR_CLKACTIVITY_IOFF_FON		(0x02 << 20)
 
+/* IDLEMODE SETTINGS for OMAP3630 */
+#define SR_IDLEMODE_MASK		(0x3 << 24)
+#define SR_FORCE_IDLE			0x0
+#define SR_NO_IDLE			0x1
+#define SR_SMART_IDLE			0x2
+#define SR_SMART_IDLE_WKUP		0x3
+
 #define ERRCONFIG_VPBOUNDINTEN		BIT(31)
 #define ERRCONFIG_VPBOUNDINTST		BIT(30)
+#define ERRCONFIG_VPBOUNDINTEN_36XX	BIT(23)
+#define ERRCONFIG_VPBOUNDINTST_36XX	BIT(22)
 #define ERRCONFIG_MCUBOUNDINTEN		BIT(25)
 #define ERRCONFIG_MCUBOUNDINTST		BIT(24)
+#define ERRCONFIG_MCUDISACKINTEN	BIT(23)
+#define ERRCONFIG_MCUDISACKINTST	BIT(22)
 
-#define SR1_ERRWEIGHT			(0x07 << 16)
+#define SR1_ERRWEIGHT			(0x04 << 16)
 #define SR1_ERRMAXLIMIT			(0x02 << 8)
-#define SR1_ERRMINLIMIT			(0xFA << 0)
+#define SR1_ERRMINLIMIT_OPPLOW		(0xF4 << 0)
+#define SR1_ERRMINLIMIT_OPPHIGH		(0xF9 << 0)
 #define SR1_IRQ				18
 
-#define SR2_ERRWEIGHT			(0x07 << 16)
+#define SR2_ERRWEIGHT			(0x04 << 16)
 #define SR2_ERRMAXLIMIT			(0x02 << 8)
-#define SR2_ERRMINLIMIT			(0xF9 << 0)
+#define SR2_ERRMINLIMIT_OPPLOW		(0xF4 << 0)
+#define SR2_ERRMINLIMIT_OPPHIGH		(0xF9 << 0)
 #define SR2_IRQ				19
 
 /* T2 SMART REFLEX */
diff --git a/arch/arm/mach-omap2/sram34xx.S b/arch/arm/mach-omap2/sram34xx.S
index b250535..1391455 100644
--- a/arch/arm/mach-omap2/sram34xx.S
+++ b/arch/arm/mach-omap2/sram34xx.S
@@ -33,6 +33,8 @@
 
 #include "sdrc.h"
 #include "cm.h"
+#include "prcm-common.h"
+#include "prm.h"
 
 	.text
 
@@ -68,6 +70,9 @@
 /* CM_CLKSEL1_PLL bit settings */
 #define CORE_DPLL_CLKOUT_DIV_SHIFT	0x1b
 
+/* PRM_RSTCTRL bit setting */
+#define EN_DPLL3_RESET                  0x4
+
 /*
  * omap3_sram_configure_core_dpll - change DPLL3 M2 divider
  * r0 = new SDRC_RFR_CTRL register contents
@@ -187,10 +192,6 @@
 configure_sdrc:
 	ldr	r11, omap3_sdrc_rfr_ctrl
 	str	r0, [r11]
-	ldr	r11, omap3_sdrc_actim_ctrla
-	str	r1, [r11]
-	ldr	r11, omap3_sdrc_actim_ctrlb
-	str	r2, [r11]
 	ldr	r11, omap3_sdrc_mr_0
 	str	r6, [r11]
 	ldr	r6, [r11]		@ posted-write barrier for SDRC
@@ -221,3 +222,50 @@
 
 ENTRY(omap3_sram_configure_core_dpll_sz)
 	.word	. - omap3_sram_configure_core_dpll
+
+
+/* omap3_sram_configure_core_dpll_warmreset
+* Enable SDRC self refresh on idle request, put SDRC in idle,
+* wait until SDRC goes to idle
+* Enable DPLL3 reset bit in RM_RSTCTRL
+*/
+
+ENTRY(omap3_sram_configure_core_dpll_warmreset)
+
+	bl	sdram_in_selfrefresh1
+	ldr	r11, omap3_reset_cntrl
+	ldr	r12, [r11]
+	orr	r12, r12, #EN_DPLL3_RESET	@ Enable DPLL3 reset bit
+	str	r12, [r11]
+
+sdram_in_selfrefresh1:
+	ldr	r11, omap3_sdrc_power1	@ read the SDRC_POWER register
+	ldr	r12, [r11]		@ read the contents of SDRC_POWER
+	mov	r9, r12			@ keep a copy of SDRC_POWER bits
+	orr 	r12, r12, #SRFRONIDLEREQ_MASK	@ enable self refresh on idle
+	str 	r12, [r11]		@ write back to SDRC_POWER register
+	ldr	r12, [r11]		@ posted-write barrier for SDRC
+	ldr	r11, omap3_cm_iclken1_core1	@ read the CM_ICLKEN1_CORE reg
+	ldr	r12, [r11]
+	bic	r12, r12, #EN_SDRC_MASK		@ disable iclk bit for SDRC
+	str 	r12, [r11]
+wait_sdrc_idle2:
+	ldr 	r11, omap3_cm_idlest1_core1
+	ldr 	r12, [r11]
+	and 	r12, r12, #ST_SDRC_MASK		@ check for SDRC idle
+	cmp 	r12, #ST_SDRC_MASK
+	bne 	wait_sdrc_idle2
+	bx 	lr
+
+omap3_reset_cntrl:
+	.word OMAP34XX_PRM_REGADDR(OMAP3430_GR_MOD, RM_RSTCTRL)
+omap3_sdrc_power1:
+	.word OMAP34XX_SDRC_REGADDR(SDRC_POWER)
+omap3_cm_idlest1_core1:
+	.word OMAP34XX_CM_REGADDR(CORE_MOD, CM_IDLEST)
+omap3_cm_iclken1_core1:
+	.word OMAP34XX_CM_REGADDR(CORE_MOD, CM_ICLKEN1)
+
+ENTRY(omap3_sram_configure_core_dpll_warmreset_sz)
+	.word	. - omap3_sram_configure_core_dpll_warmreset
+
diff --git a/arch/arm/mach-omap2/usb-musb.c b/arch/arm/mach-omap2/usb-musb.c
index 37ad014..7245577 100644
--- a/arch/arm/mach-omap2/usb-musb.c
+++ b/arch/arm/mach-omap2/usb-musb.c
@@ -32,13 +32,25 @@
 #include <mach/irqs.h>
 #include <mach/mux.h>
 #include <mach/usb.h>
+#include <mach/omap-pm.h>
 
 #define OTG_SYSCONFIG	   0x404
 #define OTG_SYSC_SOFTRESET BIT(1)
+#define OTG_SYSSTATUS     0x408
+#define OTG_SYSS_RESETDONE BIT(0)
+
+static struct platform_device dummy_pdev = {
+	.dev = {
+		.bus = &platform_bus_type,
+	},
+};
+
+static void __iomem *otg_base;
+static struct clk *otg_clk;
 
 static void __init usb_musb_pm_init(void)
 {
-	void __iomem *otg_base;
+	struct device *dev = &dummy_pdev.dev;
 
 	if (!cpu_is_omap34xx())
 		return;
@@ -47,13 +59,30 @@
 	if (WARN_ON(!otg_base))
 		return;
 
-	/* Reset OTG controller.  After reset, it will be in
-	 * force-idle, force-standby mode. */
-	__raw_writel(OTG_SYSC_SOFTRESET, otg_base + OTG_SYSCONFIG);
+	otg_clk = clk_get(dev, "hsotgusb_ick");
 
-	iounmap(otg_base);
+	if (otg_clk && clk_enable(otg_clk)) {
+		printk(KERN_WARNING
+			"%s: Unable to enable clocks for MUSB, "
+			"cannot reset.\n",  __func__);
+	} else {
+		/* Reset OTG controller. After reset, it will be in
+		 * force-idle, force-standby mode. */
+		__raw_writel(OTG_SYSC_SOFTRESET, otg_base + OTG_SYSCONFIG);
+
+		while (!(OTG_SYSS_RESETDONE &
+					__raw_readl(otg_base + OTG_SYSSTATUS)))
+			cpu_relax();
+	}
+
+	if (otg_clk)
+		clk_disable(otg_clk);
 }
 
+void usb_musb_disable_autoidle(void)
+{
+	__raw_writel(0, otg_base + OTG_SYSCONFIG);
+}
 #ifdef CONFIG_USB_MUSB_SOC
 static struct resource musb_resources[] = {
 	[0] = { /* start and end set dynamically */
@@ -135,6 +164,8 @@
 	.eps_bits	= musb_eps,
 };
 
+extern unsigned get_last_off_on_transaction_id(struct device *dev);
+
 static struct musb_hdrc_platform_data musb_plat = {
 #ifdef CONFIG_USB_MUSB_OTG
 	.mode		= MUSB_OTG,
@@ -152,6 +183,9 @@
 	 * "mode", and should be passed to usb_musb_init().
 	 */
 	.power		= 50,			/* up to 100 mA */
+
+	.context_loss_counter = get_last_off_on_transaction_id,
+	.set_vdd1_opp 	= omap_pm_set_min_mpu_freq,
 };
 
 static u64 musb_dmamask = DMA_32BIT_MASK;
diff --git a/arch/arm/mach-omap2/usb-ohci.c b/arch/arm/mach-omap2/usb-ohci.c
new file mode 100644
index 0000000..2110ef9
--- /dev/null
+++ b/arch/arm/mach-omap2/usb-ohci.c
@@ -0,0 +1,129 @@
+/*
+ * linux/arch/arm/mach-omap2/usb-ohci.c
+ *
+ * This file will contain the board specific details for the
+ * Synopsys OHCI host controller on OMAP3430
+ *
+ * Copyright (C) 2009 Texas Instruments
+ * Author: Vikram Pandita <vikram.pandita@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+#include <asm/io.h>
+#include <mach/mux.h>
+
+#include <mach/hardware.h>
+#include <mach/irqs.h>
+#include <mach/usb.h>
+
+/* OHCI platform specific data */
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static struct resource ohci_resources[] = {
+	[0] = {
+		.start   = OMAP34XX_HSUSB_HOST_BASE + 0x400,
+		.end     = OMAP34XX_HSUSB_HOST_BASE + 0x400 + SZ_1K - 1,
+		.flags   = IORESOURCE_MEM,
+	},
+	[1] = {         /* general IRQ */
+		.start   = 76,
+		.flags   = IORESOURCE_IRQ,
+	}
+};
+
+/* The dmamask must be set for OHCI to work */
+static u64 ohci_dmamask = ~(u32)0;
+
+static void usb_release(struct device *dev)
+{
+	/* normally not freed */
+}
+
+static struct platform_device ohci_device = {
+	.name           = "ohci-omap",
+	.id             = 0,
+	.dev = {
+		.release		= usb_release,
+		.dma_mask               = &ohci_dmamask,
+		.coherent_dma_mask      = 0xffffffff,
+		.platform_data          = NULL,
+	},
+	.num_resources  = ARRAY_SIZE(ohci_resources),
+	.resource       = ohci_resources,
+};
+#endif /* OHCI specific data */
+
+/* MUX settings for OHCI pins */
+/*
+ * setup_ehci_io_mux - initialize IO pad mux for USBHOST
+ */
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static void setup_ohci_io_mux(void)
+{
+
+/* Configure pin-muxing on a per-port basis
+ * We can configure a port for either ULPI PHY mode (EHCI), or for
+ * ULPI TLL mode (EHCI), or for serial PHY mode (OHCI)
+ * TODO: Add pin-mux settings for PORT 2 serial PHY mode
+ * 	 and for OHCI TLL mode
+ */
+
+/* PHY mode for board: 750-2083-001
+ * On this board, ISP1301 is connected to Port 1
+ * Another ISP1301 transceiver is connected to Port 3
+ */
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1)
+
+	omap_cfg_reg(AF10_3430_USB1FS_PHY_MM1_RXDP);
+	omap_cfg_reg(AG9_3430_USB1FS_PHY_MM1_RXDM);
+	omap_cfg_reg(W13_3430_USB1FS_PHY_MM1_RXRCV);
+	omap_cfg_reg(W12_3430_USB1FS_PHY_MM1_TXSE0);
+	omap_cfg_reg(W11_3430_USB1FS_PHY_MM1_TXDAT);
+	omap_cfg_reg(Y11_3430_USB1FS_PHY_MM1_TXEN_N);
+
+#endif /* Port 1 */
+
+/* PHY mode for board: 750-2099-001(C)
+ * On this board, there is only one ISP1301 connected to Port3
+ */
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3)
+
+	omap_cfg_reg(AH3_3430_USB3FS_PHY_MM3_RXDP);
+	omap_cfg_reg(AE3_3430_USB3FS_PHY_MM3_RXDM);
+	omap_cfg_reg(AD1_3430_USB3FS_PHY_MM3_RXRCV);
+	omap_cfg_reg(AE1_3430_USB3FS_PHY_MM3_TXSE0);
+	omap_cfg_reg(AD2_3430_USB3FS_PHY_MM3_TXDAT);
+	omap_cfg_reg(AC1_3430_USB3FS_PHY_MM3_TXEN_N);
+
+#endif	/* Port3: */
+
+	return;
+}
+#endif /* CONFIG_USB_OHCI_HCD */
+
+
+void __init usb_ohci_init(void)
+{
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+
+	/* Setup Pin IO MUX for OHCI */
+	if (cpu_is_omap34xx())
+		setup_ohci_io_mux();
+
+	if (platform_device_register(&ohci_device) < 0) {
+		printk(KERN_ERR "Unable to register FS-USB (OHCI) device\n");
+		return;
+	}
+#endif
+}
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 9a6a482..7a2bbd1 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -657,6 +657,14 @@
 	help
 	  Say Y here to disable branch prediction.  If unsure, say N.
 
+config CPU_USER_L2_PLE_ACCESS
+	bool "Allow user space to access cache preload engine"
+	depends on ARCH_OMAP34XX && EXPERIMENTAL
+	default n
+	help
+	  Say Y to allow user space to access preload engine. This is useful
+	  for data steaming to a NEON codec
+
 config TLS_REG_EMUL
 	bool
 	help
@@ -717,3 +725,8 @@
 	select OUTER_CACHE
 	help
 	  This option enables the L2 cache on XScale3.
+
+config ARM_L1_CACHE_SHIFT
+	int
+	default 6 if ARCH_OMAP3
+	default 5
diff --git a/arch/arm/mm/ioremap.c b/arch/arm/mm/ioremap.c
index 8441351..0ab75c6 100644
--- a/arch/arm/mm/ioremap.c
+++ b/arch/arm/mm/ioremap.c
@@ -110,15 +110,10 @@
 	return err;
 }
 
-int ioremap_page(unsigned long virt, unsigned long phys, unsigned int mtype)
+int ioremap_page(unsigned long virt, unsigned long phys,
+		 const struct mem_type *mtype)
 {
-	const struct mem_type *type;
-
-	type = get_mem_type(mtype);
-	if (!type)
-		return -EINVAL;
-
-	return remap_area_pages(virt, __phys_to_pfn(phys), PAGE_SIZE, type);
+	return remap_area_pages(virt, __phys_to_pfn(phys), PAGE_SIZE, mtype);
 }
 EXPORT_SYMBOL(ioremap_page);
 
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 6031abc..9b54429 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -253,6 +253,7 @@
 {
 	return type < ARRAY_SIZE(mem_types) ? &mem_types[type] : NULL;
 }
+EXPORT_SYMBOL(get_mem_type);
 
 /*
  * Adjust the PMD section entries according to the CPU in use.
@@ -717,7 +718,7 @@
 		 * the vmalloc area.
 		 */
 		if (__va(bank->start) >= VMALLOC_MIN ||
-		    __va(bank->start) < PAGE_OFFSET) {
+		    __va(bank->start) < (void *)PAGE_OFFSET) {
 			printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
 			       "(vmalloc region overlap).\n",
 			       bank->start, bank->start + bank->size - 1);
diff --git a/arch/arm/mm/proc-v7.S b/arch/arm/mm/proc-v7.S
index cdaba2e..9088886 100644
--- a/arch/arm/mm/proc-v7.S
+++ b/arch/arm/mm/proc-v7.S
@@ -205,6 +205,10 @@
 	ldr	r6, =0x40e040e0
 	mcr	p15, 0, r5, c10, c2, 0		@ write PRRR
 	mcr	p15, 0, r6, c10, c2, 1		@ write NMRR
+#ifdef CONFIG_CPU_USER_L2_PLE_ACCESS
+	mov	r10, #0x3
+	mcr     p15, 0, r10, c11, c1, 0
+#endif
 	adr	r5, v7_crval
 	ldmia	r5, {r5, r6}
    	mrc	p15, 0, r0, c1, c0, 0		@ read control register
diff --git a/arch/arm/oprofile/Makefile b/arch/arm/oprofile/Makefile
index 88e31f5..fc2bc02 100644
--- a/arch/arm/oprofile/Makefile
+++ b/arch/arm/oprofile/Makefile
@@ -8,6 +8,7 @@
 
 oprofile-y				:= $(DRIVER_OBJS) common.o backtrace.o
 oprofile-$(CONFIG_CPU_XSCALE)		+= op_model_xscale.o
+oprofile-$(CONFIG_OPROFILE_OMAP_GPTIMER)	+= op_model_omap_gptimer.o
 oprofile-$(CONFIG_OPROFILE_ARM11_CORE)	+= op_model_arm11_core.o
 oprofile-$(CONFIG_OPROFILE_ARMV6)	+= op_model_v6.o
 oprofile-$(CONFIG_OPROFILE_MPCORE)	+= op_model_mpcore.o
diff --git a/arch/arm/oprofile/common.c b/arch/arm/oprofile/common.c
index 3fcd752..add3cb4 100644
--- a/arch/arm/oprofile/common.c
+++ b/arch/arm/oprofile/common.c
@@ -133,6 +133,11 @@
 
 	ops->backtrace = arm_backtrace;
 
+/* comes first, so that it can be overrided by a better implementation */
+#ifdef CONFIG_OPROFILE_OMAP_GPTIMER
+	spec = &op_omap_gptimer_spec;
+#endif
+
 #ifdef CONFIG_CPU_XSCALE
 	spec = &op_xscale_spec;
 #endif
diff --git a/arch/arm/oprofile/op_arm_model.h b/arch/arm/oprofile/op_arm_model.h
index 8c4e4f6..db936da 100644
--- a/arch/arm/oprofile/op_arm_model.h
+++ b/arch/arm/oprofile/op_arm_model.h
@@ -24,6 +24,8 @@
 extern struct op_arm_model_spec op_xscale_spec;
 #endif
 
+extern struct op_arm_model_spec op_omap_gptimer_spec;
+
 extern struct op_arm_model_spec op_armv6_spec;
 extern struct op_arm_model_spec op_mpcore_spec;
 extern struct op_arm_model_spec op_armv7_spec;
diff --git a/arch/arm/oprofile/op_model_omap_gptimer.c b/arch/arm/oprofile/op_model_omap_gptimer.c
new file mode 100644
index 0000000..c93fac9
--- /dev/null
+++ b/arch/arm/oprofile/op_model_omap_gptimer.c
@@ -0,0 +1,93 @@
+/**
+ * OMAP gptimer based event monitor driver for oprofile
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ * Author: Siarhei Siamashka <siarhei.siamashka@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/types.h>
+#include <linux/oprofile.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+
+#include <mach/dmtimer.h>
+
+#include "op_counter.h"
+#include "op_arm_model.h"
+
+static struct omap_dm_timer *gptimer;
+
+static int gptimer_init(void)
+{
+	return 0;
+}
+
+static int gptimer_setup(void)
+{
+	return 0;
+}
+
+static irqreturn_t gptimer_interrupt(int irq, void *arg)
+{
+	omap_dm_timer_write_status(gptimer, OMAP_TIMER_INT_OVERFLOW);
+	oprofile_add_sample(get_irq_regs(), 0);
+	return IRQ_HANDLED;
+}
+
+static int gptimer_start(void)
+{
+	int err;
+	u32 count = counter_config[0].count;
+
+	BUG_ON(gptimer != NULL);
+	/* First try to request timers from CORE power domain for OMAP3 */
+	if (cpu_is_omap34xx()) {
+		gptimer = omap_dm_timer_request_specific(10);
+		if (gptimer == NULL)
+			gptimer = omap_dm_timer_request_specific(11);
+	}
+	/* Just any timer would be fine */
+	if (gptimer == NULL)
+		gptimer = omap_dm_timer_request();
+	if (gptimer == NULL)
+		return -ENODEV;
+
+	omap_dm_timer_set_source(gptimer, OMAP_TIMER_SRC_32_KHZ);
+	err = request_irq(omap_dm_timer_get_irq(gptimer), gptimer_interrupt,
+				IRQF_DISABLED, "oprofile gptimer", NULL);
+	if (err) {
+		omap_dm_timer_free(gptimer);
+		gptimer = NULL;
+		printk(KERN_ERR "oprofile: unable to request gptimer IRQ\n");
+		return err;
+	}
+
+	if (count < 1)
+		count = 1;
+
+	omap_dm_timer_set_load_start(gptimer, 1, 0xffffffff - count);
+	omap_dm_timer_set_int_enable(gptimer, OMAP_TIMER_INT_OVERFLOW);
+	return 0;
+}
+
+static void gptimer_stop(void)
+{
+	omap_dm_timer_set_int_enable(gptimer, 0);
+	free_irq(omap_dm_timer_get_irq(gptimer), NULL);
+	omap_dm_timer_free(gptimer);
+	gptimer = NULL;
+}
+
+struct op_arm_model_spec op_omap_gptimer_spec = {
+	.init		= gptimer_init,
+	.num_counters	= 1,
+	.setup_ctrs	= gptimer_setup,
+	.start		= gptimer_start,
+	.stop		= gptimer_stop,
+	.name		= "timer",
+};
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 12ffecd..483c228 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -197,6 +197,10 @@
 	  Say Y here if you want to use OMAP IOMMU support for IVA2 and
 	  Camera in OMAP3.
 
+config OMAP_IOMMU_DEBUG
+	depends on OMAP_IOMMU
+	tristate
+
 choice
         prompt "System timer"
 	default OMAP_MPU_TIMER
@@ -260,7 +264,7 @@
 choice
 	prompt "Low-level debug console UART"
 	depends on ARCH_OMAP
-	default OMAP_LL_DEBUG_UART1
+	default OMAP_LL_DEBUG_NONE
 
 config OMAP_LL_DEBUG_UART1
 	bool "UART1"
@@ -274,6 +278,9 @@
 config OMAP_LL_DEBUG_UART_EXT
 	bool "UART_EXT"
 
+config OMAP_LL_DEBUG_NONE
+	bool "None"
+
 endchoice
 
 config OMAP_SERIAL_WAKE
@@ -285,6 +292,96 @@
 	  to data on the serial RX line. This allows you to wake the
 	  system from serial console.
 
+comment "USBHOST Port Configuration"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+
+choice
+	prompt "Port 1"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	default OMAP_EHCI_PHY_MODE_PORT1
+
+config OMAP_EHCI_PHY_MODE_PORT1
+	bool "ULPI PHY mode: 12-pin ULPI"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  12-pin ULPI PHY Mode. For use with a HS transceiver.
+
+config OMAP_EHCI_TLL_MODE_PORT1
+	bool "ULPI TLL mode: 12-pin ULPI"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  12-pin ULPI TLL Mode
+
+config OMAP_OHCI_PHY_MODE_3PIN_PORT1
+	bool "Serial PHY mode: 3-pin Bi-directional DAT/SE0"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  Serial PHY Mode (3-pin Bi-directional DAT/SE0)
+
+config OMAP_OHCI_PHY_MODE_4PIN_PORT1
+	bool "Serial PHY mode: 4-pin Bi-directional DP/DM"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  Serial PHY Mode (4-pin Bidirectional DP/DM)
+
+endchoice
+
+choice
+	prompt "Port 2"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	default OMAP_EHCI_PHY_MODE_PORT2
+
+config OMAP_EHCI_PHY_MODE_PORT2
+	bool "ULPI PHY mode: 12-pin ULPI"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  12-pin ULPI PHY Mode
+
+config OMAP_EHCI_TLL_MODE_PORT2
+	bool "ULPI TLL mode: 12-pin ULPI"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  12-pin ULPI TLL Mode
+
+config OMAP_OHCI_PHY_MODE_3PIN_PORT2
+	bool "Serial PHY mode: 3-pin Bi-directional DAT/SE0"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  Serial PHY Mode (3-pin Bi-directional DAT/SE0)
+
+config OMAP_OHCI_PHY_MODE_4PIN_PORT2
+	bool "Serial PHY mode: 4-pin Bi-directional DP/DM"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  Serial PHY Mode (4-pin Bidirectional DP/DM)
+
+endchoice
+
+choice
+	prompt "Port 3"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	default OMAP_OHCI_PHY_MODE_3PIN_PORT3
+
+config OMAP_EHCI_TLL_MODE_PORT3
+	bool "ULPI TLL mode: 12-pin ULPI"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  12-pin ULPI TLL Mode
+
+config OMAP_OHCI_PHY_MODE_3PIN_PORT3
+	bool "Serial PHY mode: 3-pin Bi-directional DAT/SE0"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  Serial PHY Mode (3-pin Bidirectional DAT/SE0)
+
+config OMAP_OHCI_PHY_MODE_4PIN_PORT3
+	bool "Serial PHY mode: 4-pin Bi-directional DP/DM"
+	depends on USB_EHCI_HCD || USB_OHCI_HCD
+	help
+	  Serial PHY Mode (4-pin Bidirectional DP/DM)
+
+endchoice
+
 choice
 	prompt "OMAP PM layer selection"
 	depends on ARCH_OMAP
@@ -302,6 +399,27 @@
 
 endchoice
 
+config OMAP3_MPU_L2_CACHE_WORKAROUND
+	bool "Enable workaround for lockup on MPU cache corruption"
+	depends on ARCH_OMAP3 || PM
+	help
+	  Workaround replaces MPU RETENTION state with INACTIVE state.
+	  Some OMAP3's manufactured before July 2009 suffer from L2
+	  cache corruption.  When the MPU fetches a corrupted
+	  instruction a system hang or reset via watchdog occurs.  OFF
+	  mode is still safe to use.
+
+config VOLTSCALE_VPFORCE
+	bool "Voltage scaling using VP force update method"
+	depends on ARCH_OMAP3 && PM
+	default y
+	help
+	 Say Y if you want to enable VP force update method
+	 of voltage scaling. This is the h/w recomended way
+	 of voltage scaling.
+
+	 If not enabled and if OMAP_SMARTREFLEX is enabled
+	 vcbypass method will be used for voltage scaling.
 endmenu
 
 endif
diff --git a/arch/arm/plat-omap/Makefile b/arch/arm/plat-omap/Makefile
index f946d83..94d1500 100644
--- a/arch/arm/plat-omap/Makefile
+++ b/arch/arm/plat-omap/Makefile
@@ -14,6 +14,7 @@
 
 obj-$(CONFIG_OMAP_MCBSP) += mcbsp.o
 obj-$(CONFIG_OMAP_IOMMU) += iommu.o iovmm.o
+obj-$(CONFIG_OMAP_IOMMU_DEBUG) += iommu-debug.o
 
 obj-$(CONFIG_CPU_FREQ) += cpu-omap.o
 obj-$(CONFIG_OMAP_DM_TIMER) += dmtimer.o
diff --git a/arch/arm/plat-omap/clock.c b/arch/arm/plat-omap/clock.c
index a1a09ef..3af8697 100644
--- a/arch/arm/plat-omap/clock.c
+++ b/arch/arm/plat-omap/clock.c
@@ -919,7 +919,7 @@
 	}
 	return 0;
 err_out:
-	debugfs_remove(clk_debugfs_root); /* REVISIT: Cleanup correctly */
+	debugfs_remove_recursive(clk_debugfs_root);
 	return err;
 }
 late_initcall(clk_debugfs_init);
diff --git a/arch/arm/plat-omap/cpu-omap.c b/arch/arm/plat-omap/cpu-omap.c
index 393c905..0f68936 100644
--- a/arch/arm/plat-omap/cpu-omap.c
+++ b/arch/arm/plat-omap/cpu-omap.c
@@ -155,7 +155,7 @@
 	policy->cur = omap_getspeed(0);
 
 	/* FIXME: what's the actual transition time? */
-	policy->cpuinfo.transition_latency = 10 * 1000 * 1000;
+	policy->cpuinfo.transition_latency = 300 * 1000;
 	return 0;
 }
 
diff --git a/arch/arm/plat-omap/devices.c b/arch/arm/plat-omap/devices.c
index e66dd8a..aba1e5c 100644
--- a/arch/arm/plat-omap/devices.c
+++ b/arch/arm/plat-omap/devices.c
@@ -336,7 +336,7 @@
 		wdt_resources[0].start = 0x48022000; /* WDT2 */
 	else if (cpu_is_omap2430())
 		wdt_resources[0].start = 0x49016000; /* WDT2 */
-	else if (cpu_is_omap343x())
+	else if (cpu_is_omap34xx())
 		wdt_resources[0].start = 0x48314000; /* WDT2 */
 	else
 		return;
diff --git a/arch/arm/plat-omap/dma.c b/arch/arm/plat-omap/dma.c
index cd53b28..e12094b 100755
--- a/arch/arm/plat-omap/dma.c
+++ b/arch/arm/plat-omap/dma.c
@@ -316,14 +316,10 @@
 
 void omap_set_dma_color_mode(int lch, enum omap_dma_color_mode mode, u32 color)
 {
-	u16 w;
-
 	BUG_ON(omap_dma_in_1510_mode());
 
-	if (cpu_class_is_omap2()) {
-		REVISIT_24XX();
-		return;
-	}
+	if (cpu_class_is_omap1()) {
+		u16 w;
 
 	w = dma_read(CCR2(lch));
 	w &= ~0x03;
@@ -351,6 +347,31 @@
 		w |= 1;		/* Channel type G */
 	}
 	dma_write(w, LCH_CTRL(lch));
+	}
+
+	if (cpu_class_is_omap2()) {
+		u32 val;
+
+		val = dma_read(CCR(lch));
+		val &= ~((1 << 17) | (1 << 16));
+
+		switch (mode) {
+		case OMAP_DMA_CONSTANT_FILL:
+			val |= 1 << 16;
+			break;
+		case OMAP_DMA_TRANSPARENT_COPY:
+			val |= 1 << 17;
+			break;
+		case OMAP_DMA_COLOR_DIS:
+			break;
+		default:
+			BUG();
+		}
+		dma_write(val, CCR(lch));
+
+		color &= 0xffffff;
+		dma_write(color, COLOR(lch));
+	}
 }
 EXPORT_SYMBOL(omap_set_dma_color_mode);
 
@@ -455,6 +476,35 @@
 }
 EXPORT_SYMBOL(omap_set_dma_src_data_pack);
 
+/**
+ * @brief omap_set_dma_prefetch : Enable/disable prefetch
+ * for a logical channel
+ *
+ * @param lch : Logical channel number
+ * @param enable : 1 to enable / 0 to disable
+ *
+ * Prefetch can only be enabled for destination synchronized transfer.
+ * It is SW user responsibility to have prefetch disabled for source
+ * synchronized transfers.
+ * It improves DMA performance by fetching data before receiving
+ * the DMA request. Therefore, the data source shall be available when
+ * the logical channel is enabled.
+ *
+ */
+void omap_set_dma_prefetch(int lch, int enable)
+{
+	u32 l;
+
+	if (cpu_class_is_omap2()) {
+		l = dma_read(CCR(lch));
+		l &= ~(1 << 23);
+		if (enable)
+			l |= (1 << 23);
+		dma_write(l, CCR(lch));
+	}
+}
+EXPORT_SYMBOL(omap_set_dma_prefetch);
+
 void omap_set_dma_src_burst_mode(int lch, enum omap_dma_burst_mode burst_mode)
 {
 	unsigned int burst = 0;
@@ -800,7 +850,10 @@
 		/* Disable all DMA interrupts for the channel. */
 		dma_write(0, CICR(lch));
 
-		/* Make sure the DMA transfer is stopped. */
+		/*
+		 * Make sure the DMA transfer is stopped
+		 * and disable prefetch.
+		 */
 		dma_write(0, CCR(lch));
 		omap_clear_dma(lch);
 	}
@@ -929,7 +982,9 @@
 
 			cur_lch = next_lch;
 		} while (next_lch != -1);
-	} else if (cpu_class_is_omap2()) {
+	} else if (cpu_is_omap242x() ||
+		(cpu_is_omap243x() &&  omap_type() <= OMAP2430_REV_ES1_0)) {
+
 		/* Errata: Need to write lch even if not using chaining */
 		dma_write(lch, CLNK_CTRL(lch));
 	}
@@ -989,6 +1044,15 @@
 }
 EXPORT_SYMBOL(omap_stop_dma);
 
+void omap_disable_lch(int lch)
+{
+	u32 l;
+	l = dma_read(CCR(lch));
+	l &= ~OMAP_DMA_CCR_EN;
+	dma_write(l, CCR(lch));
+}
+EXPORT_SYMBOL(omap_disable_lch);
+
 /*
  * Allows changing the DMA callback function or data. This may be needed if
  * the driver shares a single DMA channel for multiple dma triggers.
diff --git a/arch/arm/plat-omap/dmtimer.c b/arch/arm/plat-omap/dmtimer.c
index a05205c..4618963 100644
--- a/arch/arm/plat-omap/dmtimer.c
+++ b/arch/arm/plat-omap/dmtimer.c
@@ -503,6 +503,17 @@
 	if (l & OMAP_TIMER_CTRL_ST) {
 		l &= ~0x1;
 		omap_dm_timer_write_reg(timer, OMAP_TIMER_CTRL_REG, l);
+		/* Readback to make sure write has completed */
+		omap_dm_timer_read_reg(timer, OMAP_TIMER_CTRL_REG);
+		/*
+		 * Wait for functional clock period x 3.5 to make sure that
+		 * timer is stopped
+		 */
+		udelay(3500000 / clk_get_rate(timer->fclk) + 1);
+		/* Ack possibly pending interrupt */
+		omap_dm_timer_write_reg(timer, OMAP_TIMER_STAT_REG,
+				OMAP_TIMER_INT_OVERFLOW);
+
 	}
 }
 EXPORT_SYMBOL_GPL(omap_dm_timer_stop);
diff --git a/arch/arm/plat-omap/fb.c b/arch/arm/plat-omap/fb.c
index 1dc3415..76cc0ae 100644
--- a/arch/arm/plat-omap/fb.c
+++ b/arch/arm/plat-omap/fb.c
@@ -107,6 +107,10 @@
 	 * address.
 	 */
 	memset(rg, 0, sizeof(*rg));
+#ifdef CONFIG_FB_OMAP2_32_BPP
+	rg->format = OMAPFB_COLOR_ARGB32;
+	rg->format_used = 1;
+#endif
 	rg->type = paddr & ~PAGE_MASK;
 	rg->paddr = paddr & PAGE_MASK;
 	rg->size = PAGE_ALIGN(conf->size);
@@ -350,6 +354,14 @@
 
 static inline int omap_init_fb(void)
 {
+#ifdef CONFIG_FB_OMAP2_32_BPP
+	/* add support for RGB32*/
+	int i;
+	for (i = 0; i < OMAPFB_PLANE_NUM; i++) {
+		omapfb_config.mem_desc.region[0].format_used = 1;
+		omapfb_config.mem_desc.region[0].format = OMAPFB_COLOR_ARGB32;
+	}
+#endif
 	return platform_device_register(&omap_fb_device);
 }
 
diff --git a/arch/arm/plat-omap/gpio.c b/arch/arm/plat-omap/gpio.c
index 667dd60..d0267fe 100644
--- a/arch/arm/plat-omap/gpio.c
+++ b/arch/arm/plat-omap/gpio.c
@@ -529,7 +529,7 @@
 {
 	struct gpio_bank *bank;
 	void __iomem *reg;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 	u32 val, l = 1 << get_gpio_index(gpio);
 
 	if (cpu_class_is_omap1())
@@ -709,7 +709,7 @@
 	struct gpio_bank *bank;
 	unsigned gpio;
 	int retval;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	if (!cpu_class_is_omap2() && irq > IH_MPUIO_BASE)
 		gpio = OMAP_MPUIO(irq - IH_MPUIO_BASE);
@@ -926,7 +926,7 @@
  */
 static int _set_gpio_wakeup(struct gpio_bank *bank, int gpio, int enable)
 {
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	switch (bank->method) {
 #ifdef CONFIG_ARCH_OMAP16XX
@@ -989,7 +989,7 @@
 static int omap_gpio_request(struct gpio_chip *chip, unsigned offset)
 {
 	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	spin_lock_irqsave(&bank->lock, flags);
 
@@ -1015,7 +1015,7 @@
 static void omap_gpio_free(struct gpio_chip *chip, unsigned offset)
 {
 	struct gpio_bank *bank = container_of(chip, struct gpio_bank, chip);
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	spin_lock_irqsave(&bank->lock, flags);
 #ifdef CONFIG_ARCH_OMAP16XX
@@ -1234,7 +1234,7 @@
 {
 	struct gpio_bank	*bank = platform_get_drvdata(pdev);
 	void __iomem		*mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
-	unsigned long		flags;
+	unsigned long		uninitialized_var(flags);
 
 	spin_lock_irqsave(&bank->lock, flags);
 	bank->saved_wakeup = __raw_readl(mask_reg);
@@ -1248,7 +1248,7 @@
 {
 	struct gpio_bank	*bank = platform_get_drvdata(pdev);
 	void __iomem		*mask_reg = bank->base + OMAP_MPUIO_GPIO_MASKIT;
-	unsigned long		flags;
+	unsigned long		uninitialized_var(flags);
 
 	spin_lock_irqsave(&bank->lock, flags);
 	__raw_writel(bank->saved_wakeup, mask_reg);
@@ -1307,7 +1307,7 @@
 static int gpio_input(struct gpio_chip *chip, unsigned offset)
 {
 	struct gpio_bank *bank;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	bank = container_of(chip, struct gpio_bank, chip);
 	spin_lock_irqsave(&bank->lock, flags);
@@ -1324,7 +1324,7 @@
 static int gpio_output(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct gpio_bank *bank;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	bank = container_of(chip, struct gpio_bank, chip);
 	spin_lock_irqsave(&bank->lock, flags);
@@ -1337,7 +1337,7 @@
 static void gpio_set(struct gpio_chip *chip, unsigned offset, int value)
 {
 	struct gpio_bank *bank;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	bank = container_of(chip, struct gpio_bank, chip);
 	spin_lock_irqsave(&bank->lock, flags);
@@ -1670,7 +1670,7 @@
 		void __iomem *wake_status;
 		void __iomem *wake_clear;
 		void __iomem *wake_set;
-		unsigned long flags;
+		unsigned long uninitialized_var(flags);
 
 		switch (bank->method) {
 #ifdef CONFIG_ARCH_OMAP16XX
@@ -1732,7 +1732,7 @@
 		struct gpio_bank *bank = &gpio_bank[i];
 		void __iomem *wake_clear;
 		void __iomem *wake_set;
-		unsigned long flags;
+		unsigned long uninitialized_var(flags);
 
 		switch (bank->method) {
 #ifdef CONFIG_ARCH_OMAP16XX
diff --git a/arch/arm/plat-omap/include/mach/board-zoom2.h b/arch/arm/plat-omap/include/mach/board-zoom2.h
index 780e7fd..5899bd6 100644
--- a/arch/arm/plat-omap/include/mach/board-zoom2.h
+++ b/arch/arm/plat-omap/include/mach/board-zoom2.h
@@ -31,6 +31,7 @@
 
 extern void ldp_flash_init(void);
 extern void twl4030_bci_battery_init(void);
+extern unsigned get_last_off_on_transaction_id(struct device *dev);
 
 #define TWL4030_IRQNUM		INT_34XX_SYS_NIRQ
 #define LDP3430_NAND_CS		0 
diff --git a/arch/arm/plat-omap/include/mach/clock.h b/arch/arm/plat-omap/include/mach/clock.h
index 3927781..f29cf76 100644
--- a/arch/arm/plat-omap/include/mach/clock.h
+++ b/arch/arm/plat-omap/include/mach/clock.h
@@ -57,6 +57,9 @@
 	u32			autoidle_mask;
 	u32			idlest_mask;
 	u32			freqsel_mask;
+	u32			dco_sel_mask;
+	u32			sd_div_mask;
+	u8			jtype;
 #  endif
 };
 
@@ -132,8 +135,8 @@
 	__s8			usecount;
 	u8			idlest_bit;
 #if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
-	u8			fixed_div;
-	u32			clksel_mask;
+	u8			fixed_div, clksel_shift;
+	u32			clksel_mask, clksel_mask2;
 	const struct clksel	*clksel;
 	struct dpll_data	*dpll_data;
 	union {
@@ -216,6 +219,7 @@
 #define PARENT_CONTROLS_CLOCK	(1 << 28)
 #define CLOCK_IN_OMAP3430ES1	(1 << 29)	/* 3430ES1 clocks only */
 #define CLOCK_IN_OMAP3430ES2	(1 << 30)	/* 3430ES2+ clocks only */
+#define CLOCK_IN_OMAP363X 	(1 << 31)
 
 /* Clksel_rate flags */
 #define DEFAULT_RATE		(1 << 0)
@@ -223,6 +227,8 @@
 #define RATE_IN_243X		(1 << 2)
 #define RATE_IN_343X		(1 << 3)	/* rates common to all 343X */
 #define RATE_IN_3430ES2		(1 << 4)	/* 3430ES2+ rates only */
+#define RATE_IN_363X		(1 << 5)	/* rates common to all 3630 */
+
 
 #define RATE_IN_24XX		(RATE_IN_242X | RATE_IN_243X)
 
diff --git a/arch/arm/plat-omap/include/mach/control.h b/arch/arm/plat-omap/include/mach/control.h
index 3b3375e..16831da 100644
--- a/arch/arm/plat-omap/include/mach/control.h
+++ b/arch/arm/plat-omap/include/mach/control.h
@@ -166,6 +166,8 @@
 #define OMAP343X_CONTROL_SRAMLDO5	(OMAP2_CONTROL_GENERAL + 0x02C0)
 #define OMAP343X_CONTROL_CSI		(OMAP2_CONTROL_GENERAL + 0x02C4)
 
+/* 36xx-only CONTROL_GENERAL register offsets */
+#define OMAP36XX_CONTROL_PROG_IO2       (OMAP2_CONTROL_GENERAL + 0x0198)
 
 /* 34xx PADCONF register offsets */
 #define OMAP343X_PADCONF_ETK(i)		(OMAP2_CONTROL_PADCONFS + 0x5a8 + \
@@ -198,6 +200,9 @@
 #define OMAP343X_CONTROL_WKUP_DEBOBS3 (OMAP343X_CONTROL_GENERAL_WKUP + 0x014)
 #define OMAP343X_CONTROL_WKUP_DEBOBS4 (OMAP343X_CONTROL_GENERAL_WKUP + 0x018)
 
+/* 36xx-only GENERAL_WKUP register offsets */
+#define OMAP36XX_CONTROL_PROG_IO_WKUP1 (OMAP343X_CONTROL_GENERAL_WKUP + 0x020)
+
 /*
  * REVISIT: This list of registers is not comprehensive - there are more
  * that should be added.
@@ -253,6 +258,17 @@
 #define OMAP2_PBIASLITEPWRDNZ0		(1 << 1)
 #define OMAP2_PBIASLITEVMODE0		(1 << 0)
 
+/* CONTROL_PROG_IO1 bits on omap3630 */
+#define OMAP3630_PRG_I2C2_PULLUPRESX    (1 << 0)
+#define OMAP3630_PRG_I2C1_PULLUPRESX	(1 << 19)
+#define OMAP3630_PRG_SDMMC1_SPEEDCTRL	(1 << 20)
+
+/* CONTROL_PROG_IO2 bits on omap3630 */
+#define OMAP3630_PRG_I2C3_PULLUPRESX    (1 << 7)
+
+/* CONTROL_PROG_IO_WKUP1 bits on omap3630 */
+#define OMAP3630_PRG_SR_PULLUPRESX    (1 << 5)
+
 /* CONTROL_PADCONF_X bits */
 #define OMAP3_PADCONF_WAKEUPEVENT0   (1 << 15)
 #define OMAP3_PADCONF_WAKEUPENABLE0  (1 << 14)
@@ -287,6 +303,7 @@
 extern u32 omap3_arm_context[128];
 extern void omap3_control_save_context(void);
 extern void omap3_control_restore_context(void);
+extern void omap3_scratchpad_dpll4autoidle(int enable);
 
 #else
 #define omap_ctrl_base_get()		0
diff --git a/arch/arm/plat-omap/include/mach/cpu.h b/arch/arm/plat-omap/include/mach/cpu.h
index 4166a97..b292e93 100644
--- a/arch/arm/plat-omap/include/mach/cpu.h
+++ b/arch/arm/plat-omap/include/mach/cpu.h
@@ -27,7 +27,7 @@
 #define __ASM_ARCH_OMAP_CPU_H
 
 struct omap_chip_id {
-	u8 oc;
+	u16 oc;
 	u8 type;
 };
 
@@ -40,6 +40,7 @@
  * CPU class bits (15xx, 16xx, 24xx, 34xx...)	[07:00]
  */
 unsigned int omap_rev(void);
+unsigned int omap_rev_id(void);
 
 /*
  * Test if multicore OMAP support is needed
@@ -138,6 +139,7 @@
 IS_OMAP_SUBCLASS(242x, 0x242)
 IS_OMAP_SUBCLASS(243x, 0x243)
 IS_OMAP_SUBCLASS(343x, 0x343)
+IS_OMAP_SUBCLASS(363x, 0x363)
 
 #define cpu_is_omap7xx()		0
 #define cpu_is_omap15xx()		0
@@ -147,6 +149,7 @@
 #define cpu_is_omap243x()		0
 #define cpu_is_omap34xx()		0
 #define cpu_is_omap343x()		0
+#define cpu_is_omap3630()		0
 
 #if defined(MULTI_OMAP1)
 # if defined(CONFIG_ARCH_OMAP730)
@@ -190,6 +193,7 @@
 #  undef  cpu_is_omap343x
 #  define cpu_is_omap34xx()		is_omap34xx()
 #  define cpu_is_omap343x()		is_omap343x()
+#  define cpu_is_omap3630()		is_omap363x()
 # endif
 #else
 # if defined(CONFIG_ARCH_OMAP24XX)
@@ -207,6 +211,8 @@
 # if defined(CONFIG_ARCH_OMAP34XX)
 #  undef  cpu_is_omap34xx
 #  define cpu_is_omap34xx()		1
+#  undef  cpu_is_omap3630
+# define cpu_is_omap3630()		is_omap363x()
 # endif
 # if defined(CONFIG_ARCH_OMAP3430)
 #  undef  cpu_is_omap343x
@@ -230,6 +236,7 @@
  * cpu_is_omap2423():	True for OMAP2423
  * cpu_is_omap2430():	True for OMAP2430
  * cpu_is_omap3430():	True for OMAP3430
+ * cpu_is_omap3630():	True for OMAP3630
  */
 #define GET_OMAP_TYPE	((omap_rev() >> 16) & 0xffff)
 
@@ -334,12 +341,14 @@
 #define OMAP243X_CLASS		0x24300024
 #define OMAP2430_REV_ES1_0	0x24300024
 
-#define OMAP343X_CLASS		0x34300034
-#define OMAP3430_REV_ES1_0	0x34300034
-#define OMAP3430_REV_ES2_0	0x34301034
-#define OMAP3430_REV_ES2_1	0x34302034
-#define OMAP3430_REV_ES3_0	0x34303034
-#define OMAP3430_REV_ES3_1	0x34304034
+#define OMAP343X_CLASS			0x34300034
+#define OMAP3430_REV_ES1_0		0x34300034
+#define OMAP3430_REV_ES2_0		0x34301034
+#define OMAP3430_REV_ES2_1		0x34302034
+#define OMAP3430_REV_ES3_0		0x34303034
+#define OMAP3430_REV_ES3_1		0x34304034
+#define OMAP3430_REV_ES3_1_1	0x34305034
+#define OMAP3630_REV_ES1_0		0x36300034
 
 /*
  * omap_chip bits
@@ -362,6 +371,8 @@
 #define CHIP_IS_OMAP3430ES2		(1 << 4)
 #define CHIP_IS_OMAP3430ES3_0		(1 << 5)
 #define CHIP_IS_OMAP3430ES3_1		(1 << 6)
+#define CHIP_IS_OMAP3430ES3_1_1	(1 << 7)
+#define CHIP_IS_OMAP3630ES1		(1 << 8)
 
 #define CHIP_IS_OMAP24XX		(CHIP_IS_OMAP2420 | CHIP_IS_OMAP2430)
 
@@ -373,9 +384,13 @@
  */
 #define CHIP_GE_OMAP3430ES2		(CHIP_IS_OMAP3430ES2 | \
 					 CHIP_IS_OMAP3430ES3_0 | \
-					 CHIP_IS_OMAP3430ES3_1)
-#define CHIP_GE_OMAP3430ES3_1		(CHIP_IS_OMAP3430ES3_1)
+					 CHIP_IS_OMAP3430ES3_1 | \
+					 CHIP_IS_OMAP3430ES3_1_1 |\
+					 CHIP_IS_OMAP3630ES1)
 
+#define CHIP_GE_OMAP3430ES3_1		(CHIP_IS_OMAP3430ES3_1 | \
+					 CHIP_IS_OMAP3430ES3_1_1 | \
+					 CHIP_IS_OMAP3630ES1)
 
 int omap_chip_is(struct omap_chip_id oci);
 int omap_type(void);
@@ -389,8 +404,19 @@
 #define OMAP2_DEVICE_TYPE_GP		3
 #define OMAP2_DEVICE_TYPE_BAD		4
 
+/*
+ * Macro to detect omap revision number (for SW tiering */
+#define OMAP_3420	0x3420
+#define OMAP_3430	0x3430
+#define OMAP_3440	0x3440
+#define OMAP_3630	0x3630
+#define OMAP_3630_800	0x3630800
+#define OMAP_3630_1000	0x36301000
+
 void omap2_check_revision(void);
 
+void omap_l2cache_enable(void);
+
 #endif    /* defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3) */
 
 #endif
diff --git a/arch/arm/plat-omap/include/mach/debug-macro.S b/arch/arm/plat-omap/include/mach/debug-macro.S
index 6fd3184..6515629 100644
--- a/arch/arm/plat-omap/include/mach/debug-macro.S
+++ b/arch/arm/plat-omap/include/mach/debug-macro.S
@@ -39,10 +39,10 @@
 #elif	CONFIG_ARCH_OMAP3
 #ifdef CONFIG_OMAP_LL_DEBUG_UART_EXT
 		moveq   \rx, #0x10000000        @ physical base address
-		movne   \rx, #0xfb000000        @ virtual base address
+		ldrne	\rx, =0xfa400000
 #else
 		moveq	\rx, #0x48000000	@ physical base address
-		movne	\rx, #0xd8000000	@ virtual base
+		movne	\rx, #0xfa000000	@ virtual base
 		orr	\rx, \rx, #0x0006a000
 #ifdef CONFIG_OMAP_LL_DEBUG_UART2
 		add	\rx, \rx, #0x00002000	@ UART 2
diff --git a/arch/arm/plat-omap/include/mach/dma.h b/arch/arm/plat-omap/include/mach/dma.h
index c023e89..88b112c 100755
--- a/arch/arm/plat-omap/include/mach/dma.h
+++ b/arch/arm/plat-omap/include/mach/dma.h
@@ -144,6 +144,7 @@
 #define OMAP_DMA4_CSSA_U(n)		0
 #define OMAP_DMA4_CDSA_L(n)		0
 #define OMAP_DMA4_CDSA_U(n)		0
+#define OMAP1_DMA_COLOR(n)		0
 
 /*----------------------------------------------------------------------------*/
 
@@ -496,6 +497,7 @@
 extern void omap_free_dma(int ch);
 extern void omap_start_dma(int lch);
 extern void omap_stop_dma(int lch);
+extern void omap_disable_lch(int lch);
 extern void omap_set_dma_transfer_params(int lch, int data_type,
 					 int elem_count, int frame_count,
 					 int sync_mode,
@@ -510,6 +512,7 @@
 				    int src_ei, int src_fi);
 extern void omap_set_dma_src_index(int lch, int eidx, int fidx);
 extern void omap_set_dma_src_data_pack(int lch, int enable);
+extern void omap_set_dma_prefetch(int lch, int enable);
 extern void omap_set_dma_src_burst_mode(int lch,
 					enum omap_dma_burst_mode burst_mode);
 
diff --git a/arch/arm/plat-omap/include/mach/gpmc.h b/arch/arm/plat-omap/include/mach/gpmc.h
index a37cfc6..2ebc0a7 100644
--- a/arch/arm/plat-omap/include/mach/gpmc.h
+++ b/arch/arm/plat-omap/include/mach/gpmc.h
@@ -114,6 +114,10 @@
 extern void gpmc_cs_free(int cs);
 extern int gpmc_cs_set_reserved(int cs, int reserved);
 extern int gpmc_cs_reserved(int cs);
+extern int gpmc_prefetch_enable(int cs, int dma_mode,
+			unsigned int u32_count, int is_write);
+extern void gpmc_prefetch_reset(void);
+extern int gpmc_prefetch_status(void);
 extern void omap3_gpmc_save_context(void);
 extern void omap3_gpmc_restore_context(void);
 extern void __init gpmc_init(void);
diff --git a/arch/arm/plat-omap/include/mach/io.h b/arch/arm/plat-omap/include/mach/io.h
index 4c8dcfa..cb54bfd 100644
--- a/arch/arm/plat-omap/include/mach/io.h
+++ b/arch/arm/plat-omap/include/mach/io.h
@@ -109,7 +109,7 @@
 #define L3_34XX_SIZE		SZ_1M   /* 44kB of 128MB used, want 1MB sect */
 
 #define L4_34XX_PHYS		L4_34XX_BASE	/* 0x48000000 */
-#define L4_34XX_VIRT		0xd8000000
+#define L4_34XX_VIRT		0xfa000000
 #define L4_34XX_SIZE		SZ_4M   /* 1MB of 128MB used, want 1MB sect */
 
 /*
@@ -118,16 +118,16 @@
  */
 
 #define L4_WK_34XX_PHYS		L4_WK_34XX_BASE /* 0x48300000 */
-#define L4_WK_34XX_VIRT		0xd8300000
+#define L4_WK_34XX_VIRT		0xfa300000
 #define L4_WK_34XX_SIZE		SZ_1M
 
 #define L4_PER_34XX_PHYS	L4_PER_34XX_BASE /* 0x49000000 */
-#define L4_PER_34XX_VIRT	0xd9000000
+#define L4_PER_34XX_VIRT	0xfb000000
 #define L4_PER_34XX_SIZE	SZ_1M
 
 #define L4_EMU_34XX_PHYS	L4_EMU_34XX_BASE /* 0x54000000 */
-#define L4_EMU_34XX_VIRT	0xe4000000
-#define L4_EMU_34XX_SIZE	SZ_64M
+#define L4_EMU_34XX_VIRT	0xf9000000
+#define L4_EMU_34XX_SIZE	SZ_8M
 
 #define OMAP34XX_GPMC_PHYS	OMAP34XX_GPMC_BASE /* 0x6E000000 */
 #define OMAP34XX_GPMC_VIRT	0xFE000000
@@ -141,12 +141,30 @@
 #define OMAP343X_SDRC_VIRT	0xFD000000
 #define OMAP343X_SDRC_SIZE	SZ_1M
 
+#define L3_IO_OFFSET		0x90000000
+#define IO_OFFSET               0xb2000000
 
-#define IO_OFFSET		0x90000000
-#define __IO_ADDRESS(pa)	((pa) + IO_OFFSET) /* Works for L3 and L4 */
-#define __OMAP2_IO_ADDRESS(pa)	((pa) + IO_OFFSET) /* Works for L3 and L4 */
-#define io_v2p(va)		((va) - IO_OFFSET) /* Works for L3 and L4 */
-#define io_p2v(pa)		((pa) + IO_OFFSET) /* Works for L3 and L4 */
+#ifndef __ASSEMBLER__
+/* Works for L3 and L4 */
+#define __IO_ADDRESS(pa)	((pa) >= L3_34XX_PHYS ? \
+				((pa) + L3_IO_OFFSET) : ((pa) + IO_OFFSET))
+
+#define __OMAP2_IO_ADDRESS(pa)	__IO_ADDRESS(pa)
+/* #define io_v2p(va)		((va) - IO_OFFSET) */
+#define io_p2v(pa)		__IO_ADDRESS(pa)
+#else
+/* Works for L3 */
+#define __L3_IO_ADDRESS(pa)	((pa) + L3_IO_OFFSET)
+#define __OMAP2_L3_IO_ADDRESS(pa)	((pa) + L3_IO_OFFSET)
+#define l3_io_v2p(va)		((va) - L3_IO_OFFSET)
+#define l3_io_p2v(pa)		((pa) + L3_IO_OFFSET)
+
+/* Works for L4 */
+#define __IO_ADDRESS(pa)	((pa) + IO_OFFSET)
+#define __OMAP2_IO_ADDRESS(pa)	((pa) + IO_OFFSET)
+#define io_p2v(pa)		((pa) + IO_OFFSET)
+#define io_v2p(va)		((va) - IO_OFFSET)
+#endif
 
 /* DSP */
 #define DSP_MEM_34XX_PHYS	OMAP34XX_DSP_MEM_BASE	/* 0x58000000 */
@@ -159,15 +177,28 @@
 #define DSP_MMU_34XX_VIRT	0xe2000000
 #define DSP_MMU_34XX_SIZE	SZ_4K
 
+
 #define ZOOM2_QUART_PHYS	0x10000000
-#define ZOOM2_QUART_VIRT	0xFB000000
+#define ZOOM2_QUART_VIRT	0xfa400000
 #define ZOOM2_QUART_SIZE	SZ_1M
 
 #endif
 
+#ifndef __ASSEMBLER__
 #define IO_ADDRESS(pa)		IOMEM(__IO_ADDRESS(pa))
 #define OMAP1_IO_ADDRESS(pa)	IOMEM(__OMAP1_IO_ADDRESS(pa))
 #define OMAP2_IO_ADDRESS(pa)	IOMEM(__OMAP2_IO_ADDRESS(pa))
+#define L3_IO_ADDRESS(pa)		IOMEM(__L3_IO_ADDRESS(pa))
+#define OMAP2_L3_IO_ADDRESS(pa)		IOMEM(__OMAP2_L3_IO_ADDRESS(pa))
+
+#else
+
+#define L3_IO_ADDRESS(pa)		IOMEM(__L3_IO_ADDRESS(pa))
+#define OMAP2_L3_IO_ADDRESS(pa)		IOMEM(__OMAP2_L3_IO_ADDRESS(pa))
+
+#define IO_ADDRESS(pa)			IOMEM(__IO_ADDRESS(pa))
+#define OMAP2_IO_ADDRESS(pa)		IOMEM(__OMAP2_IO_ADDRESS(pa))
+#endif
 
 #ifdef __ASSEMBLER__
 #define IOMEM(x)		x
diff --git a/arch/arm/plat-omap/include/mach/iommu.h b/arch/arm/plat-omap/include/mach/iommu.h
index ef04d7a..46d41ac 100644
--- a/arch/arm/plat-omap/include/mach/iommu.h
+++ b/arch/arm/plat-omap/include/mach/iommu.h
@@ -95,7 +95,7 @@
 
 	void (*save_ctx)(struct iommu *obj);
 	void (*restore_ctx)(struct iommu *obj);
-	ssize_t (*dump_ctx)(struct iommu *obj, char *buf);
+	ssize_t (*dump_ctx)(struct iommu *obj, char *buf, ssize_t len);
 };
 
 struct iommu_platform_data {
@@ -104,7 +104,11 @@
 	const int nr_tlb_entries;
 };
 
+#if defined(CONFIG_ARCH_OMAP1)
+#error "iommu for this processor not implemented yet"
+#else
 #include <mach/iommu2.h>
+#endif
 
 /*
  * utilities for super page(16MB, 1MB, 64KB and 4KB)
@@ -135,13 +139,14 @@
  */
 extern u32 iommu_arch_version(void);
 
+extern void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e);
+extern u32 iotlb_cr_to_virt(struct cr_regs *cr);
+
 extern int load_iotlb_entry(struct iommu *obj, struct iotlb_entry *e);
 extern void flush_iotlb_page(struct iommu *obj, u32 da);
 extern void flush_iotlb_range(struct iommu *obj, u32 start, u32 end);
 extern void flush_iotlb_all(struct iommu *obj);
 
-ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf);
-
 extern int iopgtable_store_entry(struct iommu *obj, struct iotlb_entry *e);
 extern size_t iopgtable_clear_entry(struct iommu *obj, u32 iova);
 
@@ -154,4 +159,10 @@
 extern int install_iommu_arch(const struct iommu_functions *ops);
 extern void uninstall_iommu_arch(const struct iommu_functions *ops);
 
+extern int foreach_iommu_device(void *data,
+				int (*fn)(struct device *, void *));
+
+extern ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t len);
+extern size_t dump_tlb_entries(struct iommu *obj, char *buf, ssize_t len);
+
 #endif /* __MACH_IOMMU_H */
diff --git a/arch/arm/plat-omap/include/mach/iommu2.h b/arch/arm/plat-omap/include/mach/iommu2.h
index d746047..10ad05f 100644
--- a/arch/arm/plat-omap/include/mach/iommu2.h
+++ b/arch/arm/plat-omap/include/mach/iommu2.h
@@ -13,6 +13,8 @@
 #ifndef __MACH_IOMMU2_H
 #define __MACH_IOMMU2_H
 
+#include <linux/io.h>
+
 /*
  * MMU Register offsets
  */
diff --git a/arch/arm/plat-omap/include/mach/irqs.h b/arch/arm/plat-omap/include/mach/irqs.h
index c9a5b19..f775408 100644
--- a/arch/arm/plat-omap/include/mach/irqs.h
+++ b/arch/arm/plat-omap/include/mach/irqs.h
@@ -388,8 +388,10 @@
 #ifndef __ASSEMBLY__
 extern void omap_init_irq(void);
 extern int omap_irq_pending(void);
+void omap3_intc_autoidle(int enable);
 void omap3_intc_save_context(void);
 void omap3_intc_restore_context(void);
+void omap3_intc_suspend(void);
 #endif
 
 #include <mach/hardware.h>
diff --git a/arch/arm/plat-omap/include/mach/isp_user.h b/arch/arm/plat-omap/include/mach/isp_user.h
index b819e26..c517f99 100644
--- a/arch/arm/plat-omap/include/mach/isp_user.h
+++ b/arch/arm/plat-omap/include/mach/isp_user.h
@@ -38,6 +38,26 @@
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 8, struct af_configuration)
 #define VIDIOC_PRIVATE_ISP_AF_REQ \
 	_IOWR('V', BASE_VIDIOC_PRIVATE + 9, struct isp_af_data)
+#define VIDIOC_PRIVATE_OMAP34XXCAM_SENSOR_INFO	\
+	_IOWR('V', BASE_VIDIOC_PRIVATE + 10, struct omap34xxcam_sensor_info)
+
+/*
+ *	P R I V A T E   E V E N T S
+ */
+
+#define V4L2_EVENT_OMAP3ISP_CLASS	(V4L2_EVENT_PRIVATE_START | 0x100)
+#define V4L2_EVENT_OMAP3ISP_AEWB	(V4L2_EVENT_OMAP3ISP_CLASS | 0x1)
+#define V4L2_EVENT_OMAP3ISP_AF		(V4L2_EVENT_OMAP3ISP_CLASS | 0x2)
+#define V4L2_EVENT_OMAP3ISP_HIST	(V4L2_EVENT_OMAP3ISP_CLASS | 0x3)
+#define V4L2_EVENT_OMAP3ISP_HS_VS	(V4L2_EVENT_OMAP3ISP_CLASS | 0x4)
+
+/* Structre for getting Sensor Information*/
+struct omap34xxcam_sensor_info {
+	__u32 current_xclk;
+	struct v4l2_rect active_size;
+	struct v4l2_rect full_size;
+	struct v4l2_rect pixel_size;
+};
 
 /* AE/AWB related structures and flags*/
 
@@ -157,41 +177,57 @@
 
 
 /* Histogram related structs */
+
 /* Flags for number of bins */
-#define BINS_32			0x0
-#define BINS_64			0x1
-#define BINS_128		0x2
-#define BINS_256		0x3
+#define HIST_BINS_32		0
+#define HIST_BINS_64		1
+#define HIST_BINS_128		2
+#define HIST_BINS_256		3
+#define HIST_MEM_SIZE_BINS(n)	((n)*16)
+
+#define HIST_MEM_SIZE		1024
+#define HIST_MIN_REGIONS	1
+#define HIST_MAX_REGIONS	4
+#define HIST_MAX_WB_GAIN	255
+#define HIST_MIN_WB_GAIN	0
+#define HIST_MAX_BIT_WIDTH	14
+#define HIST_MIN_BIT_WIDTH	8
+#define HIST_MAX_BUFF		5
+#define HIST_MAX_WG		4
+
+/* Source */
+#define HIST_SOURCE_CCDC	0
+#define HIST_SOURCE_MEM		1
+
+/* CFA pattern */
+#define HIST_CFA_BAYER		0
+#define HIST_CFA_FOVEONX3	1
 
 struct isp_hist_config {
-	__u8 hist_source;		/* CCDC or Memory */
+	__u8 enable;
+	__u8 source;		/* CCDC or memory */
 	__u8 input_bit_width;	/* Needed o know the size per pixel */
-	__u8 hist_frames;		/* Num of frames to be processed and
-				 * accumulated
-				 */
+	__u8 num_acc_frames;	/* Num of frames to be processed and accumulated
+				   for each generated histogram frame */
 	__u8 hist_h_v_info;	/* frame-input width and height if source is
-				 * memory
-				 */
-	__u16 hist_radd;		/* frame-input address in memory */
+				 * memory */
+	__u16 hist_radd;	/* frame-input address in memory */
 	__u16 hist_radd_off;	/* line-offset for frame-input */
 	__u16 hist_bins;	/* number of bins: 32, 64, 128, or 256 */
-	__u16 wb_gain_R;	/* White Balance Field-to-Pattern Assignments */
-	__u16 wb_gain_RG;	/* White Balance Field-to-Pattern Assignments */
-	__u16 wb_gain_B;	/* White Balance Field-to-Pattern Assignments */
-	__u16 wb_gain_BG;	/* White Balance Field-to-Pattern Assignments */
-	__u8 num_regions;		/* number of regions to be configured */
-	__u16 reg0_hor;		/* Region 0 size and position */
-	__u16 reg0_ver;		/* Region 0 size and position */
-	__u16 reg1_hor;		/* Region 1 size and position */
-	__u16 reg1_ver;		/* Region 1 size and position */
-	__u16 reg2_hor;		/* Region 2 size and position */
-	__u16 reg2_ver;		/* Region 2 size and position */
-	__u16 reg3_hor;		/* Region 3 size and position */
-	__u16 reg3_ver;		/* Region 3 size and position */
+	__u8 cfa;		/* BAYER or FOVEON X3 */
+	__u8 wg[HIST_MAX_WG];	/* White Balance Gain */
+	__u8 num_regions;	/* number of regions to be configured */
+	__u32 reg_hor[HIST_MAX_REGIONS];	/* Regions size and position */
+	__u32 reg_ver[HIST_MAX_REGIONS];	/* Regions size and position */
 };
 
 struct isp_hist_data {
 	__u32 *hist_statistics_buf;	/* Pointer to pass to user */
+	__u8 update;
+	__u16 frame_number;
+	__u16 curr_frame;
+	__u32 config_counter;
+	struct timeval ts;
 };
 
 /* Auto Focus related structs */
diff --git a/arch/arm/plat-omap/include/mach/mcbsp.h b/arch/arm/plat-omap/include/mach/mcbsp.h
index ec61b89..2d3c499 100644
--- a/arch/arm/plat-omap/include/mach/mcbsp.h
+++ b/arch/arm/plat-omap/include/mach/mcbsp.h
@@ -136,6 +136,7 @@
 #define OMAP_MCBSP_REG_XCERG	0x74
 #define OMAP_MCBSP_REG_XCERH	0x78
 #define OMAP_MCBSP_REG_SYSCON	0x8C
+#define OMAP_MCBSP_REG_THRSH2	0x90
 #define OMAP_MCBSP_REG_WAKEUPEN	0xA8
 #define OMAP_MCBSP_REG_XCCR	0xAC
 #define OMAP_MCBSP_REG_RCCR	0xB0
@@ -298,6 +299,7 @@
 	u16 xcerh;
 	u16 xccr;
 	u16 rccr;
+	u16 wken;
 };
 
 typedef enum {
@@ -308,6 +310,20 @@
 	OMAP_MCBSP5
 } omap_mcbsp_id;
 
+/* McBSP threshold */
+#if defined(CONFIG_ARCH_OMAP34XX)
+static const int omap34xx_mcbsp_thresholds[][2] = {
+	{ 0, 0 },
+	{ 1260, 0},
+	{ 0, 0},
+	{ 0, 0},
+	{ 0, 0},
+};
+#else
+static const int omap34xx_mcbsp_thresholds[][2] = {};
+#endif
+
+
 typedef int __bitwise omap_mcbsp_io_type_t;
 #define OMAP_MCBSP_IRQ_IO ((__force omap_mcbsp_io_type_t) 1)
 #define OMAP_MCBSP_POLL_IO ((__force omap_mcbsp_io_type_t) 2)
@@ -409,8 +425,10 @@
 void omap_mcbsp_config(unsigned int id, const struct omap_mcbsp_reg_cfg * config);
 int omap_mcbsp_request(unsigned int id);
 void omap_mcbsp_free(unsigned int id);
-void omap_mcbsp_start(unsigned int id);
-void omap_mcbsp_stop(unsigned int id);
+void omap_mcbsp_disable_fclk(unsigned int id);
+void omap_mcbsp_enable_fclk(unsigned int id);
+void omap_mcbsp_start(unsigned int id, int tx, int rx);
+void omap_mcbsp_stop(unsigned int id, int tx, int rx);
 void omap_mcbsp_xmit_word(unsigned int id, u32 word);
 u32 omap_mcbsp_recv_word(unsigned int id);
 
@@ -418,6 +436,7 @@
 int omap_mcbsp_recv_buffer(unsigned int id, dma_addr_t buffer, unsigned int length);
 int omap_mcbsp_spi_master_xmit_word_poll(unsigned int id, u32 word);
 int omap_mcbsp_spi_master_recv_word_poll(unsigned int id, u32 * word);
+void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold);
 
 
 /* SPI specific API */
diff --git a/arch/arm/plat-omap/include/mach/mmc.h b/arch/arm/plat-omap/include/mach/mmc.h
index 94617d3..22154f0 100644
--- a/arch/arm/plat-omap/include/mach/mmc.h
+++ b/arch/arm/plat-omap/include/mach/mmc.h
@@ -64,6 +64,10 @@
 
 	/* To get the OFF mode counter */
 	unsigned (*context_loss) (struct device *dev);
+	/* Setup the vdd1 opp */
+	void (*set_vdd1_opp) (struct device *dev, unsigned long);
+	unsigned long max_vdd1_opp;
+	unsigned long min_vdd1_opp;
 
 	u64 dma_mask;
 
diff --git a/arch/arm/plat-omap/include/mach/mux.h b/arch/arm/plat-omap/include/mach/mux.h
index 3cf9467..dfe50e5 100644
--- a/arch/arm/plat-omap/include/mach/mux.h
+++ b/arch/arm/plat-omap/include/mach/mux.h
@@ -826,6 +826,7 @@
 	AH17_34XX_GPIO100,
 	B24_34XX_GPIO101,
 	B24_34XX_GPIO101_OUT,
+	B25_34XX_GPIO109,
 	B26_34XX_GPIO111,
 	AG4_34XX_GPIO134_OUT,
 	AE4_34XX_GPIO136_OUT,
@@ -871,6 +872,10 @@
 	AH4_3430_MMC2_DAT1,
 	AG4_3430_MMC2_DAT2,
 	AF4_3430_MMC2_DAT3,
+	AE4_3430_MMC2_DAT4,
+	AH3_3430_MMC2_DAT5,
+	AF3_3430_MMC2_DAT6,
+	AE3_3430_MMC2_DAT7,
 
 	/* MMC3 */
 	AF10_3430_MMC3_CLK,
@@ -944,6 +949,8 @@
 
 	/* SYS_NIRQ T2 INT1 */
 	AF26_34XX_SYS_NIRQ,
+	D25_34XX_GPIO126,
+	R8_34XX_GPIO56_TRISTATE,
 };
 
 struct omap_mux_cfg {
diff --git a/arch/arm/plat-omap/include/mach/nand.h b/arch/arm/plat-omap/include/mach/nand.h
index 631a7be..1612e35 100644
--- a/arch/arm/plat-omap/include/mach/nand.h
+++ b/arch/arm/plat-omap/include/mach/nand.h
@@ -18,7 +18,11 @@
 	int			nr_parts;
 	int			(*nand_setup)(void __iomem *);
 	int			(*dev_ready)(struct omap_nand_platform_data *);
+	int			(*unlock)(struct mtd_info *, loff_t, size_t);
+	void			(*board_unlock)(struct mtd_info *,
+					struct device *);
 	int			dma_channel;
 	void __iomem		*gpmc_cs_baseaddr;
 	void __iomem		*gpmc_baseaddr;
+	int			ecc_opt; /* 0x0 - sw ecc, 0x1 - hw ecc */
 };
diff --git a/arch/arm/plat-omap/include/mach/omap-pm.h b/arch/arm/plat-omap/include/mach/omap-pm.h
index f690a05..26f8ee0 100644
--- a/arch/arm/plat-omap/include/mach/omap-pm.h
+++ b/arch/arm/plat-omap/include/mach/omap-pm.h
@@ -273,6 +273,63 @@
  */
 
 /**
+ * omap_pm_get_max_vdd1_opp - get the maximum supported VDD1 OPP number
+ *
+ * Report the maximum  VDD1 OPP number.
+ *
+ * Returns the maximum supported VDD1 OPP number.
+ */
+u8 omap_pm_get_max_vdd1_opp(void);
+
+
+/**
+ * omap_pm_get_min_vdd1_opp - get the minimum supported VDD1 OPP number
+ *
+ * Report the minimum  VDD1 OPP number.
+ *
+ * Returns the minimum supported VDD1 OPP number.
+ */
+u8 omap_pm_get_min_vdd1_opp(void);
+
+
+/**
+ * omap_pm_get_max_vdd2_opp - get the maximum supported VDD2 OPP number
+ *
+ * Report the maximum  VDD2 OPP number.
+ *
+ * Returns the maximum supported VDD2 OPP number.
+ */
+u8 omap_pm_get_max_vdd2_opp(void);
+
+
+/**
+ * omap_pm_get_min_vdd2_opp - get the minimum supported VDD2 OPP number
+ *
+ * Report the minimum  VDD2 OPP number.
+ *
+ * Returns the minimum supported VDD2 OPP number.
+ */
+u8 omap_pm_get_min_vdd2_opp(void);
+
+/**
+ * omap_get_mpu_rate_table - get the mpu OPP table
+ *
+ * returns mpu rate table.
+ *
+ * Returns the pointer to rate table
+ */
+struct omap_opp *omap_get_mpu_rate_table(void);
+
+/**
+ * omap_get_dsp_rate_table - get the dsp OPP table
+ *
+ * returns dsp rate table.
+ *
+ * Returns the pointer to rate table
+ */
+struct omap_opp *omap_get_dsp_rate_table(void);
+
+/**
  * omap_pm_cpu_get_freq_table - return a cpufreq_frequency_table array ptr
  *
  * Provide a frequency table usable by CPUFreq for the current chip/board.
@@ -293,13 +350,24 @@
 void omap_pm_cpu_set_freq(unsigned long f);
 
 /**
+ * omap_pm_set_min_mpu_freq - set the current minimum MPU frequency
+ * @f: MPU frequency in Hz
+ * @dev: struct device *
+ *
+ * Set the current minimum CPU frequency.  The actual CPU frequency
+ * used could end up higher if the DSP requested a higher OPP.
+ * Intended to be called by all Kernel components.  No
+ * return value.
+ */
+void omap_pm_set_min_mpu_freq(struct device *dev, unsigned long f);
+
+/**
  * omap_pm_cpu_get_freq - report the current CPU frequency
  *
  * Returns the current MPU frequency, or 0 upon error.
  */
 unsigned long omap_pm_cpu_get_freq(void);
 
-
 /*
  * Device context loss tracking
  */
diff --git a/arch/arm/plat-omap/include/mach/omap-serial.h b/arch/arm/plat-omap/include/mach/omap-serial.h
index 45aa4a4..cc94e66 100644
--- a/arch/arm/plat-omap/include/mach/omap-serial.h
+++ b/arch/arm/plat-omap/include/mach/omap-serial.h
@@ -33,11 +33,8 @@
 					         IO_ADDRESS(OMAP_UART3_BASE) ))
 extern unsigned int fcr[MAX_UARTS];
 
-/* This allows the OMAP to wake-up from the UARTs[cts line],
- * the definition should come from drivers/serial/omap-serial.c
- * BT in that case uses UART2 [uart_no=1], and state=1[enable]
- */
-extern int omap24xx_uart_cts_wakeup(int uart_no, int state);
+int omap_uart_active(int num);
+int omap_uart_cts_wakeup(int uart_no, int state);
 
 #endif /* __OMAP_SERIAL_H__ */
 
diff --git a/arch/arm/plat-omap/include/mach/omap34xx.h b/arch/arm/plat-omap/include/mach/omap34xx.h
index 8535173..b7cbfc0 100644
--- a/arch/arm/plat-omap/include/mach/omap34xx.h
+++ b/arch/arm/plat-omap/include/mach/omap34xx.h
@@ -23,12 +23,10 @@
 
 #ifndef __ASM_ARCH_OMAP34XX_H
 #define __ASM_ARCH_OMAP34XX_H
-
 /*
  * Please place only base defines here and put the rest in device
  * specific headers.
  */
-
 #define L4_34XX_BASE		0x48000000
 #define L4_WK_34XX_BASE		0x48300000
 #define L4_WK_OMAP_BASE		L4_WK_34XX_BASE
@@ -62,6 +60,7 @@
 #define OMAP3430_ISP_MMU_BASE		(OMAP3430_ISP_BASE + 0x1400)
 #define OMAP3430_ISP_CSI2A_BASE		(OMAP3430_ISP_BASE + 0x1800)
 #define OMAP3430_ISP_CSI2PHY_BASE	(OMAP3430_ISP_BASE + 0x1970)
+#define OMAP3430_ISP_CSI2PHY2_BASE      (OMAP3430_ISP_BASE + 0x1D70)
 
 #define OMAP3430_ISP_END		(OMAP3430_ISP_BASE         + 0x06F)
 #define OMAP3430_ISP_CBUFF_END		(OMAP3430_ISP_CBUFF_BASE   + 0x077)
@@ -75,6 +74,7 @@
 #define OMAP3430_ISP_MMU_END		(OMAP3430_ISP_MMU_BASE     + 0x06F)
 #define OMAP3430_ISP_CSI2A_END		(OMAP3430_ISP_CSI2A_BASE   + 0x16F)
 #define OMAP3430_ISP_CSI2PHY_END	(OMAP3430_ISP_CSI2PHY_BASE + 0x007)
+#define OMAP3430_ISP_CSI2PHY2_END       (OMAP3430_ISP_CSI2PHY2_BASE + 0x007)
 
 #define OMAP34XX_IVA_INTC_BASE	0x40000000
 #define OMAP34XX_HSUSB_OTG_BASE	(L4_34XX_BASE + 0xAB000)
@@ -110,16 +110,19 @@
 #define VDD1_OPP3	0x3
 #define VDD1_OPP4	0x4
 #define VDD1_OPP5	0x5
+#define VDD1_OPP6	0x6
 
 /* VDD2 OPPS */
 #define VDD2_OPP1	0x1
 #define VDD2_OPP2	0x2
 #define VDD2_OPP3	0x3
+#define VDD2_OPP4	0x4
 
-#define MIN_VDD1_OPP	VDD1_OPP1
-#define MAX_VDD1_OPP	VDD1_OPP5
-#define MIN_VDD2_OPP	VDD2_OPP1
-#define MAX_VDD2_OPP	VDD2_OPP3
+#define MIN_VDD1_OPP	(omap_pm_get_min_vdd1_opp())
+#define MAX_VDD1_OPP	(omap_pm_get_max_vdd1_opp())
+#define MIN_VDD2_OPP	(omap_pm_get_min_vdd2_opp())
+#define MAX_VDD2_OPP	(omap_pm_get_max_vdd2_opp())
+#define VDD1_THRESHOLD  MAX_VDD2_OPP
 
 #endif /* __ASM_ARCH_OMAP34XX_H */
 
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/mach/powerdomain.h
index 6271d85..bae4e7d 100644
--- a/arch/arm/plat-omap/include/mach/powerdomain.h
+++ b/arch/arm/plat-omap/include/mach/powerdomain.h
@@ -37,6 +37,8 @@
 
 #define PWRSTS_OFF_RET_ON	(PWRSTS_OFF_RET | (1 << PWRDM_POWER_ON))
 
+#define PWRSTS_OFF_RET_INA_ON	(PWRSTS_OFF_RET_ON | \
+				 (1 << PWRDM_POWER_INACTIVE))
 
 /* Powerdomain flags */
 #define PWRDM_HAS_HDWR_SAR	(1 << 0) /* hardware save-and-restore support */
@@ -53,6 +55,11 @@
  * CORE powerdomain on OMAP3 is the worst case
  */
 #define PWRDM_MAX_CLKDMS	4
+/*
+ * Maximum number of FCLK register masks that can be associated with a
+ * powerdomain. CORE powerdomain on OMAP3 is the worst case
+ */
+#define PWRDM_MAX_FCLK		2
 
 /* XXX A completely arbitrary number. What is reasonable here? */
 #define PWRDM_TRANSITION_BAILOUT 100000
@@ -117,9 +124,14 @@
 
 	struct list_head node;
 
-	int state;
+	s8 state;
+	s8 next_state;
 	unsigned state_counter[4];
+	unsigned ret_logic_off_counter;
+	unsigned ret_mem_off_counter;
 
+	u8 fclk_reg_amt;
+	u32 fclk_masks[PWRDM_MAX_FCLK];
 #ifdef CONFIG_PM_DEBUG
 	s64 timer;
 	s64 state_timer[4];
@@ -135,6 +147,8 @@
 
 int pwrdm_for_each(int (*fn)(struct powerdomain *pwrdm, void *user),
 			void *user);
+int pwrdm_for_each_nolock(int (*fn)(struct powerdomain *pwrdm, void *user),
+			void *user);
 
 int pwrdm_add_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
 int pwrdm_del_clkdm(struct powerdomain *pwrdm, struct clockdomain *clkdm);
@@ -163,14 +177,17 @@
 
 int pwrdm_read_logic_pwrst(struct powerdomain *pwrdm);
 int pwrdm_read_prev_logic_pwrst(struct powerdomain *pwrdm);
+int pwrdm_read_next_logic_pwrst(struct powerdomain *pwrdm);
 int pwrdm_read_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
 int pwrdm_read_prev_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
+int pwrdm_read_next_mem_pwrst(struct powerdomain *pwrdm, u8 bank);
 
 int pwrdm_enable_hdwr_sar(struct powerdomain *pwrdm);
 int pwrdm_disable_hdwr_sar(struct powerdomain *pwrdm);
 bool pwrdm_has_hdwr_sar(struct powerdomain *pwrdm);
 
 int pwrdm_wait_transition(struct powerdomain *pwrdm);
+int pwrdm_can_idle(struct powerdomain *pwrdm);
 
 int pwrdm_state_switch(struct powerdomain *pwrdm);
 int pwrdm_clkdm_state_switch(struct clockdomain *clkdm);
diff --git a/arch/arm/plat-omap/include/mach/prcm.h b/arch/arm/plat-omap/include/mach/prcm.h
index d0cbe80..d28fda4 100644
--- a/arch/arm/plat-omap/include/mach/prcm.h
+++ b/arch/arm/plat-omap/include/mach/prcm.h
@@ -35,6 +35,10 @@
 
 void omap3_prcm_save_context(void);
 void omap3_prcm_restore_context(void);
+
+/* SMC core off notification defines */
+#define PRCM_ENTER_OFF	1
+#define PRCM_EXIT_OFF	0
 #endif
 
 
diff --git a/arch/arm/plat-omap/include/mach/resource.h b/arch/arm/plat-omap/include/mach/resource.h
index f91d8ce..f5d7f26 100644
--- a/arch/arm/plat-omap/include/mach/resource.h
+++ b/arch/arm/plat-omap/include/mach/resource.h
@@ -25,7 +25,12 @@
 #include <linux/device.h>
 #include <mach/cpu.h>
 
-#define RES_DEFAULTLEVEL	0x0
+#define RES_PERFORMANCE_DEFAULTLEVEL	0
+#define RES_LATENCY_DEFAULTLEVEL	-1
+
+/* Types of resources */
+#define RES_TYPE_PERFORMANCE	0x1
+#define RES_TYPE_LATENCY	0x2
 
 struct shared_resource_ops; /* forward declaration */
 
@@ -35,6 +40,8 @@
 	char *name;
 	/* Used to represent the OMAP chip types containing this res */
 	const struct omap_chip_id omap_chip;
+	/* Resource type flags */
+	const u8 flags;
 	/* Total no of users at any point of this resource */
 	u8 no_of_users;
 	/* Current level of this resource */
@@ -46,6 +53,8 @@
 	/* Shared resource operations */
 	struct shared_resource_ops *ops;
 	struct list_head node;
+	/* Protect each resource */
+	struct mutex resource_mutex;
 };
 
 struct shared_resource_ops {
diff --git a/arch/arm/plat-omap/include/mach/sdrc.h b/arch/arm/plat-omap/include/mach/sdrc.h
index 4af5c6a..0b13837 100644
--- a/arch/arm/plat-omap/include/mach/sdrc.h
+++ b/arch/arm/plat-omap/include/mach/sdrc.h
@@ -44,6 +44,7 @@
 #define SDRC_RFR_CTRL_1		0x0D4
 #define SDRC_MANUAL_1		0x0D8
 
+#define SDRC_POWER_SRFRONRESET_SHIFT	7
 #define SDRC_POWER_AUTOCOUNT_SHIFT	8
 #define SDRC_POWER_AUTOCOUNT_MASK	(0xffff << SDRC_POWER_AUTOCOUNT_SHIFT)
 #define SDRC_POWER_CLKCTRL_SHIFT	4
@@ -87,7 +88,11 @@
 
 #define OMAP242X_SMS_REGADDR(reg)	IO_ADDRESS(OMAP2420_SMS_BASE + reg)
 #define OMAP243X_SMS_REGADDR(reg)	IO_ADDRESS(OMAP243X_SMS_BASE + reg)
+#ifdef __ASSEMBLER__
+#define OMAP343X_SMS_REGADDR(reg)	L3_IO_ADDRESS(OMAP343X_SMS_BASE + reg)
+#else
 #define OMAP343X_SMS_REGADDR(reg)	IO_ADDRESS(OMAP343X_SMS_BASE + reg)
+#endif
 
 /* SMS register offsets - read/write with sms_{read,write}_reg() */
 
diff --git a/arch/arm/plat-omap/include/mach/serial.h b/arch/arm/plat-omap/include/mach/serial.h
index 4f877ad..4da9721 100644
--- a/arch/arm/plat-omap/include/mach/serial.h
+++ b/arch/arm/plat-omap/include/mach/serial.h
@@ -28,7 +28,7 @@
 #define OMAP_UART_EXT_BASE	0x10000000
 #endif
 
-#ifdef CONFIG_MACH_OMAP_ZOOM2
+#if defined(CONFIG_MACH_OMAP_ZOOM2) || defined(CONFIG_MACH_OMAP_ZOOM3)
 #define OMAP_MAX_NR_PORTS	4
 #else
 #define OMAP_MAX_NR_PORTS	3
@@ -50,9 +50,9 @@
 extern int omap_uart_can_sleep(void);
 extern void omap_uart_check_wakeup(void);
 extern void omap_uart_prepare_suspend(void);
-extern void omap_uart_prepare_idle(int num);
+extern void omap_uart_prepare_idle(int num, int power_state);
 extern void omap_uart_resume_idle(int num);
-extern void omap_uart_enable_irqs(int enable);
+extern int omap_uart_enable_irqs(int enable);
 #endif
 
 #endif
diff --git a/arch/arm/plat-omap/include/mach/sram.h b/arch/arm/plat-omap/include/mach/sram.h
index ad0a600..6a6c488 100644
--- a/arch/arm/plat-omap/include/mach/sram.h
+++ b/arch/arm/plat-omap/include/mach/sram.h
@@ -26,6 +26,9 @@
 				     u32 sdrc_actim_ctrlb, u32 m2,
 				     u32 unlock_dll, u32 f, u32 sdrc_mr,
 				     u32 inc);
+
+extern u32 omap3_configure_core_dpll_warmreset(void);
+
 extern void omap3_sram_restore_context(void);
 
 /* Do not use these */
@@ -68,6 +71,10 @@
 					  u32 inc);
 extern unsigned long omap3_sram_configure_core_dpll_sz;
 
+extern u32 omap3_sram_configure_core_dpll_warmreset(void);
+
+extern unsigned long omap3_sram_configure_core_dpll_warmreset_sz;
+
 #ifdef CONFIG_PM
 extern void omap_push_sram_idle(void);
 #else
diff --git a/arch/arm/plat-omap/include/mach/uncompress.h b/arch/arm/plat-omap/include/mach/uncompress.h
index 082c0cd..d29e4b4 100644
--- a/arch/arm/plat-omap/include/mach/uncompress.h
+++ b/arch/arm/plat-omap/include/mach/uncompress.h
@@ -46,8 +46,12 @@
 	uart = (volatile u8 *)(OMAP_UART3_BASE);
 #elif defined(CONFIG_OMAP_LL_DEBUG_UART2)
 	uart = (volatile u8 *)(OMAP_UART2_BASE);
-#else
+#elif defined(CONFIG_OMAP_LL_DEBUG_UART1)
 	uart = (volatile u8 *)(OMAP_UART1_BASE);
+#elif defined(CONFIG_OMAP_LL_DEBUG_NONE)
+	return;
+#else
+	return;
 #endif
 
 #ifdef CONFIG_ARCH_OMAP1
diff --git a/arch/arm/plat-omap/include/mach/usb.h b/arch/arm/plat-omap/include/mach/usb.h
index daedcb5..7293ab8 100644
--- a/arch/arm/plat-omap/include/mach/usb.h
+++ b/arch/arm/plat-omap/include/mach/usb.h
@@ -37,6 +37,18 @@
 }
 #endif	/* !OMAP1 && !EHCI */
 
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+extern void usb_ohci_init(void);
+#else
+static inline void usb_ohci_init(void)
+{
+}
+#endif	/* !OMAP1 && !OHCI */
+
+/* This is needed for OMAP3 errata 1.164: enabled autoidle can prevent sleep */
+extern void usb_musb_disable_autoidle(void);
+
+
 #endif	/* !OMAP1 */
 
 void omap_usb_init(struct omap_usb_config *pdata);
diff --git a/arch/arm/plat-omap/include/mach/vmalloc.h b/arch/arm/plat-omap/include/mach/vmalloc.h
index b97dfaf..9eebf62 100644
--- a/arch/arm/plat-omap/include/mach/vmalloc.h
+++ b/arch/arm/plat-omap/include/mach/vmalloc.h
@@ -17,5 +17,5 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  */
-#define VMALLOC_END	  (PAGE_OFFSET + 0x18000000)
+#define VMALLOC_END	  (PAGE_OFFSET + 0x38000000)
 
diff --git a/arch/arm/plat-omap/iommu-debug.c b/arch/arm/plat-omap/iommu-debug.c
new file mode 100644
index 0000000..9811c19
--- /dev/null
+++ b/arch/arm/plat-omap/iommu-debug.c
@@ -0,0 +1,334 @@
+/*
+ * omap iommu: debugfs interface
+ *
+ * Copyright (C) 2008-2009 Nokia Corporation
+ *
+ * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/uaccess.h>
+#include <linux/platform_device.h>
+#include <linux/debugfs.h>
+
+#include <mach/iommu.h>
+#include <mach/iovmm.h>
+
+#include "iopgtable.h"
+
+#define MAXCOLUMN 100 /* for short messages */
+
+static DEFINE_MUTEX(iommu_debug_lock);
+static char local_buffer[SZ_4K];
+
+static struct dentry *iommu_debug_root;
+
+static ssize_t debug_read_ver(struct file *file, char __user *userbuf,
+			      size_t count, loff_t *ppos)
+{
+	u32 ver = iommu_arch_version();
+	char buf[MAXCOLUMN], *p = buf;
+
+	p += sprintf(p, "H/W version: %d.%d\n", (ver >> 4) & 0xf , ver & 0xf);
+
+	return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
+}
+
+static ssize_t debug_read_regs(struct file *file, char __user *userbuf,
+			       size_t count, loff_t *ppos)
+{
+	struct iommu *obj = file->private_data;
+	char *p = local_buffer;
+	ssize_t bytes;
+
+	mutex_lock(&iommu_debug_lock);
+	p += iommu_dump_ctx(obj, p);
+	bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+					p - local_buffer);
+	mutex_unlock(&iommu_debug_lock);
+	return bytes;
+}
+
+static ssize_t debug_read_tlb(struct file *file, char __user *userbuf,
+			      size_t count, loff_t *ppos)
+{
+	struct iommu *obj = file->private_data;
+	char *p = local_buffer;
+	ssize_t bytes;
+
+	mutex_lock(&iommu_debug_lock);
+	p += sprintf(p, "%8s %8s\n", "cam:", "ram:");
+	p += sprintf(p, "-----------------------------------------\n");
+	p += dump_tlb_entries(obj, p);
+	bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+					p - local_buffer);
+	mutex_unlock(&iommu_debug_lock);
+	return bytes;
+}
+
+static ssize_t debug_write_pagetable(struct file *file,
+		     const char __user *userbuf, size_t count, loff_t *ppos)
+{
+	struct iotlb_entry e;
+	struct cr_regs cr;
+	int err;
+	struct iommu *obj = file->private_data;
+	char buf[MAXCOLUMN], *p = buf;
+
+	count = min(count, sizeof(buf));
+
+	mutex_lock(&iommu_debug_lock);
+	if (copy_from_user(p, userbuf, count)) {
+		mutex_unlock(&iommu_debug_lock);
+		return -EFAULT;
+	}
+
+	sscanf(p, "%x %x", &cr.cam, &cr.ram);
+	if (!cr.cam || !cr.ram) {
+		mutex_unlock(&iommu_debug_lock);
+		return -EINVAL;
+	}
+
+	iotlb_cr_to_e(&cr, &e);
+	err = iopgtable_store_entry(obj, &e);
+	if (err)
+		dev_err(obj->dev, "%s: fail to store cr\n", __func__);
+
+	mutex_unlock(&iommu_debug_lock);
+	return count;
+}
+
+static ssize_t debug_read_pagetable(struct file *file, char __user *userbuf,
+				    size_t count, loff_t *ppos)
+{
+	int i;
+	u32 *iopgd;
+	struct iommu *obj = file->private_data;
+	char *p = local_buffer;
+	ssize_t bytes;
+
+	mutex_lock(&iommu_debug_lock);
+
+	p += sprintf(p, "L: %8s %8s\n", "da:", "pa:");
+	p += sprintf(p, "-----------------------------------------\n");
+
+	spin_lock(&obj->page_table_lock);
+
+	iopgd = iopgd_offset(obj, 0);
+	for (i = 0; i < PTRS_PER_IOPGD; i++, iopgd++) {
+		int j;
+		u32 *iopte;
+
+		if (!*iopgd)
+			continue;
+
+		if (!(*iopgd & IOPGD_TABLE)) {
+			u32 da;
+
+			da = i << IOPGD_SHIFT;
+			p += sprintf(p, "1: %08x %08x\n", da, *iopgd);
+			continue;
+		}
+
+		iopte = iopte_offset(iopgd, 0);
+
+		for (j = 0; j < PTRS_PER_IOPTE; j++, iopte++) {
+			u32 da;
+
+			if (!*iopte)
+				continue;
+
+			da = (i << IOPGD_SHIFT) + (j << IOPTE_SHIFT);
+			p += sprintf(p, "2: %08x %08x\n", da, *iopte);
+		}
+	}
+	spin_unlock(&obj->page_table_lock);
+
+	bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+					p - local_buffer);
+	mutex_unlock(&iommu_debug_lock);
+	return bytes;
+}
+
+static ssize_t debug_read_mmap(struct file *file, char __user *userbuf,
+			       size_t count, loff_t *ppos)
+{
+	struct iommu *obj = file->private_data;
+	char *p = local_buffer;
+	struct iovm_struct *tmp;
+	int uninitialized_var(i);
+	ssize_t bytes;
+
+	mutex_lock(&iommu_debug_lock);
+
+	p += sprintf(p, "%-3s %-8s %-8s %6s %8s\n",
+		     "No", "start", "end", "size", "flags");
+	p += sprintf(p, "-------------------------------------------------\n");
+
+	list_for_each_entry(tmp, &obj->mmap, list) {
+		size_t len;
+
+		len = tmp->da_end - tmp->da_start;
+		p += sprintf(p, "%3d %08x-%08x %6x %8x\n",
+			     i, tmp->da_start, tmp->da_end, len, tmp->flags);
+		i++;
+	}
+	bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+					p - local_buffer);
+	mutex_unlock(&iommu_debug_lock);
+	return bytes;
+}
+
+static ssize_t debug_read_mem(struct file *file, char __user *userbuf,
+			      size_t count, loff_t *ppos)
+{
+	struct iommu *obj = file->private_data;
+	char *p = local_buffer;
+	struct iovm_struct *area;
+	ssize_t bytes;
+
+	mutex_lock(&iommu_debug_lock);
+
+	area = find_iovm_area(obj, (u32)ppos);
+	if (IS_ERR(area)) {
+		mutex_unlock(&iommu_debug_lock);
+		return -EINVAL;
+	}
+	memcpy(p, area->va, count);
+	p += count;
+
+	bytes = simple_read_from_buffer(userbuf, count, ppos, local_buffer,
+					p - local_buffer);
+	mutex_unlock(&iommu_debug_lock);
+	return bytes;
+}
+
+static ssize_t debug_write_mem(struct file *file, const char __user *userbuf,
+			       size_t count, loff_t *ppos)
+{
+	struct iommu *obj = file->private_data;
+	struct iovm_struct *area;
+	char *p = local_buffer;
+
+	count = min(count, sizeof(local_buffer));
+
+	mutex_lock(&iommu_debug_lock);
+
+	if (copy_from_user(p, userbuf, count)) {
+		mutex_unlock(&iommu_debug_lock);
+		return -EFAULT;
+	}
+
+	area = find_iovm_area(obj, (u32)ppos);
+	if (IS_ERR(area)) {
+		mutex_unlock(&iommu_debug_lock);
+		return -EINVAL;
+	}
+	memcpy(area->va, p, count);
+	mutex_unlock(&iommu_debug_lock);
+	return count;
+}
+
+static int debug_open_generic(struct inode *inode, struct file *file)
+{
+	file->private_data = inode->i_private;
+	return 0;
+}
+
+#define DEBUG_FOPS(name)						\
+	static const struct file_operations debug_##name##_fops = {	\
+		.open = debug_open_generic,				\
+		.read = debug_read_##name,				\
+		.write = debug_write_##name,				\
+	};
+
+#define DEBUG_FOPS_RO(name)						\
+	static const struct file_operations debug_##name##_fops = {	\
+		.open = debug_open_generic,				\
+		.read = debug_read_##name,				\
+	};
+
+DEBUG_FOPS_RO(ver);
+DEBUG_FOPS_RO(regs);
+DEBUG_FOPS_RO(tlb);
+DEBUG_FOPS(pagetable);
+DEBUG_FOPS_RO(mmap);
+DEBUG_FOPS(mem);
+
+#define __DEBUG_ADD_FILE(attr, mode)					\
+	{								\
+		struct dentry *dent;					\
+		dent = debugfs_create_file(#attr, mode, parent,		\
+					   obj, &debug_##attr##_fops);	\
+		if (!dent)						\
+			return -ENOMEM;					\
+	}
+
+#define DEBUG_ADD_FILE(name) __DEBUG_ADD_FILE(name, 600)
+#define DEBUG_ADD_FILE_RO(name) __DEBUG_ADD_FILE(name, 400)
+
+static int iommu_debug_register(struct device *dev, void *data)
+{
+	struct platform_device *pdev = to_platform_device(dev);
+	struct iommu *obj = platform_get_drvdata(pdev);
+	struct dentry *d, *parent;
+
+	if (!obj || !obj->dev)
+		return -EINVAL;
+
+	d = debugfs_create_dir(obj->name, iommu_debug_root);
+	if (!d)
+		return -ENOMEM;
+	parent = d;
+
+	d = debugfs_create_u8("nr_tlb_entries", 400, parent,
+			      (u8 *)&obj->nr_tlb_entries);
+	if (!d)
+		return -ENOMEM;
+
+	DEBUG_ADD_FILE_RO(ver);
+	DEBUG_ADD_FILE_RO(regs);
+	DEBUG_ADD_FILE_RO(tlb);
+	DEBUG_ADD_FILE(pagetable);
+	DEBUG_ADD_FILE_RO(mmap);
+	DEBUG_ADD_FILE(mem);
+
+	return 0;
+}
+
+static int __init iommu_debug_init(void)
+{
+	struct dentry *d;
+	int err;
+
+	d = debugfs_create_dir("iommu", NULL);
+	if (!d)
+		return -ENOMEM;
+	iommu_debug_root = d;
+
+	err = foreach_iommu_device(d, iommu_debug_register);
+	if (err)
+		goto err_out;
+	return 0;
+
+err_out:
+	debugfs_remove_recursive(iommu_debug_root);
+	return err;
+}
+module_init(iommu_debug_init)
+
+static void __exit iommu_debugfs_exit(void)
+{
+	debugfs_remove_recursive(iommu_debug_root);
+}
+module_exit(iommu_debugfs_exit)
+
+MODULE_DESCRIPTION("omap iommu: debugfs interface");
+MODULE_AUTHOR("Hiroshi DOYU <Hiroshi.DOYU@nokia.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/arch/arm/plat-omap/iommu.c b/arch/arm/plat-omap/iommu.c
index e638883..d1a0661 100644
--- a/arch/arm/plat-omap/iommu.c
+++ b/arch/arm/plat-omap/iommu.c
@@ -1,7 +1,7 @@
 /*
  * omap iommu: tlb and pagetable primitives
  *
- * Copyright (C) 2008-2009 Nokia Corporation
+ * Copyright (C) 2008-2010 Nokia Corporation
  *
  * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>,
  *		Paul Mundt and Toshihiro Kobayashi
@@ -18,10 +18,8 @@
 #include <linux/clk.h>
 #include <linux/platform_device.h>
 
-#include <asm/io.h>
 #include <asm/cacheflush.h>
 
-#include <mach/clock.h>
 #include <mach/iommu.h>
 
 #include "iopgtable.h"
@@ -33,7 +31,7 @@
 static struct kmem_cache *iopte_cachep;
 
 /**
- * install_iommu_arch() - Install archtecure specific iommu functions
+ * install_iommu_arch - Install archtecure specific iommu functions
  * @ops:	a pointer to architecture specific iommu functions
  *
  * There are several kind of iommu algorithm(tlb, pagetable) among
@@ -50,7 +48,7 @@
 EXPORT_SYMBOL_GPL(install_iommu_arch);
 
 /**
- * uninstall_iommu_arch() - Uninstall archtecure specific iommu functions
+ * uninstall_iommu_arch - Uninstall archtecure specific iommu functions
  * @ops:	a pointer to architecture specific iommu functions
  *
  * This interface uninstalls the iommu algorighm installed previously.
@@ -65,7 +63,7 @@
 EXPORT_SYMBOL_GPL(uninstall_iommu_arch);
 
 /**
- * iommu_save_ctx() - Save registers for pm off-mode support
+ * iommu_save_ctx - Save registers for pm off-mode support
  * @obj:	target iommu
  **/
 void iommu_save_ctx(struct iommu *obj)
@@ -75,7 +73,7 @@
 EXPORT_SYMBOL_GPL(iommu_save_ctx);
 
 /**
- * iommu_restore_ctx() - Restore registers for pm off-mode support
+ * iommu_restore_ctx - Restore registers for pm off-mode support
  * @obj:	target iommu
  **/
 void iommu_restore_ctx(struct iommu *obj)
@@ -85,7 +83,7 @@
 EXPORT_SYMBOL_GPL(iommu_restore_ctx);
 
 /**
- * iommu_arch_version() - Return running iommu arch version
+ * iommu_arch_version - Return running iommu arch version
  **/
 u32 iommu_arch_version(void)
 {
@@ -120,25 +118,16 @@
 	clk_disable(obj->clk);
 }
 
-#ifdef DEBUG
-static ssize_t iommu_dump_ctx(struct iommu *obj, char *buf)
-{
-	if (!obj || !buf)
-		return -EINVAL;
-
-	return arch_iommu->dump_ctx(obj, buf);
-}
-#endif
-
 /*
  *	TLB operations
  */
-static inline void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
+void iotlb_cr_to_e(struct cr_regs *cr, struct iotlb_entry *e)
 {
 	BUG_ON(!cr || !e);
 
 	arch_iommu->cr_to_e(cr, e);
 }
+EXPORT_SYMBOL_GPL(iotlb_cr_to_e);
 
 static inline int iotlb_cr_valid(struct cr_regs *cr)
 {
@@ -157,10 +146,11 @@
 	return arch_iommu->alloc_cr(obj, e);
 }
 
-static inline u32 iotlb_cr_to_virt(struct cr_regs *cr)
+u32 iotlb_cr_to_virt(struct cr_regs *cr)
 {
 	return arch_iommu->cr_to_virt(cr);
 }
+EXPORT_SYMBOL_GPL(iotlb_cr_to_virt);
 
 static u32 get_iopte_attr(struct iotlb_entry *e)
 {
@@ -210,21 +200,21 @@
 }
 
 /**
- * iotlb_dump_cr() - Dump an iommu tlb entry into buf
+ * iotlb_dump_cr - Dump an iommu tlb entry into buf
  * @obj:	target iommu
  * @cr:		contents of cam and ram register
  * @buf:	output buffer
  **/
-ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr, char *buf)
+static inline ssize_t iotlb_dump_cr(struct iommu *obj, struct cr_regs *cr,
+				    char *buf)
 {
 	BUG_ON(!cr || !buf);
 
 	return arch_iommu->dump_cr(obj, cr, buf);
 }
-EXPORT_SYMBOL_GPL(iotlb_dump_cr);
 
 /**
- * load_iotlb_entry() - Set an iommu tlb entry
+ * load_iotlb_entry - Set an iommu tlb entry
  * @obj:	target iommu
  * @e:		an iommu tlb entry info
  **/
@@ -277,7 +267,7 @@
 EXPORT_SYMBOL_GPL(load_iotlb_entry);
 
 /**
- * flush_iotlb_page() - Clear an iommu tlb entry
+ * flush_iotlb_page - Clear an iommu tlb entry
  * @obj:	target iommu
  * @da:		iommu device virtual address
  *
@@ -308,7 +298,7 @@
 		if ((start <= da) && (da < start + bytes)) {
 			dev_dbg(obj->dev, "%s: %08x<=%08x(%x)\n",
 				__func__, start, da, bytes);
-
+			iotlb_load_cr(obj, &cr);
 			iommu_write_reg(obj, 1, MMU_FLUSH_ENTRY);
 		}
 	}
@@ -320,7 +310,7 @@
 EXPORT_SYMBOL_GPL(flush_iotlb_page);
 
 /**
- * flush_iotlb_range() - Clear an iommu tlb entries
+ * flush_iotlb_range - Clear an iommu tlb entries
  * @obj:	target iommu
  * @start:	iommu device virtual address(start)
  * @end:	iommu device virtual address(end)
@@ -340,7 +330,7 @@
 EXPORT_SYMBOL_GPL(flush_iotlb_range);
 
 /**
- * flush_iotlb_all() - Clear all iommu tlb entries
+ * flush_iotlb_all - Clear all iommu tlb entries
  * @obj:	target iommu
  **/
 void flush_iotlb_all(struct iommu *obj)
@@ -359,6 +349,88 @@
 }
 EXPORT_SYMBOL_GPL(flush_iotlb_all);
 
+#if defined(CONFIG_OMAP_IOMMU_DEBUG_MODULE)
+
+ssize_t iommu_dump_ctx(struct iommu *obj, char *buf, ssize_t bytes)
+{
+	if (!obj || !buf)
+		return -EINVAL;
+
+	clk_enable(obj->clk);
+
+	bytes = arch_iommu->dump_ctx(obj, buf, bytes);
+
+	clk_disable(obj->clk);
+
+	return bytes;
+}
+EXPORT_SYMBOL_GPL(iommu_dump_ctx);
+
+static int __dump_tlb_entries(struct iommu *obj, struct cr_regs *crs, int num)
+{
+	int i;
+	struct iotlb_lock saved, l;
+	struct cr_regs *p = crs;
+
+	clk_enable(obj->clk);
+
+	iotlb_lock_get(obj, &saved);
+	memcpy(&l, &saved, sizeof(saved));
+
+	for (i = 0; i < num; i++) {
+		struct cr_regs tmp;
+
+		iotlb_lock_get(obj, &l);
+		l.vict = i;
+		iotlb_lock_set(obj, &l);
+		iotlb_read_cr(obj, &tmp);
+		if (!iotlb_cr_valid(&tmp))
+			continue;
+
+		*p++ = tmp;
+	}
+	iotlb_lock_set(obj, &saved);
+	clk_disable(obj->clk);
+
+	return  p - crs;
+}
+
+/**
+ * dump_tlb_entries - dump cr arrays to given buffer
+ * @obj:	target iommu
+ * @buf:	output buffer
+ **/
+size_t dump_tlb_entries(struct iommu *obj, char *buf, ssize_t bytes)
+{
+	int i, num;
+	struct cr_regs *cr;
+	char *p = buf;
+
+	num = bytes / sizeof(*cr);
+	num = min(obj->nr_tlb_entries, num);
+
+	cr = kcalloc(num, sizeof(*cr), GFP_KERNEL);
+	if (!cr)
+		return 0;
+
+	num = __dump_tlb_entries(obj, cr, num);
+	for (i = 0; i < num; i++)
+		p += iotlb_dump_cr(obj, cr + i, p);
+	kfree(cr);
+
+	return p - buf;
+}
+EXPORT_SYMBOL_GPL(dump_tlb_entries);
+
+int foreach_iommu_device(void *data, int (*fn)(struct device *, void *))
+{
+	return driver_for_each_device(&omap_iommu_driver.driver,
+				      NULL, data, fn);
+}
+EXPORT_SYMBOL_GPL(foreach_iommu_device);
+
+#endif /* CONFIG_OMAP_IOMMU_DEBUG_MODULE */
+
 /*
  *	H/W pagetable operations
  */
@@ -515,41 +587,8 @@
 	return err;
 }
 
-#ifdef DEBUG
-static void dump_tlb_entries(struct iommu *obj)
-{
-	int i;
-	struct iotlb_lock l;
-
-	clk_enable(obj->clk);
-
-	pr_info("%8s %8s\n", "cam:", "ram:");
-	pr_info("-----------------------------------------\n");
-
-	for (i = 0; i < obj->nr_tlb_entries; i++) {
-		struct cr_regs cr;
-		static char buf[4096];
-
-		iotlb_lock_get(obj, &l);
-		l.vict = i;
-		iotlb_lock_set(obj, &l);
-		iotlb_read_cr(obj, &cr);
-		if (!iotlb_cr_valid(&cr))
-			continue;
-
-		memset(buf, 0, 4096);
-		iotlb_dump_cr(obj, &cr, buf);
-		pr_err("%s", buf);
-	}
-
-	clk_disable(obj->clk);
-}
-#else
-static inline void dump_tlb_entries(struct iommu *obj) {}
-#endif
-
 /**
- * iopgtable_store_entry() - Make an iommu pte entry
+ * iopgtable_store_entry - Make an iommu pte entry
  * @obj:	target iommu
  * @e:		an iommu tlb entry info
  **/
@@ -559,7 +598,7 @@
 
 	flush_iotlb_page(obj, e->da);
 	err = iopgtable_store_entry_core(obj, e);
-#ifdef USE_IOTLB
+#ifdef PREFETCH_IOTLB
 	if (!err)
 		load_iotlb_entry(obj, e);
 #endif
@@ -568,7 +607,7 @@
 EXPORT_SYMBOL_GPL(iopgtable_store_entry);
 
 /**
- * iopgtable_lookup_entry() - Lookup an iommu pte entry
+ * iopgtable_lookup_entry - Lookup an iommu pte entry
  * @obj:	target iommu
  * @da:		iommu device virtual address
  * @ppgd:	iommu pgd entry pointer to be returned
@@ -607,7 +646,7 @@
 		if (*iopte & IOPTE_LARGE) {
 			nent *= 16;
 			/* rewind to the 1st entry */
-			iopte = (u32 *)((u32)iopte & IOLARGE_MASK);
+			iopte = iopte_offset(iopgd, (da & IOLARGE_MASK));
 		}
 		bytes *= nent;
 		memset(iopte, 0, nent * sizeof(*iopte));
@@ -625,10 +664,10 @@
 		nent = 1; /* for the next L1 entry */
 	} else {
 		bytes = IOPGD_SIZE;
-		if (*iopgd & IOPGD_SUPER) {
+		if ((*iopgd & IOPGD_SUPER) == IOPGD_SUPER) {
 			nent *= 16;
 			/* rewind to the 1st entry */
-			iopgd = (u32 *)((u32)iopgd & IOSUPER_MASK);
+			iopgd = iopgd_offset(obj, (da & IOSUPER_MASK));
 		}
 		bytes *= nent;
 	}
@@ -639,7 +678,7 @@
 }
 
 /**
- * iopgtable_clear_entry() - Remove an iommu pte entry
+ * iopgtable_clear_entry - Remove an iommu pte entry
  * @obj:	target iommu
  * @da:		iommu device virtual address
  **/
@@ -696,6 +735,9 @@
 	int err = -EIO;
 	struct iommu *obj = data;
 
+	if (!obj->refcount)
+		return IRQ_NONE;
+
 	/* Dynamic loading TLB or PTE */
 	if (obj->isr)
 		err = obj->isr(obj);
@@ -703,7 +745,9 @@
 	if (!err)
 		return IRQ_HANDLED;
 
+	clk_enable(obj->clk);
 	stat = iommu_report_fault(obj, &da);
+	clk_disable(obj->clk);
 	if (!stat)
 		return IRQ_HANDLED;
 
@@ -720,8 +764,6 @@
 	dev_err(obj->dev, "%s: da:%08x pgd:%p *pgd:%08x pte:%p *pte:%08x\n",
 		__func__, da, iopgd, *iopgd, iopte, *iopte);
 
-	dump_tlb_entries(obj);
-
 	return IRQ_NONE;
 }
 
@@ -736,7 +778,7 @@
 }
 
 /**
- * iommu_put() - Get iommu handler
+ * iommu_get - Get iommu handler
  * @name:	target iommu name
  **/
 struct iommu *iommu_get(const char *name)
@@ -773,13 +815,14 @@
 	if (obj->refcount == 1)
 		iommu_disable(obj);
 err_enable:
+	obj->refcount--;
 	mutex_unlock(&obj->iommu_lock);
 	return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(iommu_get);
 
 /**
- * iommu_put() - Put back iommu handler
+ * iommu_put - Put back iommu handler
  * @obj:	target iommu
  **/
 void iommu_put(struct iommu *obj)
@@ -928,8 +971,9 @@
 {
 	struct kmem_cache *p;
 	const unsigned long flags = SLAB_HWCACHE_ALIGN;
+	size_t align = 1 << 10; /* L2 pagetable alignement */
 
-	p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, 0, flags,
+	p = kmem_cache_create("iopte_cache", IOPTE_TABLE_SIZE, align, flags,
 			      iopte_cachep_ctor);
 	if (!p)
 		return -ENOMEM;
diff --git a/arch/arm/plat-omap/iopgtable.h b/arch/arm/plat-omap/iopgtable.h
index 37dac43..ab23b6a 100644
--- a/arch/arm/plat-omap/iopgtable.h
+++ b/arch/arm/plat-omap/iopgtable.h
@@ -1,7 +1,7 @@
 /*
  * omap iommu: pagetable definitions
  *
- * Copyright (C) 2008-2009 Nokia Corporation
+ * Copyright (C) 2008-2010 Nokia Corporation
  *
  * Written by Hiroshi DOYU <Hiroshi.DOYU@nokia.com>
  *
@@ -13,26 +13,52 @@
 #ifndef __PLAT_OMAP_IOMMU_H
 #define __PLAT_OMAP_IOMMU_H
 
+/*
+ * "L2 table" address mask and size definitions.
+ */
 #define IOPGD_SHIFT		20
-#define IOPGD_SIZE		(1 << IOPGD_SHIFT)
+#define IOPGD_SIZE		(1UL << IOPGD_SHIFT)
 #define IOPGD_MASK		(~(IOPGD_SIZE - 1))
-#define IOSECTION_MASK		IOPGD_MASK
-#define PTRS_PER_IOPGD		(1 << (32 - IOPGD_SHIFT))
-#define IOPGD_TABLE_SIZE	(PTRS_PER_IOPGD * sizeof(u32))
 
-#define IOSUPER_SIZE		(IOPGD_SIZE << 4)
+/*
+ * "section" address mask and size definitions.
+ */
+#define IOSECTION_SHIFT		20
+#define IOSECTION_SIZE		(1UL << IOSECTION_SHIFT)
+#define IOSECTION_MASK		(~(IOSECTION_SIZE - 1))
+
+/*
+ * "supersection" address mask and size definitions.
+ */
+#define IOSUPER_SHIFT		24
+#define IOSUPER_SIZE		(1UL << IOSUPER_SHIFT)
 #define IOSUPER_MASK		(~(IOSUPER_SIZE - 1))
 
-#define IOPTE_SHIFT		12
-#define IOPTE_SIZE		(1 << IOPTE_SHIFT)
-#define IOPTE_MASK		(~(IOPTE_SIZE - 1))
-#define IOPAGE_MASK		IOPTE_MASK
-#define PTRS_PER_IOPTE		(1 << (IOPGD_SHIFT - IOPTE_SHIFT))
-#define IOPTE_TABLE_SIZE	(PTRS_PER_IOPTE * sizeof(u32))
+#define PTRS_PER_IOPGD		(1UL << (32 - IOPGD_SHIFT))
+#define IOPGD_TABLE_SIZE	(PTRS_PER_IOPGD * sizeof(u32))
 
-#define IOLARGE_SIZE		(IOPTE_SIZE << 4)
+/*
+ * "small page" address mask and size definitions.
+ */
+#define IOPTE_SHIFT		12
+#define IOPTE_SIZE		(1UL << IOPTE_SHIFT)
+#define IOPTE_MASK		(~(IOPTE_SIZE - 1))
+
+/*
+ * "large page" address mask and size definitions.
+ */
+#define IOLARGE_SHIFT		16
+#define IOLARGE_SIZE		(1UL << IOLARGE_SHIFT)
 #define IOLARGE_MASK		(~(IOLARGE_SIZE - 1))
 
+#define PTRS_PER_IOPTE		(1UL << (IOPGD_SHIFT - IOPTE_SHIFT))
+#define IOPTE_TABLE_SIZE	(PTRS_PER_IOPTE * sizeof(u32))
+
+#define IOPAGE_MASK		IOPTE_MASK
+
+/*
+ * some descriptor attributes.
+ */
 #define IOPGD_TABLE		(1 << 0)
 #define IOPGD_SECTION		(2 << 0)
 #define IOPGD_SUPER		(1 << 18 | 2 << 0)
@@ -40,12 +66,14 @@
 #define IOPTE_SMALL		(2 << 0)
 #define IOPTE_LARGE		(1 << 0)
 
+/* to find an entry in a page-table-directory */
 #define iopgd_index(da)		(((da) >> IOPGD_SHIFT) & (PTRS_PER_IOPGD - 1))
 #define iopgd_offset(obj, da)	((obj)->iopgd + iopgd_index(da))
 
 #define iopte_paddr(iopgd)	(*iopgd & ~((1 << 10) - 1))
 #define iopte_vaddr(iopgd)	((u32 *)phys_to_virt(iopte_paddr(iopgd)))
 
+/* to find an entry in the second-level page table. */
 #define iopte_index(da)		(((da) >> IOPTE_SHIFT) & (PTRS_PER_IOPTE - 1))
 #define iopte_offset(iopgd, da)	(iopte_vaddr(iopgd) + iopte_index(da))
 
diff --git a/arch/arm/plat-omap/iovmm.c b/arch/arm/plat-omap/iovmm.c
index bdfbb09..6792f3d 100644
--- a/arch/arm/plat-omap/iovmm.c
+++ b/arch/arm/plat-omap/iovmm.c
@@ -15,8 +15,8 @@
 #include <linux/device.h>
 #include <linux/scatterlist.h>
 
-#include <asm/io.h>
 #include <asm/cacheflush.h>
+#include <asm/mach/map.h>
 
 #include <mach/iommu.h>
 #include <mach/iovmm.h>
@@ -47,7 +47,7 @@
  *	'va':	mpu virtual address
  *
  *	'c':	contiguous memory area
- *	'd':	dicontiguous memory area
+ *	'd':	discontiguous memory area
  *	'a':	anonymous memory allocation
  *	'()':	optional feature
  *
@@ -167,6 +167,11 @@
 	unsigned int i;
 	struct scatterlist *sg;
 	struct vm_struct *new;
+	const struct mem_type *mtype;
+
+	mtype = get_mem_type(MT_DEVICE);
+	if (!mtype)
+		return ERR_PTR(-EINVAL);
 
 	total = sgtable_len(sgt);
 	if (!total)
@@ -187,14 +192,15 @@
 
 		BUG_ON(bytes != PAGE_SIZE);
 
-		err = ioremap_page(va,  pa, MT_DEVICE);
+		err = ioremap_page(va,  pa, mtype);
 		if (err)
 			goto err_out;
 
 		va += bytes;
 	}
 
-	flush_cache_vmap(new->addr, total);
+	flush_cache_vmap((unsigned long)new->addr,
+				(unsigned long)(new->addr + total));
 	return new->addr;
 
 err_out:
@@ -353,12 +359,13 @@
 
 	area = __find_iovm_area(obj, da);
 	if (!area) {
-		dev_warn(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+		dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
 		goto out;
 	}
 	va = area->va;
-	mutex_unlock(&obj->mmap_lock);
 out:
+	mutex_unlock(&obj->mmap_lock);
+
 	return va;
 }
 EXPORT_SYMBOL_GPL(da_to_va);
@@ -385,14 +392,13 @@
 	}
 
 	va_end = _va + PAGE_SIZE * i;
-	flush_cache_vmap(_va, va_end);
 }
 
 static inline void sgtable_drain_vmalloc(struct sg_table *sgt)
 {
 	/*
 	 * Actually this is not necessary at all, just exists for
-	 * consistency of the code readibility.
+	 * consistency of the code readability.
 	 */
 	BUG_ON(!sgt);
 }
@@ -420,15 +426,13 @@
 		len -= bytes;
 	}
 	BUG_ON(len);
-
-	clean_dcache_area(va, len);
 }
 
 static inline void sgtable_drain_kmalloc(struct sg_table *sgt)
 {
 	/*
 	 * Actually this is not necessary at all, just exists for
-	 * consistency of the code readibility
+	 * consistency of the code readability
 	 */
 	BUG_ON(!sgt);
 }
@@ -442,7 +446,7 @@
 	struct scatterlist *sg;
 	u32 da = new->da_start;
 
-	if (!obj || !new || !sgt)
+	if (!obj || !sgt)
 		return -EINVAL;
 
 	BUG_ON(!sgtable_ok(sgt));
@@ -532,7 +536,7 @@
 
 	area = __find_iovm_area(obj, da);
 	if (!area) {
-		dev_err(obj->dev, "%s: no da area(%08x)\n", __func__, da);
+		dev_dbg(obj->dev, "%s: no da area(%08x)\n", __func__, da);
 		goto out;
 	}
 
@@ -610,7 +614,7 @@
 		 u32 flags)
 {
 	size_t bytes;
-	void *va;
+	void *va = NULL;
 
 	if (!obj || !obj->dev || !sgt)
 		return -EINVAL;
@@ -620,9 +624,11 @@
 		return -EINVAL;
 	bytes = PAGE_ALIGN(bytes);
 
-	va = vmap_sg(sgt);
-	if (IS_ERR(va))
-		return PTR_ERR(va);
+	if (flags & IOVMF_MMIO) {
+		va = vmap_sg(sgt);
+		if (IS_ERR(va))
+			return PTR_ERR(va);
+	}
 
 	flags &= IOVMF_HW_MASK;
 	flags |= IOVMF_DISCONT;
@@ -654,7 +660,7 @@
 	 */
 	sgt = unmap_vm_area(obj, da, vunmap_sg, IOVMF_DISCONT | IOVMF_MMIO);
 	if (!sgt)
-		dev_err(obj->dev, "%s: No sgt\n", __func__);
+		dev_dbg(obj->dev, "%s: No sgt\n", __func__);
 	return sgt;
 }
 EXPORT_SYMBOL_GPL(iommu_vunmap);
@@ -724,7 +730,7 @@
 
 	sgt = unmap_vm_area(obj, da, vfree, IOVMF_DISCONT | IOVMF_ALLOC);
 	if (!sgt)
-		dev_err(obj->dev, "%s: No sgt\n", __func__);
+		dev_dbg(obj->dev, "%s: No sgt\n", __func__);
 	sgtable_free(sgt);
 }
 EXPORT_SYMBOL_GPL(iommu_vfree);
@@ -797,10 +803,12 @@
 void iommu_kunmap(struct iommu *obj, u32 da)
 {
 	struct sg_table *sgt;
+	typedef void (*func_t)(const void *);
 
-	sgt = unmap_vm_area(obj, da, __iounmap, IOVMF_LINEAR | IOVMF_MMIO);
+	sgt = unmap_vm_area(obj, da, (func_t)__iounmap,
+			    IOVMF_LINEAR | IOVMF_MMIO);
 	if (!sgt)
-		dev_err(obj->dev, "%s: No sgt\n", __func__);
+		dev_dbg(obj->dev, "%s: No sgt\n", __func__);
 	sgtable_free(sgt);
 }
 EXPORT_SYMBOL_GPL(iommu_kunmap);
@@ -857,7 +865,7 @@
 
 	sgt = unmap_vm_area(obj, da, kfree, IOVMF_LINEAR | IOVMF_ALLOC);
 	if (!sgt)
-		dev_err(obj->dev, "%s: No sgt\n", __func__);
+		dev_dbg(obj->dev, "%s: No sgt\n", __func__);
 	sgtable_free(sgt);
 }
 EXPORT_SYMBOL_GPL(iommu_kfree);
diff --git a/arch/arm/plat-omap/mcbsp.c b/arch/arm/plat-omap/mcbsp.c
index e2e8b76..2eafca0 100644
--- a/arch/arm/plat-omap/mcbsp.c
+++ b/arch/arm/plat-omap/mcbsp.c
@@ -91,11 +91,20 @@
 static irqreturn_t omap_mcbsp_tx_irq_handler(int irq, void *dev_id)
 {
 	struct omap_mcbsp *mcbsp_tx = dev_id;
+	u16 irqst_spcr2;
 
-	dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n",
-		OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2));
+	irqst_spcr2 = OMAP_MCBSP_READ(mcbsp_tx->io_base, SPCR2);
+	dev_dbg(mcbsp_tx->dev, "TX IRQ callback : 0x%x\n", irqst_spcr2);
 
-	complete(&mcbsp_tx->tx_irq_completion);
+	if (irqst_spcr2 & XSYNC_ERR) {
+		dev_err(mcbsp_tx->dev, "TX Frame Sync Error! : 0x%x\n",
+			irqst_spcr2);
+		/* Writing zero to XSYNC_ERR clears the IRQ */
+		OMAP_MCBSP_WRITE(mcbsp_tx->io_base, SPCR2,
+			irqst_spcr2 & ~(XSYNC_ERR));
+	} else {
+		complete(&mcbsp_tx->tx_irq_completion);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -103,11 +112,20 @@
 static irqreturn_t omap_mcbsp_rx_irq_handler(int irq, void *dev_id)
 {
 	struct omap_mcbsp *mcbsp_rx = dev_id;
+	u16 irqst_spcr1;
 
-	dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n",
-		OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR2));
+	irqst_spcr1 = OMAP_MCBSP_READ(mcbsp_rx->io_base, SPCR1);
+	dev_dbg(mcbsp_rx->dev, "RX IRQ callback : 0x%x\n", irqst_spcr1);
 
-	complete(&mcbsp_rx->rx_irq_completion);
+	if (irqst_spcr1 & RSYNC_ERR) {
+		dev_err(mcbsp_rx->dev, "RX Frame Sync Error! : 0x%x\n",
+			irqst_spcr1);
+		/* Writing zero to RSYNC_ERR clears the IRQ */
+		OMAP_MCBSP_WRITE(mcbsp_rx->io_base, SPCR1,
+			irqst_spcr1 & ~(RSYNC_ERR));
+	} else {
+		complete(&mcbsp_rx->tx_irq_completion);
+	}
 
 	return IRQ_HANDLED;
 }
@@ -176,6 +194,7 @@
 	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
 		OMAP_MCBSP_WRITE(io_base, XCCR, config->xccr);
 		OMAP_MCBSP_WRITE(io_base, RCCR, config->rccr);
+		OMAP_MCBSP_WRITE(io_base, WAKEUPEN, config->wken);
 	}
 }
 EXPORT_SYMBOL(omap_mcbsp_config);
@@ -290,6 +309,33 @@
 }
 EXPORT_SYMBOL(omap_mcbsp_request);
 
+void omap_mcbsp_disable_fclk(unsigned int id)
+{
+	struct omap_mcbsp *mcbsp;
+
+	if (!omap_mcbsp_check_valid_id(id)) {
+		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+		return;
+	}
+	mcbsp = id_to_mcbsp_ptr(id);
+	clk_disable(mcbsp->clks[1]);
+}
+EXPORT_SYMBOL(omap_mcbsp_disable_fclk);
+
+
+void omap_mcbsp_enable_fclk(unsigned int id)
+{
+	struct omap_mcbsp *mcbsp;
+
+	if (!omap_mcbsp_check_valid_id(id)) {
+		printk(KERN_ERR "%s: Invalid id (%d)\n", __func__, id + 1);
+		return;
+	}
+	mcbsp = id_to_mcbsp_ptr(id);
+	clk_enable(mcbsp->clks[1]);
+}
+EXPORT_SYMBOL(omap_mcbsp_enable_fclk);
+
 void omap_mcbsp_free(unsigned int id)
 {
 	struct omap_mcbsp *mcbsp;
@@ -343,15 +389,16 @@
 }
 EXPORT_SYMBOL(omap_mcbsp_free);
 
-/*
- * Here we start the McBSP, by enabling the sample
- * generator, both transmitter and receivers,
- * and the frame sync.
- */
-void omap_mcbsp_start(unsigned int id)
+ /*
+  * Here we start the McBSP, by enabling transmitter, receiver or both.
+  * If no transmitter or receiver is active prior calling, then sample-rate
+  * generator and frame sync are started.
+  */
+void omap_mcbsp_start(unsigned int id, int tx, int rx)
 {
 	struct omap_mcbsp *mcbsp;
 	void __iomem *io_base;
+	int idle;
 	u16 w;
 
 	if (!omap_mcbsp_check_valid_id(id)) {
@@ -364,32 +411,40 @@
 	mcbsp->rx_word_length = (OMAP_MCBSP_READ(io_base, RCR1) >> 5) & 0x7;
 	mcbsp->tx_word_length = (OMAP_MCBSP_READ(io_base, XCR1) >> 5) & 0x7;
 
-	/* Start the sample generator */
-	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+	idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
+		OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
+
+	if (idle) {
+		/* Start the sample generator */
+		w = OMAP_MCBSP_READ(io_base, SPCR2);
+		OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 6));
+	}
 
 	/* Enable transmitter and receiver */
 	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w | 1);
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (tx & 1));
 
 	w = OMAP_MCBSP_READ(io_base, SPCR1);
-	OMAP_MCBSP_WRITE(io_base, SPCR1, w | 1);
+	OMAP_MCBSP_WRITE(io_base, SPCR1, w | (rx & 1));
 
 	udelay(100);
 
-	/* Start frame sync */
-	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+	if (idle) {
+		/* Start frame sync */
+		w = OMAP_MCBSP_READ(io_base, SPCR2);
+		OMAP_MCBSP_WRITE(io_base, SPCR2, w | (1 << 7));
+	}
 
 	/* Dump McBSP Regs */
 	omap_mcbsp_dump_reg(id);
 }
 EXPORT_SYMBOL(omap_mcbsp_start);
 
-void omap_mcbsp_stop(unsigned int id)
+void omap_mcbsp_stop(unsigned int id, int tx, int rx)
 {
 	struct omap_mcbsp *mcbsp;
 	void __iomem *io_base;
+	int idle;
 	u16 w;
 
 	if (!omap_mcbsp_check_valid_id(id)) {
@@ -402,15 +457,20 @@
 
 	/* Reset transmitter */
 	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1));
+	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(tx & 1));
 
 	/* Reset receiver */
 	w = OMAP_MCBSP_READ(io_base, SPCR1);
-	OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(1));
+	OMAP_MCBSP_WRITE(io_base, SPCR1, w & ~(rx & 1));
 
-	/* Reset the sample rate generator */
-	w = OMAP_MCBSP_READ(io_base, SPCR2);
-	OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+	idle = !((OMAP_MCBSP_READ(io_base, SPCR2) |
+		OMAP_MCBSP_READ(io_base, SPCR1)) & 1);
+
+	if (idle) {
+		/* Reset the sample rate generator */
+		w = OMAP_MCBSP_READ(io_base, SPCR2);
+		OMAP_MCBSP_WRITE(io_base, SPCR2, w & ~(1 << 6));
+	}
 }
 EXPORT_SYMBOL(omap_mcbsp_stop);
 
@@ -899,6 +959,21 @@
 }
 EXPORT_SYMBOL(omap_mcbsp_set_spi_mode);
 
+void omap_mcbsp_set_tx_threshold(unsigned int id, u16 threshold)
+{
+	struct omap_mcbsp       *mcbsp;
+	void __iomem            *io_base;
+	u16                     w;
+
+	mcbsp = id_to_mcbsp_ptr(id);
+	io_base = mcbsp->io_base;
+
+
+	OMAP_MCBSP_WRITE(io_base, THRSH2, threshold-1);
+	w = OMAP_MCBSP_READ(io_base, THRSH2);
+}
+EXPORT_SYMBOL(omap_mcbsp_set_tx_threshold);
+
 /*
  * McBSP1 and McBSP3 are directly mapped on 1610 and 1510.
  * 730 has only 2 McBSP, and both of them are MPU peripherals.
diff --git a/arch/arm/plat-omap/omap-pm-srf.c b/arch/arm/plat-omap/omap-pm-srf.c
index 226662d..19bff37 100644
--- a/arch/arm/plat-omap/omap-pm-srf.c
+++ b/arch/arm/plat-omap/omap-pm-srf.c
@@ -27,6 +27,7 @@
 #include <mach/powerdomain.h>
 #include <mach/resource.h>
 #include <mach/omapdev.h>
+#include <mach/omap34xx.h>
 
 struct omap_opp *dsp_opps;
 struct omap_opp *mpu_opps;
@@ -93,6 +94,7 @@
 		resource_request("vdd2_opp", dev, r);
 	}
 }
+EXPORT_SYMBOL(omap_pm_set_min_bus_tput);
 
 void omap_pm_set_max_dev_wakeup_lat(struct device *dev, long t)
 {
@@ -183,7 +185,7 @@
 	 * array should have .rate = .opp_id = 0.
 	 */
 
-	return NULL;
+	return dsp_opps;
 }
 EXPORT_SYMBOL(omap_pm_dsp_get_opp_table);
 
@@ -263,6 +265,21 @@
 }
 EXPORT_SYMBOL(omap_pm_cpu_set_freq);
 
+void omap_pm_set_min_mpu_freq(struct device *dev, unsigned long f)
+{
+	if (f == 0) {
+		WARN_ON(1);
+		return;
+	}
+
+	pr_debug("OMAP PM: CPUFreq requests CPU frequency to be set to %lu\n",
+		 f);
+
+	resource_request("mpu_freq", dev, f);
+	return;
+}
+EXPORT_SYMBOL(omap_pm_set_min_mpu_freq);
+
 unsigned long omap_pm_cpu_get_freq(void)
 {
 	pr_debug("OMAP PM: CPUFreq requests current CPU frequency\n");
@@ -352,3 +369,70 @@
 {
 	/* Deallocate CPUFreq frequency table here */
 }
+
+u8 omap_pm_get_max_vdd1_opp()
+{
+	if (cpu_is_omap3630()) {
+		switch (omap_rev_id()) {
+		case OMAP_3630:
+		default:
+			return VDD1_OPP4;
+		case OMAP_3630_800:
+			return VDD1_OPP3;
+		case OMAP_3630_1000:
+			return VDD1_OPP4;
+		}
+	} else {
+		if (omap_rev() < OMAP3430_REV_ES3_1)
+			return VDD1_OPP5;
+		else {
+			switch (omap_rev_id()) {
+			case OMAP_3420:
+			case OMAP_3430:
+				return VDD1_OPP5;
+			case OMAP_3440:
+				return VDD1_OPP6;
+			default:
+				return VDD1_OPP5;
+			}
+		}
+	}
+}
+EXPORT_SYMBOL(omap_pm_get_max_vdd1_opp);
+
+u8 omap_pm_get_min_vdd1_opp(void)
+{
+	return VDD1_OPP1;
+}
+EXPORT_SYMBOL(omap_pm_get_min_vdd1_opp);
+
+
+u8 omap_pm_get_max_vdd2_opp(void)
+{
+	if (cpu_is_omap3630())
+		return VDD2_OPP2;
+	else
+		return VDD2_OPP3;
+}
+EXPORT_SYMBOL(omap_pm_get_max_vdd2_opp);
+
+u8 omap_pm_get_min_vdd2_opp(void)
+{
+	if (cpu_is_omap3630())
+		return VDD2_OPP1;
+	else
+		return VDD2_OPP2;
+}
+EXPORT_SYMBOL(omap_pm_get_min_vdd2_opp);
+
+struct omap_opp *omap_get_mpu_rate_table()
+{
+	return mpu_opps;
+}
+EXPORT_SYMBOL(omap_get_mpu_rate_table);
+
+struct omap_opp *omap_get_dsp_rate_table()
+{
+	return dsp_opps;
+}
+EXPORT_SYMBOL(omap_get_dsp_rate_table);
diff --git a/arch/arm/plat-omap/resource.c b/arch/arm/plat-omap/resource.c
index ec31727..80e42da 100644
--- a/arch/arm/plat-omap/resource.c
+++ b/arch/arm/plat-omap/resource.c
@@ -106,11 +106,20 @@
 	int ret;
 
 	/* Regenerate the target_value for the resource */
-	target_level = RES_DEFAULTLEVEL;
-	list_for_each_entry(user, &resp->users_list, node)
-		if (user->level > target_level)
-			target_level = user->level;
-
+	if (resp->flags & RES_TYPE_PERFORMANCE) {
+		target_level = RES_PERFORMANCE_DEFAULTLEVEL;
+		list_for_each_entry(user, &resp->users_list, node)
+			if (user->level > target_level)
+				target_level = user->level;
+	} else if (resp->flags & RES_TYPE_LATENCY) {
+		target_level = RES_LATENCY_DEFAULTLEVEL;
+		list_for_each_entry(user, &resp->users_list, node)
+			if (user->level < target_level)
+				target_level = user->level;
+	} else {
+		pr_debug("SRF: Unknown resource type\n");
+		return -EINVAL;
+	}
 	pr_debug("SRF: Changing Level for resource %s to %ld\n",
 				resp->name, target_level);
 	ret = resp->ops->change_level(resp, target_level);
@@ -182,7 +191,6 @@
 		kfree(user);
 	} else {
 		user->usage = UNUSED;
-		user->level = RES_DEFAULTLEVEL;
 		user->dev = NULL;
 	}
 }
@@ -213,7 +221,6 @@
 	for (ind = 0; ind < MAX_USERS; ind++) {
 		usr_list[ind].usage = UNUSED;
 		usr_list[ind].dev = NULL;
-		usr_list[ind].level = RES_DEFAULTLEVEL;
 	}
 
 	if (resources)
@@ -253,6 +260,8 @@
  */
 int resource_register(struct shared_resource *resp)
 {
+	int ret = 0;
+
 	if (!resp)
 		return -EINVAL;
 
@@ -260,12 +269,15 @@
 		return -EINVAL;
 
 	/* Verify that the resource is not already registered */
-	if (resource_lookup(resp->name))
-		return -EEXIST;
+	down(&res_mutex);
+	if (_resource_lookup(resp->name)) {
+		ret = -EEXIST;
+		goto out;
+	}
 
 	INIT_LIST_HEAD(&resp->users_list);
+	mutex_init(&resp->resource_mutex);
 
-	down(&res_mutex);
 	/* Add the resource to the resource list */
 	list_add(&resp->node, &res_list);
 
@@ -273,10 +285,11 @@
 	if (resp->ops->init)
 		resp->ops->init(resp);
 
-	up(&res_mutex);
 	pr_debug("resource: registered %s\n", resp->name);
 
-	return 0;
+out:
+	up(&res_mutex);
+	return ret;
 }
 EXPORT_SYMBOL(resource_register);
 
@@ -326,14 +339,13 @@
 	struct  users_list *user;
 	int 	found = 0, ret = 0;
 
-	down(&res_mutex);
-	resp = _resource_lookup(name);
+	resp = resource_lookup(name);
 	if (!resp) {
 		printk(KERN_ERR "resource_request: Invalid resource name\n");
-		ret = -EINVAL;
-		goto res_unlock;
+		return -EINVAL;
 	}
 
+	mutex_lock(&resp->resource_mutex);
 	/* Call the resource specific validate function */
 	if (resp->ops->validate_level) {
 		ret = resp->ops->validate_level(resp, level);
@@ -361,16 +373,11 @@
 	}
 	user->level = level;
 
+	/* Recompute and set the current level for the resource */
+	ret = update_resource_level(resp);
+
 res_unlock:
-	up(&res_mutex);
-	/*
-	 * Recompute and set the current level for the resource.
-	 * NOTE: update_resource level moved out of spin_lock, as it may call
-	 * pm_qos_add_requirement, which does a kzmalloc. This won't be allowed
-	 * in iterrupt context. The spin_lock still protects add/remove users.
-	 */
-	if (!ret)
-		ret = update_resource_level(resp);
+	mutex_unlock(&resp->resource_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(resource_request);
@@ -393,14 +400,13 @@
 	struct users_list *user;
 	int found = 0, ret = 0;
 
-	down(&res_mutex);
-	resp = _resource_lookup(name);
+	resp = resource_lookup(name);
 	if (!resp) {
 		printk(KERN_ERR "resource_release: Invalid resource name\n");
-		ret = -EINVAL;
-		goto res_unlock;
+		return -EINVAL;
 	}
 
+	mutex_lock(&resp->resource_mutex);
 	list_for_each_entry(user, &resp->users_list, node) {
 		if (user->dev == dev) {
 			found = 1;
@@ -421,7 +427,7 @@
 	/* Recompute and set the current level for the resource */
 	ret = update_resource_level(resp);
 res_unlock:
-	up(&res_mutex);
+	mutex_unlock(&resp->resource_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(resource_release);
@@ -438,15 +444,14 @@
 	struct shared_resource *resp;
 	u32 ret;
 
-	down(&res_mutex);
-	resp = _resource_lookup(name);
+	resp = resource_lookup(name);
 	if (!resp) {
 		printk(KERN_ERR "resource_release: Invalid resource name\n");
-		up(&res_mutex);
 		return -EINVAL;
 	}
+	mutex_lock(&resp->resource_mutex);
 	ret = resp->curr_level;
-	up(&res_mutex);
+	mutex_unlock(&resp->resource_mutex);
 	return ret;
 }
 EXPORT_SYMBOL(resource_get_level);
diff --git a/arch/arm/plat-omap/sram.c b/arch/arm/plat-omap/sram.c
index 755ccaa..1ed08b5 100644
--- a/arch/arm/plat-omap/sram.c
+++ b/arch/arm/plat-omap/sram.c
@@ -38,10 +38,10 @@
 #define OMAP1_SRAM_VA		VMALLOC_END
 #define OMAP2_SRAM_PA		0x40200000
 #define OMAP2_SRAM_PUB_PA	0x4020f800
-#define OMAP2_SRAM_VA		0xe3000000
+#define OMAP2_SRAM_VA		0xfe400000
 #define OMAP2_SRAM_PUB_VA	(OMAP2_SRAM_VA + 0x800)
 #define OMAP3_SRAM_PA           0x40200000
-#define OMAP3_SRAM_VA           0xe3000000
+#define OMAP3_SRAM_VA           0xfc800000
 #define OMAP3_SRAM_PUB_PA       0x40208000
 #define OMAP3_SRAM_PUB_VA       (OMAP3_SRAM_VA + 0x8000)
 
@@ -386,6 +386,20 @@
 					       unlock_dll, f, sdrc_mr, inc);
  }
 
+
+/* Function for SDRC config for warm reset */
+static u32 (*_omap3_sram_configure_core_dpll_warmreset)(void);
+
+u32 omap3_configure_core_dpll_warmreset(void)
+{
+	if (!_omap3_sram_configure_core_dpll_warmreset)
+		omap_sram_error();
+
+	return _omap3_sram_configure_core_dpll_warmreset();
+}
+
+
+
 #ifdef CONFIG_PM
 void omap3_sram_restore_context(void)
 {
@@ -394,6 +408,11 @@
 	_omap3_sram_configure_core_dpll =
 		omap_sram_push(omap3_sram_configure_core_dpll,
 			       omap3_sram_configure_core_dpll_sz);
+
+	_omap3_sram_configure_core_dpll_warmreset =
+	omap_sram_push(omap3_sram_configure_core_dpll_warmreset,
+			omap3_sram_configure_core_dpll_warmreset_sz);
+
 	omap_push_sram_idle();
 }
 #endif /* CONFIG_PM */
@@ -403,6 +422,11 @@
 	_omap3_sram_configure_core_dpll =
 		omap_sram_push(omap3_sram_configure_core_dpll,
 			       omap3_sram_configure_core_dpll_sz);
+
+	_omap3_sram_configure_core_dpll_warmreset =
+	omap_sram_push(omap3_sram_configure_core_dpll_warmreset,
+			omap3_sram_configure_core_dpll_warmreset_sz);
+
 	omap_push_sram_idle();
 	return 0;
 }
diff --git a/arch/arm/plat-omap/vrfb.c b/arch/arm/plat-omap/vrfb.c
index f84d2f5..4ce57df 100644
--- a/arch/arm/plat-omap/vrfb.c
+++ b/arch/arm/plat-omap/vrfb.c
@@ -87,8 +87,7 @@
 
 void omap_vrfb_setup(struct vrfb *vrfb, unsigned long paddr,
 		u16 width, u16 height,
-		enum omap_color_mode color_mode,
-		int rotation)
+		enum omap_color_mode color_mode, int rotation)
 {
 	unsigned pixel_size_exp;
 	u16 vrfb_width;
@@ -129,6 +128,7 @@
 			color_mode == OMAP_DSS_COLOR_UYVY)
 		width >>= 1;
 
+	/* Configure the vrfb buffer for rotation*/
 	if (rotation == 1 || rotation == 3) {
 		temp = width;
 		width = height;
@@ -142,6 +142,14 @@
 	else
 		BUG();
 
+	/* VDMA Optimization */
+	/* TODO: VDMA support for RGB16 mode */
+	if (cpu_is_omap3630())
+		if (color_mode == OMAP_DSS_COLOR_YUV2)
+			if ((rotation == 1) || (rotation == 3))
+				pixel_size_exp = 2;
+
+
 	vrfb_width = ALIGN(width * bytespp, VRFB_PAGE_WIDTH) / bytespp;
 	vrfb_height = ALIGN(height, VRFB_PAGE_HEIGHT);
 
diff --git a/arch/arm/tools/mach-types b/arch/arm/tools/mach-types
index b4211d8b2..7581295 100644
--- a/arch/arm/tools/mach-types
+++ b/arch/arm/tools/mach-types
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Thu Mar 12 18:01:45 2009
+# Last update: Fri Oct 9 02:40:40 2009
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -916,7 +916,7 @@
 apf9328			MACH_APF9328		APF9328			906
 omap_wipoq		MACH_OMAP_WIPOQ		OMAP_WIPOQ		907
 omap_twip		MACH_OMAP_TWIP		OMAP_TWIP		908
-palmt650		MACH_PALMT650		PALMT650		909
+treo650			MACH_TREO650		TREO650			909
 acumen			MACH_ACUMEN		ACUMEN			910
 xp100			MACH_XP100		XP100			911
 fs2410			MACH_FS2410		FS2410			912
@@ -1232,7 +1232,7 @@
 vpac270			MACH_VPAC270		VPAC270			1227
 rd129			MACH_RD129		RD129			1228
 htcwizard		MACH_HTCWIZARD		HTCWIZARD		1229
-xscale_treo680		MACH_XSCALE_TREO680	XSCALE_TREO680		1230
+treo680			MACH_TREO680		TREO680			1230
 tecon_tmezon		MACH_TECON_TMEZON	TECON_TMEZON		1231
 zylonite		MACH_ZYLONITE		ZYLONITE		1233
 gene1270		MACH_GENE1270		GENE1270		1234
@@ -1418,10 +1418,10 @@
 cnty_titan		MACH_CNTY_TITAN		CNTY_TITAN		1418
 app3xx			MACH_APP3XX		APP3XX			1419
 sideoatsgrama		MACH_SIDEOATSGRAMA	SIDEOATSGRAMA		1420
-palmtreo700p		MACH_PALMTREO700P	PALMTREO700P		1421
-palmtreo700w		MACH_PALMTREO700W	PALMTREO700W		1422
-palmtreo750		MACH_PALMTREO750	PALMTREO750		1423
-palmtreo755p		MACH_PALMTREO755P	PALMTREO755P		1424
+treo700p		MACH_TREO700P		TREO700P		1421
+treo700w		MACH_TREO700W		TREO700W		1422
+treo750			MACH_TREO750		TREO750			1423
+treo755p		MACH_TREO755P		TREO755P		1424
 ezreganut9200		MACH_EZREGANUT9200	EZREGANUT9200		1425
 sarge			MACH_SARGE		SARGE			1426
 a696			MACH_A696		A696			1427
@@ -1455,7 +1455,7 @@
 h6044			MACH_H6044		H6044			1458
 app			MACH_APP		APP			1459
 tct_hammer		MACH_TCT_HAMMER		TCT_HAMMER		1460
-herald			MACH_HERMES		HERMES			1461
+herald			MACH_HERALD		HERALD			1461
 artemis			MACH_ARTEMIS		ARTEMIS			1462
 htctitan		MACH_HTCTITAN		HTCTITAN		1463
 qranium			MACH_QRANIUM		QRANIUM			1464
@@ -1638,7 +1638,7 @@
 aml_m8050		MACH_AML_M8050		AML_M8050		1644
 mx35_3ds		MACH_MX35_3DS		MX35_3DS		1645
 mars			MACH_MARS		MARS			1646
-ntosd_644xa		MACH_NTOSD_644XA	NTOSD_644XA		1647
+neuros_osd2		MACH_NEUROS_OSD2	NEUROS_OSD2		1647
 badger			MACH_BADGER		BADGER			1648
 trizeps4wl		MACH_TRIZEPS4WL		TRIZEPS4WL		1649
 trizeps5		MACH_TRIZEPS5		TRIZEPS5		1650
@@ -1654,7 +1654,7 @@
 zoran43xx		MACH_ZORAN43XX		ZORAN43XX		1660
 sonix926		MACH_SONIX926		SONIX926		1661
 celestialsemi		MACH_CELESTIALSEMI	CELESTIALSEMI		1662
-cc9m2443		MACH_CC9M2443		CC9M2443		1663
+cc9m2443js		MACH_CC9M2443JS		CC9M2443JS		1663
 tw5334			MACH_TW5334		TW5334			1664
 omap_htcartemis		MACH_HTCARTEMIS		HTCARTEMIS		1665
 nal_hlite		MACH_NAL_HLITE		NAL_HLITE		1666
@@ -1721,7 +1721,7 @@
 csb637xo		MACH_CSB637XO		CSB637XO		1730
 evisiong		MACH_EVISIONG		EVISIONG		1731
 stmp37xx		MACH_STMP37XX		STMP37XX		1732
-stmp378x		MACH_STMP38XX		STMP38XX		1733
+stmp378x		MACH_STMP378X		STMP378X		1733
 tnt			MACH_TNT		TNT			1734
 tbxt			MACH_TBXT		TBXT			1735
 playmate		MACH_PLAYMATE		PLAYMATE		1736
@@ -1769,7 +1769,7 @@
 mi424wr			MACH_MI424WR		MI424WR			1778
 axs_ultrax		MACH_AXS_ULTRAX		AXS_ULTRAX		1779
 at572d940deb		MACH_AT572D940DEB	AT572D940DEB		1780
-davinci_da8xx_evm	MACH_DAVINCI_DA8XX_EVM	DAVINCI_DA8XX_EVM	1781
+davinci_da830_evm	MACH_DAVINCI_DA830_EVM	DAVINCI_DA830_EVM	1781
 ep9302			MACH_EP9302		EP9302			1782
 at572d940hfek		MACH_AT572D940HFEB	AT572D940HFEB		1783
 cybook3			MACH_CYBOOK3		CYBOOK3			1784
@@ -1802,7 +1802,7 @@
 rd88f5181l_ge		MACH_RD88F5181L_GE	RD88F5181L_GE		1812
 sifmain			MACH_SIFMAIN		SIFMAIN			1813
 sam9_l9261		MACH_SAM9_L9261		SAM9_L9261		1814
-cc9m2443js		MACH_CC9M2443JS		CC9M2443JS		1815
+cc9m2443		MACH_CC9M2443		CC9M2443		1815
 xaria300		MACH_XARIA300		XARIA300		1816
 it9200			MACH_IT9200		IT9200			1817
 rd88f5181l_fxo		MACH_RD88F5181L_FXO	RD88F5181L_FXO		1818
@@ -1817,7 +1817,7 @@
 tavorevb		MACH_TAVOREVB		TAVOREVB		1827
 saar			MACH_SAAR		SAAR			1828
 deister_eyecam		MACH_DEISTER_EYECAM	DEISTER_EYECAM		1829
-at91sam9m10ek		MACH_AT91SAM9M10EK	AT91SAM9M10EK		1830
+at91sam9m10g45ek	MACH_AT91SAM9M10G45EK	AT91SAM9M10G45EK	1830
 linkstation_produo	MACH_LINKSTATION_PRODUO	LINKSTATION_PRODUO	1831
 hit_b0			MACH_HIT_B0		HIT_B0			1832
 adx_rmu			MACH_ADX_RMU		ADX_RMU			1833
@@ -1962,7 +1962,7 @@
 arm11			MACH_ARM11		ARM11			1972
 cpuat9260		MACH_CPUAT9260		CPUAT9260		1973
 cpupxa255		MACH_CPUPXA255		CPUPXA255		1974
-cpuimx27		MACH_CPUIMX27		CPUIMX27		1975
+eukrea_cpuimx27		MACH_CPUIMX27		CPUIMX27		1975
 cheflux			MACH_CHEFLUX		CHEFLUX			1976
 eb_cpux9k2		MACH_EB_CPUX9K2		EB_CPUX9K2		1977
 opcotec			MACH_OPCOTEC		OPCOTEC			1978
@@ -2124,3 +2124,336 @@
 fmzwebmodul		MACH_FMZWEBMODUL	FMZWEBMODUL		2134
 rd78x00_masa		MACH_RD78X00_MASA	RD78X00_MASA		2135
 smallogger		MACH_SMALLOGGER		SMALLOGGER		2136
+ccw9p9215		MACH_CCW9P9215		CCW9P9215		2137
+dm355_leopard		MACH_DM355_LEOPARD	DM355_LEOPARD		2138
+ts219			MACH_TS219		TS219			2139
+tny_a9263		MACH_TNY_A9263		TNY_A9263		2140
+apollo			MACH_APOLLO		APOLLO			2141
+at91cap9stk		MACH_AT91CAP9STK	AT91CAP9STK		2142
+spc300			MACH_SPC300		SPC300			2143
+eko			MACH_EKO		EKO			2144
+ccw9m2443		MACH_CCW9M2443		CCW9M2443		2145
+ccw9m2443js		MACH_CCW9M2443JS	CCW9M2443JS		2146
+m2m_router_device	MACH_M2M_ROUTER_DEVICE	M2M_ROUTER_DEVICE	2147
+str9104nas		MACH_STAR9104NAS	STAR9104NAS		2148
+pca100			MACH_PCA100		PCA100			2149
+z3_dm365_mod_01		MACH_Z3_DM365_MOD_01	Z3_DM365_MOD_01		2150
+hipox			MACH_HIPOX		HIPOX			2151
+omap3_piteds		MACH_OMAP3_PITEDS	OMAP3_PITEDS		2152
+bm150r			MACH_BM150R		BM150R			2153
+tbone			MACH_TBONE		TBONE			2154
+merlin			MACH_MERLIN		MERLIN			2155
+falcon			MACH_FALCON		FALCON			2156
+davinci_da850_evm	MACH_DAVINCI_DA850_EVM	DAVINCI_DA850_EVM	2157
+s5p6440			MACH_S5P6440		S5P6440			2158
+at91sam9g10ek		MACH_AT91SAM9G10EK	AT91SAM9G10EK		2159
+omap_4430sdp		MACH_OMAP_4430SDP	OMAP_4430SDP		2160
+lpc313x			MACH_LPC313X		LPC313X			2161
+magx_zn5		MACH_MAGX_ZN5		MAGX_ZN5		2162
+magx_em30		MACH_MAGX_EM30		MAGX_EM30		2163
+magx_ve66		MACH_MAGX_VE66		MAGX_VE66		2164
+meesc			MACH_MEESC		MEESC			2165
+otc570			MACH_OTC570		OTC570			2166
+bcu2412			MACH_BCU2412		BCU2412			2167
+beacon			MACH_BEACON		BEACON			2168
+actia_tgw		MACH_ACTIA_TGW		ACTIA_TGW		2169
+e4430			MACH_E4430		E4430			2170
+ql300			MACH_QL300		QL300			2171
+btmavb101		MACH_BTMAVB101		BTMAVB101		2172
+btmawb101		MACH_BTMAWB101		BTMAWB101		2173
+sq201			MACH_SQ201		SQ201			2174
+quatro45xx		MACH_QUATRO45XX		QUATRO45XX		2175
+openpad			MACH_OPENPAD		OPENPAD			2176
+tx25			MACH_TX25		TX25			2177
+omap3_torpedo		MACH_OMAP3_TORPEDO	OMAP3_TORPEDO		2178
+htcraphael_k		MACH_HTCRAPHAEL_K	HTCRAPHAEL_K		2179
+lal43			MACH_LAL43		LAL43			2181
+htcraphael_cdma500	MACH_HTCRAPHAEL_CDMA500	HTCRAPHAEL_CDMA500	2182
+anw6410			MACH_ANW6410		ANW6410			2183
+htcprophet		MACH_HTCPROPHET		HTCPROPHET		2185
+cfa_10022		MACH_CFA_10022		CFA_10022		2186
+imx27_visstrim_m10	MACH_IMX27_VISSTRIM_M10	IMX27_VISSTRIM_M10	2187
+px2imx27		MACH_PX2IMX27		PX2IMX27		2188
+stm3210e_eval		MACH_STM3210E_EVAL	STM3210E_EVAL		2189
+dvs10			MACH_DVS10		DVS10			2190
+portuxg20		MACH_PORTUXG20		PORTUXG20		2191
+arm_spv			MACH_ARM_SPV		ARM_SPV			2192
+smdkc110		MACH_SMDKC110		SMDKC110		2193
+cabespresso		MACH_CABESPRESSO	CABESPRESSO		2194
+hmc800			MACH_HMC800		HMC800			2195
+sholes			MACH_SHOLES		SHOLES			2196
+btmxc31			MACH_BTMXC31		BTMXC31			2197
+dt501			MACH_DT501		DT501			2198
+ktx			MACH_KTX		KTX			2199
+omap3517evm		MACH_OMAP3517EVM	OMAP3517EVM		2200
+netspace_v2		MACH_NETSPACE_V2	NETSPACE_V2		2201
+netspace_max_v2		MACH_NETSPACE_MAX_V2	NETSPACE_MAX_V2		2202
+d2net_v2		MACH_D2NET_V2		D2NET_V2		2203
+net2big_v2		MACH_NET2BIG_V2		NET2BIG_V2		2204
+net4big_v2		MACH_NET4BIG_V2		NET4BIG_V2		2205
+net5big_v2		MACH_NET5BIG_V2		NET5BIG_V2		2206
+endb2443		MACH_ENDB2443		ENDB2443		2207
+inetspace_v2		MACH_INETSPACE_V2	INETSPACE_V2		2208
+tros			MACH_TROS		TROS			2209
+pelco_homer		MACH_PELCO_HOMER	PELCO_HOMER		2210
+ofsp8			MACH_OFSP8		OFSP8			2211
+at91sam9g45ekes		MACH_AT91SAM9G45EKES	AT91SAM9G45EKES		2212
+guf_cupid		MACH_GUF_CUPID		GUF_CUPID		2213
+eab1r			MACH_EAB1R		EAB1R			2214
+desirec			MACH_DESIREC		DESIREC			2215
+cordoba			MACH_CORDOBA		CORDOBA			2216
+irvine			MACH_IRVINE		IRVINE			2217
+sff772			MACH_SFF772		SFF772			2218
+pelco_milano		MACH_PELCO_MILANO	PELCO_MILANO		2219
+pc7302			MACH_PC7302		PC7302			2220
+bip6000			MACH_BIP6000		BIP6000			2221
+silvermoon		MACH_SILVERMOON		SILVERMOON		2222
+vc0830			MACH_VC0830		VC0830			2223
+dt430			MACH_DT430		DT430			2224
+ji42pf			MACH_JI42PF		JI42PF			2225
+gnet_ksm		MACH_GNET_KSM		GNET_KSM		2226
+gnet_sgm		MACH_GNET_SGM		GNET_SGM		2227
+gnet_sgr		MACH_GNET_SGR		GNET_SGR		2228
+omap3_icetekevm		MACH_OMAP3_ICETEKEVM	OMAP3_ICETEKEVM		2229
+pnp			MACH_PNP		PNP			2230
+ctera_2bay_k		MACH_CTERA_2BAY_K	CTERA_2BAY_K		2231
+ctera_2bay_u		MACH_CTERA_2BAY_U	CTERA_2BAY_U		2232
+sas_c			MACH_SAS_C		SAS_C			2233
+vma2315			MACH_VMA2315		VMA2315			2234
+vcs			MACH_VCS		VCS			2235
+spear600		MACH_SPEAR600		SPEAR600		2236
+spear300		MACH_SPEAR300		SPEAR300		2237
+spear1300		MACH_SPEAR1300		SPEAR1300		2238
+lilly1131		MACH_LILLY1131		LILLY1131		2239
+arvoo_ax301		MACH_ARVOO_AX301	ARVOO_AX301		2240
+mapphone		MACH_MAPPHONE		MAPPHONE		2241
+legend			MACH_LEGEND		LEGEND			2242
+salsa			MACH_SALSA		SALSA			2243
+lounge			MACH_LOUNGE		LOUNGE			2244
+vision			MACH_VISION		VISION			2245
+vmb20			MACH_VMB20		VMB20			2246
+hy2410			MACH_HY2410		HY2410			2247
+hy9315			MACH_HY9315		HY9315			2248
+bullwinkle		MACH_BULLWINKLE		BULLWINKLE		2249
+arm_ultimator2		MACH_ARM_ULTIMATOR2	ARM_ULTIMATOR2		2250
+vs_v210			MACH_VS_V210		VS_V210			2252
+vs_v212			MACH_VS_V212		VS_V212			2253
+hmt			MACH_HMT		HMT			2254
+suen3			MACH_SUEN3		SUEN3			2255
+vesper			MACH_VESPER		VESPER			2256
+str9			MACH_STR9		STR9			2257
+omap3_wl_ff		MACH_OMAP3_WL_FF	OMAP3_WL_FF		2258
+simcom			MACH_SIMCOM		SIMCOM			2259
+mcwebio			MACH_MCWEBIO		MCWEBIO			2260
+omap3_phrazer		MACH_OMAP3_PHRAZER	OMAP3_PHRAZER		2261
+darwin			MACH_DARWIN		DARWIN			2262
+oratiscomu		MACH_ORATISCOMU		ORATISCOMU		2263
+rtsbc20			MACH_RTSBC20		RTSBC20			2264
+sgh_i780		MACH_I780		I780			2265
+gemini324		MACH_GEMINI324		GEMINI324		2266
+oratislan		MACH_ORATISLAN		ORATISLAN		2267
+oratisalog		MACH_ORATISALOG		ORATISALOG		2268
+oratismadi		MACH_ORATISMADI		ORATISMADI		2269
+oratisot16		MACH_ORATISOT16		ORATISOT16		2270
+oratisdesk		MACH_ORATISDESK		ORATISDESK		2271
+v2_ca9			MACH_V2P_CA9		V2P_CA9			2272
+sintexo			MACH_SINTEXO		SINTEXO			2273
+cm3389			MACH_CM3389		CM3389			2274
+omap3_cio		MACH_OMAP3_CIO		OMAP3_CIO		2275
+sgh_i900		MACH_SGH_I900		SGH_I900		2276
+bst100			MACH_BST100		BST100			2277
+passion			MACH_PASSION		PASSION			2278
+indesign_at91sam	MACH_INDESIGN_AT91SAM	INDESIGN_AT91SAM	2279
+c4_badger		MACH_C4_BADGER		C4_BADGER		2280
+c4_viper		MACH_C4_VIPER		C4_VIPER		2281
+d2net			MACH_D2NET		D2NET			2282
+bigdisk			MACH_BIGDISK		BIGDISK			2283
+notalvision		MACH_NOTALVISION	NOTALVISION		2284
+omap3_kboc		MACH_OMAP3_KBOC		OMAP3_KBOC		2285
+cyclone			MACH_CYCLONE		CYCLONE			2286
+ninja			MACH_NINJA		NINJA			2287
+at91sam9g20ek_2mmc	MACH_AT91SAM9G20EK_2MMC	AT91SAM9G20EK_2MMC	2288
+bcmring			MACH_BCMRING		BCMRING			2289
+resol_dl2		MACH_RESOL_DL2		RESOL_DL2		2290
+ifosw			MACH_IFOSW		IFOSW			2291
+htcrhodium		MACH_HTCRHODIUM		HTCRHODIUM		2292
+htctopaz		MACH_HTCTOPAZ		HTCTOPAZ		2293
+matrix504		MACH_MATRIX504		MATRIX504		2294
+mrfsa			MACH_MRFSA		MRFSA			2295
+sc_p270			MACH_SC_P270		SC_P270			2296
+atlas5_evb		MACH_ATLAS5_EVB		ATLAS5_EVB		2297
+pelco_lobox		MACH_PELCO_LOBOX	PELCO_LOBOX		2298
+dilax_pcu200		MACH_DILAX_PCU200	DILAX_PCU200		2299
+leonardo		MACH_LEONARDO		LEONARDO		2300
+zoran_approach7		MACH_ZORAN_APPROACH7	ZORAN_APPROACH7		2301
+dp6xx			MACH_DP6XX		DP6XX			2302
+bcm2153_vesper		MACH_BCM2153_VESPER	BCM2153_VESPER		2303
+mahimahi		MACH_MAHIMAHI		MAHIMAHI		2304
+clickc			MACH_CLICKC		CLICKC			2305
+zb_gateway		MACH_ZB_GATEWAY		ZB_GATEWAY		2306
+tazcard			MACH_TAZCARD		TAZCARD			2307
+tazdev			MACH_TAZDEV		TAZDEV			2308
+annax_cb_arm		MACH_ANNAX_CB_ARM	ANNAX_CB_ARM		2309
+annax_dm3		MACH_ANNAX_DM3		ANNAX_DM3		2310
+cerebric		MACH_CEREBRIC		CEREBRIC		2311
+orca			MACH_ORCA		ORCA			2312
+pc9260			MACH_PC9260		PC9260			2313
+ems285a			MACH_EMS285A		EMS285A			2314
+gec2410			MACH_GEC2410		GEC2410			2315
+gec2440			MACH_GEC2440		GEC2440			2316
+mw903			MACH_ARCH_MW903		ARCH_MW903		2317
+mw2440			MACH_MW2440		MW2440			2318
+ecac2378		MACH_ECAC2378		ECAC2378		2319
+tazkiosk		MACH_TAZKIOSK		TAZKIOSK		2320
+whiterabbit_mch		MACH_WHITERABBIT_MCH	WHITERABBIT_MCH		2321
+sbox9263		MACH_SBOX9263		SBOX9263		2322
+oreo			MACH_OREO		OREO			2323
+smdk6442		MACH_SMDK6442		SMDK6442		2324
+openrd_base		MACH_OPENRD_BASE	OPENRD_BASE		2325
+incredible		MACH_INCREDIBLE		INCREDIBLE		2326
+incrediblec		MACH_INCREDIBLEC	INCREDIBLEC		2327
+heroct			MACH_HEROCT		HEROCT			2328
+mmnet1000		MACH_MMNET1000		MMNET1000		2329
+devkit8000		MACH_DEVKIT8000		DEVKIT8000		2330
+devkit9000		MACH_DEVKIT9000		DEVKIT9000		2331
+mx31txtr		MACH_MX31TXTR		MX31TXTR		2332
+u380			MACH_U380		U380			2333
+oamp3_hualu		MACH_HUALU_BOARD	HUALU_BOARD		2334
+npcmx50			MACH_NPCMX50		NPCMX50			2335
+mx51_lange51		MACH_MX51_LANGE51	MX51_LANGE51		2336
+mx51_lange52		MACH_MX51_LANGE52	MX51_LANGE52		2337
+riom			MACH_RIOM		RIOM			2338
+comcas			MACH_COMCAS		COMCAS			2339
+wsi_mx27		MACH_WSI_MX27		WSI_MX27		2340
+cm_t35			MACH_CM_T35		CM_T35			2341
+net2big			MACH_NET2BIG		NET2BIG			2342
+motorola_a1600		MACH_MOTOROLA_A1600	MOTOROLA_A1600		2343
+igep0020		MACH_IGEP0020		IGEP0020		2344
+igep0010		MACH_IGEP0010		IGEP0010		2345
+mv6281gtwge2		MACH_MV6281GTWGE2	MV6281GTWGE2		2346
+scat100			MACH_SCAT100		SCAT100			2347
+sanmina			MACH_SANMINA		SANMINA			2348
+momento			MACH_MOMENTO		MOMENTO			2349
+nuc9xx			MACH_NUC9XX		NUC9XX			2350
+nuc910evb		MACH_NUC910EVB		NUC910EVB		2351
+nuc920evb		MACH_NUC920EVB		NUC920EVB		2352
+nuc950evb		MACH_NUC950EVB		NUC950EVB		2353
+nuc945evb		MACH_NUC945EVB		NUC945EVB		2354
+nuc960evb		MACH_NUC960EVB		NUC960EVB		2355
+nuc932evb		MACH_NUC932EVB		NUC932EVB		2356
+nuc900			MACH_NUC900		NUC900			2357
+sd1soc			MACH_SD1SOC		SD1SOC			2358
+ln2440bc		MACH_LN2440BC		LN2440BC		2359
+rsbc			MACH_RSBC		RSBC			2360
+openrd_client		MACH_OPENRD_CLIENT	OPENRD_CLIENT		2361
+hpipaq11x		MACH_HPIPAQ11X		HPIPAQ11X		2362
+wayland			MACH_WAYLAND		WAYLAND			2363
+acnbsx102		MACH_ACNBSX102		ACNBSX102		2364
+hwat91			MACH_HWAT91		HWAT91			2365
+at91sam9263cs		MACH_AT91SAM9263CS	AT91SAM9263CS		2366
+csb732			MACH_CSB732		CSB732			2367
+u8500			MACH_U8500		U8500			2368
+huqiu			MACH_HUQIU		HUQIU			2369
+mx51_kunlun		MACH_MX51_KUNLUN	MX51_KUNLUN		2370
+pmt1g			MACH_PMT1G		PMT1G			2371
+htcelf			MACH_HTCELF		HTCELF			2372
+armadillo420		MACH_ARMADILLO420	ARMADILLO420		2373
+armadillo440		MACH_ARMADILLO440	ARMADILLO440		2374
+u_chip_dual_arm		MACH_U_CHIP_DUAL_ARM	U_CHIP_DUAL_ARM		2375
+csr_bdb3		MACH_CSR_BDB3		CSR_BDB3		2376
+dolby_cat1018		MACH_DOLBY_CAT1018	DOLBY_CAT1018		2377
+hy9307			MACH_HY9307		HY9307			2378
+aspire_easystore	MACH_A_ES		A_ES			2379
+davinci_irif		MACH_DAVINCI_IRIF	DAVINCI_IRIF		2380
+agama9263		MACH_AGAMA9263		AGAMA9263		2381
+marvell_jasper		MACH_MARVELL_JASPER	MARVELL_JASPER		2382
+flint			MACH_FLINT		FLINT			2383
+tavorevb3		MACH_TAVOREVB3		TAVOREVB3		2384
+sch_m490		MACH_SCH_M490		SCH_M490		2386
+rbl01			MACH_RBL01		RBL01			2387
+omnifi			MACH_OMNIFI		OMNIFI			2388
+otavalo			MACH_OTAVALO		OTAVALO			2389
+sienna			MACH_SIENNA		SIENNA			2390
+htc_excalibur_s620	MACH_HTC_EXCALIBUR_S620	HTC_EXCALIBUR_S620	2391
+htc_opal		MACH_HTC_OPAL		HTC_OPAL		2392
+touchbook		MACH_TOUCHBOOK		TOUCHBOOK		2393
+latte			MACH_LATTE		LATTE			2394
+xa200			MACH_XA200		XA200			2395
+nimrod			MACH_NIMROD		NIMROD			2396
+cc9p9215_3g		MACH_CC9P9215_3G	CC9P9215_3G		2397
+cc9p9215_3gjs		MACH_CC9P9215_3GJS	CC9P9215_3GJS		2398
+tk71			MACH_TK71		TK71			2399
+comham3525		MACH_COMHAM3525		COMHAM3525		2400
+mx31erebus		MACH_MX31EREBUS		MX31EREBUS		2401
+mcardmx27		MACH_MCARDMX27		MCARDMX27		2402
+paradise		MACH_PARADISE		PARADISE		2403
+tide			MACH_TIDE		TIDE			2404
+wzl2440			MACH_WZL2440		WZL2440			2405
+sdrdemo			MACH_SDRDEMO		SDRDEMO			2406
+ethercan2		MACH_ETHERCAN2		ETHERCAN2		2407
+ecmimg20		MACH_ECMIMG20		ECMIMG20		2408
+omap_dragon		MACH_OMAP_DRAGON	OMAP_DRAGON		2409
+halo			MACH_HALO		HALO			2410
+huangshan		MACH_HUANGSHAN		HUANGSHAN		2411
+vl_ma2sc		MACH_VL_MA2SC		VL_MA2SC		2412
+raumfeld_rc		MACH_RAUMFELD_RC	RAUMFELD_RC		2413
+raumfeld_connector	MACH_RAUMFELD_CONNECTOR	RAUMFELD_CONNECTOR	2414
+raumfeld_speaker	MACH_RAUMFELD_SPEAKER	RAUMFELD_SPEAKER	2415
+multibus_master		MACH_MULTIBUS_MASTER	MULTIBUS_MASTER		2416
+multibus_pbk		MACH_MULTIBUS_PBK	MULTIBUS_PBK		2417
+tnetv107x		MACH_TNETV107X		TNETV107X		2418
+snake			MACH_SNAKE		SNAKE			2419
+cwmx27			MACH_CWMX27		CWMX27			2420
+sch_m480		MACH_SCH_M480		SCH_M480		2421
+platypus		MACH_PLATYPUS		PLATYPUS		2422
+pss2			MACH_PSS2		PSS2			2423
+davinci_apm150		MACH_DAVINCI_APM150	DAVINCI_APM150		2424
+str9100			MACH_STR9100		STR9100			2425
+net5big			MACH_NET5BIG		NET5BIG			2426
+seabed9263		MACH_SEABED9263		SEABED9263		2427
+mx51_m2id		MACH_MX51_M2ID		MX51_M2ID		2428
+octvocplus_eb		MACH_OCTVOCPLUS_EB	OCTVOCPLUS_EB		2429
+klk_firefox		MACH_KLK_FIREFOX	KLK_FIREFOX		2430
+klk_wirma_module	MACH_KLK_WIRMA_MODULE	KLK_WIRMA_MODULE	2431
+klk_wirma_mmi		MACH_KLK_WIRMA_MMI	KLK_WIRMA_MMI		2432
+supersonic		MACH_SUPERSONIC		SUPERSONIC		2433
+liberty			MACH_LIBERTY		LIBERTY			2434
+mh355			MACH_MH355		MH355			2435
+pc7802			MACH_PC7802		PC7802			2436
+gnet_sgc		MACH_GNET_SGC		GNET_SGC		2437
+einstein15		MACH_EINSTEIN15		EINSTEIN15		2438
+cmpd			MACH_CMPD		CMPD			2439
+davinci_hase1		MACH_DAVINCI_HASE1	DAVINCI_HASE1		2440
+lgeincitephone		MACH_LGEINCITEPHONE	LGEINCITEPHONE		2441
+ea313x			MACH_EA313X		EA313X			2442
+fwbd_39064		MACH_FWBD_39064		FWBD_39064		2443
+fwbd_390128		MACH_FWBD_390128	FWBD_390128		2444
+pelco_moe		MACH_PELCO_MOE		PELCO_MOE		2445
+minimix27		MACH_MINIMIX27		MINIMIX27		2446
+omap3_thunder		MACH_OMAP3_THUNDER	OMAP3_THUNDER		2447
+passionc		MACH_PASSIONC		PASSIONC		2448
+mx27amata		MACH_MX27AMATA		MX27AMATA		2449
+bgat1			MACH_BGAT1		BGAT1			2450
+buzz			MACH_BUZZ		BUZZ			2451
+mb9g20			MACH_MB9G20		MB9G20			2452
+yushan			MACH_YUSHAN		YUSHAN			2453
+lizard			MACH_LIZARD		LIZARD			2454
+omap3polycom		MACH_OMAP3POLYCOM	OMAP3POLYCOM		2455
+smdkv210		MACH_SMDKV210		SMDKV210		2456
+bravo			MACH_BRAVO		BRAVO			2457
+siogentoo1		MACH_SIOGENTOO1		SIOGENTOO1		2458
+siogentoo2		MACH_SIOGENTOO2		SIOGENTOO2		2459
+sm3k			MACH_SM3K		SM3K			2460
+acer_tempo_f900		MACH_ACER_TEMPO_F900	ACER_TEMPO_F900		2461
+sst61vc010_dev		MACH_SST61VC010_DEV	SST61VC010_DEV		2462
+glittertind		MACH_GLITTERTIND	GLITTERTIND		2463
+omap_zoom3		MACH_OMAP_ZOOM3		OMAP_ZOOM3		2464
+omap_3630sdp		MACH_OMAP_3630SDP	OMAP_3630SDP		2465
+cybook2440		MACH_CYBOOK2440		CYBOOK2440		2466
+torino_s		MACH_TORINO_S		TORINO_S		2467
+havana			MACH_HAVANA		HAVANA			2468
+beaumont_11		MACH_BEAUMONT_11	BEAUMONT_11		2469
+vanguard		MACH_VANGUARD		VANGUARD		2470
+s5pc110_draco		MACH_S5PC110_DRACO	S5PC110_DRACO		2471
+cartesio_two		MACH_CARTESIO_TWO	CARTESIO_TWO		2472
+aster			MACH_ASTER		ASTER			2473
diff --git a/arch/arm/vfp/entry.S b/arch/arm/vfp/entry.S
index ba592a9..a2bed62 100644
--- a/arch/arm/vfp/entry.S
+++ b/arch/arm/vfp/entry.S
@@ -15,13 +15,16 @@
  *  r10 = thread_info structure
  *  lr  = failure return
  */
-#include <linux/linkage.h>
-#include <linux/init.h>
-#include <asm/asm-offsets.h>
-#include <asm/assembler.h>
+#include <asm/thread_info.h>
 #include <asm/vfpmacros.h>
+#include "../kernel/entry-header.S"
 
 ENTRY(do_vfp)
+#ifdef CONFIG_PREEMPT
+	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count
+	add	r11, r4, #1		@ increment it
+	str	r11, [r10, #TI_PREEMPT]
+#endif
 	enable_irq
  	ldr	r4, .LCvfp
 	ldr	r11, [r10, #TI_CPU]	@ CPU number
@@ -30,6 +33,12 @@
 ENDPROC(do_vfp)
 
 ENTRY(vfp_null_entry)
+#ifdef CONFIG_PREEMPT
+	get_thread_info	r10
+	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count
+	sub	r11, r4, #1		@ decrement it
+	str	r11, [r10, #TI_PREEMPT]
+#endif
 	mov	pc, lr
 ENDPROC(vfp_null_entry)
 
@@ -41,6 +50,12 @@
 
 	__INIT
 ENTRY(vfp_testing_entry)
+#ifdef CONFIG_PREEMPT
+	get_thread_info	r10
+	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count
+	sub	r11, r4, #1		@ decrement it
+	str	r11, [r10, #TI_PREEMPT]
+#endif
 	ldr	r0, VFP_arch_address
 	str	r5, [r0]		@ known non-zero value
 	mov	pc, r9			@ we have handled the fault
diff --git a/arch/arm/vfp/vfp.h b/arch/arm/vfp/vfp.h
index 8de86e4..3394d42 100644
--- a/arch/arm/vfp/vfp.h
+++ b/arch/arm/vfp/vfp.h
@@ -377,6 +377,5 @@
 	u32 flags;
 };
 
-#if defined(CONFIG_SMP) || defined(CONFIG_PM)
 extern void vfp_save_state(void *location, u32 fpexc);
-#endif
+extern void vfp_pm_save_context(void);
diff --git a/arch/arm/vfp/vfphw.S b/arch/arm/vfp/vfphw.S
index c92a08b..83c4e38 100644
--- a/arch/arm/vfp/vfphw.S
+++ b/arch/arm/vfp/vfphw.S
@@ -137,6 +137,12 @@
 	VFPFMXR	FPEXC, r1		@ restore FPEXC last
 	sub	r2, r2, #4
 	str	r2, [sp, #S_PC]		@ retry the instruction
+#ifdef CONFIG_PREEMPT
+	get_thread_info	r10
+	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count
+	sub	r11, r4, #1		@ decrement it
+	str	r11, [r10, #TI_PREEMPT]
+#endif
 	mov	pc, r9			@ we think we have handled things
 
 
@@ -155,6 +161,12 @@
 	@ not recognised by VFP
 
 	DBGSTR	"not VFP"
+#ifdef CONFIG_PREEMPT
+	get_thread_info	r10
+	ldr	r4, [r10, #TI_PREEMPT]	@ get preempt count
+	sub	r11, r4, #1		@ decrement it
+	str	r11, [r10, #TI_PREEMPT]
+#endif
 	mov	pc, lr
 
 process_exception:
@@ -172,7 +184,6 @@
 					@ retry the faulted instruction
 ENDPROC(vfp_support_entry)
 
-#if defined(CONFIG_SMP) || defined(CONFIG_PM)
 ENTRY(vfp_save_state)
 	@ Save the current VFP state
 	@ r0 - save location
@@ -190,7 +201,6 @@
 	stmia	r0, {r1, r2, r3, r12}	@ save FPEXC, FPSCR, FPINST, FPINST2
 	mov	pc, lr
 ENDPROC(vfp_save_state)
-#endif
 
 last_VFP_context_address:
 	.word	last_VFP_context
diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c
index 9f476a1..93da971 100644
--- a/arch/arm/vfp/vfpmodule.c
+++ b/arch/arm/vfp/vfpmodule.c
@@ -266,7 +266,7 @@
 		 * on VFP subarch 1.
 		 */
 		 vfp_raise_exceptions(VFP_EXCEPTION_ERROR, trigger, fpscr, regs);
-		 return;
+		goto exit;
 	}
 
 	/*
@@ -297,7 +297,7 @@
 	 * the FPEXC.FP2V bit is valid only if FPEXC.EX is 1.
 	 */
 	if (fpexc ^ (FPEXC_EX | FPEXC_FP2V))
-		return;
+		goto exit;
 
 	/*
 	 * The barrier() here prevents fpinst2 being read
@@ -310,6 +310,8 @@
 	exceptions = vfp_emulate_instruction(trigger, orig_fpscr, regs);
 	if (exceptions)
 		vfp_raise_exceptions(exceptions, trigger, orig_fpscr, regs);
+ exit:
+	preempt_enable();
 }
 
 static void vfp_enable(void *unused)
@@ -325,34 +327,41 @@
 #ifdef CONFIG_PM
 #include <linux/sysdev.h>
 
+ void vfp_pm_save_context(void)
+ {
+	struct thread_info *thread = current_thread_info();
+	u32 fpexc = fmrx(FPEXC);
+	__u32 cpu = thread->cpu;
+	int vfp_enabled;
+
+	vfp_enabled = fpexc & FPEXC_EN;
+
+	if (last_VFP_context[cpu]) {
+		if (!vfp_enabled) {
+			/* enable vfp now to save context */
+			vfp_enable(NULL);
+			fmxr(FPEXC, fmrx(FPEXC) | FPEXC_EN);
+		}
+		vfp_save_state(last_VFP_context[cpu], fpexc);
+
+		/* Disable vfp. The next inst traps an exception and restores*/
+		fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
+
+		/*
+		 * This is needed else the restore might fail if it sees
+		 * last_VFP_context if same as the current threads vfp_state.
+		 */
+		last_VFP_context[cpu] = NULL;
+	}
+ }
+
 static int vfp_pm_suspend(struct sys_device *dev, pm_message_t state)
 {
-	struct thread_info *ti = current_thread_info();
-	u32 fpexc = fmrx(FPEXC);
-
-	/* if vfp is on, then save state for resumption */
-	if (fpexc & FPEXC_EN) {
-		printk(KERN_DEBUG "%s: saving vfp state\n", __func__);
-		vfp_save_state(&ti->vfpstate, fpexc);
-
-		/* disable, just in case */
-		fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
-	}
-
-	/* clear any information we had about last context state */
-	memset(last_VFP_context, 0, sizeof(last_VFP_context));
-
 	return 0;
 }
 
 static int vfp_pm_resume(struct sys_device *dev)
 {
-	/* ensure we have access to the vfp */
-	vfp_enable(NULL);
-
-	/* and disable it to ensure the next usage restores the state */
-	fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN);
-
 	return 0;
 }
 
@@ -377,6 +386,55 @@
 static inline void vfp_pm_init(void) { }
 #endif /* CONFIG_PM */
 
+/*
+ * Synchronise the hardware VFP state of a thread other than current with the
+ * saved one. This function is used by the ptrace mechanism.
+ */
+#ifdef CONFIG_SMP
+void vfp_sync_state(struct thread_info *thread)
+{
+	/*
+	 * On SMP systems, the VFP state is automatically saved at every
+	 * context switch. We mark the thread VFP state as belonging to a
+	 * non-existent CPU so that the saved one will be reloaded when
+	 * needed.
+	 */
+	thread->vfpstate.hard.cpu = NR_CPUS;
+}
+#else
+void vfp_sync_state(struct thread_info *thread)
+{
+	unsigned int cpu = get_cpu();
+	u32 fpexc = fmrx(FPEXC);
+
+	/*
+	 * If VFP is enabled, the previous state was already saved and
+	 * last_VFP_context updated.
+	 */
+	if (fpexc & FPEXC_EN)
+		goto out;
+
+	if (!last_VFP_context[cpu])
+		goto out;
+
+	/*
+	 * Save the last VFP state on this CPU.
+	 */
+	fmxr(FPEXC, fpexc | FPEXC_EN);
+	vfp_save_state(last_VFP_context[cpu], fpexc);
+	fmxr(FPEXC, fpexc);
+
+	/*
+	 * Set the context to NULL to force a reload the next time the thread
+	 * uses the VFP.
+	 */
+	last_VFP_context[cpu] = NULL;
+
+out:
+	put_cpu();
+}
+#endif
+
 #include <linux/smp.h>
 
 /*
@@ -427,6 +485,18 @@
 		 * in place; report VFP support to userspace.
 		 */
 		elf_hwcap |= HWCAP_VFP;
+#ifdef CONFIG_VFPv3
+		if (VFP_arch >= 3) {
+			elf_hwcap |= HWCAP_VFPv3;
+
+			/*
+			 * Check for VFPv3 D16. CPUs in this configuration
+			 * only have 16 x 64bit registers.
+			 */
+			if (((fmrx(MVFR0) & MVFR0_A_SIMD_MASK)) == 1)
+				elf_hwcap |= HWCAP_VFPv3D16;
+		}
+#endif
 #ifdef CONFIG_NEON
 		/*
 		 * Check for the presence of the Advanced SIMD
diff --git a/block/genhd.c b/block/genhd.c
index a9ec910..21f8b4e 100644
--- a/block/genhd.c
+++ b/block/genhd.c
@@ -977,6 +977,22 @@
 	free_part_stats(&disk->part0);
 	kfree(disk);
 }
+
+static int disk_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct gendisk *disk = dev_to_disk(dev);
+	struct disk_part_iter piter;
+	struct hd_struct *part;
+	int cnt = 0;
+
+	disk_part_iter_init(&piter, disk, 0);
+	while((part = disk_part_iter_next(&piter)))
+		cnt++;
+	disk_part_iter_exit(&piter);
+	add_uevent_var(env, "NPARTS=%u", cnt);
+	return 0;
+}
+
 struct class block_class = {
 	.name		= "block",
 };
@@ -985,6 +1001,7 @@
 	.name		= "disk",
 	.groups		= disk_attr_groups,
 	.release	= disk_release,
+	.uevent		= disk_uevent,
 };
 
 #ifdef CONFIG_PROC_FS
diff --git a/drivers/bluetooth/hci_ll.c b/drivers/bluetooth/hci_ll.c
index a942bf1..a73ff9e 100644
--- a/drivers/bluetooth/hci_ll.c
+++ b/drivers/bluetooth/hci_ll.c
@@ -32,7 +32,6 @@
 
 #include <linux/init.h>
 #include <linux/sched.h>
-#include <linux/types.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
 #include <linux/ptrace.h>
@@ -49,9 +48,10 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#ifdef CONFIG_SERIAL_OMAP
-#include <mach/omap-serial.h>
-#endif
+#include <linux/stddef.h>
+#include <linux/spinlock.h>
+#include <linux/gfp.h>
+#include <net/bluetooth/hci.h>
 
 #include "hci_uart.h"
 
@@ -69,12 +69,10 @@
 #define HCILL_W4_DATA		4
 
 /* HCILL states */
-enum hcill_states_e {
-	HCILL_ASLEEP,
-	HCILL_ASLEEP_TO_AWAKE,
-	HCILL_AWAKE,
-	HCILL_AWAKE_TO_ASLEEP
-};
+#define HCILL_ASLEEP            0
+#define HCILL_ASLEEP_TO_AWAKE   1
+#define HCILL_AWAKE             2
+#define HCILL_AWAKE_TO_ASLEEP   3
 
 struct hcill_cmd {
 	u8 cmd;
@@ -90,6 +88,7 @@
 	struct sk_buff_head tx_wait_q;	/* HCILL wait queue	*/
 };
 
+static inline int ll_check_data_len(struct ll_struct *ll, int len);
 /*
  * Builds and sends an HCILL command packet.
  * These are very simple packets with only 1 cmd byte
@@ -198,7 +197,7 @@
  */
 static void ll_device_want_to_wakeup(struct hci_uart *hu)
 {
-	unsigned long flags;
+	unsigned long flags = 0;
 	struct ll_struct *ll = hu->priv;
 
 	BT_DBG("hu %p", hu);
@@ -248,7 +247,7 @@
  */
 static void ll_device_want_to_sleep(struct hci_uart *hu)
 {
-	unsigned long flags;
+	unsigned long flags = 0;
 	struct ll_struct *ll = hu->priv;
 
 	BT_DBG("hu %p", hu);
@@ -281,7 +280,7 @@
  */
 static void ll_device_woke_up(struct hci_uart *hu)
 {
-	unsigned long flags;
+	unsigned long flags = 0;
 	struct ll_struct *ll = hu->priv;
 
 	BT_DBG("hu %p", hu);
@@ -530,16 +529,10 @@
 	else
 		BT_ERR("HCILL protocol registration failed");
 
-#ifdef CONFIG_SERIAL_OMAP
-	omap24xx_uart_cts_wakeup(1, 1);
-#endif
 	return err;
 }
 
 int ll_deinit(void)
 {
-#ifdef CONFIG_SERIAL_OMAP
-	omap24xx_uart_cts_wakeup(1, 0);
-#endif
 	return hci_uart_unregister_proto(&llp);
 }
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c
index cbfc99d..2ca76ef 100644
--- a/drivers/cpufreq/cpufreq_conservative.c
+++ b/drivers/cpufreq/cpufreq_conservative.c
@@ -522,7 +522,7 @@
 			if (latency == 0)
 				latency = 1;
 
-			def_sampling_rate = 10 * latency *
+			def_sampling_rate = latency *
 				CONFIG_CPU_FREQ_SAMPLING_LATENCY_MULTIPLIER;
 
 			if (def_sampling_rate < MIN_STAT_SAMPLING_RATE)
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c
index 6c80533..2999fa7 100644
--- a/drivers/cpufreq/cpufreq_ondemand.c
+++ b/drivers/cpufreq/cpufreq_ondemand.c
@@ -489,7 +489,8 @@
 	/* We want all CPUs to do sampling nearly on same jiffy */
 	int delay = usecs_to_jiffies(dbs_tuners_ins.sampling_rate);
 
-	delay -= jiffies % delay;
+	if (num_online_cpus() > 1)
+		delay -= jiffies % delay;
 
 	if (lock_policy_rwsem_write(cpu) < 0)
 		return;
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index c0ff97d..ee53ccb 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -23,10 +23,11 @@
 
 static spinlock_t cpufreq_stats_lock;
 
-#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show) \
+#define CPUFREQ_STATDEVICE_ATTR(_name,_mode,_show, _store) \
 static struct freq_attr _attr_##_name = {\
 	.attr = {.name = __stringify(_name), .mode = _mode, }, \
 	.show = _show,\
+	.store = _store,\
 };
 
 struct cpufreq_stats {
@@ -43,6 +44,8 @@
 #endif
 };
 
+static int ignore_idle;
+
 static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table);
 
 struct cpufreq_stats_attribute {
@@ -139,15 +142,33 @@
 		return PAGE_SIZE;
 	return len;
 }
-CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table);
+CPUFREQ_STATDEVICE_ATTR(trans_table,0444,show_trans_table, NULL);
 #endif
 
-CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans);
-CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state);
+static ssize_t store_ignore_idle(struct cpufreq_policy *policy, char *buf)
+{
+	int input;
+	if (sscanf(buf, "%d", &input) != 1)
+		return -EINVAL;
+
+	ignore_idle = input;
+	return 1;
+}
+
+static ssize_t show_ignore_idle(struct cpufreq_policy *policy, char *buf)
+{
+	return sprintf(buf, "%d\n", ignore_idle);
+}
+
+CPUFREQ_STATDEVICE_ATTR(total_trans,0444,show_total_trans, NULL);
+CPUFREQ_STATDEVICE_ATTR(time_in_state,0444,show_time_in_state, NULL);
+CPUFREQ_STATDEVICE_ATTR(ignore_idle, 0664, show_ignore_idle, store_ignore_idle);
+
 
 static struct attribute *default_attrs[] = {
 	&_attr_total_trans.attr,
 	&_attr_time_in_state.attr,
+	&_attr_ignore_idle.attr,
 #ifdef CONFIG_CPU_FREQ_STAT_DETAILS
 	&_attr_trans_table.attr,
 #endif
@@ -308,6 +329,21 @@
 	return 0;
 }
 
+void cpufreq_exit_idle(int cpu, unsigned long ticks)
+{
+	struct cpufreq_stats *stat;
+	stat = per_cpu(cpufreq_stats_table, cpu);
+
+	/* Wait until cpu stats is initalized */
+	if (!ignore_idle || !stat || !stat->time_in_state)
+		return;
+
+	spin_lock(&cpufreq_stats_lock);
+	stat->time_in_state[stat->last_index] =
+		cputime_sub(stat->time_in_state[stat->last_index], ticks);
+	spin_unlock(&cpufreq_stats_lock);
+}
+
 static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb,
 					       unsigned long action,
 					       void *hcpu)
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 8504a21..03e78c6 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -75,8 +75,10 @@
 #endif
 	/* ask the governor for the next state */
 	next_state = cpuidle_curr_governor->select(dev);
-	if (need_resched())
+	if (need_resched()) {
+		local_irq_enable();
 		return;
+	}
 	target_state = &dev->states[next_state];
 
 	/* enter the state and update stats */
@@ -175,6 +177,7 @@
 	}
 	dev->last_residency = 0;
 	dev->last_state = NULL;
+	dev->max_state = dev->state_count;
 
 	smp_wmb();
 
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index f1df59f..5f4a26d 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -56,7 +56,7 @@
 	data->predicted_us /= 100;
 
 	/* find the deepest idle state that satisfies our constraints */
-	for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->state_count; i++) {
+	for (i = CPUIDLE_DRIVER_STATE_START + 1; i < dev->max_state; i++) {
 		struct cpuidle_state *s = &dev->states[i];
 
 		if (s->target_residency > data->expected_us)
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 97b0038..2d70050 100644
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -162,12 +162,36 @@
 
 #define kobj_to_cpuidledev(k) container_of(k, struct cpuidle_device, kobj)
 #define attr_to_cpuidleattr(a) container_of(a, struct cpuidle_attr, attr)
+
+static ssize_t show_cpuidle_maxstate(struct cpuidle_device *dev, char *buf)
+{
+	return sprintf(buf, "%x\n", (dev->max_state - 1));
+}
+
+static size_t store_cpuidle_maxstate(struct cpuidle_device *dev, char *buf,
+						size_t count)
+{
+	 int value;
+
+	if (sscanf(buf, "%x", &value) != 1) {
+		printk(KERN_ERR "store_cpuidle_maxstate: Invalid value\n");
+		return -EINVAL;
+	}
+	dev->max_state = value + 1;
+	return count;
+}
+
+define_one_rw(max_state, show_cpuidle_maxstate, store_cpuidle_maxstate);
+static struct attribute *cpuidle_default_attr[] = {
+	&attr_max_state.attr,
+	NULL
+};
+
 static ssize_t cpuidle_show(struct kobject * kobj, struct attribute * attr ,char * buf)
 {
 	int ret = -EIO;
 	struct cpuidle_device *dev = kobj_to_cpuidledev(kobj);
 	struct cpuidle_attr * cattr = attr_to_cpuidleattr(attr);
-
 	if (cattr->show) {
 		mutex_lock(&cpuidle_lock);
 		ret = cattr->show(dev, buf);
@@ -205,6 +229,7 @@
 
 static struct kobj_type ktype_cpuidle = {
 	.sysfs_ops = &cpuidle_sysfs_ops,
+	.default_attrs = cpuidle_default_attr,
 	.release = cpuidle_sysfs_release,
 };
 
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 42fb2fd..501fb64 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -140,7 +140,7 @@
 int __init gpiochip_reserve(int start, int ngpio)
 {
 	int ret = 0;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 	int i;
 
 	if (!gpio_is_valid(start) || !gpio_is_valid(start + ngpio - 1))
@@ -435,7 +435,7 @@
  */
 int gpio_export(unsigned gpio, bool direction_may_change)
 {
-	unsigned long		flags;
+	unsigned long		uninitialized_var(flags);
 	struct gpio_desc	*desc;
 	int			status = -EINVAL;
 
@@ -559,7 +559,7 @@
 	mutex_unlock(&sysfs_lock);
 
 	if (status) {
-		unsigned long	flags;
+		unsigned long	uninitialized_var(flags);
 		unsigned	gpio;
 
 		spin_lock_irqsave(&gpio_lock, flags);
@@ -599,7 +599,7 @@
 static int __init gpiolib_sysfs_init(void)
 {
 	int		status;
-	unsigned long	flags;
+	unsigned long	uninitialized_var(flags);
 	unsigned	gpio;
 
 	status = class_register(&gpio_class);
@@ -662,7 +662,7 @@
  */
 int gpiochip_add(struct gpio_chip *chip)
 {
-	unsigned long	flags;
+	unsigned long	uninitialized_var(flags);
 	int		status = 0;
 	unsigned	id;
 	int		base = chip->base;
@@ -729,7 +729,7 @@
  */
 int gpiochip_remove(struct gpio_chip *chip)
 {
-	unsigned long	flags;
+	unsigned long	uninitialized_var(flags);
 	int		status = 0;
 	unsigned	id;
 
@@ -765,7 +765,7 @@
 	struct gpio_desc	*desc;
 	struct gpio_chip	*chip;
 	int			status = -EINVAL;
-	unsigned long		flags;
+	unsigned long		uninitialized_var(flags);
 
 	spin_lock_irqsave(&gpio_lock, flags);
 
@@ -816,7 +816,7 @@
 
 void gpio_free(unsigned gpio)
 {
-	unsigned long		flags;
+	unsigned long		uninitialized_var(flags);
 	struct gpio_desc	*desc;
 	struct gpio_chip	*chip;
 
@@ -892,7 +892,7 @@
 
 int gpio_direction_input(unsigned gpio)
 {
-	unsigned long		flags;
+	unsigned long		uninitialized_var(flags);
 	struct gpio_chip	*chip;
 	struct gpio_desc	*desc = &gpio_desc[gpio];
 	int			status = -EINVAL;
@@ -945,7 +945,7 @@
 
 int gpio_direction_output(unsigned gpio, int value)
 {
-	unsigned long		flags;
+	unsigned long		uninitialized_var(flags);
 	struct gpio_chip	*chip;
 	struct gpio_desc	*desc = &gpio_desc[gpio];
 	int			status = -EINVAL;
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index c35ada8..1ee0bfd 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -37,6 +37,7 @@
 #include <linux/platform_device.h>
 #include <linux/clk.h>
 #include <linux/io.h>
+#include <mach/omap-pm.h>
 
 /* I2C controller revisions */
 #define OMAP_I2C_REV_2			0x20
@@ -156,6 +157,9 @@
 #define SYSC_IDLEMODE_SMART		0x2
 #define SYSC_CLOCKACTIVITY_FCLK		0x2
 
+/* MPU wake-up latency Constraint in usec */
+#define OMAP_MPU_WAKEUP_LAT		400
+
 
 struct omap_i2c_dev {
 	struct device		*dev;
@@ -238,12 +242,14 @@
 		clk_enable(dev->iclk);
 	clk_enable(dev->fclk);
 	if (cpu_is_omap34xx()) {
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, 0);
 		omap_i2c_write_reg(dev, OMAP_I2C_PSC_REG, dev->pscstate);
 		omap_i2c_write_reg(dev, OMAP_I2C_SCLL_REG, dev->scllstate);
 		omap_i2c_write_reg(dev, OMAP_I2C_SCLH_REG, dev->sclhstate);
 		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG, dev->bufstate);
 		omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, dev->syscstate);
 		omap_i2c_write_reg(dev, OMAP_I2C_WE_REG, dev->westate);
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG, OMAP_I2C_CON_EN);
 	}
 	dev->idle = 0;
 	omap_i2c_write_reg(dev, OMAP_I2C_IE_REG, dev->iestate);
@@ -280,6 +286,21 @@
 	unsigned long internal_clk = 0;
 
 	if (dev->rev >= OMAP_I2C_REV_2) {
+		/* Disable I2C controller before soft reset */
+		omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
+			omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
+				~(OMAP_I2C_CON_EN));
+		timeout = jiffies + OMAP_I2C_TIMEOUT;
+		while ((omap_i2c_read_reg(dev, OMAP_I2C_CON_REG) &
+			OMAP_I2C_CON_EN)) {
+			if (time_after(jiffies, timeout)) {
+				dev_warn(dev->dev, "timeout waiting "
+						"for controller reset\n");
+				return -ETIMEDOUT;
+			}
+			schedule();
+		}
+
 		omap_i2c_write_reg(dev, OMAP_I2C_SYSC_REG, SYSC_SOFTRESET_MASK);
 		/* For some reason we need to set the EN bit before the
 		 * reset done bit gets set. */
@@ -292,7 +313,7 @@
 						"for controller reset\n");
 				return -ETIMEDOUT;
 			}
-			msleep(1);
+			schedule();
 		}
 
 		/* SYSC register is cleared by the reset; rewrite it */
@@ -530,8 +551,16 @@
 	 * REVISIT: We should abort the transfer on signals, but the bus goes
 	 * into arbitration and we're currently unable to recover from it.
 	 */
+
+	/*
+	 * REVISIT: Add a mpu wake-up latency constraint to let us wake
+	 * quickly enough for i2c transfers to work properly. Should change
+	 * the code to use a latency constraint function passed from pdata.
+	 */
+	omap_pm_set_max_mpu_wakeup_lat(dev->dev, OMAP_MPU_WAKEUP_LAT);
 	r = wait_for_completion_timeout(&dev->cmd_complete,
 					OMAP_I2C_TIMEOUT);
+	omap_pm_set_max_mpu_wakeup_lat(dev->dev, -1);
 	dev->buf_len = 0;
 	if (r < 0)
 		return r;
@@ -675,37 +704,6 @@
 #define omap_i2c_rev1_isr		NULL
 #endif
 
-/* I2C Errata 1.153:
- * When an XRDY/XDR is hit, wait for XUDF before writing data to DATA_REG.
- * Otherwise some data bytes can be lost while transferring them from the
- * memory to the I2C interface.
- */
-
-static int omap_i2c_wait_for_xudf(struct omap_i2c_dev *dev)
-{
-	u16 xudf;
-	int counter = 500;
-
-	/* We are in interrupt context. Wait for XUDF for max 7 msec */
-	xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
-	while (!(xudf & OMAP_I2C_STAT_XUDF) && counter--) {
-		if (xudf & (OMAP_I2C_STAT_ROVR | OMAP_I2C_STAT_NACK |
-			    OMAP_I2C_STAT_AL))
-			return -EINVAL;
-		udelay(10);
-		xudf = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
-	}
-
-	if (!counter) {
-		/* Clear Tx FIFO */
-		omap_i2c_write_reg(dev, OMAP_I2C_BUF_REG,
-				OMAP_I2C_BUF_TXFIF_CLR);
-		return -ETIMEDOUT;
-	}
-
-	return 0;
-}
-
 static irqreturn_t
 omap_i2c_isr(int this_irq, void *dev_id)
 {
@@ -713,7 +711,6 @@
 	u16 bits;
 	u16 stat, w;
 	int err, count = 0;
-	int error;
 
 	if (dev->idle)
 		return IRQ_NONE;
@@ -726,9 +723,18 @@
 			break;
 		}
 
-		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat);
-
 		err = 0;
+
+complete:
+		/*
+		 * Ack the stat in one go, but [R/X]DR and [R/X]RDY should be
+		 * acked after the data operation is complete.
+		 * Ref: TRM SWPU114Q Figure 18-31
+		 */
+		omap_i2c_write_reg(dev, OMAP_I2C_STAT_REG, stat &
+				~(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+				OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+
 		if (stat & OMAP_I2C_STAT_NACK) {
 			err |= OMAP_I2C_STAT_NACK;
 			omap_i2c_write_reg(dev, OMAP_I2C_CON_REG,
@@ -739,8 +745,13 @@
 			err |= OMAP_I2C_STAT_AL;
 		}
 		if (stat & (OMAP_I2C_STAT_ARDY | OMAP_I2C_STAT_NACK |
-					OMAP_I2C_STAT_AL))
+					OMAP_I2C_STAT_AL)) {
+			omap_i2c_ack_stat(dev, stat &
+				(OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR |
+				OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
 			omap_i2c_complete_cmd(dev, err);
+			return IRQ_HANDLED;
+		}
 		if (stat & (OMAP_I2C_STAT_RRDY | OMAP_I2C_STAT_RDR)) {
 			u8 num_bytes = 1;
 			/* 3430 I2C Errata 1.15
@@ -801,23 +812,11 @@
 							& 0x3F;
 			}
 			while (num_bytes) {
+				num_bytes--;
 				w = 0;
 				if (dev->buf_len) {
-					if (cpu_is_omap34xx()) {
-						/* OMAP3430 Errata 1.153 */
-						error = omap_i2c_wait_for_xudf(dev);
-						if (error) {
-							omap_i2c_ack_stat(dev, stat &
-								(OMAP_I2C_STAT_XRDY |
-								 OMAP_I2C_STAT_XDR));
-							dev_err(dev->dev, "Transmit error\n");
-							omap_i2c_complete_cmd(dev, OMAP_I2C_STAT_XUDF);
-
-							return IRQ_HANDLED;
-						}
-					}
-
 					w = *dev->buf++;
+					dev->buf_len--;
 					/* Data reg from  2430 is 8 bit wide */
 					if (!cpu_is_omap2430() &&
 							!cpu_is_omap34xx()) {
@@ -826,10 +825,6 @@
 							dev->buf_len--;
 						}
 					}
-					omap_i2c_write_reg(dev,
-						OMAP_I2C_DATA_REG, w);
-					num_bytes--;
-					dev->buf_len--;
 				} else {
 					if (stat & OMAP_I2C_STAT_XRDY)
 						dev_err(dev->dev,
@@ -841,6 +836,28 @@
 							"data to send\n");
 					break;
 				}
+
+				/*
+				 * OMAP3430 Errata 1.153: When an XRDY/XDR
+				 * is hit, wait for XUDF before writing data
+				 * to DATA_REG. Otherwise some data bytes can
+				 * be lost while transferring them from the
+				 * memory to the I2C interface.
+				 */
+
+				if (dev->rev <= OMAP_I2C_REV_ON_3430) {
+						while (!(stat & OMAP_I2C_STAT_XUDF)) {
+							if (stat & (OMAP_I2C_STAT_NACK | OMAP_I2C_STAT_AL)) {
+								omap_i2c_ack_stat(dev, stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
+								err |= OMAP_I2C_STAT_XUDF;
+								goto complete;
+							}
+							cpu_relax();
+							stat = omap_i2c_read_reg(dev, OMAP_I2C_STAT_REG);
+						}
+				}
+
+				omap_i2c_write_reg(dev, OMAP_I2C_DATA_REG, w);
 			}
 			omap_i2c_ack_stat(dev,
 				stat & (OMAP_I2C_STAT_XRDY | OMAP_I2C_STAT_XDR));
diff --git a/drivers/i2c/chips/twl4030-poweroff.c b/drivers/i2c/chips/twl4030-poweroff.c
index 0ebab0b..89761fe 100644
--- a/drivers/i2c/chips/twl4030-poweroff.c
+++ b/drivers/i2c/chips/twl4030-poweroff.c
@@ -27,29 +27,47 @@
 
 #define PWR_P1_SW_EVENTS	0x10
 #define PWR_DEVOFF	(1<<0)
+#define PWR_STOPON_POWERON (1<<6)
+
+#define CFG_P123_TRANSITION	0x03
+#define SEQ_OFFSYNC	(1<<0)
 
 static void twl4030_poweroff(void)
 {
-	u8 val;
+	u8 uninitialized_var(val);
 	int err;
 
+	/* Make sure SEQ_OFFSYNC is set so that all the res goes to wait-on */
+	err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
+				   CFG_P123_TRANSITION);
+	if (err) {
+		pr_warning("I2C error %d while reading TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err);
+		return;
+	}
+
+	val |= SEQ_OFFSYNC;
+	err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
+				    CFG_P123_TRANSITION);
+	if (err) {
+		pr_warning("I2C error %d while writing TWL4030 PM_MASTER CFG_P123_TRANSITION\n", err);
+		return;
+	}
+
 	err = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &val,
 				  PWR_P1_SW_EVENTS);
 	if (err) {
-		printk(KERN_WARNING "I2C error %d while reading TWL4030"
-					"PM_MASTER P1_SW_EVENTS\n", err);
-		return ;
+		pr_warning("I2C error %d while reading TWL4030 PM_MASTER P1_SW_EVENTS\n", err);
+		return;
 	}
 
-	val |= PWR_DEVOFF;
+	val |= PWR_STOPON_POWERON | PWR_DEVOFF;
 
 	err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, val,
 				   PWR_P1_SW_EVENTS);
 
 	if (err) {
-		printk(KERN_WARNING "I2C error %d while writing TWL4030"
-					"PM_MASTER P1_SW_EVENTS\n", err);
-		return ;
+		pr_warning("I2C error %d while writing TWL4030 PM_MASTER P1_SW_EVENTS\n", err);
+		return;
 	}
 
 	return;
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index af87135..88f3259 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -45,6 +45,7 @@
 	struct evdev *evdev;
 	struct list_head node;
 	struct wake_lock wake_lock;
+	char name[28];
 };
 
 static struct evdev *evdev_table[EVDEV_MINORS];
@@ -279,7 +280,9 @@
 	}
 
 	spin_lock_init(&client->buffer_lock);
-	wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, "evdev");
+	snprintf(client->name, sizeof(client->name), "%s-%d", evdev->name,
+			task_tgid_vnr(current));
+	wake_lock_init(&client->wake_lock, WAKE_LOCK_SUSPEND, client->name);
 	client->evdev = evdev;
 	evdev_attach_client(evdev, client);
 
diff --git a/drivers/input/keyboard/twl4030_keypad.c b/drivers/input/keyboard/twl4030_keypad.c
index 8bfd650..bb8976e 100644
--- a/drivers/input/keyboard/twl4030_keypad.c
+++ b/drivers/input/keyboard/twl4030_keypad.c
@@ -270,7 +270,7 @@
 static irqreturn_t do_kp_irq(int irq, void *_kp)
 {
 	struct twl4030_keypad *kp = _kp;
-	u8 reg;
+	u8 uninitialized_var(reg);
 	int ret;
 
 #ifdef CONFIG_LOCKDEP
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 94b4c75..5ab3146 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -49,7 +49,6 @@
 	tristate
 	depends on MEDIA_TUNER
 
-source "drivers/media/video/omap-vout/Kconfig"
 #
 # Multimedia Video device configuration
 #
@@ -747,7 +746,7 @@
 	---help---
         V4L2 DSS and Camera driver support for OMAP2/3 based boards.
 
-# source "drivers/media/video/omap/Kconfig"
+source "drivers/media/video/omap/Kconfig"
 
 source "drivers/media/video/isp/Kconfig"
 
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 2c6194a..18f928f 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -10,7 +10,8 @@
 
 omap2cam-objs	:=	omap24xxcam.o omap24xxcam-dma.o
 
-videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o
+videodev-objs	:=	v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-subdev.o \
+			v4l2-fh.o v4l2-event.o
 
 obj-$(CONFIG_VIDEO_DEV) += videodev.o v4l2-int-device.o
 ifeq ($(CONFIG_COMPAT),y)
@@ -112,6 +113,8 @@
 
 obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
 
+obj-$(CONFIG_VIDEO_OMAP3_V4L2) += omap/
+
 obj-$(CONFIG_VIDEO_IMX046)      += imx046.o
 obj-$(CONFIG_VIDEO_LV8093)      += lv8093.o
 obj-$(CONFIG_USB_DABUSB)        += dabusb.o
@@ -143,7 +146,6 @@
 obj-$(CONFIG_VIDEO_PXA27x)	+= pxa_camera.o
 obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)	+= sh_mobile_ceu_camera.o
 obj-$(CONFIG_VIDEO_OMAP2)		+= omap2cam.o
-obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT) += omap-vout/
 obj-$(CONFIG_SOC_CAMERA)	+= soc_camera.o
 obj-$(CONFIG_SOC_CAMERA_MT9M001)	+= mt9m001.o
 obj-$(CONFIG_SOC_CAMERA_MT9M111)	+= mt9m111.o
diff --git a/drivers/media/video/imx046.c b/drivers/media/video/imx046.c
index 852e1a1..84cc80c 100644
--- a/drivers/media/video/imx046.c
+++ b/drivers/media/video/imx046.c
@@ -93,7 +93,6 @@
 	int scaler;
 	int ver;
 	int fps;
-	int state;
 	bool resuming;
 };
 
@@ -105,15 +104,13 @@
 /* list of image formats supported by imx046 sensor */
 const static struct v4l2_fmtdesc imx046_formats[] = {
 	{
-		.description	= "Bayer10 (GrR/BGb)",
-		.pixelformat	= V4L2_PIX_FMT_SGRBG10,
+		.description	= "Bayer10 (RGr/GbB)",
+		.pixelformat	= V4L2_PIX_FMT_SRGGB10,
 	}
 };
 
 #define NUM_CAPTURE_FORMATS ARRAY_SIZE(imx046_formats)
 
-static u32 min_exposure_time = 1000;
-static u32 max_exposure_time = 128000;
 static enum v4l2_power current_power_state;
 
 /* Structure of Sensor settings that change with image size */
@@ -190,6 +187,41 @@
 		},
 	},
 
+	/* 729p_MP */
+	{
+		.clk = {
+			.pre_pll_div = 1,
+			.pll_mult = 36,
+			.post_pll_div = 1,
+			.vt_pix_clk_div = 10,
+			.vt_sys_clk_div = 1,
+		},
+		.mipi = {
+			.data_lanes = 1,
+			.ths_prepare = 6,
+			.ths_zero = 9,
+			.ths_settle_lower = 23,
+			.ths_settle_upper = 59,
+		},
+		.frame = {
+			.frame_len_lines_min = 1250,
+			.line_len_pck = 3456,
+			.x_addr_start = 348,
+			.x_addr_end = 2931,
+			.y_addr_start = 503,
+			.y_addr_end = 1960,
+			.x_output_size = 1292,
+			.y_output_size = 729,
+			.x_even_inc = 1,
+			.x_odd_inc = 3,
+			.y_even_inc = 1,
+			.y_odd_inc = 3,
+			.v_mode_add = 0,
+			.h_mode_add = 0,
+			.h_add_ave = 1,
+		},
+	},
+
 	/* TWO_MP */
 	{
 		.clk = {
@@ -201,10 +233,10 @@
 		},
 		.mipi = {
 			.data_lanes = 2,
-			.ths_prepare = 4,
-			.ths_zero = 5,
-			.ths_settle_lower = 13,
-			.ths_settle_upper = 33,
+			.ths_prepare = 2,
+			.ths_zero = 4,
+			.ths_settle_lower = 8,
+			.ths_settle_upper = 24,
 		},
 		.frame = {
 			.frame_len_lines_min = 629,
@@ -236,10 +268,10 @@
 		},
 		.mipi = {
 			.data_lanes = 2,
-			.ths_prepare = 4,
-			.ths_zero = 5,
-			.ths_settle_lower = 13,
-			.ths_settle_upper = 33,
+			.ths_prepare = 2,
+			.ths_zero = 4,
+			.ths_settle_lower = 8,
+			.ths_settle_upper = 24,
 		},
 		.frame = {
 			.frame_len_lines_min = 2510,
@@ -545,7 +577,6 @@
 	u16 isize = isize_current;
 	u32 frame_length_lines, line_time_q8;
 	struct imx046_sensor *sensor = s->priv;
-	struct i2c_client *client = sensor->i2c_client;
 	struct imx046_sensor_settings *ss;
 
 	if ((fper->numerator == 0) || (fper->denominator == 0)) {
@@ -579,17 +610,11 @@
 	else if (frame_length_lines < ss->frame.frame_len_lines_min)
 		frame_length_lines = ss->frame.frame_len_lines_min;
 
-	imx046_write_reg(client, IMX046_REG_FRAME_LEN_LINES,
-					frame_length_lines, I2C_16BIT);
-
 	sensor_settings[isize].frame.frame_len_lines = frame_length_lines;
 
-	/* Update max exposure time */
-	max_exposure_time = (line_time_q8 * (frame_length_lines - 1)) >> 8;
-
 	printk(KERN_DEBUG "IMX046 Set Framerate: fper=%d/%d, "
 		"frame_len_lines=%d, max_expT=%dus\n", fper->numerator,
-		fper->denominator, frame_length_lines, max_exposure_time);
+		fper->denominator, frame_length_lines, IMX046_MAX_EXPOSURE);
 
 	return err;
 }
@@ -645,22 +670,24 @@
 	struct imx046_sensor_settings *ss;
 
 	if ((current_power_state == V4L2_POWER_ON) || sensor->resuming) {
-		if (exp_time < min_exposure_time) {
+		if (exp_time < IMX046_MIN_EXPOSURE) {
 			v4l_err(client, "Exposure time %d us not within"
 					" the legal range.\n", exp_time);
 			v4l_err(client, "Exposure time must be between"
 					" %d us and %d us\n",
-					min_exposure_time, max_exposure_time);
-			exp_time = min_exposure_time;
+					IMX046_MIN_EXPOSURE,
+					IMX046_MAX_EXPOSURE);
+			exp_time = IMX046_MIN_EXPOSURE;
 		}
 
-		if (exp_time > max_exposure_time) {
+		if (exp_time > IMX046_MAX_EXPOSURE) {
 			v4l_err(client, "Exposure time %d us not within"
 					" the legal range.\n", exp_time);
 			v4l_err(client, "Exposure time must be between"
 					" %d us and %d us\n",
-					min_exposure_time, max_exposure_time);
-			exp_time = max_exposure_time;
+					IMX046_MIN_EXPOSURE,
+					IMX046_MAX_EXPOSURE);
+			exp_time = IMX046_MAX_EXPOSURE;
 		}
 
 		ss = &sensor_settings[isize_current];
@@ -673,7 +700,15 @@
 				 line_time_q8;
 
 		if (coarse_int_time > ss->frame.frame_len_lines - 2)
-			coarse_int_time = ss->frame.frame_len_lines - 2;
+			err = imx046_write_reg(client,
+						IMX046_REG_FRAME_LEN_LINES,
+						coarse_int_time + 2,
+						I2C_16BIT);
+		else
+			err = imx046_write_reg(client,
+						IMX046_REG_FRAME_LEN_LINES,
+						ss->frame.frame_len_lines,
+						I2C_16BIT);
 
 		err = imx046_write_reg(client, IMX046_REG_COARSE_INT_TIME,
 					coarse_int_time, I2C_16BIT);
@@ -846,9 +881,10 @@
  * @c: i2c client driver structure
  * @isize: image size enum
  */
-int imx046_setup_mipi(struct imx046_sensor *sensor,
+int imx046_setup_mipi(struct v4l2_int_device *s,
 			enum imx046_image_size isize)
 {
+	struct imx046_sensor *sensor = s->priv;
 	struct i2c_client *client = sensor->i2c_client;
 
 	/* NOTE: Make sure imx046_update_clocks is called 1st */
@@ -873,10 +909,11 @@
 		imx046_write_reg(client, IMX046_REG_RGLANESEL, 0x01, I2C_8BIT);
 
 	/* Set number of lanes in isp */
-	sensor->pdata->csi2_lane_count(sensor_settings[isize].mipi.data_lanes);
+	sensor->pdata->csi2_lane_count(s,
+				       sensor_settings[isize].mipi.data_lanes);
 
 	/* Send settings to ISP-CSI2 Receiver PHY */
-	sensor->pdata->csi2_calc_phy_cfg0(current_clk.mipi_clk,
+	sensor->pdata->csi2_calc_phy_cfg0(s, current_clk.mipi_clk,
 		sensor_settings[isize].mipi.ths_settle_lower,
 		sensor_settings[isize].mipi.ths_settle_upper);
 
@@ -902,7 +939,7 @@
 	u32 val;
 
 	imx046_write_reg(client, IMX046_REG_FRAME_LEN_LINES,
-		sensor_settings[isize].frame.frame_len_lines_min, I2C_16BIT);
+		sensor_settings[isize].frame.frame_len_lines, I2C_16BIT);
 
 	imx046_write_reg(client, IMX046_REG_LINE_LEN_PCK,
 		sensor_settings[isize].frame.line_len_pck, I2C_16BIT);
@@ -1029,38 +1066,30 @@
 static int imx046_configure(struct v4l2_int_device *s)
 {
 	struct imx046_sensor *sensor = s->priv;
-	struct v4l2_pix_format *pix = &sensor->pix;
 	struct i2c_client *client = sensor->i2c_client;
-	enum imx046_image_size isize;
+	enum imx046_image_size isize = isize_current;
 	int err, i;
 	struct vcontrol *lvc = NULL;
 
-	isize = imx046_find_size(pix->width, pix->height);
-	isize_current = isize;
-
 	err = imx046_write_reg(client, IMX046_REG_SW_RESET, 0x01, I2C_8BIT);
 	mdelay(5);
 
 	imx046_write_regs(client, initial_list);
 
-	imx046_update_clocks(xclk_current, isize);
 	imx046_setup_pll(client, isize);
 
-	imx046_setup_mipi(sensor, isize);
+	imx046_setup_mipi(s, isize);
 
 	/* configure image size and pixel format */
 	imx046_configure_frame(client, isize);
 
-	/* Setting of frame rate */
-	err = imx046_set_framerate(s, &sensor->timeperframe);
-
 	imx046_set_orientation(client, sensor->ver);
 
-	sensor->pdata->csi2_cfg_vp_out_ctrl(2);
-	sensor->pdata->csi2_ctrl_update(false);
+	sensor->pdata->csi2_cfg_vp_out_ctrl(s, 2);
+	sensor->pdata->csi2_ctrl_update(s, false);
 
-	sensor->pdata->csi2_cfg_virtual_id(0, IMX046_CSI2_VIRTUAL_ID);
-	sensor->pdata->csi2_ctx_update(0, false);
+	sensor->pdata->csi2_cfg_virtual_id(s, 0, IMX046_CSI2_VIRTUAL_ID);
+	sensor->pdata->csi2_ctx_update(s, 0, false);
 	imx046_set_virtual_id(client, IMX046_CSI2_VIRTUAL_ID);
 
 	/* Set initial exposure and gain */
@@ -1283,6 +1312,7 @@
 	struct v4l2_pix_format *pix2 = &sensor->pix;
 
 	isize = imx046_find_size(pix->width, pix->height);
+	isize_current = isize;
 
 	pix->width = imx046_sizes[isize].width;
 	pix->height = imx046_sizes[isize].height;
@@ -1346,6 +1376,87 @@
 }
 
 /**
+ * ioctl_g_pixclk - V4L2 sensor interface handler for ioctl_g_pixclk
+ * @s: pointer to standard V4L2 device structure
+ * @pixclk: pointer to unsigned 32 var to store pixelclk in HZ
+ *
+ * Returns the sensor's current pixel clock in HZ
+ */
+static int ioctl_priv_g_pixclk(struct v4l2_int_device *s, u32 *pixclk)
+{
+	*pixclk = current_clk.vt_pix_clk;
+
+	return 0;
+}
+
+/**
+ * ioctl_g_activesize - V4L2 sensor interface handler for ioctl_g_activesize
+ * @s: pointer to standard V4L2 device structure
+ * @pix: pointer to standard V4L2 v4l2_pix_format structure
+ *
+ * Returns the sensor's current active image basesize.
+ */
+static int ioctl_priv_g_activesize(struct v4l2_int_device *s,
+			      struct v4l2_rect *pix)
+{
+	struct imx046_frame_settings *frm;
+
+	frm = &sensor_settings[isize_current].frame;
+	pix->left = frm->x_addr_start /
+		((frm->x_even_inc + frm->x_odd_inc) / 2);
+	pix->top = frm->y_addr_start /
+		((frm->y_even_inc + frm->y_odd_inc) / 2);
+	pix->width = ((frm->x_addr_end + 1) - frm->x_addr_start) /
+		((frm->x_even_inc + frm->x_odd_inc) / 2);
+	pix->height = ((frm->y_addr_end + 1) - frm->y_addr_start) /
+		((frm->y_even_inc + frm->y_odd_inc) / 2);
+
+	return 0;
+}
+
+/**
+ * ioctl_g_fullsize - V4L2 sensor interface handler for ioctl_g_fullsize
+ * @s: pointer to standard V4L2 device structure
+ * @pix: pointer to standard V4L2 v4l2_pix_format structure
+ *
+ * Returns the sensor's biggest image basesize.
+ */
+static int ioctl_priv_g_fullsize(struct v4l2_int_device *s,
+			    struct v4l2_rect *pix)
+{
+	struct imx046_frame_settings *frm;
+
+	frm = &sensor_settings[isize_current].frame;
+	pix->left = 0;
+	pix->top = 0;
+	pix->width = frm->line_len_pck;
+	pix->height = frm->frame_len_lines;
+
+	return 0;
+}
+
+/**
+ * ioctl_g_pixelsize - V4L2 sensor interface handler for ioctl_g_pixelsize
+ * @s: pointer to standard V4L2 device structure
+ * @pix: pointer to standard V4L2 v4l2_pix_format structure
+ *
+ * Returns the sensor's configure pixel size.
+ */
+static int ioctl_priv_g_pixelsize(struct v4l2_int_device *s,
+			    struct v4l2_rect *pix)
+{
+	struct imx046_frame_settings *frm;
+
+	frm = &sensor_settings[isize_current].frame;
+	pix->left = 0;
+	pix->top = 0;
+	pix->width = (frm->x_even_inc + frm->x_odd_inc) / 2;
+	pix->height = (frm->y_even_inc + frm->y_odd_inc) / 2;
+
+	return 0;
+}
+
+/**
  * ioctl_g_parm - V4L2 sensor interface handler for VIDIOC_G_PARM ioctl
  * @s: pointer to standard V4L2 device structure
  * @a: pointer to standard V4L2 VIDIOC_G_PARM ioctl structure
@@ -1384,12 +1495,15 @@
 {
 	struct imx046_sensor *sensor = s->priv;
 	struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
+	int err = 0;
 
 	sensor->timeperframe = *timeperframe;
 	imx046sensor_calc_xclk();
+	imx046_update_clocks(xclk_current, isize_current);
+	err = imx046_set_framerate(s, &sensor->timeperframe);
 	*timeperframe = sensor->timeperframe;
 
-	return 0;
+	return err;
 }
 
 
@@ -1404,10 +1518,57 @@
 {
 	struct imx046_sensor *sensor = s->priv;
 
-	return sensor->pdata->priv_data_set(p);
+	return sensor->pdata->priv_data_set(s, p);
 
 }
 
+static int __imx046_power_off_standby(struct v4l2_int_device *s,
+				      enum v4l2_power on)
+{
+	struct imx046_sensor *sensor = s->priv;
+	struct i2c_client *client = sensor->i2c_client;
+	int rval;
+
+	rval = sensor->pdata->power_set(s, on);
+	if (rval < 0) {
+		v4l_err(client, "Unable to set the power state: "
+			IMX046_DRIVER_NAME " sensor\n");
+		return rval;
+	}
+
+	sensor->pdata->set_xclk(s, 0);
+	return 0;
+}
+
+static int imx046_power_off(struct v4l2_int_device *s)
+{
+	return __imx046_power_off_standby(s, V4L2_POWER_OFF);
+}
+
+static int imx046_power_standby(struct v4l2_int_device *s)
+{
+	return __imx046_power_off_standby(s, V4L2_POWER_STANDBY);
+}
+
+static int imx046_power_on(struct v4l2_int_device *s)
+{
+	struct imx046_sensor *sensor = s->priv;
+	struct i2c_client *client = sensor->i2c_client;
+	int rval;
+
+	sensor->pdata->set_xclk(s, xclk_current);
+
+	rval = sensor->pdata->power_set(s, V4L2_POWER_ON);
+	if (rval < 0) {
+		v4l_err(client, "Unable to set the power state: "
+			IMX046_DRIVER_NAME " sensor\n");
+		sensor->pdata->set_xclk(s, 0);
+		return rval;
+	}
+
+	return 0;
+}
+
 /**
  * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
  * @s: pointer to standard V4L2 device structure
@@ -1418,57 +1579,20 @@
 static int ioctl_s_power(struct v4l2_int_device *s, enum v4l2_power on)
 {
 	struct imx046_sensor *sensor = s->priv;
-	struct i2c_client *client = sensor->i2c_client;
-	struct omap34xxcam_hw_config hw_config;
 	struct vcontrol *lvc;
-	int rval, i;
+	int i;
 
-	rval = ioctl_g_priv(s, &hw_config);
-	if (rval) {
-		v4l_err(client, "Unable to get hw params\n");
-		return rval;
-	}
-
-	if ((on == V4L2_POWER_STANDBY) && (sensor->state == SENSOR_DETECTED)) {
-		/* imx046_write_regs(c, stream_off_list,
-						I2C_STREAM_OFF_LIST_SIZE); */
-	}
-
-	if (on != V4L2_POWER_ON)
-		sensor->pdata->set_xclk(0, hw_config.u.sensor.xclk);
-	else
-		sensor->pdata->set_xclk(xclk_current, hw_config.u.sensor.xclk);
-
-	rval = sensor->pdata->power_set(&client->dev, on);
-	if (rval < 0) {
-		v4l_err(client, "Unable to set the power state: "
-			IMX046_DRIVER_NAME " sensor\n");
-		sensor->pdata->set_xclk(0, hw_config.u.sensor.xclk);
-		return rval;
-	}
-
-	if ((current_power_state == V4L2_POWER_STANDBY) &&
-					(on == V4L2_POWER_ON) &&
-					(sensor->state == SENSOR_DETECTED)) {
-		sensor->resuming = true;
-		imx046_configure(s);
-	}
-
-	if ((on == V4L2_POWER_ON) && (sensor->state == SENSOR_NOT_DETECTED)) {
-		rval = imx046_detect(client);
-		if (rval < 0) {
-			v4l_err(client, "Unable to detect "
-					IMX046_DRIVER_NAME " sensor\n");
-			sensor->state = SENSOR_NOT_DETECTED;
-			return rval;
+	switch (on) {
+	case V4L2_POWER_ON:
+		imx046_power_on(s);
+		if (current_power_state == V4L2_POWER_STANDBY) {
+			sensor->resuming = true;
+			imx046_configure(s);
 		}
-		sensor->state = SENSOR_DETECTED;
-		sensor->ver = rval;
-		v4l_info(client, IMX046_DRIVER_NAME
-			" chip version 0x%02x detected\n", sensor->ver);
-	}
+		break;
+	case V4L2_POWER_OFF:
+		imx046_power_off(s);
 
-	if (on == V4L2_POWER_OFF) {
 		/* Reset defaults for controls */
 		i = find_vctrl(V4L2_CID_GAIN);
 		if (i >= 0) {
@@ -1485,6 +1609,10 @@
 			lvc = &imx046sensor_video_control[i];
 			lvc->current_value = IMX046_MIN_TEST_PATT_MODE;
 		}
+		break;
+	case V4L2_POWER_STANDBY:
+		imx046_power_standby(s);
+		break;
 	}
 
 	sensor->resuming = false;
@@ -1527,16 +1655,23 @@
 	struct i2c_client *client = sensor->i2c_client;
 	int err;
 
+	err = imx046_power_on(s);
+	if (err)
+		return -ENODEV;
+
 	err = imx046_detect(client);
 	if (err < 0) {
-		v4l_err(client, "Unable to detect " IMX046_DRIVER_NAME
-				" sensor\n");
+		v4l_err(client, "Unable to detect "
+				IMX046_DRIVER_NAME " sensor\n");
 		return err;
 	}
-
 	sensor->ver = err;
-	v4l_info(client, IMX046_DRIVER_NAME " chip version "
-			"0x%02x detected\n", sensor->ver);
+	v4l_info(client, IMX046_DRIVER_NAME
+		" chip version 0x%02x detected\n", sensor->ver);
+
+	err = imx046_power_off(s);
+	if (err)
+		return -ENODEV;
 
 	return 0;
 }
@@ -1575,6 +1710,10 @@
 
 const struct v4l2_fract imx046_frameintervals[] = {
 	{ .numerator = 3, .denominator = 30 },
+	{ .numerator = 2, .denominator = 25 },
+	{ .numerator = 1, .denominator = 15 },
+	{ .numerator = 1, .denominator = 20 },
+	{ .numerator = 1, .denominator = 25 },
 	{ .numerator = 1, .denominator = 30 },
 };
 
@@ -1645,6 +1784,14 @@
 	  .func = (v4l2_int_ioctl_func *)ioctl_g_ctrl },
 	{ .num = vidioc_int_s_ctrl_num,
 	  .func = (v4l2_int_ioctl_func *)ioctl_s_ctrl },
+	{ .num = vidioc_int_priv_g_pixclk_num,
+	  .func = (v4l2_int_ioctl_func *)ioctl_priv_g_pixclk },
+	{ .num = vidioc_int_priv_g_activesize_num,
+	  .func = (v4l2_int_ioctl_func *)ioctl_priv_g_activesize },
+	{ .num = vidioc_int_priv_g_fullsize_num,
+	  .func = (v4l2_int_ioctl_func *)ioctl_priv_g_fullsize },
+	{ .num = vidioc_int_priv_g_pixelsize_num,
+	  .func = (v4l2_int_ioctl_func *)ioctl_priv_g_pixelsize },
 };
 
 static struct v4l2_int_slave imx046_slave = {
@@ -1690,10 +1837,10 @@
 
 	i2c_set_clientdata(client, sensor);
 
-	/* Make the default capture format QCIF V4L2_PIX_FMT_SGRBG10 */
+	/* Make the default capture format QCIF V4L2_PIX_FMT_SRGGB10 */
 	sensor->pix.width = IMX046_IMAGE_WIDTH_MAX;
 	sensor->pix.height = IMX046_IMAGE_HEIGHT_MAX;
-	sensor->pix.pixelformat = V4L2_PIX_FMT_SGRBG10;
+	sensor->pix.pixelformat = V4L2_PIX_FMT_SRGGB10;
 
 	err = v4l2_int_device_register(sensor->v4l2_int_device);
 	if (err)
@@ -1744,7 +1891,6 @@
 		.numerator = 1,
 		.denominator = 30,
 	},
-	.state = SENSOR_NOT_DETECTED,
 };
 
 /**
diff --git a/drivers/media/video/imx046_regs.h b/drivers/media/video/imx046_regs.h
index 1ab2e63..62c4ff2 100644
--- a/drivers/media/video/imx046_regs.h
+++ b/drivers/media/video/imx046_regs.h
@@ -15,8 +15,6 @@
 #ifndef IMX046_REGS_H
 #define IMX046_REGS_H
 
-#define V4L2_CID_TEST_PATTERN		(V4L2_CID_PRIVATE_BASE + 1)
-
 /* The ID values we are looking for */
 #define IMX046_MOD_ID			0x0046
 #define IMX046_MFR_ID			0x000B
@@ -209,10 +207,12 @@
 enum imx046_image_size {
 	QUART_MP,
 	HALF_MP,
+	p729p_MP,
 	TWO_MP,
 	EIGHT_MP
 };
 
+#define NUM_IMAGE_SIZES ARRAY_SIZE(imx046_sizes)
 /**
  * struct imx046_capture_size - image capture size information
  * @width: image width in pixels
@@ -230,7 +230,7 @@
 struct imx046_clk_settings {
 	u16	pre_pll_div;
 	u16	pll_mult;
-	u16  post_pll_div;
+	u16	post_pll_div;
 	u16	vt_pix_clk_div;
 	u16	vt_sys_clk_div;
 };
@@ -298,16 +298,9 @@
 const static struct imx046_capture_size imx046_sizes[] = {
 	{ 410, 308 },	/* QUART_MP - 1/8 Vertical Elim */
 	{ 820, 616 },		/* 0.5Mp - 4X Horizontal & Vertical Elim. */
+	{ 1292, 729},		/*1292x729 - 1/2 vertical & horizontal Elim. */
 	{ 3280, 616 },	/* 2Mp - 4X Vertical Elim. */
 	{ 3280, 2464},	/* 8MP - Full Resolution */
 };
 
-/* PLL settings for imx046 */
-enum imx046_pll_type {
-	PLL_QUART_MP = 0,
-	PLL_0_5MP,
-	PLL_2MP,
-	PLL_8MP,
-};
-
 #endif /* ifndef IMX046_REGS_H */
diff --git a/drivers/media/video/isp/Kconfig b/drivers/media/video/isp/Kconfig
index eeabc8f..230a1fe 100644
--- a/drivers/media/video/isp/Kconfig
+++ b/drivers/media/video/isp/Kconfig
@@ -2,8 +2,8 @@
 
 config VIDEO_OMAP34XX_ISP_PREVIEWER
 	tristate "OMAP ISP Previewer"
-	depends on !ARCH_OMAP3410
+	depends on !ARCH_OMAP3410 && VIDEO_OMAP3
 
 config VIDEO_OMAP34XX_ISP_RESIZER
 	tristate "OMAP ISP Resizer"
-	depends on !ARCH_OMAP3410
+	depends on !ARCH_OMAP3410 && VIDEO_OMAP3
diff --git a/drivers/media/video/isp/Makefile b/drivers/media/video/isp/Makefile
index 67329ef..3bb3702 100644
--- a/drivers/media/video/isp/Makefile
+++ b/drivers/media/video/isp/Makefile
@@ -1,12 +1,9 @@
 # Makefile for OMAP3 ISP driver
 
-ifdef CONFIG_ARCH_OMAP3410
 isp-mod-objs += \
-	isp.o ispccdc.o
-else
-isp-mod-objs += \
-	isp.o ispccdc.o ispmmu.o \
-	isppreview.o ispresizer.o isph3a.o isphist.o isp_af.o ispcsi2.o
+	isp.o ispccdc.o \
+	isppreview.o ispresizer.o isph3a.o isphist.o isp_af.o ispcsi2.o \
+	ispstat.o
 
 obj-$(CONFIG_VIDEO_OMAP34XX_ISP_PREVIEWER) += \
 	omap_previewer.o
@@ -14,6 +11,5 @@
 obj-$(CONFIG_VIDEO_OMAP34XX_ISP_RESIZER) += \
 	omap_resizer.o
 
-endif
-
 obj-$(CONFIG_VIDEO_OMAP3) += isp-mod.o
+
diff --git a/drivers/media/video/isp/isp.c b/drivers/media/video/isp/isp.c
index dee2b0f..a9e9735 100644
--- a/drivers/media/video/isp/isp.c
+++ b/drivers/media/video/isp/isp.c
@@ -32,9 +32,9 @@
 #include <linux/dma-mapping.h>
 #include <linux/vmalloc.h>
 #include <linux/platform_device.h>
+#include <linux/device.h>
 
 #include "isp.h"
-#include "ispmmu.h"
 #include "ispreg.h"
 #include "ispccdc.h"
 #include "isph3a.h"
@@ -44,16 +44,14 @@
 #include "ispresizer.h"
 #include "ispcsi2.h"
 
-static struct isp_device *omap3isp;
+static struct platform_device *omap3isp_pdev;
+static int isp_complete_reset = 1;
 
-static int isp_try_size(struct v4l2_pix_format *pix_input,
-			struct v4l2_pix_format *pix_output);
+static void isp_save_ctx(struct device *dev);
 
-static void isp_save_ctx(void);
+static void isp_restore_ctx(struct device *dev);
 
-static void isp_restore_ctx(void);
-
-static void isp_buf_init(void);
+static void isp_buf_init(struct device *dev);
 
 /* List of image formats supported via OMAP ISP */
 const static struct v4l2_fmtdesc isp_formats[] = {
@@ -69,12 +67,20 @@
 		.description = "Bayer10 (GrR/BGb)",
 		.pixelformat = V4L2_PIX_FMT_SGRBG10,
 	},
+	{
+		.description = "Bayer10 (GrR/BGb)",
+		.pixelformat = V4L2_PIX_FMT_SRGGB10,
+	},
+	{
+		.description = "Bayer10 (GrR/BGb)",
+		.pixelformat = V4L2_PIX_FMT_SGBRG10,
+	},
+	{
+		.description = "Bayer10 (GrR/BGb)",
+		.pixelformat = V4L2_PIX_FMT_SBGGR10,
+	},
 };
 
-/* ISP Crop capabilities */
-static struct v4l2_rect ispcroprect;
-static struct v4l2_rect cur_rect;
-
 /**
  * struct vcontrol - Video control structure.
  * @qc: V4L2 Query control structure.
@@ -140,129 +146,6 @@
 	},
 };
 
-struct isp_buf {
-	dma_addr_t isp_addr;
-	void (*complete)(struct videobuf_buffer *vb, void *priv);
-	struct videobuf_buffer *vb;
-	void *priv;
-	u32 vb_state;
-};
-
-#define ISP_BUFS_IS_FULL(bufs)					\
-	(((bufs)->queue + 1) % NUM_BUFS == (bufs)->done)
-#define ISP_BUFS_IS_EMPTY(bufs)		((bufs)->queue == (bufs)->done)
-#define ISP_BUFS_IS_LAST(bufs)					\
-	((bufs)->queue == ((bufs)->done + 1) % NUM_BUFS)
-#define ISP_BUFS_QUEUED(bufs)						\
-	((((bufs)->done - (bufs)->queue + NUM_BUFS)) % NUM_BUFS)
-#define ISP_BUF_DONE(bufs)		((bufs)->buf + (bufs)->done)
-#define ISP_BUF_NEXT_DONE(bufs)				\
-	((bufs)->buf + ((bufs)->done + 1) % NUM_BUFS)
-#define ISP_BUF_QUEUE(bufs)		((bufs)->buf + (bufs)->queue)
-#define ISP_BUF_MARK_DONE(bufs)				\
-	(bufs)->done = ((bufs)->done + 1) % NUM_BUFS;
-#define ISP_BUF_MARK_QUEUED(bufs)			\
-	(bufs)->queue = ((bufs)->queue + 1) % NUM_BUFS;
-
-struct isp_bufs {
-	dma_addr_t isp_addr_capture[VIDEO_MAX_FRAME];
-	spinlock_t lock;	/* For handling current buffer */
-	/* queue full: (ispsg.queue + 1) % NUM_BUFS == ispsg.done
-	   queue empty: ispsg.queue == ispsg.done */
-	struct isp_buf buf[NUM_BUFS];
-	/* Next slot to queue a buffer. */
-	int queue;
-	/* Buffer that is being processed. */
-	int done;
-	/* Wait for this many hs_vs before anything else. */
-	int wait_hs_vs;
-};
-
-/**
- * struct ispirq - Structure for containing callbacks to be called in ISP ISR.
- * @isp_callbk: Array which stores callback functions, indexed by the type of
- *              callback (8 possible types).
- * @isp_callbk_arg1: Pointer to array containing pointers to the first argument
- *                   to be passed to the requested callback function.
- * @isp_callbk_arg2: Pointer to array containing pointers to the second
- *                   argument to be passed to the requested callback function.
- *
- * This structure is used to contain all the callback functions related for
- * each callback type (CBK_CCDC_VD0, CBK_CCDC_VD1, CBK_PREV_DONE,
- * CBK_RESZ_DONE, CBK_MMU_ERR, CBK_H3A_AWB_DONE, CBK_HIST_DONE, CBK_HS_VS,
- * CBK_LSC_ISR).
- */
-struct isp_irq {
-	isp_callback_t isp_callbk[CBK_END];
-	isp_vbq_callback_ptr isp_callbk_arg1[CBK_END];
-	void *isp_callbk_arg2[CBK_END];
-};
-
-/**
- * struct ispmodule - Structure for storing ISP sub-module information.
- * @isp_pipeline: Bit mask for submodules enabled within the ISP.
- * @applyCrop: Flag to do a crop operation when video buffer queue ISR is done
- * @pix: Structure containing the format and layout of the output image.
- * @ccdc_input_width: ISP CCDC module input image width.
- * @ccdc_input_height: ISP CCDC module input image height.
- * @ccdc_output_width: ISP CCDC module output image width.
- * @ccdc_output_height: ISP CCDC module output image height.
- * @preview_input_width: ISP Preview module input image width.
- * @preview_input_height: ISP Preview module input image height.
- * @preview_output_width: ISP Preview module output image width.
- * @preview_output_height: ISP Preview module output image height.
- * @resizer_input_width: ISP Resizer module input image width.
- * @resizer_input_height: ISP Resizer module input image height.
- * @resizer_output_width: ISP Resizer module output image width.
- * @resizer_output_height: ISP Resizer module output image height.
- */
-struct isp_module {
-	unsigned int isp_pipeline;
-	int applyCrop;
-	struct v4l2_pix_format pix;
-	unsigned int ccdc_input_width;
-	unsigned int ccdc_input_height;
-	unsigned int ccdc_output_width;
-	unsigned int ccdc_output_height;
-	unsigned int preview_input_width;
-	unsigned int preview_input_height;
-	unsigned int preview_output_width;
-	unsigned int preview_output_height;
-	unsigned int resizer_input_width;
-	unsigned int resizer_input_height;
-	unsigned int resizer_output_width;
-	unsigned int resizer_output_height;
-};
-
-#define RAW_CAPTURE(isp)					\
-	(!((isp)->module.isp_pipeline & OMAP_ISP_PREVIEW))
-
-/**
- * struct isp - Structure for storing ISP Control module information
- * @lock: Spinlock to sync between isr and processes.
- * @isp_mutex: Semaphore used to get access to the ISP.
- * @ref_count: Reference counter.
- * @cam_ick: Pointer to ISP Interface clock.
- * @cam_fck: Pointer to ISP Functional clock.
- *
- * This structure is used to store the OMAP ISP Control Information.
- */
-static struct isp {
-	spinlock_t lock;	/* For handling registered ISP callbacks */
-	struct mutex isp_mutex;	/* For handling ref_count field */
-	int ref_count;
-	struct clk *cam_ick;
-	struct clk *cam_mclk;
-	struct clk *csi2_fck;
-	struct isp_interface_config *config;
-	dma_addr_t tmp_buf;
-	size_t tmp_buf_size;
-	unsigned long tmp_buf_offset;
-	struct isp_bufs bufs;
-	struct isp_irq irq;
-	struct isp_module module;
-} isp_obj;
-
 /* Structure for saving/restoring ISP module registers */
 static struct isp_reg isp_reg_list[] = {
 	{OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG, 0},
@@ -292,19 +175,21 @@
 	{0, ISP_TOK_TERM, 0}
 };
 
-u32 isp_reg_readl(enum isp_mem_resources isp_mmio_range, u32 reg_offset)
+/**
+ * isp_flush - Post pending L3 bus writes by doing a register readback
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * In order to force posting of pending writes, we need to write and
+ * readback the same register, in this case the revision register.
+ *
+ * See this link for reference:
+ *   http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
+ **/
+void isp_flush(struct device *dev)
 {
-	return __raw_readl(omap3isp->mmio_base[isp_mmio_range] + reg_offset);
+	isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+	isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
 }
-EXPORT_SYMBOL(isp_reg_readl);
-
-void isp_reg_writel(u32 reg_value, enum isp_mem_resources isp_mmio_range,
-		    u32 reg_offset)
-{
-	__raw_writel(reg_value,
-		     omap3isp->mmio_base[isp_mmio_range] + reg_offset);
-}
-EXPORT_SYMBOL(isp_reg_writel);
 
 /*
  *
@@ -313,7 +198,7 @@
  */
 
 /**
- * find_vctrl - Returns the index of the ctrl array of the requested ctrl ID.
+ * find_vctrl - Return the index of the ctrl array of the requested ctrl ID.
  * @id: Requested control ID.
  *
  * Returns 0 if successful, -EINVAL if not found, or -EDOM if its out of
@@ -336,6 +221,12 @@
 	return i;
 }
 
+/**
+ * find_next_vctrl - Return next v4l2 ctrl ID available after the specified ID
+ * @id: Reference V4L2 control ID.
+ *
+ * Returns 0 if successful, or -EINVAL if not found.
+ **/
 static int find_next_vctrl(int id)
 {
 	int i;
@@ -357,7 +248,7 @@
 }
 
 /**
- * find_vmenu - Returns index of the menu array of the requested ctrl option.
+ * find_vmenu - Return index of the menu array of the requested ctrl option.
  * @id: Requested control ID.
  * @index: Requested menu option index.
  *
@@ -381,80 +272,128 @@
 }
 
 /**
- * isp_release_resources - Free ISP submodules
+ * isp_release_resources - Free all currently requested ISP submodules.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  **/
-static void isp_release_resources(void)
+static void isp_release_resources(struct device *dev)
 {
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_CCDC)
-		ispccdc_free();
+	struct isp_device *isp = dev_get_drvdata(dev);
 
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW)
-		isppreview_free();
+	if (isp->pipeline.modules & OMAP_ISP_CCDC)
+		ispccdc_free(&isp->isp_ccdc);
 
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER)
-		ispresizer_free();
+	if (isp->pipeline.modules & OMAP_ISP_PREVIEW)
+		isppreview_free(&isp->isp_prev);
+
+	if (isp->pipeline.modules & OMAP_ISP_RESIZER)
+		ispresizer_free(&isp->isp_res);
 	return;
 }
 
-static int isp_wait(int (*busy)(void), int wait_for_busy, int max_wait)
+/**
+ * isp_wait - Wait for idle or busy state transition with a time limit
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @busy: Function pointer which determines if submodule is busy.
+ * @wait_for_busy: If 0, waits for idle state, if 1, waits for busy state.
+ * @max_wait: Max retry count in us for wait for idle/busy transition.
+ * @priv: Function parameter to send to busy check function.
+ **/
+static int isp_wait(struct device *dev, int (*busy)(void *), int wait_for_busy,
+		    int max_wait, void *priv)
 {
 	int wait = 0;
 
 	if (max_wait == 0)
 		max_wait = 10000; /* 10 ms */
 
-	while ((wait_for_busy && !busy())
-	       || (!wait_for_busy && busy())) {
+	while ((wait_for_busy && !busy(priv))
+	       || (!wait_for_busy && busy(priv))) {
 		rmb();
 		udelay(1);
 		wait++;
-		if (wait > max_wait) {
-			printk(KERN_ALERT "%s: wait is too much\n", __func__);
+		if (wait > max_wait)
 			return -EBUSY;
-		}
 	}
 	DPRINTK_ISPCTRL(KERN_ALERT "%s: wait %d\n", __func__, wait);
 
 	return 0;
 }
 
-static int ispccdc_sbl_wait_idle(int max_wait)
+/**
+ * ispccdc_sbl_wait_idle - Wrapper to wait for ccdc sbl status bits to be idle.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @max_wait: Max retry count for wait for idle transition of the CCDC SBL bits
+ **/
+static int ispccdc_sbl_wait_idle(struct isp_ccdc_device *isp_ccdc, int max_wait)
 {
-	return isp_wait(ispccdc_sbl_busy, 0, max_wait);
+	struct device *dev = to_device(isp_ccdc);
+
+	return isp_wait(dev, ispccdc_sbl_busy, 0, max_wait, isp_ccdc);
 }
 
-static void isp_enable_interrupts(int is_raw)
+/**
+ * isp_enable_interrupts - Enable ISP interrupts.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_enable_interrupts(struct device *dev)
 {
-	isp_reg_writel(-1, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
-	isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-		   IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ |
-		   IRQ0ENABLE_HS_VS_IRQ |
-		   IRQ0ENABLE_CCDC_VD0_IRQ |
-		   IRQ0ENABLE_CCDC_VD1_IRQ);
+	struct isp_device *isp = dev_get_drvdata(dev);
+	u32 irq0enable;
 
-	if (is_raw)
-		return;
+	irq0enable = IRQ0ENABLE_CCDC_VD0_IRQ
+		| IRQ0ENABLE_CSIA_IRQ
+		| IRQ0ENABLE_CSIB_IRQ | IRQ0ENABLE_HIST_DONE_IRQ
+		| IRQ0ENABLE_H3A_AWB_DONE_IRQ | IRQ0ENABLE_H3A_AF_DONE_IRQ
+		| isp->interrupts;
 
-	isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-		   IRQ0ENABLE_PRV_DONE_IRQ |
-		   IRQ0ENABLE_RSZ_DONE_IRQ);
+	if (CCDC_PREV_CAPTURE(isp))
+		irq0enable |= IRQ0ENABLE_PRV_DONE_IRQ;
+
+	if (CCDC_PREV_RESZ_CAPTURE(isp))
+		irq0enable |= IRQ0ENABLE_PRV_DONE_IRQ | IRQ0ENABLE_RSZ_DONE_IRQ;
+
+	if (isp_complete_reset) {
+		isp_reg_writel(dev, -1, OMAP3_ISP_IOMEM_MAIN,
+			       ISP_IRQ0STATUS);
+		isp_complete_reset = 0;
+	}
+	isp_reg_writel(dev, irq0enable, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
 
 	return;
 }
 
-static void isp_disable_interrupts(void)
+/**
+ * isp_disable_interrupts - Disable all ISP interrupts.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_disable_interrupts(struct device *dev)
 {
-	isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-		    ~(IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ |
-		      IRQ0ENABLE_HS_VS_IRQ |
-		      IRQ0ENABLE_CCDC_VD0_IRQ |
-		      IRQ0ENABLE_CCDC_VD1_IRQ |
-		      IRQ0ENABLE_PRV_DONE_IRQ |
-		      IRQ0ENABLE_RSZ_DONE_IRQ));
+	struct isp_device *isp = dev_get_drvdata(dev);
+	u32 irq0enable;
+	u32 v ;
+
+	irq0enable = ~(IRQ0ENABLE_CCDC_VD0_IRQ
+		| IRQ0ENABLE_CSIA_IRQ
+		| IRQ0ENABLE_CSIB_IRQ | IRQ0ENABLE_HIST_DONE_IRQ
+		| IRQ0ENABLE_H3A_AWB_DONE_IRQ | IRQ0ENABLE_H3A_AF_DONE_IRQ
+		| isp->interrupts);
+
+	if (CCDC_PREV_CAPTURE(isp))
+		irq0enable &= ~IRQ0ENABLE_PRV_DONE_IRQ;
+
+	if (CCDC_PREV_RESZ_CAPTURE(isp))
+		irq0enable &= ~(IRQ0ENABLE_PRV_DONE_IRQ
+			| IRQ0ENABLE_RSZ_DONE_IRQ);
+
+	v = isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+
+	isp_reg_writel(dev, v & irq0enable,
+		OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
 }
 
 /**
- * isp_set_callback - Sets the callback for the ISP module done events.
+ * isp_set_callback - Set an external callback for an ISP interrupt.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @type: Type of the event for which callback is requested.
  * @callback: Method to be called as callback in the ISR context.
  * @arg1: First argument to be passed when callback is called in ISR.
@@ -463,10 +402,11 @@
  * This function sets a callback function for a done event in the ISP
  * module, and enables the corresponding interrupt.
  **/
-int isp_set_callback(enum isp_callback_type type, isp_callback_t callback,
-		     isp_vbq_callback_ptr arg1,
+int isp_set_callback(struct device *dev, enum isp_callback_type type,
+		     isp_callback_t callback, isp_vbq_callback_ptr arg1,
 		     void *arg2)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	unsigned long irqflags = 0;
 
 	if (callback == NULL) {
@@ -474,41 +414,23 @@
 		return -EINVAL;
 	}
 
-	spin_lock_irqsave(&isp_obj.lock, irqflags);
-	isp_obj.irq.isp_callbk[type] = callback;
-	isp_obj.irq.isp_callbk_arg1[type] = arg1;
-	isp_obj.irq.isp_callbk_arg2[type] = arg2;
-	spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+	spin_lock_irqsave(&isp->lock, irqflags);
+	isp->irq.isp_callbk[type] = callback;
+	isp->irq.isp_callbk_arg1[type] = arg1;
+	isp->irq.isp_callbk_arg2[type] = arg2;
+	spin_unlock_irqrestore(&isp->lock, irqflags);
 
 	switch (type) {
-	case CBK_H3A_AWB_DONE:
-		isp_reg_writel(IRQ0ENABLE_H3A_AWB_DONE_IRQ,
-			       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
-		isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-			   IRQ0ENABLE_H3A_AWB_DONE_IRQ);
-		break;
-	case CBK_H3A_AF_DONE:
-		isp_reg_writel(IRQ0ENABLE_H3A_AF_DONE_IRQ,
-			       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
-		isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-			   IRQ0ENABLE_H3A_AF_DONE_IRQ);
-		break;
-	case CBK_HIST_DONE:
-		isp_reg_writel(IRQ0ENABLE_HIST_DONE_IRQ,
-			       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
-		isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-			   IRQ0ENABLE_HIST_DONE_IRQ);
-		break;
 	case CBK_PREV_DONE:
-		isp_reg_writel(IRQ0ENABLE_PRV_DONE_IRQ,
+		isp_reg_writel(dev, IRQ0ENABLE_PRV_DONE_IRQ,
 			       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
-		isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
 			   IRQ0ENABLE_PRV_DONE_IRQ);
 		break;
 	case CBK_RESZ_DONE:
-		isp_reg_writel(IRQ0ENABLE_RSZ_DONE_IRQ,
+		isp_reg_writel(dev, IRQ0ENABLE_RSZ_DONE_IRQ,
 			       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
-		isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
 			   IRQ0ENABLE_RSZ_DONE_IRQ);
 		break;
 	default:
@@ -521,49 +443,30 @@
 
 /**
  * isp_unset_callback - Clears the callback for the ISP module done events.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @type: Type of the event for which callback to be cleared.
  *
  * This function clears a callback function for a done event in the ISP
  * module, and disables the corresponding interrupt.
  **/
-int isp_unset_callback(enum isp_callback_type type)
+int isp_unset_callback(struct device *dev, enum isp_callback_type type)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	unsigned long irqflags = 0;
 
-	spin_lock_irqsave(&isp_obj.lock, irqflags);
-	isp_obj.irq.isp_callbk[type] = NULL;
-	isp_obj.irq.isp_callbk_arg1[type] = NULL;
-	isp_obj.irq.isp_callbk_arg2[type] = NULL;
-	spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+	spin_lock_irqsave(&isp->lock, irqflags);
+	isp->irq.isp_callbk[type] = NULL;
+	isp->irq.isp_callbk_arg1[type] = NULL;
+	isp->irq.isp_callbk_arg2[type] = NULL;
+	spin_unlock_irqrestore(&isp->lock, irqflags);
 
 	switch (type) {
-	case CBK_H3A_AWB_DONE:
-		isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-			    ~IRQ0ENABLE_H3A_AWB_DONE_IRQ);
-		break;
-	case CBK_H3A_AF_DONE:
-		isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-			    ~IRQ0ENABLE_H3A_AF_DONE_IRQ);
-		break;
-	case CBK_HIST_DONE:
-		isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-			    ~IRQ0ENABLE_HIST_DONE_IRQ);
-		break;
-	case CBK_CSIA:
-		isp_csi2_irq_set(0);
-		break;
-	case CBK_CSIB:
-		isp_reg_writel(IRQ0ENABLE_CSIB_IRQ, OMAP3_ISP_IOMEM_MAIN,
-			       ISP_IRQ0STATUS);
-		isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-			   IRQ0ENABLE_CSIB_IRQ);
-		break;
 	case CBK_PREV_DONE:
-		isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
 			    ~IRQ0ENABLE_PRV_DONE_IRQ);
 		break;
 	case CBK_RESZ_DONE:
-		isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
 			    ~IRQ0ENABLE_RSZ_DONE_IRQ);
 		break;
 	default:
@@ -576,29 +479,31 @@
 
 /**
  * isp_set_xclk - Configures the specified cam_xclk to the desired frequency.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @xclk: Desired frequency of the clock in Hz.
  * @xclksel: XCLK to configure (0 = A, 1 = B).
  *
  * Configures the specified MCLK divisor in the ISP timing control register
  * (TCTRL_CTRL) to generate the desired xclk clock value.
  *
- * Divisor = CM_CAM_MCLK_HZ / xclk
+ * Divisor = mclk / xclk
  *
  * Returns the final frequency that is actually being generated
  **/
-u32 isp_set_xclk(u32 xclk, u8 xclksel)
+u32 isp_set_xclk(struct device *dev, u32 xclk, u8 xclksel)
 {
 	u32 divisor;
 	u32 currentxclk;
+	struct isp_device *isp = dev_get_drvdata(dev);
 
-	if (xclk >= CM_CAM_MCLK_HZ) {
+	if (xclk >= isp->mclk) {
 		divisor = ISPTCTRL_CTRL_DIV_BYPASS;
-		currentxclk = CM_CAM_MCLK_HZ;
+		currentxclk = isp->mclk;
 	} else if (xclk >= 2) {
-		divisor = CM_CAM_MCLK_HZ / xclk;
+		divisor = isp->mclk / xclk;
 		if (divisor >= ISPTCTRL_CTRL_DIV_BYPASS)
 			divisor = ISPTCTRL_CTRL_DIV_BYPASS - 1;
-		currentxclk = CM_CAM_MCLK_HZ / divisor;
+		currentxclk = isp->mclk / divisor;
 	} else {
 		divisor = xclk;
 		currentxclk = 0;
@@ -606,14 +511,14 @@
 
 	switch (xclksel) {
 	case 0:
-		isp_reg_and_or(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+		isp_reg_and_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
 			       ~ISPTCTRL_CTRL_DIVA_MASK,
 			       divisor << ISPTCTRL_CTRL_DIVA_SHIFT);
 		DPRINTK_ISPCTRL("isp_set_xclk(): cam_xclka set to %d Hz\n",
 				currentxclk);
 		break;
 	case 1:
-		isp_reg_and_or(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
+		isp_reg_and_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL,
 			       ~ISPTCTRL_CTRL_DIVB_MASK,
 			       divisor << ISPTCTRL_CTRL_DIVB_SHIFT);
 		DPRINTK_ISPCTRL("isp_set_xclk(): cam_xclkb set to %d Hz\n",
@@ -621,8 +526,7 @@
 		break;
 	default:
 		DPRINTK_ISPCTRL("ISP_ERR: isp_set_xclk(): Invalid requested "
-				"xclk. Must be 0 (A) or 1 (B)."
-				"\n");
+				"xclk. Must be 0 (A) or 1 (B).\n");
 		return -EINVAL;
 	}
 
@@ -632,54 +536,53 @@
 
 /**
  * isp_power_settings - Sysconfig settings, for Power Management.
- * @isp_sysconfig: Structure containing the power settings for ISP to configure
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @idle: Consider idle state.
  *
  * Sets the power settings for the ISP, and SBL bus.
  **/
-static void isp_power_settings(int idle)
+static void isp_power_settings(struct device *dev, int idle)
 {
 	if (idle) {
-		isp_reg_writel(ISP_SYSCONFIG_AUTOIDLE |
+		isp_reg_writel(dev,
 			       (ISP_SYSCONFIG_MIDLEMODE_SMARTSTANDBY <<
 				ISP_SYSCONFIG_MIDLEMODE_SHIFT),
-			       OMAP3_ISP_IOMEM_MAIN,
-			       ISP_SYSCONFIG);
+			       OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
 		if (omap_rev() == OMAP3430_REV_ES1_0) {
-			isp_reg_writel(ISPCSI1_AUTOIDLE |
+			isp_reg_writel(dev, ISPCSI1_AUTOIDLE |
 				       (ISPCSI1_MIDLEMODE_SMARTSTANDBY <<
 					ISPCSI1_MIDLEMODE_SHIFT),
 				       OMAP3_ISP_IOMEM_CSI2A,
 				       ISP_CSIA_SYSCONFIG);
-			isp_reg_writel(ISPCSI1_AUTOIDLE |
+			isp_reg_writel(dev, ISPCSI1_AUTOIDLE |
 				       (ISPCSI1_MIDLEMODE_SMARTSTANDBY <<
 					ISPCSI1_MIDLEMODE_SHIFT),
 				       OMAP3_ISP_IOMEM_CCP2,
 				       ISP_CSIB_SYSCONFIG);
 		}
-		isp_reg_writel(ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
+		isp_reg_writel(dev, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
 			       ISP_CTRL);
 
 	} else {
-		isp_reg_writel(ISP_SYSCONFIG_AUTOIDLE |
+		isp_reg_writel(dev,
 			       (ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY <<
 				ISP_SYSCONFIG_MIDLEMODE_SHIFT),
-			       OMAP3_ISP_IOMEM_MAIN,
-			       ISP_SYSCONFIG);
+			       OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
 		if (omap_rev() == OMAP3430_REV_ES1_0) {
-			isp_reg_writel(ISPCSI1_AUTOIDLE |
+			isp_reg_writel(dev, ISPCSI1_AUTOIDLE |
 				       (ISPCSI1_MIDLEMODE_FORCESTANDBY <<
 					ISPCSI1_MIDLEMODE_SHIFT),
 				       OMAP3_ISP_IOMEM_CSI2A,
 				       ISP_CSIA_SYSCONFIG);
 
-			isp_reg_writel(ISPCSI1_AUTOIDLE |
+			isp_reg_writel(dev, ISPCSI1_AUTOIDLE |
 				       (ISPCSI1_MIDLEMODE_FORCESTANDBY <<
 					ISPCSI1_MIDLEMODE_SHIFT),
 				       OMAP3_ISP_IOMEM_CCP2,
 				       ISP_CSIB_SYSCONFIG);
 		}
 
-		isp_reg_writel(ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
+		isp_reg_writel(dev, ISPCTRL_SBL_AUTOIDLE, OMAP3_ISP_IOMEM_MAIN,
 			       ISP_CTRL);
 	}
 }
@@ -690,7 +593,31 @@
 			| (val << shift);	\
 	} while (0)
 
-static int isp_init_csi(struct isp_interface_config *config)
+/**
+ * isp_csi_enable - Enable CSI1/CCP2 interface.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @enable: Enable flag.
+ **/
+static void isp_csi_enable(struct device *dev, u8 enable)
+{
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL,
+		       ~(BIT(0) | BIT(4)),
+		       enable ? (BIT(0) | BIT(4)) : 0);
+}
+
+/**
+ * isp_init_csi - Initialize CSI1/CCP2 interface.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @config: Pointer to ISP interface config structure.
+ *
+ * This will analize the parameters passed by the interface config
+ * structure, and configure the respective registers for proper CSI1/CCP2
+ * config.
+ *
+ * Returns -EINVAL if wrong format, -EIO if strobe is choosen in CSI1 mode, or
+ * 0 on success.
+ **/
+static int isp_init_csi(struct device *dev, struct isp_interface_config *config)
 {
 	u32 i = 0, val, reg;
 	int format;
@@ -703,29 +630,28 @@
 		format = 0x12;		/* RAW8+DPCM10+VP */
 		break;
 	default:
-		printk(KERN_ERR "isp_init_csi: bad csi format\n");
+		dev_err(dev, "isp_init_csi: bad csi format\n");
 		return -EINVAL;
 	}
 
 	/* Reset the CSI and wait for reset to complete */
-	isp_reg_writel(isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSCONFIG) |
-		       BIT(1),
-		       OMAP3_ISP_IOMEM_CCP2,
-		       ISPCSI1_SYSCONFIG);
-	while (!(isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSSTATUS) &
+	isp_reg_writel(dev, isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2,
+		       ISPCSI1_SYSCONFIG) | BIT(1),
+		       OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSCONFIG);
+	while (!(isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSSTATUS) &
 		 BIT(0))) {
 		udelay(10);
 		if (i++ > 10)
 			break;
 	}
-	if (!(isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSSTATUS) &
+	if (!(isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_SYSSTATUS) &
 	      BIT(0))) {
-		printk(KERN_WARNING
+		dev_warn(dev,
 		       "omap3_isp: timeout waiting for csi reset\n");
 	}
 
 	/* ISPCSI1_CTRL */
-	val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
+	val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
 	val &= ~BIT(11);	/* Enable VP only off ->
 				   extract embedded data to interconnect */
 	BIT_SET(val, 8, 0x3, config->u.csi.vpclk);	/* Video port clock */
@@ -740,43 +666,55 @@
 	BIT_SET(val, 1, 1, config->u.csi.signalling);
 	BIT_SET(val, 10, 1, config->u.csi.strobe_clock_inv);
 	val |= BIT(4);		/* Magic bit to enable CSI1 and strobe mode */
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
 
 	/* ISPCSI1_LCx_CTRL logical channel #0 */
 	reg = ISPCSI1_LCx_CTRL(0);	/* reg = ISPCSI1_CTRL1; */
-	val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, reg);
+	val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, reg);
 	/* Format = RAW10+VP or RAW8+DPCM10+VP*/
 	BIT_SET(val, 3, 0x1f, format);
 	/* Enable setting of frame regions of interest */
 	BIT_SET(val, 1, 1, 1);
 	BIT_SET(val, 2, 1, config->u.csi.crc);
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, reg);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2, reg);
 
 	/* ISPCSI1_DAT_START for logical channel #0 */
 	reg = ISPCSI1_LCx_DAT_START(0);		/* reg = ISPCSI1_DAT_START; */
-	val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, reg);
+	val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, reg);
 	BIT_SET(val, 16, 0xfff, config->u.csi.data_start);
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, reg);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2, reg);
 
 	/* ISPCSI1_DAT_SIZE for logical channel #0 */
 	reg = ISPCSI1_LCx_DAT_SIZE(0);		/* reg = ISPCSI1_DAT_SIZE; */
-	val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, reg);
+	val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2, reg);
 	BIT_SET(val, 16, 0xfff, config->u.csi.data_size);
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, reg);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2, reg);
 
 	/* Clear status bits for logical channel #0 */
-	isp_reg_writel(0xFFF & ~BIT(6), OMAP3_ISP_IOMEM_CCP2,
+	val = ISPCSI1_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
+	      ISPCSI1_LC01_IRQSTATUS_LC0_CRC_IRQ |
+	      ISPCSI1_LC01_IRQSTATUS_LC0_FSP_IRQ |
+	      ISPCSI1_LC01_IRQSTATUS_LC0_FW_IRQ |
+	      ISPCSI1_LC01_IRQSTATUS_LC0_FSC_IRQ |
+	      ISPCSI1_LC01_IRQSTATUS_LC0_SSC_IRQ;
+
+	/* Clear IRQ status bits for logical channel #0 */
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_CCP2,
 		       ISPCSI1_LC01_IRQSTATUS);
 
-	/* Enable CSI1 */
-	val = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
-	val |=  BIT(0) | BIT(4);
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL);
+	/* Enable IRQs for logical channel #0 */
+	isp_reg_or(dev, OMAP3_ISP_IOMEM_CCP2, ISPCSI1_LC01_IRQENABLE, val);
 
-	if (!(isp_reg_readl(OMAP3_ISP_IOMEM_CCP2, ISPCSI1_CTRL) & BIT(4))) {
-		printk(KERN_WARNING "OMAP3 CSI1 bus not available\n");
-		if (config->u.csi.signalling)	/* Strobe mode requires CSI1 */
+	/* Enable CSI1 */
+	isp_csi_enable(dev, 1);
+
+	if (!(isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2,
+			    ISPCSI1_CTRL) & BIT(4))) {
+		dev_warn(dev, "OMAP3 CSI1 bus not available\n");
+		if (config->u.csi.signalling) {
+			/* Strobe mode requires CCP2 */
 			return -EIO;
+		}
 	}
 
 	return 0;
@@ -784,8 +722,9 @@
 
 /**
  * isp_configure_interface - Configures ISP Control I/F related parameters.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @config: Pointer to structure containing the desired configuration for the
- * 	ISP.
+ *          ISP.
  *
  * Configures ISP control register (ISP_CTRL) with the values specified inside
  * the config structure. Controls:
@@ -794,13 +733,18 @@
  * - Pixel clock polarity.
  * - 8 to 16-bit bridge at the input of CCDC module.
  * - HS or VS synchronization signal detection
+ *
+ * Returns 0 on success, otherwise, will return other negative error value.
  **/
-int isp_configure_interface(struct isp_interface_config *config)
+int isp_configure_interface(struct device *dev,
+			    struct isp_interface_config *config)
 {
-	u32 ispctrl_val = isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+	struct isp_device *isp = dev_get_drvdata(dev);
+	u32 ispctrl_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+	u32 fmtcfg;
 	int r;
 
-	isp_obj.config = config;
+	isp->config = config;
 
 	ispctrl_val &= ISPCTRL_SHIFT_MASK;
 	ispctrl_val |= config->dataline_shift << ISPCTRL_SHIFT_SHIFT;
@@ -808,7 +752,7 @@
 
 	ispctrl_val &= ISPCTRL_PAR_SER_CLK_SEL_MASK;
 
-	isp_buf_init();
+	isp_buf_init(dev);
 
 	switch (config->ccdc_par_ser) {
 	case ISP_PARLL:
@@ -824,26 +768,27 @@
 		ispctrl_val &= ~ISPCTRL_PAR_BRIDGE_BENDIAN;
 
 		if (config->u.csi.crc)
-			isp_csi2_ctrl_config_ecc_enable(true);
+			isp_csi2_ctrl_config_ecc_enable(&isp->isp_csi2, true);
 
-		isp_csi2_ctrl_config_vp_out_ctrl(config->u.csi.vpclk);
-		isp_csi2_ctrl_config_vp_only_enable(true);
-		isp_csi2_ctrl_config_vp_clk_enable(true);
-		isp_csi2_ctrl_update(false);
+		isp_csi2_ctrl_config_vp_out_ctrl(&isp->isp_csi2,
+						 config->u.csi.vpclk);
+		isp_csi2_ctrl_config_vp_only_enable(&isp->isp_csi2, true);
+		isp_csi2_ctrl_config_vp_clk_enable(&isp->isp_csi2, true);
+		isp_csi2_ctrl_update(&isp->isp_csi2, false);
 
-		isp_csi2_ctx_config_format(0, config->u.csi.format);
-		isp_csi2_ctx_update(0, false);
+		isp_csi2_ctx_config_format(&isp->isp_csi2, 0,
+					   config->u.csi.format);
+		isp_csi2_ctx_update(&isp->isp_csi2, 0, false);
 
-		isp_csi2_irq_complexio1_set(1);
-		isp_csi2_irq_status_set(1);
-		isp_csi2_irq_set(1);
+		isp_csi2_irq_complexio1_set(&isp->isp_csi2, 1);
+		isp_csi2_irq_status_set(&isp->isp_csi2, 1);
 
-		isp_csi2_enable(1);
+		isp_csi2_enable(&isp->isp_csi2, 1);
 		mdelay(3);
 		break;
 	case ISP_CSIB:
 		ispctrl_val |= ISPCTRL_PAR_SER_CLK_SEL_CSIB;
-		r = isp_init_csi(config);
+		r = isp_init_csi(dev, config);
 		if (r)
 			return r;
 		break;
@@ -856,90 +801,190 @@
 	ispctrl_val &= ~ISPCTRL_SYNC_DETECT_VSRISE;
 	ispctrl_val |= config->hsvs_syncdetect;
 
-	isp_reg_writel(ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+	isp_reg_writel(dev, ispctrl_val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 
-	/* Set sensor specific fields in CCDC and Previewer module.*/
-	ispccdc_set_wenlog(config->wenlog);
-	ispccdc_set_crop_offset(config->raw_fmt_in);
+	/* Set sensor specific fields in CCDC and Previewer module. */
+	ispccdc_set_wenlog(&isp->isp_ccdc, config->wenlog);
+	ispccdc_set_raw_offset(&isp->isp_ccdc, config->raw_fmt_in);
+
+	isp->mclk = config->cam_mclk;
+	isp_enable_mclk(dev);
+	/* FIXME: this should be set in ispccdc_config_vp() */
+	fmtcfg = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
+	fmtcfg &= ISPCCDC_FMTCFG_VPIF_FRQ_MASK;
+	if (config->pixelclk) {
+		unsigned long l3_ick = clk_get_rate(isp->l3_ick);
+		unsigned long div = l3_ick / config->pixelclk;
+		if (div < 2)
+			div = 2;
+		if (div > 6)
+			div = 6;
+		fmtcfg |= (div - 2) << ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT;
+	}
+	isp_reg_writel(dev, fmtcfg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
 
 	return 0;
 }
 EXPORT_SYMBOL(isp_configure_interface);
 
-static int isp_buf_process(struct isp_bufs *bufs);
+void isp_hist_dma_done(struct device *dev)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_irq *irqdis = &isp->irq;
+
+	isp_hist_enable(&isp->isp_hist, 1);
+	if (ispccdc_busy(&isp->isp_ccdc)) {
+		/* Histogram cannot be enabled in this frame anymore */
+		isp_hist_enable(&isp->isp_hist, 0);
+		if (isp_hist_busy(&isp->isp_hist))
+			isp_hist_mark_invalid_buf(&isp->isp_hist);
+	}
+	if (irqdis->isp_callbk[CBK_CATCHALL]) {
+		irqdis->isp_callbk[CBK_CATCHALL](
+			HIST_DONE,
+			irqdis->isp_callbk_arg1[CBK_CATCHALL],
+			irqdis->isp_callbk_arg2[CBK_CATCHALL]);
+	}
+}
+
+static void isp_buf_process(struct device *dev, struct isp_bufs *bufs);
 
 /**
- * omap34xx_isp_isr - Interrupt Service Routine for Camera ISP module.
+ * isp_isr - Interrupt Service Routine for Camera ISP module.
  * @irq: Not used currently.
- * @ispirq_disp: Pointer to the object that is passed while request_irq is
- *               called. This is the isp_obj.irq object containing info on the
- *               callback.
+ * @_pdev: Pointer to the platform device associated with the OMAP3 ISP.
  *
  * Handles the corresponding callback if plugged in.
  *
  * Returns IRQ_HANDLED when IRQ was correctly handled, or IRQ_NONE when the
  * IRQ wasn't handled.
  **/
-static irqreturn_t omap34xx_isp_isr(int irq, void *_isp)
+static irqreturn_t isp_isr(int irq, void *_pdev)
 {
-	struct isp *isp = _isp;
+	struct device *dev = &((struct platform_device *)_pdev)->dev;
+	struct isp_device *isp = dev_get_drvdata(dev);
 	struct isp_irq *irqdis = &isp->irq;
 	struct isp_bufs *bufs = &isp->bufs;
+	struct isp_buf *buf;
 	unsigned long flags;
 	u32 irqstatus = 0;
-	unsigned long irqflags = 0;
+	u32 sbl_pcr;
 	int wait_hs_vs = 0;
+	int ret;
 
-	irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
-	isp_reg_writel(irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+	if ((isp->running == ISP_STOPPED) &&
+		!irqdis->isp_callbk[CBK_RESZ_DONE])
+		return IRQ_NONE;
 
-	spin_lock_irqsave(&bufs->lock, flags);
+	irqstatus = isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+	isp_reg_writel(dev, irqstatus, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+
+	/* Handle first LSC states */
+	if ((irqstatus & LSC_DONE) || (irqstatus & LSC_DONE) ||
+	    (irqstatus & CCDC_VD1))
+		ispccdc_lsc_state_handler(&isp->isp_ccdc, irqstatus);
+
+	if ((isp->running == ISP_STOPPING) &&
+		!(irqdis->isp_callbk[CBK_RESZ_DONE] &&
+			(irqstatus & RESZ_DONE)))
+		goto out_stopping_isp;
+
+	spin_lock_irqsave(&isp->lock, flags);
 	wait_hs_vs = bufs->wait_hs_vs;
-	if (irqstatus & HS_VS && bufs->wait_hs_vs)
+	if (irqstatus & CCDC_VD0 && bufs->wait_hs_vs)
 		bufs->wait_hs_vs--;
-	spin_unlock_irqrestore(&bufs->lock, flags);
-
-	spin_lock_irqsave(&isp_obj.lock, irqflags);
 	/*
 	 * We need to wait for the first HS_VS interrupt from CCDC.
 	 * Otherwise our frame (and everything else) might be bad.
 	 */
-	if (wait_hs_vs)
-		goto out_ignore_buff;
+	switch (wait_hs_vs) {
+	case 1:
+		/*
+		 * Enable preview for the first time. We just have
+		 * missed the start-of-frame so we can do it now.
+		 */
+		if (irqstatus & CCDC_VD0) {
+			/*
+			 * For some reason resizer is always busy after boot up
+			 * do not check resizer busy now.
+			 */
+			if ((isp->pipeline.modules & OMAP_ISP_RESIZER) &&
+			    (isp->pipeline.rsz_in == RSZ_OTFLY_YUV) &&
+			    !(isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ,
+					    ISPRSZ_PCR) & (ISPRSZ_PCR_ENABLE |
+					    ISPRSZ_PCR_BUSY))) {
+				ispresizer_config_shadow_registers(
+					&isp->isp_res);
+				ispresizer_enable(&isp->isp_res, 1);
+			}
+			if (((isp)->pipeline.modules & OMAP_ISP_PREVIEW) &&
+			    !(isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+					    ISPPRV_PCR) & (ISPPRV_PCR_BUSY |
+					    ISPPRV_PCR_EN))) {
+				isppreview_config_shadow_registers(
+					&isp->isp_prev);
+				isppreview_enable(&isp->isp_prev, 1);
+			}
+		}
+	default:
+		/*
+		 * For some sensors (like stingray), after a _restart_
+		 * from sw standby state, starting couple of frames
+		 * are erroneous. From stingray datasheet:
+		 *  "When sensor restarts, Normal image can get 2 frames after"
+		 *
+		 * So while we wait for HS_VS, check cnd clear the CSIA and
+		 * CSIB error interrupts, if any
+		 */
+		if (irqstatus & CSIA)
+			isp_csi2_isr(&isp->isp_csi2);
 
-	if (irqstatus & CCDC_VD0) {
-		if (RAW_CAPTURE(&isp_obj))
-			isp_buf_process(bufs);
-		if (!ispccdc_busy())
-			ispccdc_config_shadow_registers();
+		if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
+			u32 csib;
+
+			csib = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2,
+					     ISPCSI1_LC01_IRQSTATUS);
+			isp_reg_writel(dev, csib, OMAP3_ISP_IOMEM_CCP2,
+				       ISPCSI1_LC01_IRQSTATUS);
+		}
+
+		if (!(irqstatus & RESZ_DONE) || CCDC_PREV_RESZ_CAPTURE(isp))
+			goto out_ignore_buff;
+	case 0:
+		break;
 	}
 
-	if (irqstatus & PREV_DONE) {
-		if (irqdis->isp_callbk[CBK_PREV_DONE])
-			irqdis->isp_callbk[CBK_PREV_DONE](
-				PREV_DONE,
-				irqdis->isp_callbk_arg1[CBK_PREV_DONE],
-				irqdis->isp_callbk_arg2[CBK_PREV_DONE]);
-		else if (!RAW_CAPTURE(&isp_obj) && !ispresizer_busy()) {
-			if (isp_obj.module.applyCrop) {
-				ispresizer_applycrop();
-				if (!ispresizer_busy())
-					isp_obj.module.applyCrop = 0;
-			}
-			if (!isppreview_busy()) {
-				ispresizer_enable(1);
-				if (isppreview_busy()) {
-					/* FIXME: locking! */
-					ISP_BUF_DONE(bufs)->vb_state =
-						VIDEOBUF_ERROR;
-					printk(KERN_ERR "%s: can't stop"
-					       " preview\n", __func__);
-				}
-			}
-			if (!isppreview_busy())
-				isppreview_config_shadow_registers();
-			if (!isppreview_busy())
-				isph3a_update_wb();
+	buf = ISP_BUF_DONE(bufs);
+
+	if (irqstatus & LSC_PRE_ERR) {
+		/* Mark buffer faulty. */
+		buf->vb_state = VIDEOBUF_ERROR;
+		dev_dbg(dev, "lsc prefetch error \n");
+	}
+
+	if (irqstatus & CSIA) {
+		int ret = isp_csi2_isr(&isp->isp_csi2);
+		if (ret)
+			buf->vb_state = VIDEOBUF_ERROR;
+	}
+
+	if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
+		static const u32 ISPCSI1_LC01_ERROR =
+			ISPCSI1_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ |
+			ISPCSI1_LC01_IRQSTATUS_LC0_CRC_IRQ |
+			ISPCSI1_LC01_IRQSTATUS_LC0_FSP_IRQ |
+			ISPCSI1_LC01_IRQSTATUS_LC0_FW_IRQ |
+			ISPCSI1_LC01_IRQSTATUS_LC0_FSC_IRQ |
+			ISPCSI1_LC01_IRQSTATUS_LC0_SSC_IRQ;
+		u32 ispcsi1_irqstatus;
+
+		ispcsi1_irqstatus = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCP2,
+						  ISPCSI1_LC01_IRQSTATUS);
+		isp_reg_writel(dev, ispcsi1_irqstatus, OMAP3_ISP_IOMEM_CCP2,
+			       ISPCSI1_LC01_IRQSTATUS);
+		if (ispcsi1_irqstatus & ISPCSI1_LC01_ERROR) {
+			buf->vb_state = VIDEOBUF_ERROR;
+			dev_dbg(dev, "CCP2 err:%x\n", ispcsi1_irqstatus);
 		}
 	}
 
@@ -949,59 +994,143 @@
 				RESZ_DONE,
 				irqdis->isp_callbk_arg1[CBK_RESZ_DONE],
 				irqdis->isp_callbk_arg2[CBK_RESZ_DONE]);
-		else if (!RAW_CAPTURE(&isp_obj)) {
-			if (!ispresizer_busy())
-				ispresizer_config_shadow_registers();
-			isp_buf_process(bufs);
+		else if (CCDC_PREV_RESZ_CAPTURE(isp)) {
+			isp_buf_process(dev, bufs);
 		}
 	}
 
-	if (irqstatus & H3A_AWB_DONE) {
-		if (irqdis->isp_callbk[CBK_H3A_AWB_DONE])
-			irqdis->isp_callbk[CBK_H3A_AWB_DONE](
-				H3A_AWB_DONE,
-				irqdis->isp_callbk_arg1[CBK_H3A_AWB_DONE],
-				irqdis->isp_callbk_arg2[CBK_H3A_AWB_DONE]);
+	if (irqstatus & CCDC_VD1) {
+		ispccdc_config_shadow_registers(&isp->isp_ccdc);
+		/*
+		 * If CCDC is writing to memory stop CCDC here
+		 * preventig to write to any of our buffers.
+		 */
+		if (CCDC_CAPTURE(isp))
+			ispccdc_enable(&isp->isp_ccdc, 0);
 	}
 
-	if (irqstatus & HIST_DONE) {
-		if (irqdis->isp_callbk[CBK_HIST_DONE])
-			irqdis->isp_callbk[CBK_HIST_DONE](
-				HIST_DONE,
-				irqdis->isp_callbk_arg1[CBK_HIST_DONE],
-				irqdis->isp_callbk_arg2[CBK_HIST_DONE]);
+	if (irqstatus & CCDC_VD0) {
+		if (CCDC_CAPTURE(isp))
+			isp_buf_process(dev, bufs);
+
+		/* Enabling configured statistic modules */
+		if (!(irqstatus & H3A_AWB_DONE))
+			isph3a_aewb_try_enable(&isp->isp_h3a);
+		if (!(irqstatus & H3A_AF_DONE))
+			isp_af_try_enable(&isp->isp_af);
+		if (!(irqstatus & HIST_DONE))
+			isp_hist_try_enable(&isp->isp_hist);
+	}
+
+	if (irqstatus & PREV_DONE) {
+		if (irqdis->isp_callbk[CBK_PREV_DONE])
+			irqdis->isp_callbk[CBK_PREV_DONE](
+				PREV_DONE,
+				irqdis->isp_callbk_arg1[CBK_PREV_DONE],
+				irqdis->isp_callbk_arg2[CBK_PREV_DONE]);
+		else {
+			if (CCDC_PREV_RESZ_CAPTURE(isp)) {
+				if (ispresizer_busy(&isp->isp_res)) {
+					buf->vb_state = VIDEOBUF_ERROR;
+					dev_dbg(dev, "resizer busy.\n");
+				} else if (!ISP_BUFS_IS_EMPTY(bufs)) {
+					ispresizer_config_shadow_registers(
+						&isp->isp_res);
+					ispresizer_enable(&isp->isp_res, 1);
+				}
+			}
+			if (!ISP_BUFS_IS_EMPTY(bufs)) {
+				isppreview_config_shadow_registers(
+					&isp->isp_prev);
+				isppreview_enable(&isp->isp_prev, 1);
+			}
+			if (CCDC_PREV_CAPTURE(isp))
+				isp_buf_process(dev, bufs);
+		}
+	}
+
+	/*
+	 * Handle shared buffer logic overflows for video buffers.
+	 * ISPSBL_PCR_CCDCPRV_2_RSZ_OVF can be safely ignored.
+	 */
+	sbl_pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR) &
+		~ISPSBL_PCR_CCDCPRV_2_RSZ_OVF;
+	isp_reg_writel(dev, sbl_pcr, OMAP3_ISP_IOMEM_SBL, ISPSBL_PCR);
+	if (sbl_pcr & (ISPSBL_PCR_RSZ1_WBL_OVF
+		       | ISPSBL_PCR_RSZ2_WBL_OVF
+		       | ISPSBL_PCR_RSZ3_WBL_OVF
+		       | ISPSBL_PCR_RSZ4_WBL_OVF
+		       | ISPSBL_PCR_PRV_WBL_OVF
+		       | ISPSBL_PCR_CCDC_WBL_OVF
+		       | ISPSBL_PCR_CSIA_WBL_OVF
+		       | ISPSBL_PCR_CSIB_WBL_OVF)) {
+		buf->vb_state = VIDEOBUF_ERROR;
+		isp->isp_af.buf_err = 1;
+		isp->isp_h3a.buf_err = 1;
+		isp_hist_mark_invalid_buf(&isp->isp_hist);
+		dev_dbg(dev, "sbl overflow, sbl_pcr = %8.8x\n", sbl_pcr);
+	}
+
+	if (sbl_pcr & ISPSBL_PCR_H3A_AF_WBL_OVF) {
+		dev_dbg(dev, "af: sbl overflow detected.\n");
+		isp->isp_af.buf_err = 1;
+	}
+
+	if (sbl_pcr & ISPSBL_PCR_H3A_AEAWB_WBL_OVF) {
+		dev_dbg(dev, "h3a: sbl overflow detected.\n");
+		isp->isp_h3a.buf_err = 1;
+	}
+
+	if (irqstatus & H3A_AWB_DONE) {
+		isph3a_aewb_enable(&isp->isp_h3a, 0);
+		/* If it's busy we can't process this buffer anymore */
+		if (!isph3a_aewb_busy(&isp->isp_h3a)) {
+			ret = isph3a_aewb_buf_process(&isp->isp_h3a);
+			isph3a_aewb_config_registers(&isp->isp_h3a);
+		} else {
+			ret = -1;
+			dev_dbg(dev, "h3a: cannot process buffer, device is "
+				     "busy.\n");
+		}
+		if (ret)
+			irqstatus &= ~H3A_AWB_DONE;
+		isph3a_aewb_enable(&isp->isp_h3a, 1);
 	}
 
 	if (irqstatus & H3A_AF_DONE) {
-		if (irqdis->isp_callbk[CBK_H3A_AF_DONE])
-			irqdis->isp_callbk[CBK_H3A_AF_DONE](
-				H3A_AF_DONE,
-				irqdis->isp_callbk_arg1[CBK_H3A_AF_DONE],
-				irqdis->isp_callbk_arg2[CBK_H3A_AF_DONE]);
+		isp_af_enable(&isp->isp_af, 0);
+		/* If it's busy we can't process this buffer anymore */
+		if (!isp_af_busy(&isp->isp_af)) {
+			ret = isp_af_buf_process(&isp->isp_af);
+			isp_af_config_registers(&isp->isp_af);
+		} else {
+			ret = -1;
+			dev_dbg(dev, "af: cannot process buffer, device is "
+				     "busy.\n");
+		}
+		if (ret)
+			irqstatus &= ~H3A_AF_DONE;
+		isp_af_enable(&isp->isp_af, 1);
 	}
 
-
-out_ignore_buff:
-	if (irqstatus & LSC_PRE_ERR) {
-		struct isp_buf *buf = ISP_BUF_DONE(bufs);
-		/* Mark buffer faulty. */
-		buf->vb_state = VIDEOBUF_ERROR;
-		ispccdc_lsc_error_handler();
-		printk(KERN_ERR "%s: lsc prefetch error\n", __func__);
-	}
-
-	if (irqstatus & CSIA) {
-		struct isp_buf *buf = ISP_BUF_DONE(bufs);
-		isp_csi2_isr();
-		buf->vb_state = VIDEOBUF_ERROR;
-	}
-
-	if (irqstatus & IRQ0STATUS_CSIB_IRQ) {
-		u32 ispcsi1_irqstatus;
-
-		ispcsi1_irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CCP2,
-						  ISPCSI1_LC01_IRQSTATUS);
-		DPRINTK_ISPCTRL("%x\n", ispcsi1_irqstatus);
+	if (irqstatus & HIST_DONE) {
+		isp_hist_enable(&isp->isp_hist, 0);
+		/* If it's busy we can't process this buffer anymore */
+		if (!isp_hist_busy(&isp->isp_hist)) {
+			ret = isp_hist_buf_process(&isp->isp_hist);
+			isp_hist_config_registers(&isp->isp_hist);
+		} else {
+			dev_dbg(dev, "hist: cannot process buffer, device is "
+				     "busy.\n");
+			/* current and next buffer might have invalid data */
+			isp_hist_mark_invalid_buf(&isp->isp_hist);
+			irqstatus &= ~HIST_DONE;
+			ret = HIST_NO_BUF;
+		}
+		if (ret != HIST_BUF_WAITING_DMA)
+			isp_hist_enable(&isp->isp_hist, 1);
+		if (ret != HIST_BUF_DONE)
+			irqstatus &= ~HIST_DONE;
 	}
 
 	if (irqdis->isp_callbk[CBK_CATCHALL]) {
@@ -1011,7 +1140,14 @@
 			irqdis->isp_callbk_arg2[CBK_CATCHALL]);
 	}
 
-	spin_unlock_irqrestore(&isp_obj.lock, irqflags);
+out_ignore_buff:
+	spin_unlock_irqrestore(&isp->lock, flags);
+
+	if (irqstatus & LSC_PRE_COMP)
+		ispccdc_lsc_pref_comp_handler(&isp->isp_ccdc);
+
+out_stopping_isp:
+	isp_flush(dev);
 
 #if 1
 	{
@@ -1074,55 +1210,68 @@
 };
 
 /**
- *  isp_tmp_buf_free - To free allocated 10MB memory
- *
+ * isp_tmp_buf_free - Free buffer for CCDC->PRV->RSZ datapath workaround.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  **/
-static void isp_tmp_buf_free(void)
+static void isp_tmp_buf_free(struct device *dev)
 {
-	if (isp_obj.tmp_buf) {
-		ispmmu_vfree(isp_obj.tmp_buf);
-		isp_obj.tmp_buf = 0;
-		isp_obj.tmp_buf_size = 0;
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	if (isp->tmp_buf) {
+		iommu_vfree(isp->iommu, isp->tmp_buf);
+		isp->tmp_buf = 0;
+		isp->tmp_buf_size = 0;
+		isp->tmp_buf_offset = 0;
 	}
 }
 
 /**
- *  isp_tmp_buf_alloc - To allocate a 10MB memory
+ * isp_tmp_buf_alloc - Allocate buffer for CCDC->PRV->RSZ datapath workaround.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @size: Byte size of the buffer to allocate
  *
+ * Returns 0 if successful, or -ENOMEM if there's no available memory.
  **/
-static u32 isp_tmp_buf_alloc(size_t size)
+static u32 isp_tmp_buf_alloc(struct device *dev, struct isp_pipeline *pipe)
 {
-	isp_tmp_buf_free();
+	struct isp_device *isp = dev_get_drvdata(dev);
+	u32 da;
+	size_t size = PAGE_ALIGN(isp->pipeline.prv_out_w *
+				 isp->pipeline.prv_out_h *
+				 ISP_BYTES_PER_PIXEL);
 
-	printk(KERN_INFO "%s: allocating %d bytes\n", __func__, size);
+	ispresizer_config_inlineoffset(&isp->isp_res,
+			pipe->prv_out_w * ISP_BYTES_PER_PIXEL);
 
-	isp_obj.tmp_buf = ispmmu_vmalloc(size);
-	if (IS_ERR((void *)isp_obj.tmp_buf)) {
-		printk(KERN_ERR "ispmmu_vmap mapping failed ");
+	if (isp->tmp_buf_size >= size)
+		return 0;
+
+	isp_tmp_buf_free(dev);
+
+	da = iommu_vmalloc(isp->iommu, 0, size, IOMMU_FLAG);
+	if (IS_ERR_VALUE(da)) {
+		dev_err(dev, "iommu_vmap mapping failed\n");
 		return -ENOMEM;
 	}
-	isp_obj.tmp_buf_size = size;
+	isp->tmp_buf = da;
+	isp->tmp_buf_size = size;
 
-	isppreview_set_outaddr(isp_obj.tmp_buf);
-	ispresizer_set_inaddr(isp_obj.tmp_buf);
+	isppreview_set_outaddr(&isp->isp_prev, isp->tmp_buf);
+	ispresizer_set_inaddr(&isp->isp_res, isp->tmp_buf, 0);
 
 	return 0;
 }
 
 /**
- * isp_start - Starts ISP submodule
- *
- * Start the needed isp components assuming these components
- * are configured correctly.
+ * isp_start - Set ISP in running state
+ * @dev: Device pointer specific to the OMAP3 ISP.
  **/
-void isp_start(void)
+void isp_start(struct device *dev)
 {
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW
-	    && is_isppreview_enabled())
-		isppreview_enable(1);
+	struct isp_device *isp = dev_get_drvdata(dev);
 
-	isph3a_notify(0);
-	isp_af_notify(0);
+	isp->running = ISP_RUNNING;
+
 	return;
 }
 EXPORT_SYMBOL(isp_start);
@@ -1130,38 +1279,57 @@
 #define ISP_STATISTICS_BUSY			\
 	()
 #define ISP_STOP_TIMEOUT	msecs_to_jiffies(1000)
-static int __isp_disable_modules(int suspend)
+
+/**
+ * __isp_disable_modules - Disable ISP submodules with a timeout to be idle.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @suspend: If 0, disable modules; if 1, send modules to suspend state.
+ *
+ * Returns 0 if stop/suspend left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to stop/suspend the submodules.
+ **/
+static int __isp_disable_modules(struct device *dev, int suspend)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	unsigned long timeout = jiffies + ISP_STOP_TIMEOUT;
 	int reset = 0;
 
+	/* We need to disble the first LSC module */
+	timeout = jiffies + ISP_STOP_TIMEOUT;
+	while (ispccdc_lsc_delay_stop(&isp->isp_ccdc)) {
+		if (time_after(jiffies, timeout)) {
+			printk(KERN_ERR "%s: can't stop lsc "
+					"disabling lsc anyway. \n", __func__);
+			reset = 1;
+			break;
+		}
+		msleep(1);
+	}
+	/* We can disable lsc now */
+	ispccdc_enable_lsc(&isp->isp_ccdc, 0);
+
 	/*
-	 * We need to stop all the modules after CCDC first or they'll
+	 * We need to stop all the modules after CCDC or they'll
 	 * never stop since they may not get a full frame from CCDC.
 	 */
 	if (suspend) {
-		isp_af_suspend();
-		isph3a_aewb_suspend();
-		isp_hist_suspend();
-		isppreview_suspend();
-		ispresizer_suspend();
+		isp_af_suspend(&isp->isp_af);
+		isph3a_aewb_suspend(&isp->isp_h3a);
+		isp_hist_suspend(&isp->isp_hist);
 	} else {
-		isp_af_enable(0);
-		isph3a_aewb_enable(0);
-		isp_hist_enable(0);
-		isppreview_enable(0);
-		ispresizer_enable(0);
+		isp_af_enable(&isp->isp_af, 0);
+		isph3a_aewb_enable(&isp->isp_h3a, 0);
+		isp_hist_enable(&isp->isp_hist, 0);
 	}
 
 	timeout = jiffies + ISP_STOP_TIMEOUT;
-	while (isp_af_busy()
-	       || isph3a_aewb_busy()
-	       || isp_hist_busy()
-	       || isppreview_busy()
-	       || ispresizer_busy()) {
+	while (isp_af_busy(&isp->isp_af)
+	       || isph3a_aewb_busy(&isp->isp_h3a)
+	       || isp_hist_busy(&isp->isp_hist)
+	       || isppreview_busy(&isp->isp_prev)
+	       || ispresizer_busy(&isp->isp_res)) {
 		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR "%s: can't stop non-ccdc modules\n",
-			       __func__);
+			dev_info(dev, "can't stop non-ccdc modules.\n");
 			reset = 1;
 			break;
 		}
@@ -1169,57 +1337,92 @@
 	}
 
 	/* Let's stop CCDC now. */
-	if (suspend)
-		/* This function supends lsc too */
-		ispccdc_suspend();
-	else {
-		ispccdc_enable_lsc(0);
-		ispccdc_enable(0);
-	}
+	ispccdc_enable(&isp->isp_ccdc, 0);
 
 	timeout = jiffies + ISP_STOP_TIMEOUT;
-	while (ispccdc_busy()) {
+	while (ispccdc_busy(&isp->isp_ccdc)) {
 		if (time_after(jiffies, timeout)) {
-			printk(KERN_ERR "%s: can't stop ccdc\n", __func__);
+			dev_info(dev, "can't stop ccdc module.\n");
 			reset = 1;
 			break;
 		}
 		msleep(1);
 	}
 
+	if (!reset) {
+		DPRINTK_ISPCTRL(KERN_INFO
+			"(%s) isp_complete_reset \n", __func__);
+		isp_complete_reset = 1;
+	}
+
+	isp_csi_enable(dev, 0);
+	isp_csi2_enable(&isp->isp_csi2, 0);
+	isp_buf_init(dev);
+
 	return reset;
 }
 
-static int isp_stop_modules(void)
+/**
+ * isp_stop_modules - Stop ISP submodules.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * Returns 0 if stop left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to stop the submodules.
+ **/
+static int isp_stop_modules(struct device *dev)
 {
-	return __isp_disable_modules(0);
+	return __isp_disable_modules(dev, 0);
 }
 
-static int isp_suspend_modules(void)
+/**
+ * isp_suspend_modules - Suspend ISP submodules.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * Returns 0 if suspend left in idle state all the submodules properly,
+ * or returns 1 if a general Reset is required to suspend the submodules.
+ **/
+static int isp_suspend_modules(struct device *dev)
 {
-	return __isp_disable_modules(1);
+	return __isp_disable_modules(dev, 1);
 }
 
-static void isp_resume_modules(void)
+/**
+ * isp_resume_modules - Resume ISP submodules.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_resume_modules(struct device *dev)
 {
-	ispresizer_resume();
-	isppreview_resume();
-	isp_hist_resume();
-	isph3a_aewb_resume();
-	isp_af_resume();
-	ispccdc_resume();
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	isp_hist_resume(&isp->isp_hist);
+	isph3a_aewb_resume(&isp->isp_h3a);
+	isp_af_resume(&isp->isp_af);
+
+	if (isp->running == ISP_RUNNING) {
+		ispccdc_enable(&isp->isp_ccdc, 1);
+		ispresizer_enable(&isp->isp_res, 1);
+		isppreview_enable(&isp->isp_prev, 1);
+		isp_csi_enable(dev, 1);
+		isp_csi2_enable(&isp->isp_csi2, 1);
+	}
 }
 
-static void isp_reset(void)
+/**
+ * isp_reset - Reset ISP with a timeout wait for idle.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_reset(struct device *dev)
 {
 	unsigned long timeout = 0;
 
-	isp_reg_writel(isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
+	isp_reg_writel(dev,
+		       isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG)
 		       | ISP_SYSCONFIG_SOFTRESET,
 		       OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG);
-	while (!(isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_SYSSTATUS) & 0x1)) {
+	while (!(isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+			       ISP_SYSSTATUS) & 0x1)) {
 		if (timeout++ > 10000) {
-			printk(KERN_ALERT "%s: cannot reset ISP\n", __func__);
+			dev_alert(dev, "cannot reset ISP\n");
 			break;
 		}
 		udelay(1);
@@ -1227,130 +1430,322 @@
 }
 
 /**
- * isp_stop - Stops isp submodules
+ * isp_stop - Stop ISP.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  **/
-void isp_stop()
+void isp_stop(struct device *dev)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	int reset;
 
-	isph3a_notify(1);
-	isp_af_notify(1);
-	isp_disable_interrupts();
-	reset = isp_stop_modules();
-	isp_buf_init();
+	isp->running = ISP_STOPPING;
+	isp_disable_interrupts(dev);
+	synchronize_irq(((struct isp_device *)dev_get_drvdata(dev))->irq_num);
+	reset = isp_stop_modules(dev);
+	isp->running = ISP_STOPPED;
 	if (!reset)
 		return;
 
-	isp_save_ctx();
-	isp_reset();
-	isp_restore_ctx();
+	isp_save_ctx(dev);
+	isp_reset(dev);
+	isp_restore_ctx(dev);
 }
 EXPORT_SYMBOL(isp_stop);
 
-static void isp_set_buf(struct isp_buf *buf)
+/**
+ * isp_set_buf - Program output buffer address based on current pipeline.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @buf: Pointer to ISP buffer structure.
+ **/
+static void isp_set_buf(struct device *dev, struct isp_buf *buf)
 {
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER
-	    && is_ispresizer_enabled())
-		ispresizer_set_outaddr(buf->isp_addr);
-	else if (isp_obj.module.isp_pipeline & OMAP_ISP_CCDC)
-		ispccdc_set_outaddr(buf->isp_addr);
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	if (CCDC_PREV_RESZ_CAPTURE(isp))
+		ispresizer_set_outaddr(&isp->isp_res, buf->isp_addr);
+	else if (CCDC_PREV_CAPTURE(isp))
+		isppreview_set_outaddr(&isp->isp_prev, buf->isp_addr);
+	else if (CCDC_CAPTURE(isp))
+		ispccdc_set_outaddr(&isp->isp_ccdc, buf->isp_addr);
 
 }
 
 /**
- * isp_calc_pipeline - Sets pipeline depending of input and output pixel format
- * @pix_input: Pointer to V4L2 pixel format structure for input image.
- * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ * isp_try_pipeline - Retrieve and simulate resulting internal ISP pipeline.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @pix_input: Pointer to pixel format to use as input in the ISP.
+ * @pipe: Pointer to ISP pipeline structure to fill back.
+ *
+ * Returns the closest possible output size based on silicon limitations
+ * detailed through the pipe structure.
+ *
+ * If the input can't be read, it'll return -EINVAL. Returns 0 on success.
  **/
-static u32 isp_calc_pipeline(struct v4l2_pix_format *pix_input,
-			     struct v4l2_pix_format *pix_output)
+static int isp_try_pipeline(struct device *dev,
+			    struct v4l2_pix_format *pix_input,
+			    struct isp_pipeline *pipe)
 {
-	isp_release_resources();
-	if ((pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10
-	     || pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)
-	    && pix_output->pixelformat != V4L2_PIX_FMT_SGRBG10) {
-		isp_obj.module.isp_pipeline =
-			OMAP_ISP_CCDC | OMAP_ISP_PREVIEW | OMAP_ISP_RESIZER;
-		ispccdc_request();
-		isppreview_request();
-		ispresizer_request();
-		ispccdc_config_datapath(CCDC_RAW, CCDC_OTHERS_VP);
-		isppreview_config_datapath(PRV_RAW_CCDC, PREVIEW_MEM);
-		ispresizer_config_datapath(RSZ_MEM_YUV);
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct v4l2_pix_format *pix_output = &pipe->pix;
+	unsigned int wanted_width = pix_output->width;
+	unsigned int wanted_height = pix_output->height;
+	int ifmt;
+	int rval;
+
+	if ((pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
+	     pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8 ||
+	     pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10 ||
+	     pix_input->pixelformat == V4L2_PIX_FMT_SBGGR10 ||
+	     pix_input->pixelformat == V4L2_PIX_FMT_SGBRG10) &&
+	    (pix_output->pixelformat == V4L2_PIX_FMT_YUYV ||
+	     pix_output->pixelformat == V4L2_PIX_FMT_UYVY)) {
+		if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
+		    pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)
+			pipe->ccdc_in = CCDC_RAW_GRBG;
+		if (pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10)
+			pipe->ccdc_in = CCDC_RAW_RGGB;
+		if (pix_input->pixelformat == V4L2_PIX_FMT_SBGGR10)
+			pipe->ccdc_in = CCDC_RAW_BGGR;
+		if (pix_input->pixelformat == V4L2_PIX_FMT_SGBRG10)
+			pipe->ccdc_in = CCDC_RAW_GBRG;
+		pipe->ccdc_out = CCDC_OTHERS_VP;
+		pipe->prv_in = PRV_RAW_CCDC;
+		if ((pix_output->width == 1280) &&
+		    (pix_output->height == 720)) {
+			pipe->modules = OMAP_ISP_PREVIEW |
+					OMAP_ISP_CCDC;
+			pipe->prv_out = PREVIEW_MEM;
+		} else {
+			pipe->modules = OMAP_ISP_PREVIEW |
+					OMAP_ISP_RESIZER |
+					OMAP_ISP_CCDC;
+			if (isp->revision <= ISP_REVISION_2_0) {
+				pipe->prv_out = PREVIEW_MEM;
+				pipe->rsz_in = RSZ_MEM_YUV;
+			} else {
+				pipe->prv_out = PREVIEW_RSZ;
+				pipe->rsz_in = RSZ_OTFLY_YUV;
+			}
+		}
 	} else {
-		isp_obj.module.isp_pipeline = OMAP_ISP_CCDC;
-		ispccdc_request();
-		if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10
-		    || pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)
-			ispccdc_config_datapath(CCDC_RAW, CCDC_OTHERS_VP_MEM);
-		else
-			ispccdc_config_datapath(CCDC_YUV_SYNC,
-						CCDC_OTHERS_MEM);
+		pipe->modules = OMAP_ISP_CCDC;
+		if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
+		    pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8 ||
+		    pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10 ||
+		    pix_input->pixelformat == V4L2_PIX_FMT_SBGGR10 ||
+		    pix_input->pixelformat == V4L2_PIX_FMT_SGBRG10) {
+			pipe->ccdc_out = CCDC_OTHERS_VP_MEM;
+			if (pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10 ||
+			    pix_input->pixelformat == V4L2_PIX_FMT_SGRBG10DPCM8)
+				pipe->ccdc_in = CCDC_RAW_GRBG;
+			if (pix_input->pixelformat == V4L2_PIX_FMT_SRGGB10)
+				pipe->ccdc_in = CCDC_RAW_RGGB;
+			if (pix_input->pixelformat == V4L2_PIX_FMT_SBGGR10)
+				pipe->ccdc_in = CCDC_RAW_BGGR;
+			if (pix_input->pixelformat == V4L2_PIX_FMT_SGBRG10)
+				pipe->ccdc_in = CCDC_RAW_GBRG;
+		} else if (pix_input->pixelformat == V4L2_PIX_FMT_YUYV ||
+			   pix_input->pixelformat == V4L2_PIX_FMT_UYVY) {
+			pipe->ccdc_in = CCDC_YUV_SYNC;
+			pipe->ccdc_out = CCDC_OTHERS_MEM;
+		} else
+			return -EINVAL;
 	}
+
+	if (pipe->modules & OMAP_ISP_CCDC) {
+		pipe->ccdc_in_w = pix_input->width;
+		pipe->ccdc_in_h = pix_input->height;
+		rval = ispccdc_try_pipeline(&isp->isp_ccdc, pipe);
+		if (rval) {
+			dev_dbg(dev, "the dimensions %dx%d are not"
+				" supported\n", pix_input->width,
+				pix_input->height);
+			return rval;
+		}
+		pix_output->width = pipe->ccdc_out_w_img;
+		pix_output->height = pipe->ccdc_out_h;
+		pix_output->bytesperline =
+			pipe->ccdc_out_w * ISP_BYTES_PER_PIXEL;
+	}
+
+	if (pipe->modules & OMAP_ISP_PREVIEW) {
+		pipe->prv_out_w = wanted_width;
+		pipe->prv_out_h = wanted_height;
+		rval = isppreview_try_pipeline(&isp->isp_prev, pipe);
+		if (rval) {
+			dev_dbg(dev, "the dimensions %dx%d are not"
+				" supported\n", pix_input->width,
+				pix_input->height);
+			return rval;
+		}
+		pix_output->width = pipe->prv_out_w;
+		pix_output->height = pipe->prv_out_h;
+		pix_output->bytesperline =
+			pipe->prv_out_w * ISP_BYTES_PER_PIXEL;
+	}
+
+	if (pipe->modules & OMAP_ISP_RESIZER) {
+		pipe->rsz_out_w = wanted_width;
+		pipe->rsz_out_h = wanted_height;
+
+		pipe->rsz_crop.left = pipe->rsz_crop.top = 0;
+		pipe->rsz_crop.width = pipe->prv_out_w_img;
+		pipe->rsz_crop.height = pipe->prv_out_h_img;
+
+		rval = ispresizer_try_pipeline(&isp->isp_res, pipe);
+		if (rval) {
+			dev_dbg(dev, "The dimensions %dx%d are not"
+				" supported\n", pix_input->width,
+				pix_input->height);
+			return rval;
+		}
+
+		pix_output->width = pipe->rsz_out_w;
+		pix_output->height = pipe->rsz_out_h;
+		pix_output->bytesperline =
+			pipe->rsz_out_w * ISP_BYTES_PER_PIXEL;
+	}
+
+	pix_output->field = V4L2_FIELD_NONE;
+	pix_output->sizeimage =
+		PAGE_ALIGN(pix_output->bytesperline * pix_output->height);
+	pix_output->priv = 0;
+
+	for (ifmt = 0; ifmt < NUM_ISP_CAPTURE_FORMATS; ifmt++) {
+		if (pix_output->pixelformat == isp_formats[ifmt].pixelformat)
+			break;
+	}
+	if (ifmt == NUM_ISP_CAPTURE_FORMATS)
+		pix_output->pixelformat = V4L2_PIX_FMT_YUYV;
+
+	switch (pix_output->pixelformat) {
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+		pix_output->colorspace = V4L2_COLORSPACE_JPEG;
+		break;
+	default:
+		pix_output->colorspace = V4L2_COLORSPACE_SRGB;
+	}
+
 	return 0;
 }
 
 /**
- * isp_config_pipeline - Configures the image size and ycpos for ISP submodules
- * @pix_input: Pointer to V4L2 pixel format structure for input image.
- * @pix_output: Pointer to V4L2 pixel format structure for output image.
+ * isp_s_pipeline - Configure internal ISP pipeline.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @pix_input: Pointer to pixel format to use as input in the ISP.
+ * @pix_output: Pointer to pixel format to use as output in the ISP.
  *
- * The configuration of ycpos depends on the output pixel format for both the
- * Preview and Resizer submodules.
+ * Returns the closest possible output size based on silicon limitations.
+ *
+ * If the input can't be read, it'll return -EINVAL. Returns 0 on success.
  **/
-static void isp_config_pipeline(struct v4l2_pix_format *pix_input,
-				struct v4l2_pix_format *pix_output)
+static int isp_s_pipeline(struct device *dev,
+			  struct v4l2_pix_format *pix_input,
+			  struct v4l2_pix_format *pix_output)
 {
-	ispccdc_config_size(isp_obj.module.ccdc_input_width,
-			    isp_obj.module.ccdc_input_height,
-			    isp_obj.module.ccdc_output_width,
-			    isp_obj.module.ccdc_output_height);
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_pipeline pipe;
+	int rval;
 
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW) {
-		isppreview_config_size(isp_obj.module.preview_input_width,
-				       isp_obj.module.preview_input_height,
-				       isp_obj.module.preview_output_width,
-				       isp_obj.module.preview_output_height);
+	isp_release_resources(dev);
+
+	pipe.pix = *pix_output;
+
+	rval = isp_try_pipeline(dev, pix_input, &pipe);
+	if (rval)
+		return rval;
+
+	ispccdc_request(&isp->isp_ccdc);
+	ispccdc_s_pipeline(&isp->isp_ccdc, &pipe);
+
+	if (pipe.modules & OMAP_ISP_PREVIEW) {
+		isppreview_request(&isp->isp_prev);
+		isppreview_s_pipeline(&isp->isp_prev, &pipe);
 	}
 
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER) {
-		ispresizer_config_size(isp_obj.module.resizer_input_width,
-				       isp_obj.module.resizer_input_height,
-				       isp_obj.module.resizer_output_width,
-				       isp_obj.module.resizer_output_height);
+	if (pipe.modules & OMAP_ISP_RESIZER) {
+		ispresizer_request(&isp->isp_res);
+		ispresizer_s_pipeline(&isp->isp_res, &pipe);
 	}
 
-	if (pix_output->pixelformat == V4L2_PIX_FMT_UYVY) {
-		isppreview_config_ycpos(YCPOS_YCrYCb);
-		if (is_ispresizer_enabled())
-			ispresizer_config_ycpos(0);
-	} else {
-		isppreview_config_ycpos(YCPOS_CrYCbY);
-		if (is_ispresizer_enabled())
-			ispresizer_config_ycpos(1);
-	}
+	isp->pipeline = pipe;
+	*pix_output = isp->pipeline.pix;
 
-	return;
+	return 0;
 }
 
-void isp_set_hs_vs(int hs_vs)
+void isp_set_hs_vs(struct device *dev, int hs_vs)
 {
-	struct isp_bufs *bufs = &isp_obj.bufs;
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_bufs *bufs = &isp->bufs;
 
 	bufs->wait_hs_vs = hs_vs;
 	return;
 }
 EXPORT_SYMBOL(isp_set_hs_vs);
 
-static void isp_buf_init(void)
+/**
+ * isp_vbq_sync - keep the video buffers coherent between cpu and isp
+ *
+ * The typical operation required here is Cache Invalidation across
+ * the (user space) buffer address range. And this _must_ be done
+ * at QBUF stage (and *only* at QBUF).
+ *
+ * We try to use optimal cache invalidation function:
+ * - dmac_inv_range:
+ *    - used when the number of pages are _low_.
+ *    - it becomes quite slow as the number of pages increase.
+ *       - for 648x492 viewfinder (150 pages) it takes 1.3 ms.
+ *       - for 5 Mpix buffer (2491 pages) it takes between 25-50 ms.
+ *
+ * - flush_cache_all:
+ *    - used when the number of pages are _high_.
+ *    - time taken in the range of 500-900 us.
+ *    - has a higher penalty but, as whole dcache + icache is invalidated
+ **/
+/**
+ * FIXME: dmac_inv_range crashes randomly on the user space buffer
+ *        address. Fall back to flush_cache_all for now.
+ */
+#define ISP_CACHE_FLUSH_PAGES_MAX       0
+
+static int isp_vbq_sync(struct videobuf_buffer *vb)
 {
-	struct isp_bufs *bufs = &isp_obj.bufs;
+	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+	if (!vb->baddr || !dma || !dma->nr_pages ||
+	    dma->nr_pages > ISP_CACHE_FLUSH_PAGES_MAX)
+		flush_cache_all();
+	else {
+		dmac_inv_range((void *)vb->baddr,
+			       (void *)vb->baddr + vb->bsize);
+		outer_inv_range(vb->baddr, vb->baddr + vb->bsize);
+	}
+
+	return 0;
+}
+
+/**
+ * isp_buf_init - Initialize the internal buffer queue handling.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_buf_init(struct device *dev)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_bufs *bufs = &isp->bufs;
 	int sg;
 
+	isp_complete_reset = 1;
 	bufs->queue = 0;
 	bufs->done = 0;
-	bufs->wait_hs_vs = isp_obj.config->wait_hs_vs;
+	bufs->wait_hs_vs = isp->config->wait_hs_vs;
 	for (sg = 0; sg < NUM_BUFS; sg++) {
+		if (bufs->buf[sg].vb) {
+			bufs->buf[sg].vb->state = VIDEOBUF_ERROR;
+			bufs->buf[sg].complete(bufs->buf[sg].vb,
+					       bufs->buf[sg].priv);
+		}
 		bufs->buf[sg].complete = NULL;
 		bufs->buf[sg].vb = NULL;
 		bufs->buf[sg].priv = NULL;
@@ -1358,31 +1753,27 @@
 }
 
 /**
- * isp_vbq_sync - Walks the pages table and flushes the cache for
- *                each page.
+ * isp_buf_process - Do final handling when a buffer has been processed.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @bufs: Pointer to ISP buffer handling structure.
+ *
+ * Updates the pointers accordingly depending of the internal pipeline.
  **/
-static int isp_vbq_sync(struct videobuf_buffer *vb, int when)
+static void isp_buf_process(struct device *dev, struct isp_bufs *bufs)
 {
-	flush_cache_all();
-
-	return 0;
-}
-
-static int isp_buf_process(struct isp_bufs *bufs)
-{
-	struct isp_buf *buf = NULL;
-	unsigned long flags;
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_buf *buf;
 	int last;
 
-	spin_lock_irqsave(&bufs->lock, flags);
-
 	if (ISP_BUFS_IS_EMPTY(bufs))
-		goto out;
+		return;
 
-	if (RAW_CAPTURE(&isp_obj) && ispccdc_sbl_wait_idle(1000)) {
-		printk(KERN_ERR "ccdc %d won't become idle!\n",
-		       RAW_CAPTURE(&isp_obj));
-		goto out;
+	if (CCDC_CAPTURE(isp)) {
+		if (ispccdc_sbl_wait_idle(&isp->isp_ccdc, 1000)) {
+			ispccdc_enable(&isp->isp_ccdc, 1);
+			dev_info(dev, "ccdc won't become idle!\n");
+			return;
+		}
 	}
 
 	/* We had at least one buffer in queue. */
@@ -1391,42 +1782,12 @@
 
 	if (!last) {
 		/* Set new buffer address. */
-		isp_set_buf(ISP_BUF_NEXT_DONE(bufs));
+		isp_set_buf(dev, ISP_BUF_NEXT_DONE(bufs));
+		if (CCDC_CAPTURE(isp))
+			ispccdc_enable(&isp->isp_ccdc, 1);
 	} else {
 		/* Tell ISP not to write any of our buffers. */
-		isp_disable_interrupts();
-		if (RAW_CAPTURE(&isp_obj))
-			ispccdc_enable(0);
-		else
-			ispresizer_enable(0);
-		/*
-		 * We must wait for the HS_VS since before that the
-		 * CCDC may trigger interrupts even if it's not
-		 * receiving a frame.
-		 */
-		bufs->wait_hs_vs = isp_obj.config->wait_hs_vs;
-	}
-	if ((RAW_CAPTURE(&isp_obj) && ispccdc_busy())
-	    || (!RAW_CAPTURE(&isp_obj) && ispresizer_busy())) {
-		/*
-		 * Next buffer available: for the transfer to succeed, the
-		 * CCDC (RAW capture) or resizer (YUV capture) must be idle
-		 * for the duration of transfer setup. Bad things happen
-		 * otherwise!
-		 *
-		 * Next buffer not available: if we fail to stop the
-		 * ISP the buffer is probably going to be bad.
-		 */
-		/* Mark this buffer faulty. */
-		buf->vb_state = VIDEOBUF_ERROR;
-		/* Mark next faulty, too, in case we have one. */
-		if (!last) {
-			ISP_BUF_NEXT_DONE(bufs)->vb_state =
-				VIDEOBUF_ERROR;
-			printk(KERN_ALERT "OUCH!!!\n");
-		} else {
-			printk(KERN_ALERT "Ouch!\n");
-		}
+		isp_disable_interrupts(dev);
 	}
 
 	/* Mark the current buffer as done. */
@@ -1437,38 +1798,48 @@
 			(bufs->buf+((bufs->done - 1 + NUM_BUFS)
 				    % NUM_BUFS))->isp_addr);
 
-out:
-	spin_unlock_irqrestore(&bufs->lock, flags);
-
-	if (buf != NULL) {
-		/*
-		 * We want to dequeue a buffer from the video buffer
-		 * queue. Let's do it!
-		 */
-		isp_vbq_sync(buf->vb, DMA_FROM_DEVICE);
-		buf->vb->state = buf->vb_state;
-		buf->complete(buf->vb, buf->priv);
-	}
-
-	return 0;
+	/*
+	 * We want to dequeue a buffer from the video buffer
+	 * queue. Let's do it!
+	 */
+	buf->vb->state = buf->vb_state;
+	buf->complete(buf->vb, buf->priv);
+	buf->vb = NULL;
 }
 
-int isp_buf_queue(struct videobuf_buffer *vb,
+/**
+ * isp_buf_queue - Queue a buffer into the internal ISP queue list.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @vb: Pointer to video buffer to queue.
+ * @complete: Pointer to function to call when buffer is completely processed.
+ * @priv: Pointer to private paramemter to send to complete function.
+ *
+ * Always returns 0.
+ **/
+int isp_buf_queue(struct device *dev, struct videobuf_buffer *vb,
 		  void (*complete)(struct videobuf_buffer *vb, void *priv),
 		  void *priv)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	unsigned long flags;
 	struct isp_buf *buf;
 	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
 	const struct scatterlist *sglist = dma->sglist;
-	struct isp_bufs *bufs = &isp_obj.bufs;
+	struct isp_bufs *bufs = &isp->bufs;
 	int sglen = dma->sglen;
 
+	if (isp->running != ISP_RUNNING) {
+		vb->state = VIDEOBUF_ERROR;
+		complete(vb, priv);
+
+		return 0;
+	}
+
 	BUG_ON(sglen < 0 || !sglist);
 
-	isp_vbq_sync(vb, DMA_TO_DEVICE);
+	isp_vbq_sync(vb);
 
-	spin_lock_irqsave(&bufs->lock, flags);
+	spin_lock_irqsave(&isp->lock, flags);
 
 	BUG_ON(ISP_BUFS_IS_FULL(bufs));
 
@@ -1479,17 +1850,26 @@
 	buf->vb = vb;
 	buf->priv = priv;
 	buf->vb_state = VIDEOBUF_DONE;
+	buf->vb->state = VIDEOBUF_ACTIVE;
 
 	if (ISP_BUFS_IS_EMPTY(bufs)) {
-		isp_enable_interrupts(RAW_CAPTURE(&isp_obj));
-		isp_set_buf(buf);
-		ispccdc_enable(1);
-		isp_start();
+		/*
+		 * We must wait for the HS_VS since before that the
+		 * CCDC may trigger interrupts even if it's not
+		 * receiving a frame.
+		 */
+		bufs->wait_hs_vs++;
+		isp_enable_interrupts(dev);
+		isp_set_buf(dev, buf);
+		isp_af_try_enable(&isp->isp_af);
+		isph3a_aewb_try_enable(&isp->isp_h3a);
+		isp_hist_try_enable(&isp->isp_hist);
+		ispccdc_enable(&isp->isp_ccdc, 1);
 	}
 
 	ISP_BUF_MARK_QUEUED(bufs);
 
-	spin_unlock_irqrestore(&bufs->lock, flags);
+	spin_unlock_irqrestore(&isp->lock, flags);
 
 	DPRINTK_ISPCTRL(KERN_ALERT "%s: queue %d vb %d, mmu %p\n", __func__,
 			(bufs->queue - 1 + NUM_BUFS) % NUM_BUFS, vb->i,
@@ -1499,24 +1879,98 @@
 }
 EXPORT_SYMBOL(isp_buf_queue);
 
-int isp_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
-		  unsigned int *size)
+/**
+ * isp_vbq_setup - Do ISP specific actions when the VB wueue is set.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @vbq: Pointer to video buffer queue.
+ * @cnt: Pointer to buffer count size of the queue list.
+ * @size: Pointer to the bytesize of every video buffer queue entry.
+ *
+ * Currently, this just allocates the temporary buffer used for the
+ * ISP Workaround when having CCDC->PRV->RSZ internal datapath.
+ **/
+int isp_vbq_setup(struct device *dev, struct videobuf_queue *vbq,
+		  unsigned int *cnt, unsigned int *size)
 {
-	int rval = 0;
-	size_t tmp_size = PAGE_ALIGN(isp_obj.module.preview_output_width
-				     * isp_obj.module.preview_output_height
-				     * ISP_BYTES_PER_PIXEL);
+	struct isp_device *isp = dev_get_drvdata(dev);
 
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW
-	    && isp_obj.tmp_buf_size < tmp_size)
-		rval = isp_tmp_buf_alloc(tmp_size);
+	if (CCDC_PREV_RESZ_CAPTURE(isp) &&
+		isp->revision <= ISP_REVISION_2_0)
+		return isp_tmp_buf_alloc(dev, &isp->pipeline);
 
-	return rval;
+	return 0;
 }
 EXPORT_SYMBOL(isp_vbq_setup);
 
 /**
+ * ispmmu_vmap - Wrapper for Virtual memory mapping of a scatter gather list
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @sglist: Pointer to source Scatter gather list to allocate.
+ * @sglen: Number of elements of the scatter-gatter list.
+ *
+ * Returns a resulting mapped device address by the ISP MMU, or -ENOMEM if
+ * we ran out of memory.
+ **/
+dma_addr_t ispmmu_vmap(struct device *dev, const struct scatterlist *sglist,
+		       int sglen)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+	int err;
+	u32 da;
+	struct sg_table *sgt;
+	unsigned int i;
+	struct scatterlist *sg, *src = (struct scatterlist *)sglist;
+
+	/*
+	 * convert isp sglist to iommu sgt
+	 * FIXME: should be fixed in the upper layer?
+	 */
+	sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
+	if (!sgt)
+		return -ENOMEM;
+	err = sg_alloc_table(sgt, sglen, GFP_KERNEL);
+	if (err)
+		goto err_sg_alloc;
+
+	for_each_sg(sgt->sgl, sg, sgt->nents, i)
+		sg_set_buf(sg, phys_to_virt(sg_dma_address(src + i)),
+			   sg_dma_len(src + i));
+
+	da = iommu_vmap(isp->iommu, 0, sgt, IOMMU_FLAG);
+	if (IS_ERR_VALUE(da))
+		goto err_vmap;
+
+	return (dma_addr_t)da;
+
+err_vmap:
+	sg_free_table(sgt);
+err_sg_alloc:
+	kfree(sgt);
+	return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(ispmmu_vmap);
+
+/**
+ * ispmmu_vunmap - Unmap a device address from the ISP MMU
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @da: Device address generated from a ispmmu_vmap call.
+ **/
+void ispmmu_vunmap(struct device *dev, dma_addr_t da)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct sg_table *sgt;
+
+	sgt = iommu_vunmap(isp->iommu, (u32)da);
+	if (!sgt)
+		return;
+	sg_free_table(sgt);
+	kfree(sgt);
+}
+EXPORT_SYMBOL_GPL(ispmmu_vunmap);
+
+/**
  * isp_vbq_prepare - Videobuffer queue prepare.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @vbq: Pointer to videobuf_queue structure.
  * @vb: Pointer to videobuf_buffer structure.
  * @field: Requested Field order for the videobuffer.
@@ -1524,18 +1978,19 @@
  * Returns 0 if successful, or -EIO if the ispmmu was unable to map a
  * scatter-gather linked list data space.
  **/
-int isp_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer *vb,
-		    enum v4l2_field field)
+int isp_vbq_prepare(struct device *dev, struct videobuf_queue *vbq,
+		    struct videobuf_buffer *vb, enum v4l2_field field)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	unsigned int isp_addr;
 	struct videobuf_dmabuf *vdma;
-	struct isp_bufs *bufs = &isp_obj.bufs;
+	struct isp_bufs *bufs = &isp->bufs;
 
 	int err = 0;
 
 	vdma = videobuf_to_dma(vb);
 
-	isp_addr = ispmmu_vmap(vdma->sglist, vdma->sglen);
+	isp_addr = ispmmu_vmap(dev, vdma->sglist, vdma->sglen);
 
 	if (IS_ERR_VALUE(isp_addr))
 		err = -EIO;
@@ -1548,14 +2003,17 @@
 
 /**
  * isp_vbq_release - Videobuffer queue release.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @vbq: Pointer to videobuf_queue structure.
  * @vb: Pointer to videobuf_buffer structure.
  **/
-void isp_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer *vb)
+void isp_vbq_release(struct device *dev, struct videobuf_queue *vbq,
+		     struct videobuf_buffer *vb)
 {
-	struct isp_bufs *bufs = &isp_obj.bufs;
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_bufs *bufs = &isp->bufs;
 
-	ispmmu_vunmap(bufs->isp_addr_capture[vb->i]);
+	ispmmu_vunmap(dev, bufs->isp_addr_capture[vb->i]);
 	bufs->isp_addr_capture[vb->i] = (dma_addr_t)NULL;
 	return;
 }
@@ -1607,30 +2065,32 @@
 EXPORT_SYMBOL(isp_querymenu);
 
 /**
- * isp_g_ctrl - Gets value of the desired V4L2 control.
+ * isp_g_ctrl - Get value of the desired V4L2 control.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @a: V4L2 control to read actual value from.
  *
  * Return 0 if successful, or -EINVAL if chosen control is not found.
  **/
-int isp_g_ctrl(struct v4l2_control *a)
+int isp_g_ctrl(struct device *dev, struct v4l2_control *a)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	u8 current_value;
 	int rval = 0;
 
-	if (!isp_obj.ref_count)
+	if (!isp->ref_count)
 		return -EINVAL;
 
 	switch (a->id) {
 	case V4L2_CID_BRIGHTNESS:
-		isppreview_query_brightness(&current_value);
+		isppreview_query_brightness(&isp->isp_prev, &current_value);
 		a->value = current_value / ISPPRV_BRIGHT_UNITS;
 		break;
 	case V4L2_CID_CONTRAST:
-		isppreview_query_contrast(&current_value);
+		isppreview_query_contrast(&isp->isp_prev, &current_value);
 		a->value = current_value / ISPPRV_CONTRAST_UNITS;
 		break;
 	case V4L2_CID_COLORFX:
-		isppreview_get_color(&current_value);
+		isppreview_get_color(&isp->isp_prev, &current_value);
 		a->value = current_value;
 		break;
 	default:
@@ -1643,7 +2103,8 @@
 EXPORT_SYMBOL(isp_g_ctrl);
 
 /**
- * isp_s_ctrl - Sets value of the desired V4L2 control.
+ * isp_s_ctrl - Set value of the desired V4L2 control.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @a: V4L2 control to read actual value from.
  *
  * Return 0 if successful, -EINVAL if chosen control is not found or value
@@ -1651,32 +2112,34 @@
  * from camera abstraction layer related controls or the transfered user space
  * pointer via the value field is not set properly.
  **/
-int isp_s_ctrl(struct v4l2_control *a)
+int isp_s_ctrl(struct device *dev, struct v4l2_control *a)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	int rval = 0;
 	u8 new_value = a->value;
 
-	if (!isp_obj.ref_count)
+	if (!isp->ref_count)
 		return -EINVAL;
 
 	switch (a->id) {
 	case V4L2_CID_BRIGHTNESS:
-		if (new_value > ISPPRV_BRIGHT_HIGH)
+		if (a->value > ISPPRV_BRIGHT_HIGH)
 			rval = -EINVAL;
 		else
-			isppreview_update_brightness(&new_value);
+			isppreview_update_brightness(&isp->isp_prev,
+						     &new_value);
 		break;
 	case V4L2_CID_CONTRAST:
-		if (new_value > ISPPRV_CONTRAST_HIGH)
+		if (a->value > ISPPRV_CONTRAST_HIGH)
 			rval = -EINVAL;
 		else
-			isppreview_update_contrast(&new_value);
+			isppreview_update_contrast(&isp->isp_prev, &new_value);
 		break;
 	case V4L2_CID_COLORFX:
-		if (new_value > V4L2_COLORFX_SEPIA)
+		if (a->value > V4L2_COLORFX_SEPIA)
 			rval = -EINVAL;
 		else
-			isppreview_set_color(&new_value);
+			isppreview_set_color(&isp->isp_prev, &new_value);
 		break;
 	default:
 		rval = -EINVAL;
@@ -1689,6 +2152,7 @@
 
 /**
  * isp_handle_private - Handle all private ioctls for isp module.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @cmd: ioctl cmd value
  * @arg: ioctl arg value
  *
@@ -1697,54 +2161,68 @@
  * Function simply routes the input ioctl cmd id to the appropriate handler in
  * the isp module.
  **/
-int isp_handle_private(int cmd, void *arg)
+int isp_handle_private(struct device *dev, struct mutex *vdev_mutex, int cmd,
+		       void *arg)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	int rval = 0;
 
-	if (!isp_obj.ref_count)
+	if (!isp->ref_count)
 		return -EINVAL;
 
 	switch (cmd) {
 	case VIDIOC_PRIVATE_ISP_CCDC_CFG:
-		rval = omap34xx_isp_ccdc_config(arg);
+		mutex_lock(vdev_mutex);
+		rval = ispccdc_config(&isp->isp_ccdc, arg);
+		mutex_unlock(vdev_mutex);
 		break;
 	case VIDIOC_PRIVATE_ISP_PRV_CFG:
-		rval = omap34xx_isp_preview_config(arg);
+		mutex_lock(vdev_mutex);
+		rval = isppreview_config(&isp->isp_prev, arg);
+		mutex_unlock(vdev_mutex);
 		break;
 	case VIDIOC_PRIVATE_ISP_AEWB_CFG: {
 		struct isph3a_aewb_config *params;
 		params = (struct isph3a_aewb_config *)arg;
-		rval = isph3a_aewb_configure(params);
+		mutex_lock(vdev_mutex);
+		rval = isph3a_aewb_config(&isp->isp_h3a, params);
+		mutex_unlock(vdev_mutex);
 	}
 		break;
 	case VIDIOC_PRIVATE_ISP_AEWB_REQ: {
 		struct isph3a_aewb_data *data;
 		data = (struct isph3a_aewb_data *)arg;
-		rval = isph3a_aewb_request_statistics(data);
+		rval = isph3a_aewb_request_statistics(&isp->isp_h3a, data);
 	}
 		break;
 	case VIDIOC_PRIVATE_ISP_HIST_CFG: {
 		struct isp_hist_config *params;
 		params = (struct isp_hist_config *)arg;
-		rval = isp_hist_configure(params);
+		mutex_lock(vdev_mutex);
+		rval = isp_hist_config(&isp->isp_hist, params);
+		mutex_unlock(vdev_mutex);
 	}
 		break;
 	case VIDIOC_PRIVATE_ISP_HIST_REQ: {
 		struct isp_hist_data *data;
 		data = (struct isp_hist_data *)arg;
-		rval = isp_hist_request_statistics(data);
+		mutex_lock(vdev_mutex);
+		rval = isp_hist_request_statistics(&isp->isp_hist, data);
+		mutex_unlock(vdev_mutex);
 	}
 		break;
 	case VIDIOC_PRIVATE_ISP_AF_CFG: {
 		struct af_configuration *params;
 		params = (struct af_configuration *)arg;
-		rval = isp_af_configure(params);
+		mutex_lock(vdev_mutex);
+		rval = isp_af_config(&isp->isp_af, params);
+		mutex_unlock(vdev_mutex);
 	}
 		break;
 	case VIDIOC_PRIVATE_ISP_AF_REQ: {
 		struct isp_af_data *data;
 		data = (struct isp_af_data *)arg;
-		rval = isp_af_request_statistics(data);
+		rval = isp_af_request_statistics(&isp->isp_af, data);
 	}
 		break;
 	default:
@@ -1756,7 +2234,7 @@
 EXPORT_SYMBOL(isp_handle_private);
 
 /**
- * isp_enum_fmt_cap - Gets more information of chosen format index and type
+ * isp_enum_fmt_cap - Get more information of chosen format index and type
  * @f: Pointer to structure containing index and type of format to read from.
  *
  * Returns 0 if successful, or -EINVAL if format index or format type is
@@ -1793,452 +2271,298 @@
 EXPORT_SYMBOL(isp_enum_fmt_cap);
 
 /**
- * isp_g_fmt_cap - Gets current output image format.
- * @f: Pointer to V4L2 format structure to be filled with current output format
+ * isp_g_fmt_cap - Get current output image format.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @pix: Pointer to V4L2 format structure to return current output format
  **/
-void isp_g_fmt_cap(struct v4l2_pix_format *pix)
+void isp_g_fmt_cap(struct device *dev, struct v4l2_pix_format *pix)
 {
-	*pix = isp_obj.module.pix;
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	*pix = isp->pipeline.pix;
 	return;
 }
 EXPORT_SYMBOL(isp_g_fmt_cap);
 
 /**
- * isp_s_fmt_cap - Sets I/O formats and crop and configures pipeline in ISP
- * @f: Pointer to V4L2 format structure to be filled with current output format
+ * isp_s_fmt_cap - Set I/O formats and crop, and configure pipeline in ISP
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @pix_input: Pointer to V4L2 format structure to represent current input.
+ * @pix_output: Pointer to V4L2 format structure to represent current output.
  *
- * Returns 0 if successful, or return value of either isp_try_size or
- * isp_try_fmt if there is an error.
+ * Returns 0 if successful, -EINVAL if ISP hasn't been opened, or return
+ * value of isp_s_pipeline if there is an error.
  **/
-int isp_s_fmt_cap(struct v4l2_pix_format *pix_input,
+int isp_s_fmt_cap(struct device *dev, struct v4l2_pix_format *pix_input,
 		  struct v4l2_pix_format *pix_output)
 {
-	int crop_scaling_w = 0, crop_scaling_h = 0;
-	int rval = 0;
+	struct isp_device *isp = dev_get_drvdata(dev);
 
-	if (!isp_obj.ref_count)
+
+	if (!isp->ref_count)
 		return -EINVAL;
 
-	rval = isp_calc_pipeline(pix_input, pix_output);
-	if (rval)
-		goto out;
-
-	rval = isp_try_size(pix_input, pix_output);
-	if (rval)
-		goto out;
-
-	rval = isp_try_fmt(pix_input, pix_output);
-	if (rval)
-		goto out;
-
-	if (ispcroprect.width != pix_output->width) {
-		crop_scaling_w = 1;
-		ispcroprect.left = 0;
-		ispcroprect.width = pix_output->width;
-	}
-
-	if (ispcroprect.height != pix_output->height) {
-		crop_scaling_h = 1;
-		ispcroprect.top = 0;
-		ispcroprect.height = pix_output->height;
-	}
-
-	isp_config_pipeline(pix_input, pix_output);
-
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER
-	    && (crop_scaling_h || crop_scaling_w))
-		isp_config_crop(pix_output);
-
-out:
-	return rval;
+	return isp_s_pipeline(dev, pix_input, pix_output);
 }
 EXPORT_SYMBOL(isp_s_fmt_cap);
 
 /**
- * isp_config_crop - Configures crop parameters in isp resizer.
- * @croppix: Pointer to V4L2 pixel format structure containing crop parameters
+ * isp_get_buf_offset - Gets offset of start of crop.
+ *
+ * Returns the offset (in bytes) of the start of the crop rectangle.
  **/
-void isp_config_crop(struct v4l2_pix_format *croppix)
+unsigned long isp_get_buf_offset(struct device *dev)
 {
-	u8 crop_scaling_w;
-	u8 crop_scaling_h;
-	unsigned long org_left, num_pix, new_top;
+	struct isp_device *isp = dev_get_drvdata(dev);
 
-	struct v4l2_pix_format *pix = croppix;
-
-	crop_scaling_w = (isp_obj.module.preview_output_width * 10) /
-		pix->width;
-	crop_scaling_h = (isp_obj.module.preview_output_height * 10) /
-		pix->height;
-
-	cur_rect.left = (ispcroprect.left * crop_scaling_w) / 10;
-	cur_rect.top = (ispcroprect.top * crop_scaling_h) / 10;
-	cur_rect.width = (ispcroprect.width * crop_scaling_w) / 10;
-	cur_rect.height = (ispcroprect.height * crop_scaling_h) / 10;
-
-	org_left = cur_rect.left;
-	while (((int)cur_rect.left & 0xFFFFFFF0) != (int)cur_rect.left)
-		(int)cur_rect.left--;
-
-	num_pix = org_left - cur_rect.left;
-	new_top = (int)(num_pix * 3) / 4;
-	cur_rect.top = cur_rect.top - new_top;
-	cur_rect.height = (2 * new_top) + cur_rect.height;
-
-	cur_rect.width = cur_rect.width + (2 * num_pix);
-	while (((int)cur_rect.width & 0xFFFFFFF0) != (int)cur_rect.width)
-		(int)cur_rect.width--;
-
-	isp_obj.tmp_buf_offset =
-		cur_rect.left * 2 +
-		isp_obj.module.preview_output_width * 2 * cur_rect.top;
-
-	ispresizer_trycrop(cur_rect.left, cur_rect.top, cur_rect.width,
-			   cur_rect.height,
-			   isp_obj.module.resizer_output_width,
-			   isp_obj.module.resizer_output_height);
-
-	return;
+	return isp->tmp_buf_offset;
 }
-EXPORT_SYMBOL(isp_config_crop);
+EXPORT_SYMBOL(isp_get_buf_offset);
 
 /**
- * isp_g_crop - Gets crop rectangle size and position.
- * @a: Pointer to V4L2 crop structure to be filled.
+ * isp_g_crop - Get crop rectangle size and position.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @crop: Pointer to V4L2 crop structure to be filled.
  *
  * Always returns 0.
  **/
-int isp_g_crop(struct v4l2_crop *a)
+int isp_g_crop(struct device *dev, struct v4l2_crop *crop)
 {
-	struct v4l2_crop *crop = a;
+	struct isp_device *isp = dev_get_drvdata(dev);
 
-	crop->c = ispcroprect;
+	if (isp->pipeline.modules & OMAP_ISP_RESIZER) {
+		crop->c = isp->pipeline.rsz_crop;
+	} else {
+		crop->c.left = 0;
+		crop->c.top = 0;
+		crop->c.width = isp->pipeline.ccdc_out_w_img;
+		crop->c.height = isp->pipeline.ccdc_out_h;
+	}
 
 	return 0;
 }
 EXPORT_SYMBOL(isp_g_crop);
 
 /**
- * isp_s_crop - Sets crop rectangle size and position and queues crop operation
+ * isp_s_crop - Set crop rectangle size and position.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @a: Pointer to V4L2 crop structure with desired parameters.
- * @pix: Pointer to V4L2 pixel format structure with desired parameters.
  *
- * Returns 0 if successful, or -EINVAL if crop parameters are out of bounds.
+ * Always returns 0.
+ *
+ * FIXME: Hardcoded to configure always the resizer, which could not be always
+ *        the case.
  **/
-int isp_s_crop(struct v4l2_crop *a, struct v4l2_pix_format *pix)
+int isp_s_crop(struct device *dev, struct v4l2_crop *a)
 {
-	struct v4l2_crop *crop = a;
-	int rval = 0;
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_pipeline *pipe = &isp->pipeline;
 
-	if (!isp_obj.ref_count)
-		return -EINVAL;
+	/*
+	 * Reset resizer output size.
+	 * FIXME: resizer should not touch the output size in the first place,
+	 * it should always correspond to the size set by S_FMT or S_FMT
+	 * should fail if not possible. If necessary, resizer should adjust
+	 * the source rectangle in ispresizer_try_pipeline instead.
+	 * When the resizer is fixed, its output size does not need to be
+	 * adjusted anymore here.
+	 */
+	pipe->rsz_out_w_img = pipe->pix.width;
+	pipe->rsz_out_w = pipe->pix.width;
+	pipe->rsz_out_h = pipe->pix.height;
 
-	if (crop->c.left < 0)
-		crop->c.left = 0;
-	if (crop->c.width < 0)
-		crop->c.width = 0;
-	if (crop->c.top < 0)
-		crop->c.top = 0;
-	if (crop->c.height < 0)
-		crop->c.height = 0;
+	ispresizer_config_crop(&isp->isp_res, a);
 
-	if (crop->c.left >= pix->width)
-		crop->c.left = pix->width - 1;
-	if (crop->c.top >= pix->height)
-		crop->c.top = pix->height - 1;
-
-	if (crop->c.left + crop->c.width > pix->width)
-		crop->c.width = pix->width - crop->c.left;
-	if (crop->c.top + crop->c.height > pix->height)
-		crop->c.height = pix->height - crop->c.top;
-
-	ispcroprect.left = crop->c.left;
-	ispcroprect.top = crop->c.top;
-	ispcroprect.width = crop->c.width;
-	ispcroprect.height = crop->c.height;
-
-	isp_config_crop(pix);
-
-	isp_obj.module.applyCrop = 1;
-
-	return rval;
+	return 0;
 }
 EXPORT_SYMBOL(isp_s_crop);
 
 /**
- * isp_try_fmt_cap - Tries desired input/output image formats
+ * isp_try_fmt_cap - Try desired input/output image formats
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @pix_input: Pointer to V4L2 pixel format structure for input image.
  * @pix_output: Pointer to V4L2 pixel format structure for output image.
  *
  * Returns 0 if successful, or return value of either isp_try_size or
  * isp_try_fmt if there is an error.
  **/
-int isp_try_fmt_cap(struct v4l2_pix_format *pix_input,
+int isp_try_fmt_cap(struct device *dev, struct v4l2_pix_format *pix_input,
 		    struct v4l2_pix_format *pix_output)
 {
-	int rval = 0;
+	struct isp_pipeline pipe;
+	int rval;
 
-	rval = isp_calc_pipeline(pix_input, pix_output);
+	pipe.pix = *pix_output;
+
+	rval = isp_try_pipeline(dev, pix_input, &pipe);
 	if (rval)
-		goto out;
+		return rval;
 
-	rval = isp_try_size(pix_input, pix_output);
-	if (rval)
-		goto out;
+	*pix_output = pipe.pix;
 
-	rval = isp_try_fmt(pix_input, pix_output);
-	if (rval)
-		goto out;
-
-out:
-	return rval;
+	return 0;
 }
 EXPORT_SYMBOL(isp_try_fmt_cap);
 
 /**
- * isp_try_size - Tries size configuration for I/O images of each ISP submodule
- * @pix_input: Pointer to V4L2 pixel format structure for input image.
- * @pix_output: Pointer to V4L2 pixel format structure for output image.
- *
- * Returns 0 if successful, or return value of ispccdc_try_size,
- * isppreview_try_size, or ispresizer_try_size (depending on the pipeline
- * configuration) if there is an error.
- **/
-static int isp_try_size(struct v4l2_pix_format *pix_input,
-			struct v4l2_pix_format *pix_output)
-{
-	int rval = 0;
-
-	if (pix_output->width <= ISPRSZ_MIN_OUTPUT
-	    || pix_output->height <= ISPRSZ_MIN_OUTPUT)
-		return -EINVAL;
-
-	if (pix_output->width >= ISPRSZ_MAX_OUTPUT
-	    || pix_output->height > ISPRSZ_MAX_OUTPUT)
-		return -EINVAL;
-
-	isp_obj.module.ccdc_input_width = pix_input->width;
-	isp_obj.module.ccdc_input_height = pix_input->height;
-	isp_obj.module.resizer_output_width = pix_output->width;
-	isp_obj.module.resizer_output_height = pix_output->height;
-
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_CCDC) {
-		rval = ispccdc_try_size(isp_obj.module.ccdc_input_width,
-					isp_obj.module.ccdc_input_height,
-					&isp_obj.module.ccdc_output_width,
-					&isp_obj.module.ccdc_output_height);
-		if (rval) {
-			printk(KERN_ERR "ISP_ERR: The dimensions %dx%d are not"
-			       " supported\n", pix_input->width,
-			       pix_input->height);
-			return rval;
-		}
-		pix_output->width = isp_obj.module.ccdc_output_width;
-		pix_output->height = isp_obj.module.ccdc_output_height;
-	}
-
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_PREVIEW) {
-		isp_obj.module.preview_input_width =
-			isp_obj.module.ccdc_output_width;
-		isp_obj.module.preview_input_height =
-			isp_obj.module.ccdc_output_height;
-		rval = isppreview_try_size(
-			isp_obj.module.preview_input_width,
-			isp_obj.module.preview_input_height,
-			&isp_obj.module.preview_output_width,
-			&isp_obj.module.preview_output_height);
-		if (rval) {
-			printk(KERN_ERR "ISP_ERR: The dimensions %dx%d are not"
-			       " supported\n", pix_input->width,
-			       pix_input->height);
-			return rval;
-		}
-		pix_output->width = isp_obj.module.preview_output_width;
-		pix_output->height = isp_obj.module.preview_output_height;
-	}
-
-	if (isp_obj.module.isp_pipeline & OMAP_ISP_RESIZER) {
-		isp_obj.module.resizer_input_width =
-			isp_obj.module.preview_output_width;
-		isp_obj.module.resizer_input_height =
-			isp_obj.module.preview_output_height;
-		rval = ispresizer_try_size(
-			&isp_obj.module.resizer_input_width,
-			&isp_obj.module.resizer_input_height,
-			&isp_obj.module.resizer_output_width,
-			&isp_obj.module.resizer_output_height);
-		if (rval) {
-			printk(KERN_ERR "ISP_ERR: The dimensions %dx%d are not"
-			       " supported\n", pix_input->width,
-			       pix_input->height);
-			return rval;
-		}
-		pix_output->width = isp_obj.module.resizer_output_width;
-		pix_output->height = isp_obj.module.resizer_output_height;
-	}
-
-	return rval;
-}
-
-/**
- * isp_try_fmt - Validates input/output format parameters.
- * @pix_input: Pointer to V4L2 pixel format structure for input image.
- * @pix_output: Pointer to V4L2 pixel format structure for output image.
- *
- * Always returns 0.
- **/
-int isp_try_fmt(struct v4l2_pix_format *pix_input,
-		struct v4l2_pix_format *pix_output)
-{
-	int ifmt;
-
-	for (ifmt = 0; ifmt < NUM_ISP_CAPTURE_FORMATS; ifmt++) {
-		if (pix_output->pixelformat == isp_formats[ifmt].pixelformat)
-			break;
-	}
-	if (ifmt == NUM_ISP_CAPTURE_FORMATS)
-		ifmt = 1;
-	pix_output->pixelformat = isp_formats[ifmt].pixelformat;
-	pix_output->field = V4L2_FIELD_NONE;
-	pix_output->bytesperline = pix_output->width * ISP_BYTES_PER_PIXEL;
-	pix_output->sizeimage =
-		PAGE_ALIGN(pix_output->bytesperline * pix_output->height);
-	pix_output->priv = 0;
-	switch (pix_output->pixelformat) {
-	case V4L2_PIX_FMT_YUYV:
-	case V4L2_PIX_FMT_UYVY:
-		pix_output->colorspace = V4L2_COLORSPACE_JPEG;
-		break;
-	default:
-		pix_output->colorspace = V4L2_COLORSPACE_SRGB;
-	}
-
-	isp_obj.module.pix.pixelformat = pix_output->pixelformat;
-	isp_obj.module.pix.width = pix_output->width;
-	isp_obj.module.pix.height = pix_output->height;
-	isp_obj.module.pix.field = pix_output->field;
-	isp_obj.module.pix.bytesperline = pix_output->bytesperline;
-	isp_obj.module.pix.sizeimage = pix_output->sizeimage;
-	isp_obj.module.pix.priv = pix_output->priv;
-	isp_obj.module.pix.colorspace = pix_output->colorspace;
-
-	return 0;
-}
-EXPORT_SYMBOL(isp_try_fmt);
-
-/**
  * isp_save_ctx - Saves ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  *
  * Routine for saving the context of each module in the ISP.
  * CCDC, HIST, H3A, PREV, RESZ and MMU.
  **/
-static void isp_save_ctx(void)
+static void isp_save_ctx(struct device *dev)
 {
-	isp_save_context(isp_reg_list);
-	ispccdc_save_context();
-	ispmmu_save_context();
-	isphist_save_context();
-	isph3a_save_context();
-	isppreview_save_context();
-	ispresizer_save_context();
-	ispcsi2_save_context();
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	isp_save_context(dev, isp_reg_list);
+	ispccdc_save_context(dev);
+	if (isp->iommu)
+		iommu_save_ctx(isp->iommu);
+	isp_hist_save_context(dev);
+	isph3a_save_context(dev);
+	isppreview_save_context(dev);
+	ispresizer_save_context(dev);
+	ispcsi2_save_context(dev);
 }
 
 /**
  * isp_restore_ctx - Restores ISP, CCDC, HIST, H3A, PREV, RESZ & MMU context.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  *
  * Routine for restoring the context of each module in the ISP.
  * CCDC, HIST, H3A, PREV, RESZ and MMU.
  **/
-static void isp_restore_ctx(void)
+static void isp_restore_ctx(struct device *dev)
 {
-	isp_restore_context(isp_reg_list);
-	ispccdc_restore_context();
-	ispmmu_restore_context();
-	isphist_restore_context();
-	isph3a_restore_context();
-	isppreview_restore_context();
-	ispresizer_restore_context();
-	ispcsi2_restore_context();
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	isp_restore_context(dev, isp_reg_list);
+	ispccdc_restore_context(dev);
+	if (isp->iommu)
+		iommu_restore_ctx(isp->iommu);
+	isp_hist_restore_context(dev);
+	isph3a_restore_context(dev);
+	isppreview_restore_context(dev);
+	ispresizer_restore_context(dev);
+	ispcsi2_restore_context(dev);
 }
 
-static int isp_enable_clocks(void)
+/**
+ * isp_enable_clocks - Enable ISP clocks
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ *
+ * Return 0 if successful, or clk_enable return value if any of tthem fails.
+ **/
+static int isp_enable_clocks(struct device *dev)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
 	int r;
 
-	r = clk_enable(isp_obj.cam_ick);
+	r = clk_enable(isp->cam_ick);
 	if (r) {
-		DPRINTK_ISPCTRL("ISP_ERR: clk_en for ick failed\n");
+		dev_err(dev, "clk_enable cam_ick failed\n");
 		goto out_clk_enable_ick;
 	}
-	r = clk_enable(isp_obj.cam_mclk);
+	r = clk_enable(isp->csi2_fck);
 	if (r) {
-		DPRINTK_ISPCTRL("ISP_ERR: clk_en for mclk failed\n");
-		goto out_clk_enable_mclk;
-	}
-	r = clk_enable(isp_obj.csi2_fck);
-	if (r) {
-		DPRINTK_ISPCTRL("ISP_ERR: clk_en for csi2_fclk"
-				" failed\n");
+		dev_err(dev, "clk_enable csi2_fck failed\n");
 		goto out_clk_enable_csi2_fclk;
 	}
 	return 0;
 
 out_clk_enable_csi2_fclk:
-	clk_disable(isp_obj.cam_mclk);
-out_clk_enable_mclk:
-	clk_disable(isp_obj.cam_ick);
+	clk_disable(isp->cam_ick);
 out_clk_enable_ick:
 	return r;
 }
 
-static void isp_disable_clocks(void)
+int isp_enable_mclk(struct device *dev)
 {
-	clk_disable(isp_obj.cam_ick);
-	clk_disable(isp_obj.cam_mclk);
-	clk_disable(isp_obj.csi2_fck);
+	struct isp_device *isp = dev_get_drvdata(dev);
+	int r;
+	unsigned long curr_mclk, curr_dpll4_m5, ratio;
+
+	/* Check ratio between DPLL4_M5 and CAM_MCLK */
+	curr_mclk = clk_get_rate(isp->cam_mclk);
+	curr_dpll4_m5 = clk_get_rate(isp->dpll4_m5_ck);
+
+	/* Protection for potential Zero division, or zero-ratio result */
+	if (!curr_mclk || !curr_dpll4_m5)
+		BUG();
+
+	ratio = curr_mclk / curr_dpll4_m5;
+
+	r = clk_set_rate(isp->dpll4_m5_ck, isp->mclk / ratio);
+		if (r) {
+			dev_err(dev, "clk_set_rate for dpll4_m5_ck failed\n");
+			return r;
+	}
+	r = clk_enable(isp->cam_mclk);
+	if (r) {
+		dev_err(dev, "clk_enable cam_mclk failed\n");
+		return r;
+	}
+	return 0;
+}
+
+void isp_disable_mclk(struct isp_device *isp)
+{
+	clk_disable(isp->cam_mclk);
 }
 
 /**
- * isp_get - Adquires the ISP resource.
+ * isp_disable_clocks - Disable ISP clocks
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+static void isp_disable_clocks(struct device *dev)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	clk_disable(isp->cam_ick);
+	clk_disable(isp->csi2_fck);
+}
+
+/**
+ * isp_get - Acquire the ISP resource.
  *
  * Initializes the clocks for the first acquire.
+ *
+ * Returns pointer for isp device structure.
  **/
-int isp_get(void)
+struct device *isp_get(void)
 {
+	struct platform_device *pdev = omap3isp_pdev;
+	struct isp_device *isp;
 	static int has_context;
 	int ret_err = 0;
 
-	if (omap3isp == NULL)
-		return -EBUSY;
+	if (!pdev)
+		return NULL;
+	isp = platform_get_drvdata(pdev);
 
-	DPRINTK_ISPCTRL("isp_get: old %d\n", isp_obj.ref_count);
-	mutex_lock(&(isp_obj.isp_mutex));
-	if (isp_obj.ref_count == 0) {
-		ret_err = isp_enable_clocks();
+	DPRINTK_ISPCTRL("isp_get: old %d\n", isp->ref_count);
+	mutex_lock(&(isp->isp_mutex));
+	if (isp->ref_count == 0) {
+		ret_err = isp_enable_clocks(&pdev->dev);
 		if (ret_err)
 			goto out_err;
 		/* We don't want to restore context before saving it! */
 		if (has_context)
-			isp_restore_ctx();
+			isp_restore_ctx(&pdev->dev);
 		else
 			has_context = 1;
-		/* HACK: Allow multiple opens meanwhile a better solution is
-		 *       found for the case of different devices sharing ISP
-		 *       settings. */
-/*	} else {
-		mutex_unlock(&isp_obj.isp_mutex);
-		return -EBUSY; */
 	}
-	isp_obj.ref_count++;
-	mutex_unlock(&(isp_obj.isp_mutex));
+	isp->ref_count++;
+	mutex_unlock(&(isp->isp_mutex));
 
-	DPRINTK_ISPCTRL("isp_get: new %d\n", isp_obj.ref_count);
-	return isp_obj.ref_count;
+	DPRINTK_ISPCTRL("isp_get: new %d\n", isp->ref_count);
+	/* FIXME: ISP should register as v4l2 device to store its priv data */
+	return &pdev->dev;
 
 out_err:
-	mutex_unlock(&(isp_obj.isp_mutex));
-	return ret_err;
+	mutex_unlock(&(isp->isp_mutex));
+	return NULL;
 }
 EXPORT_SYMBOL(isp_get);
 
@@ -2246,83 +2570,97 @@
  * isp_put - Releases the ISP resource.
  *
  * Releases the clocks also for the last release.
+ *
+ * Return resulting reference count, or -EBUSY if ISP structure is not
+ * allocated.
  **/
 int isp_put(void)
 {
-	if (omap3isp == NULL)
+	struct platform_device *pdev = omap3isp_pdev;
+	struct isp_device *isp = platform_get_drvdata(pdev);
+
+	if (!isp)
 		return -EBUSY;
 
-	DPRINTK_ISPCTRL("isp_put: old %d\n", isp_obj.ref_count);
-	mutex_lock(&(isp_obj.isp_mutex));
-	if (isp_obj.ref_count) {
-		if (--isp_obj.ref_count == 0) {
-			isp_save_ctx();
-			isp_tmp_buf_free();
-			isp_release_resources();
-			isp_obj.module.isp_pipeline = 0;
-			isp_disable_clocks();
-			memset(&ispcroprect, 0, sizeof(ispcroprect));
-			memset(&cur_rect, 0, sizeof(cur_rect));
+	DPRINTK_ISPCTRL("isp_put: old %d\n", isp->ref_count);
+	mutex_lock(&(isp->isp_mutex));
+	if (isp->ref_count) {
+		if (--isp->ref_count == 0) {
+			isp_save_ctx(&pdev->dev);
+			if (isp->revision <= ISP_REVISION_2_0)
+				isp_tmp_buf_free(&pdev->dev);
+			isp_release_resources(&pdev->dev);
+			isp_disable_clocks(&pdev->dev);
 		}
 	}
-	mutex_unlock(&(isp_obj.isp_mutex));
-	DPRINTK_ISPCTRL("isp_put: new %d\n", isp_obj.ref_count);
-	return isp_obj.ref_count;
+	mutex_unlock(&(isp->isp_mutex));
+	DPRINTK_ISPCTRL("isp_put: new %d\n", isp->ref_count);
+	return isp->ref_count;
 }
 EXPORT_SYMBOL(isp_put);
 
 /**
  * isp_save_context - Saves the values of the ISP module registers.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @reg_list: Structure containing pairs of register address and value to
  *            modify on OMAP.
  **/
-void isp_save_context(struct isp_reg *reg_list)
+void isp_save_context(struct device *dev, struct isp_reg *reg_list)
 {
 	struct isp_reg *next = reg_list;
 
 	for (; next->reg != ISP_TOK_TERM; next++)
-		next->val = isp_reg_readl(next->mmio_range, next->reg);
+		next->val = isp_reg_readl(dev, next->mmio_range, next->reg);
 }
-EXPORT_SYMBOL(isp_save_context);
 
 /**
  * isp_restore_context - Restores the values of the ISP module registers.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  * @reg_list: Structure containing pairs of register address and value to
  *            modify on OMAP.
  **/
-void isp_restore_context(struct isp_reg *reg_list)
+void isp_restore_context(struct device *dev, struct isp_reg *reg_list)
 {
 	struct isp_reg *next = reg_list;
 
 	for (; next->reg != ISP_TOK_TERM; next++)
-		isp_reg_writel(next->val, next->mmio_range, next->reg);
+		isp_reg_writel(dev, next->val, next->mmio_range, next->reg);
 }
-EXPORT_SYMBOL(isp_restore_context);
 
+/**
+ * isp_remove - Remove ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Always returns 0.
+ **/
 static int isp_remove(struct platform_device *pdev)
 {
 	struct isp_device *isp = platform_get_drvdata(pdev);
 	int i;
 
-	isp_csi2_cleanup();
-	isp_af_exit();
-	isp_resizer_cleanup();
-	isp_preview_cleanup();
-	ispmmu_cleanup();
-	isph3a_aewb_cleanup();
-	isp_hist_cleanup();
-	isp_ccdc_cleanup();
-
 	if (!isp)
 		return 0;
 
-	clk_put(isp_obj.cam_ick);
-	clk_put(isp_obj.cam_mclk);
-	clk_put(isp_obj.csi2_fck);
+	isp_csi2_cleanup(&pdev->dev);
+	isp_af_exit(&pdev->dev);
+	isp_resizer_cleanup(&pdev->dev);
+	isp_get();
+	if (isp->iommu)
+		iommu_put(isp->iommu);
+	isp_put();
+	isph3a_aewb_cleanup(&pdev->dev);
+	isp_hist_cleanup(&pdev->dev);
+	isp_ccdc_cleanup(&pdev->dev);
 
-	free_irq(isp->irq, &isp_obj);
+	clk_put(isp->cam_ick);
+	clk_put(isp->cam_mclk);
+	clk_put(isp->dpll4_m5_ck);
+	clk_put(isp->csi2_fck);
+	clk_put(isp->l3_ick);
 
-	for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY; i++) {
+	free_irq(isp->irq_num, isp);
+
+	for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY2; i++) {
 		if (isp->mmio_base[i]) {
 			iounmap((void *)isp->mmio_base[i]);
 			isp->mmio_base[i] = 0;
@@ -2335,8 +2673,7 @@
 		}
 	}
 
-	omap3isp = NULL;
-
+	omap3isp_pdev = NULL;
 	kfree(isp);
 
 	return 0;
@@ -2344,50 +2681,68 @@
 
 #ifdef CONFIG_PM
 
+/**
+ * isp_suspend - Suspend routine for the ISP
+ * @pdev: Pointer to Platform device
+ * @state: New power state
+ *
+ * Always returns 0.
+ **/
 static int isp_suspend(struct platform_device *pdev, pm_message_t state)
 {
+	struct isp_device *isp = platform_get_drvdata(pdev);
 	int reset;
 
-	mutex_lock(&(isp_obj.isp_mutex));
 	DPRINTK_ISPCTRL("isp_suspend: starting\n");
-	if (isp_obj.ref_count == 0)
+
+	WARN_ON(mutex_is_locked(&isp->isp_mutex));
+
+	if (isp->ref_count == 0)
 		goto out;
 
-	isp_disable_interrupts();
-	reset = isp_suspend_modules();
-	isp_save_ctx();
+	isp_disable_interrupts(&pdev->dev);
+	reset = isp_suspend_modules(&pdev->dev);
+	isp_save_ctx(&pdev->dev);
 	if (reset)
-		isp_reset();
+		isp_reset(&pdev->dev);
 
-	isp_disable_clocks();
+	isp_disable_clocks(&pdev->dev);
+	isp_disable_mclk(isp);
 
 out:
 	DPRINTK_ISPCTRL("isp_suspend: done\n");
-	mutex_unlock(&(isp_obj.isp_mutex));
+
 	return 0;
 }
 
+/**
+ * isp_resume - Resume routine for the ISP
+ * @pdev: Pointer to platform device
+ *
+ * Returns 0 if successful, or isp_enable_clocks return value otherwise.
+ **/
 static int isp_resume(struct platform_device *pdev)
 {
+	struct isp_device *isp = platform_get_drvdata(pdev);
 	int ret_err = 0;
 
 	DPRINTK_ISPCTRL("isp_resume: starting\n");
 
-	if (omap3isp == NULL)
+	if (isp->ref_count == 0)
 		goto out;
 
-	if (isp_obj.ref_count >= 0) {
-		ret_err = isp_enable_clocks();
-		if (ret_err)
-			goto out;
-		isp_restore_ctx();
-		isp_resume_modules();
-		isp_enable_interrupts(RAW_CAPTURE(&isp_obj));
-		isp_start();
-	}
+	ret_err = isp_enable_clocks(&pdev->dev);
+	if (ret_err)
+		goto out;
+	ret_err = isp_enable_mclk(&pdev->dev);
+	if (ret_err)
+		goto out;
+	isp_restore_ctx(&pdev->dev);
+	isp_resume_modules(&pdev->dev);
 
 out:
 	DPRINTK_ISPCTRL("isp_resume: done \n");
+
 	return ret_err;
 }
 
@@ -2398,7 +2753,19 @@
 
 #endif /* CONFIG_PM */
 
+static u64 raw_dmamask = DMA_32BIT_MASK;
 
+/**
+ * isp_probe - Probe ISP platform device
+ * @pdev: Pointer to ISP platform device
+ *
+ * Returns 0 if successful,
+ *   -ENOMEM if no memory available,
+ *   -ENODEV if no platform device resources found
+ *     or no space for remapping registers,
+ *   -EINVAL if couldn't install ISR,
+ *   or clk_get return error value.
+ **/
 static int isp_probe(struct platform_device *pdev)
 {
 	struct isp_device *isp;
@@ -2415,21 +2782,22 @@
 
 	isp->dev = &pdev->dev;
 
-	for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY; i++) {
+	for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY2; i++) {
 		struct resource *mem;
 		/* request the mem region for the camera registers */
 		mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
 		if (!mem) {
 			dev_err(isp->dev, "no mem resource?\n");
-			return -ENODEV;
+			ret_err = -ENODEV;
+			goto out_free_mmio;
 		}
 
 		if (!request_mem_region(mem->start, mem->end - mem->start + 1,
 					pdev->name)) {
 			dev_err(isp->dev,
 				"cannot reserve camera register I/O region\n");
-			return -ENODEV;
-
+			ret_err = -ENODEV;
+			goto out_free_mmio;
 		}
 		isp->mmio_base_phys[i] = mem->start;
 		isp->mmio_size[i] = mem->end - mem->start + 1;
@@ -2441,83 +2809,126 @@
 		if (!isp->mmio_base[i]) {
 			dev_err(isp->dev,
 				"cannot map camera register I/O region\n");
-			return -ENODEV;
+			ret_err = -ENODEV;
+			goto out_free_mmio;
 		}
 	}
 
-	isp->irq = platform_get_irq(pdev, 0);
-	if (isp->irq <= 0) {
+	isp->irq_num = platform_get_irq(pdev, 0);
+	if (isp->irq_num <= 0) {
 		dev_err(isp->dev, "no irq for camera?\n");
-		return -ENODEV;
+		ret_err = -ENODEV;
+		goto out_free_mmio;
 	}
 
-	isp_obj.cam_ick = clk_get(&camera_dev, "cam_ick");
-	if (IS_ERR(isp_obj.cam_ick)) {
-		DPRINTK_ISPCTRL("ISP_ERR: clk_get for "
-				"cam_ick failed\n");
-		return PTR_ERR(isp_obj.cam_ick);
+	isp->mclk = CM_CAM_MCLK_HZ / 2;
+
+	isp->cam_ick = clk_get(&camera_dev, "cam_ick");
+	if (IS_ERR(isp->cam_ick)) {
+		dev_err(isp->dev, "clk_get cam_ick failed\n");
+		ret_err = PTR_ERR(isp->cam_ick);
+		goto out_free_mmio;
 	}
-	isp_obj.cam_mclk = clk_get(&camera_dev, "cam_mclk");
-	if (IS_ERR(isp_obj.cam_mclk)) {
-		DPRINTK_ISPCTRL("ISP_ERR: clk_get for "
-				"cam_mclk failed\n");
-		ret_err = PTR_ERR(isp_obj.cam_mclk);
+	isp->cam_mclk = clk_get(&camera_dev, "cam_mclk");
+	if (IS_ERR(isp->cam_mclk)) {
+		dev_err(isp->dev, "clk_get cam_mclk failed\n");
+		ret_err = PTR_ERR(isp->cam_mclk);
 		goto out_clk_get_mclk;
 	}
-	isp_obj.csi2_fck = clk_get(&camera_dev, "csi2_96m_fck");
-	if (IS_ERR(isp_obj.csi2_fck)) {
-		DPRINTK_ISPCTRL("ISP_ERR: clk_get for csi2_fclk"
-				" failed\n");
-		ret_err = PTR_ERR(isp_obj.csi2_fck);
+	isp->dpll4_m5_ck = clk_get(&camera_dev, "dpll4_m5_ck");
+	if (IS_ERR(isp->dpll4_m5_ck)) {
+		dev_err(isp->dev, "clk_get dpll4_m5_ck failed\n");
+		ret_err = PTR_ERR(isp->dpll4_m5_ck);
+		goto out_clk_get_dpll4_m5_ck;
+	}
+	isp->csi2_fck = clk_get(&camera_dev, "csi2_96m_fck");
+	if (IS_ERR(isp->csi2_fck)) {
+		dev_err(isp->dev, "clk_get csi2_96m_fck failed\n");
+		ret_err = PTR_ERR(isp->csi2_fck);
 		goto out_clk_get_csi2_fclk;
 	}
+	isp->l3_ick = clk_get(&camera_dev, "l3_ick");
+	if (IS_ERR(isp->l3_ick)) {
+		dev_err(isp->dev, "clk_get l3_ick failed\n");
+		ret_err = PTR_ERR(isp->l3_ick);
+		goto out_clk_get_l3_ick;
+	}
 
-	if (request_irq(isp->irq, omap34xx_isp_isr, IRQF_SHARED,
-			"Omap 3 Camera ISP", &isp_obj)) {
-		DPRINTK_ISPCTRL("Could not install ISR\n");
+	if (request_irq(isp->irq_num, isp_isr, IRQF_SHARED,
+			"Omap 3 Camera ISP", pdev)) {
+		dev_err(isp->dev, "could not install isr\n");
 		ret_err = -EINVAL;
 		goto out_request_irq;
 	}
 
-	isp_obj.ref_count = 0;
+	isp->ref_count = 0;
+	omap3isp_pdev = pdev;
 
-	mutex_init(&(isp_obj.isp_mutex));
-	spin_lock_init(&isp_obj.lock);
-	spin_lock_init(&isp_obj.bufs.lock);
+	mutex_init(&(isp->isp_mutex));
+	spin_lock_init(&isp->lock);
+	spin_lock_init(&isp->h3a_lock);
 
-	omap3isp = isp;
-
-	ret_err = ispmmu_init();
-	if (ret_err)
-		goto out_ispmmu_init;
-
-	isp_ccdc_init();
-	isp_hist_init();
-	isph3a_aewb_init();
-	isp_preview_init();
-	isp_resizer_init();
-	isp_af_init();
-	isp_csi2_init();
+	isp->dev->dma_mask = &raw_dmamask;
+	isp->dev->coherent_dma_mask = DMA_32BIT_MASK;
 
 	isp_get();
-	isp_power_settings(1);
-	isp_put();
+	/* Get ISP revision */
+	isp->revision = isp_reg_readl(isp->dev,
+				      OMAP3_ISP_IOMEM_MAIN, ISP_REVISION);
+	dev_info(isp->dev, "Revision %d.%d found\n",
+		 (isp->revision & 0xF0) >> 4, isp->revision & 0xF);
 
-	isph3a_notify(1);
-	isp_af_notify(1);
+	isp->iommu = iommu_get("isp");
+	if (IS_ERR(isp->iommu)) {
+		ret_err = PTR_ERR(isp->iommu);
+		isp->iommu = NULL;
+	}
+	isp_put();
+	if (!isp->iommu)
+		goto out_iommu_get;
+
+	isp_ccdc_init(&pdev->dev);
+	isp_hist_init(&pdev->dev);
+	isph3a_aewb_init(&pdev->dev);
+	isp_preview_init(&pdev->dev);
+	isp_resizer_init(&pdev->dev);
+	isp_af_init(&pdev->dev);
+	isp_csi2_init(&pdev->dev);
+
+	isp_get();
+	isp_power_settings(&pdev->dev, 1);
+	isp_put();
 
 	return 0;
 
-out_ispmmu_init:
-	omap3isp = NULL;
-	free_irq(isp->irq, &isp_obj);
+out_iommu_get:
+	free_irq(isp->irq_num, isp);
+	omap3isp_pdev = NULL;
 out_request_irq:
-	clk_put(isp_obj.csi2_fck);
+	clk_put(isp->l3_ick);
+out_clk_get_l3_ick:
+	clk_put(isp->csi2_fck);
 out_clk_get_csi2_fclk:
-	clk_put(isp_obj.cam_mclk);
+	clk_put(isp->dpll4_m5_ck);
+out_clk_get_dpll4_m5_ck:
+	clk_put(isp->cam_mclk);
 out_clk_get_mclk:
-	clk_put(isp_obj.cam_ick);
+	clk_put(isp->cam_ick);
+out_free_mmio:
+	for (i = 0; i <= OMAP3_ISP_IOMEM_CSI2PHY; i++) {
+		if (isp->mmio_base[i]) {
+			iounmap((void *)isp->mmio_base[i]);
+			isp->mmio_base[i] = 0;
+		}
 
+		if (isp->mmio_base_phys[i]) {
+			release_mem_region(isp->mmio_base_phys[i],
+					   isp->mmio_size[i]);
+			isp->mmio_base_phys[i] = 0;
+		}
+	}
+
+	kfree(isp);
 	return ret_err;
 }
 
@@ -2549,28 +2960,31 @@
 
 /**
  * isp_print_status - Prints the values of the ISP Control Module registers
- *
- * Also prints other debug information stored in the ISP module structure.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  **/
-void isp_print_status(void)
+void isp_print_status(struct device *dev)
 {
 	if (!is_ispctrl_debug_enabled())
 		return;
 
 	DPRINTK_ISPCTRL("###ISP_CTRL=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
 	DPRINTK_ISPCTRL("###ISP_TCTRL_CTRL=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_TCTRL_CTRL));
 	DPRINTK_ISPCTRL("###ISP_SYSCONFIG=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_SYSCONFIG));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_SYSCONFIG));
 	DPRINTK_ISPCTRL("###ISP_SYSSTATUS=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_SYSSTATUS));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_SYSSTATUS));
 	DPRINTK_ISPCTRL("###ISP_IRQ0ENABLE=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_IRQ0ENABLE));
 	DPRINTK_ISPCTRL("###ISP_IRQ0STATUS=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_IRQ0STATUS));
 }
-EXPORT_SYMBOL(isp_print_status);
 
 module_init(isp_init);
 module_exit(isp_cleanup);
diff --git a/drivers/media/video/isp/isp.h b/drivers/media/video/isp/isp.h
index 43a32bf..b54cd06 100644
--- a/drivers/media/video/isp/isp.h
+++ b/drivers/media/video/isp/isp.h
@@ -9,7 +9,7 @@
  *
  * Contributors:
  * 	Sameer Venkatraman <sameerv@ti.com>
- * 	Mohit Jalori <mjalori@ti.com>
+ * 	Mohit Jalori
  * 	Sergio Aguirre <saaguirre@ti.com>
  * 	Sakari Ailus <sakari.ailus@nokia.com>
  * 	Tuukka Toivonen <tuukka.o.toivonen@nokia.com>
@@ -28,6 +28,26 @@
 #include <mach/cpu.h>
 #include <media/videobuf-dma-sg.h>
 #include <linux/videodev2.h>
+
+#include <asm/io.h>
+
+#include <mach/iommu.h>
+#include <mach/iovmm.h>
+
+struct isp_pipeline;
+
+#include "ispstat.h"
+#include "isp_af.h"
+#include "isphist.h"
+#include "ispccdc.h"
+#include "ispreg.h"
+#include "isph3a.h"
+#include "ispresizer.h"
+#include "isppreview.h"
+#include "ispcsi2.h"
+
+#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
+
 #define OMAP_ISP_CCDC		(1 << 0)
 #define OMAP_ISP_PREVIEW	(1 << 1)
 #define OMAP_ISP_RESIZER	(1 << 2)
@@ -41,19 +61,19 @@
 						 */
 #define NUM_BUFS		VIDEO_MAX_FRAME
 
-#ifndef CONFIG_ARCH_OMAP3410
-#define USE_ISP_PREVIEW
-#define USE_ISP_RESZ
-#define is_isppreview_enabled()		1
-#define is_ispresizer_enabled()		1
-#else
-#define is_isppreview_enabled()		0
-#define is_ispresizer_enabled()		0
-#endif
+#define ISP_REVISION_2_0            0x20
+#define ISP_REVISION_2_1            0x21
+#define ISP_REVISION_RAPXXX         0xF0
 
 #define ISP_BYTES_PER_PIXEL		2
 #define NUM_ISP_CAPTURE_FORMATS 	(sizeof(isp_formats) /		\
 					 sizeof(isp_formats[0]))
+
+#define to_isp_device(ptr_module)				\
+	container_of(ptr_module, struct isp_device, ptr_module)
+#define to_device(ptr_module)						\
+	(to_isp_device(ptr_module)->dev)
+
 typedef int (*isp_vbq_callback_ptr) (struct videobuf_buffer *vb);
 typedef void (*isp_callback_t) (unsigned long status,
 				isp_vbq_callback_ptr arg1, void *arg2);
@@ -69,29 +89,8 @@
 	OMAP3_ISP_IOMEM_RESZ,
 	OMAP3_ISP_IOMEM_SBL,
 	OMAP3_ISP_IOMEM_CSI2A,
-	OMAP3_ISP_IOMEM_CSI2PHY
-};
-
-struct isp_device {
-	struct device *dev;
-
-	/*** platform HW resources ***/
-	unsigned int irq;
-
-#define mmio_base_main mmio_base[OMAP3_ISP_IOMEM_MAIN]
-#define mmio_cbuff_main mmio_base[OMAP3_ISP_IOMEM_CBUFF]
-#define mmio_ccp2_main mmio_base[OMAP3_ISP_IOMEM_CCP2]
-#define mmio_ccdc_main mmio_base[OMAP3_ISP_IOMEM_CCDC]
-#define mmio_hist_main mmio_base[OMAP3_ISP_IOMEM_HIST]
-#define mmio_h3a_main mmio_base[OMAP3_ISP_IOMEM_H3A]
-#define mmio_prev_main mmio_base[OMAP3_ISP_IOMEM_PREV]
-#define mmio_resz_main mmio_base[OMAP3_ISP_IOMEM_RESZ]
-#define mmio_sbl_main mmio_base[OMAP3_ISP_IOMEM_SBL]
-#define mmio_csi2_main mmio_base[OMAP3_ISP_IOMEM_CSI2A]
-#define mmio_csi2phy_main mmio_base[OMAP3_ISP_IOMEM_CSI2PHY]
-	unsigned long mmio_base[OMAP3_ISP_IOMEM_CSI2PHY + 1];
-	unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_CSI2PHY + 1];
-	unsigned long mmio_size[OMAP3_ISP_IOMEM_CSI2PHY + 1];
+	OMAP3_ISP_IOMEM_CSI2PHY,
+	OMAP3_ISP_IOMEM_CSI2PHY2
 };
 
 enum isp_interface_type {
@@ -128,22 +127,19 @@
 	CBK_PREV_DONE,
 	CBK_RESZ_DONE,
 	CBK_MMU_ERR,
-	CBK_H3A_AWB_DONE,
 	CBK_HIST_DONE,
 	CBK_HS_VS,
 	CBK_LSC_ISR,
-	CBK_H3A_AF_DONE,
 	CBK_CATCHALL,
 	CBK_CSIA,
 	CBK_CSIB,
 	CBK_END,
 };
 
-enum ispccdc_raw_fmt {
-	ISPCCDC_INPUT_FMT_GR_BG,
-	ISPCCDC_INPUT_FMT_RG_GB,
-	ISPCCDC_INPUT_FMT_BG_GR,
-	ISPCCDC_INPUT_FMT_GB_RG,
+enum isp_running {
+	ISP_STOPPED,
+	ISP_RUNNING,
+	ISP_STOPPING,
 };
 
 /**
@@ -160,11 +156,6 @@
 /**
  * struct isp_interface_config - ISP interface configuration.
  * @ccdc_par_ser: ISP interface type. 0 - Parallel, 1 - CSIA, 2 - CSIB to CCDC.
- * @par_bridge: CCDC Bridge input control. Parallel interface.
- *                  0 - Disable, 1 - Enable, first byte->cam_d(bits 7 to 0)
- *                  2 - Enable, first byte -> cam_d(bits 15 to 8)
- * @par_clk_pol: Pixel clock polarity on the parallel interface.
- *                    0 - Non Inverted, 1 - Inverted
  * @dataline_shift: Data lane shifter.
  *                      0 - No Shift, 1 - CAMEXT[13 to 2]->CAM[11 to 0]
  *                      2 - CAMEXT[13 to 4]->CAM[9 to 0]
@@ -175,10 +166,27 @@
  * @strobe: Strobe related parameter.
  * @prestrobe: PreStrobe related parameter.
  * @shutter: Shutter related parameter.
- * @hskip: Horizontal Start Pixel performed in Preview module.
- * @vskip: Vertical Start Line performed in Preview module.
+ * @prev_sph: Horizontal Start Pixel performed in Preview module.
+ * @prev_slv: Vertical Start Line performed in Preview module.
  * @wenlog: Store the value for the sensor specific wenlog field.
  * @wait_hs_vs: Wait for this many hs_vs before anything else in the beginning.
+ * @pixelclk: Pixel data rate from sensor.
+ * @par_bridge: CCDC Bridge input control. Parallel interface.
+ *                  0 - Disable, 1 - Enable, first byte->cam_d(bits 7 to 0)
+ *                  2 - Enable, first byte -> cam_d(bits 15 to 8)
+ * @par_clk_pol: Pixel clock polarity on the parallel interface.
+ *                    0 - Non Inverted, 1 - Inverted
+ * @crc: Use cyclic redundancy check.
+ * @mode: (?)
+ * @edge: Falling or rising edge
+ * @signalling: Use strobe mode (only valid for CCP2 mode)
+ * @strobe_clock_inv: Strobe/clock signal inversion.
+ * @vs_edge: Type of edge used for detecting VSync signal.
+ * @channel: Logical channel number used in transmission.
+ * @vpclk: Video port output clock.
+ * @data_start: Start vertical position of the region of interest.
+ * @data_size: Vertical size of the region of interest.
+ * @format: V4L2 format which matches with the transmitted frame data.
  */
 struct isp_interface_config {
 	enum isp_interface_type ccdc_par_ser;
@@ -189,7 +197,9 @@
 	int shutter;
 	u32 wenlog;
 	int wait_hs_vs;
+	u32 cam_mclk;
 	enum ispccdc_raw_fmt raw_fmt_in;
+	unsigned int pixelclk;
 	union {
 		struct par {
 			unsigned par_bridge:2;
@@ -211,116 +221,416 @@
 	} u;
 };
 
-u32 isp_reg_readl(enum isp_mem_resources isp_mmio_range, u32 reg_offset);
+/**
+ * struct isp_buf - ISP buffer information structure.
+ * @isp_addr: MMU mapped address (a.k.a. device address) of the buffer.
+ * @complete: Pointer to function used to handle the buffer once its complete
+ * @vb: Pointer to associated video buffer structure.
+ * @priv: Private pointer to send to associated complete handling function.
+ * @vb_state: Current ISP video buffer state.
+ */
+struct isp_buf {
+	dma_addr_t isp_addr;
+	void (*complete)(struct videobuf_buffer *vb, void *priv);
+	struct videobuf_buffer *vb;
+	void *priv;
+	u32 vb_state;
+};
 
-void isp_reg_writel(u32 reg_value, enum isp_mem_resources isp_mmio_range,
-		    u32 reg_offset);
+#define ISP_BUFS_IS_FULL(bufs)					\
+	(((bufs)->queue + 1) % NUM_BUFS == (bufs)->done)
+#define ISP_BUFS_IS_EMPTY(bufs)		((bufs)->queue == (bufs)->done)
+#define ISP_BUFS_IS_LAST(bufs)					\
+	((bufs)->queue == ((bufs)->done + 1) % NUM_BUFS)
+#define ISP_BUFS_QUEUED(bufs)						\
+	((((bufs)->done - (bufs)->queue + NUM_BUFS)) % NUM_BUFS)
+#define ISP_BUF_DONE(bufs)		((bufs)->buf + (bufs)->done)
+#define ISP_BUF_NEXT_DONE(bufs)				\
+	((bufs)->buf + ((bufs)->done + 1) % NUM_BUFS)
+#define ISP_BUF_QUEUE(bufs)		((bufs)->buf + (bufs)->queue)
+#define ISP_BUF_MARK_DONE(bufs)				\
+	(bufs)->done = ((bufs)->done + 1) % NUM_BUFS;
+#define ISP_BUF_MARK_QUEUED(bufs)			\
+	(bufs)->queue = ((bufs)->queue + 1) % NUM_BUFS;
 
-static inline void isp_reg_and(enum isp_mem_resources mmio_range, u32 reg,
-			       u32 and_bits)
-{
-	u32 v = isp_reg_readl(mmio_range, reg);
+/**
+ * struct isp_bufs - ISP internal buffer queue list.
+ * @isp_addr_capture: Array of addresses for the ISP buffers inside the list.
+ * @buf: Array of ISP buffers inside the list.
+ * @queue: Next slot to queue a buffer.
+ * @done: Buffer that is being processed.
+ * @wait_hs_vs: Wait for this many hs_vs before anything else.
+ */
+struct isp_bufs {
+	dma_addr_t isp_addr_capture[VIDEO_MAX_FRAME];
+	struct isp_buf buf[NUM_BUFS];
+	int queue;
+	int done;
+	int wait_hs_vs;
+};
 
-	isp_reg_writel(v & and_bits, mmio_range, reg);
-}
+/**
+ * struct ispirq - Structure for containing callbacks to be called in ISP ISR.
+ * @isp_callbk: Array which stores callback functions, indexed by the type of
+ *              callback (8 possible types).
+ * @isp_callbk_arg1: Pointer to array containing pointers to the first argument
+ *                   to be passed to the requested callback function.
+ * @isp_callbk_arg2: Pointer to array containing pointers to the second
+ *                   argument to be passed to the requested callback function.
+ *
+ * This structure is used to contain all the callback functions related for
+ * each callback type (CBK_CCDC_VD0, CBK_CCDC_VD1, CBK_PREV_DONE,
+ * CBK_RESZ_DONE, CBK_MMU_ERR, CBK_H3A_AWB_DONE, CBK_HIST_DONE, CBK_HS_VS,
+ * CBK_LSC_ISR).
+ */
+struct isp_irq {
+	isp_callback_t isp_callbk[CBK_END];
+	isp_vbq_callback_ptr isp_callbk_arg1[CBK_END];
+	void *isp_callbk_arg2[CBK_END];
+};
 
-static inline void isp_reg_or(enum isp_mem_resources mmio_range, u32 reg,
-			      u32 or_bits)
-{
-	u32 v = isp_reg_readl(mmio_range, reg);
+/**
+ * struct isp_pipeline - ISP pipeline description.
+ * @modules: ISP submodules in use.
+ * @pix: Output pixel format details in v4l2_pix_format structure.
+ * @ccdc_in_v_st: CCDC input vertical start.
+ * @ccdc_in_h_st: CCDC input horizontal start.
+ * @ccdc_in_w: CCDC input width.
+ * @ccdc_in_h: CCDC input height.
+ * @ccdc_out_w: CCDC output width (with extra padding pixels).
+ * @ccdc_out_h: CCDC output height.
+ * @ccdc_out_w_img: CCDC output width.
+ * @ccdc_in: CCDC input source.
+ * @ccdc_out: CCDC output destination.
+ * @prv_out_w: Preview output width (with extra padding pixels).
+ * @prv_out_h: Preview output height (with extra padding pixels).
+ * @prv_out_w_img: Preview output width.
+ * @prv_out_h_img: Preview output height.
+ * @prv_fmt_avg: Preview formatter averager.
+ * @prv_in: Preview input source.
+ * @prv_out: Preview output destination.
+ * @rsz_crop: Resizer crop region.
+ * @rsz_out_w: Resizer output width (with extra padding pixels).
+ * @rsz_out_h: Resizer output height.
+ * @rsz_out_w_img: Resizer output width (valid image region).
+ * @rsz_in: Resizer input source.
+ */
+struct isp_pipeline {
+	unsigned int modules;		/* modules in use */
+	struct v4l2_pix_format pix;	/* output pix */
+	unsigned int ccdc_in_v_st;
+	unsigned int ccdc_in_h_st;
+	unsigned int ccdc_in_w;
+	unsigned int ccdc_in_h;
+	unsigned int ccdc_out_w;	/* ccdc output data width (pixels) */
+	unsigned int ccdc_out_h;	/* ccdc output data height */
+	unsigned int ccdc_out_w_img;	/* ccdc output visible image width */
+	enum ccdc_input ccdc_in;
+	enum ccdc_output ccdc_out;
+	unsigned int prv_out_w;
+	unsigned int prv_out_h;
+	unsigned int prv_out_w_img;
+	unsigned int prv_out_h_img;
+	unsigned int prv_fmt_avg;
+	enum preview_input prv_in;
+	enum preview_output prv_out;
+	struct v4l2_rect rsz_crop;
+	unsigned int rsz_out_w;
+	unsigned int rsz_out_h;
+	unsigned int rsz_out_w_img;
+	enum resizer_input rsz_in;
+};
 
-	isp_reg_writel(v | or_bits, mmio_range, reg);
-}
+#define CCDC_CAPTURE(isp)					\
+	((isp)->pipeline.modules == OMAP_ISP_CCDC)
 
-static inline void isp_reg_and_or(enum isp_mem_resources mmio_range, u32 reg,
-				  u32 and_bits, u32 or_bits)
-{
-	u32 v = isp_reg_readl(mmio_range, reg);
+#define CCDC_PREV_CAPTURE(isp)					\
+	((isp)->pipeline.modules == (OMAP_ISP_CCDC | OMAP_ISP_PREVIEW))
 
-	isp_reg_writel((v & and_bits) | or_bits, mmio_range, reg);
-}
+#define CCDC_PREV_RESZ_CAPTURE(isp)				\
+	((isp)->pipeline.modules == (OMAP_ISP_CCDC | \
+				     OMAP_ISP_PREVIEW | \
+				     OMAP_ISP_RESIZER))
 
-void isp_start(void);
+/**
+ * struct isp_device - ISP device structure.
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @revision: Stores current ISP module revision.
+ * @irq_num: Currently used IRQ number.
+ * @mmio_base: Array with kernel base addresses for ioremapped ISP register
+ *             regions.
+ * @mmio_base_phys: Array with physical L4 bus addresses for ISP register
+ *                  regions.
+ * @mmio_size: Array with ISP register regions size in bytes.
+ * @lock: Spinlock for handling registered ISP callbacks.
+ * @h3a_lock: Spinlock for handling H3a (Not used) (?)
+ * @isp_mutex: Mutex for serializing requests to ISP.
+ * @ref_count: Reference count for handling multiple ISP requests.
+ * @cam_ick: Pointer to camera interface clock structure.
+ * @cam_mclk: Pointer to camera functional clock structure.
+ * @dpll4_m5_ck: Pointer to DPLL4 M5 clock structure.
+ * @csi2_fck: Pointer to camera CSI2 complexIO clock structure.
+ * @l3_ick: Pointer to OMAP3 L3 bus interface clock.
+ * @config: Pointer to currently set ISP interface configuration.
+ * @tmp_buf: ISP MMU mapped temporary buffer address used for 34xx Workaround
+ *           for CCDC->PRV->RSZ datapath errata.
+ * @tmp_buf_size: ISP MMU mapped temporary buffer size used for 34xx Workaround
+ *                for CCDC->PRV->RSZ datapath errata.
+ * @tmp_buf_offset: ISP MMU mapped temporary buffer line offset used for 34xx
+ *                  Workaround for CCDC->PRV->RSZ datapath errata.
+ * @bufs: Internal ISP buffer queue list.
+ * @irq: Currently attached ISP ISR callbacks information structure.
+ * @pipeline: Currently used internal ISP pipeline information.
+ * @interrupts: ISP interrupts staged for deferred enabling.
+ * @running: Current running/stopped status of ISP.
+ * @isp_af: Pointer to current settings for ISP AutoFocus SCM.
+ * @isp_hist: Pointer to current settings for ISP Histogram SCM.
+ * @isp_h3a: Pointer to current settings for ISP Auto Exposure and
+ *           White Balance SCM.
+ * @isp_res: Pointer to current settings for ISP Resizer.
+ * @isp_prev: Pointer to current settings for ISP Preview.
+ * @isp_ccdc: Pointer to current settings for ISP CCDC.
+ * @iommu: Pointer to requested IOMMU instance for ISP.
+ *
+ * This structure is used to store the OMAP ISP Information.
+ */
+struct isp_device {
+	struct device *dev;
+	u32 revision;
 
-void isp_stop(void);
+	/*** platform HW resources ***/
+	unsigned int irq_num;
 
-int isp_buf_queue(struct videobuf_buffer *vb,
+#define mmio_base_main mmio_base[OMAP3_ISP_IOMEM_MAIN]
+#define mmio_cbuff_main mmio_base[OMAP3_ISP_IOMEM_CBUFF]
+#define mmio_ccp2_main mmio_base[OMAP3_ISP_IOMEM_CCP2]
+#define mmio_ccdc_main mmio_base[OMAP3_ISP_IOMEM_CCDC]
+#define mmio_hist_main mmio_base[OMAP3_ISP_IOMEM_HIST]
+#define mmio_h3a_main mmio_base[OMAP3_ISP_IOMEM_H3A]
+#define mmio_prev_main mmio_base[OMAP3_ISP_IOMEM_PREV]
+#define mmio_resz_main mmio_base[OMAP3_ISP_IOMEM_RESZ]
+#define mmio_sbl_main mmio_base[OMAP3_ISP_IOMEM_SBL]
+#define mmio_csi2_main mmio_base[OMAP3_ISP_IOMEM_CSI2A]
+#define mmio_csi2phy_main mmio_base[OMAP3_ISP_IOMEM_CSI2PHY2]
+	unsigned long mmio_base[OMAP3_ISP_IOMEM_CSI2PHY2 + 1];
+	unsigned long mmio_base_phys[OMAP3_ISP_IOMEM_CSI2PHY2 + 1];
+	unsigned long mmio_size[OMAP3_ISP_IOMEM_CSI2PHY2 + 1];
+
+	/* ISP Obj */
+	spinlock_t lock;	/* For handling registered ISP callbacks */
+	spinlock_t h3a_lock;
+	struct mutex isp_mutex;	/* For handling ref_count field */
+	int ref_count;
+	struct clk *cam_ick;
+	struct clk *cam_mclk;
+	struct clk *dpll4_m5_ck;
+	struct clk *csi2_fck;
+	struct clk *l3_ick;
+	struct isp_interface_config *config;
+	dma_addr_t tmp_buf;
+	size_t tmp_buf_size;
+	unsigned long tmp_buf_offset;
+	struct isp_bufs bufs;
+	struct isp_irq irq;
+	struct isp_pipeline pipeline;
+	u32 interrupts;
+	u32 mclk;
+	enum isp_running running;
+
+	/* ISP modules */
+	struct isp_af_device isp_af;
+	struct isp_hist_device isp_hist;
+	struct isp_h3a_device isp_h3a;
+	struct isp_res_device isp_res;
+	struct isp_prev_device isp_prev;
+	struct isp_ccdc_device isp_ccdc;
+	struct isp_csi2_device isp_csi2;
+
+	struct iommu *iommu;
+};
+
+void isp_hist_dma_done(struct device *dev);
+
+u32 isp_rev(struct device *dev);
+
+void isp_flush(struct device *dev);
+
+void isp_start(struct device *dev);
+
+void isp_stop(struct device *dev);
+
+int isp_buf_queue(struct device *dev, struct videobuf_buffer *vb,
 		  void (*complete)(struct videobuf_buffer *vb, void *priv),
 		  void *priv);
 
-int isp_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
-		  unsigned int *size);
+int isp_vbq_setup(struct device *dev, struct videobuf_queue *vbq,
+		  unsigned int *cnt, unsigned int *size);
 
-int isp_vbq_prepare(struct videobuf_queue *vbq, struct videobuf_buffer *vb,
-		    enum v4l2_field field);
+int isp_vbq_prepare(struct device *dev, struct videobuf_queue *vbq,
+		    struct videobuf_buffer *vb, enum v4l2_field field);
 
-void isp_vbq_release(struct videobuf_queue *vbq, struct videobuf_buffer *vb);
+void isp_vbq_release(struct device *dev, struct videobuf_queue *vbq,
+		    struct videobuf_buffer *vb);
 
-int isp_set_callback(enum isp_callback_type type, isp_callback_t callback,
-		     isp_vbq_callback_ptr arg1, void *arg2);
+int isp_set_callback(struct device *dev, enum isp_callback_type type,
+		     isp_callback_t callback, isp_vbq_callback_ptr arg1,
+		     void *arg2);
 
-int isp_unset_callback(enum isp_callback_type type);
+int isp_unset_callback(struct device *dev, enum isp_callback_type type);
 
-u32 isp_set_xclk(u32 xclk, u8 xclksel);
+u32 isp_set_xclk(struct device *dev, u32 xclk, u8 xclksel);
 
-int isp_configure_interface(struct isp_interface_config *config);
+int isp_configure_interface(struct device *dev,
+			    struct isp_interface_config *config);
 
-int isp_get(void);
+struct device *isp_get(void);
 
 int isp_put(void);
 
+int isp_enable_mclk(struct device *dev);
+
+void isp_disable_mclk(struct isp_device *dev);
+
 int isp_queryctrl(struct v4l2_queryctrl *a);
 
 int isp_querymenu(struct v4l2_querymenu *a);
 
-int isp_g_ctrl(struct v4l2_control *a);
+int isp_g_ctrl(struct device *dev, struct v4l2_control *a);
 
-int isp_s_ctrl(struct v4l2_control *a);
+int isp_s_ctrl(struct device *dev, struct v4l2_control *a);
 
 int isp_enum_fmt_cap(struct v4l2_fmtdesc *f);
 
-int isp_try_fmt_cap(struct v4l2_pix_format *pix_input,
+int isp_try_fmt_cap(struct device *dev, struct v4l2_pix_format *pix_input,
 		    struct v4l2_pix_format *pix_output);
 
-void isp_g_fmt_cap(struct v4l2_pix_format *pix);
+void isp_g_fmt_cap(struct device *dev, struct v4l2_pix_format *pix);
 
-int isp_s_fmt_cap(struct v4l2_pix_format *pix_input,
+int isp_s_fmt_cap(struct device *dev, struct v4l2_pix_format *pix_input,
 		  struct v4l2_pix_format *pix_output);
 
-int isp_g_crop(struct v4l2_crop *a);
+int isp_g_crop(struct device *dev, struct v4l2_crop *a);
 
-int isp_s_crop(struct v4l2_crop *a, struct v4l2_pix_format *pix);
+int isp_s_crop(struct device *dev, struct v4l2_crop *a);
 
-void isp_config_crop(struct v4l2_pix_format *pix);
-
-int isp_try_fmt(struct v4l2_pix_format *pix_input,
+int isp_try_fmt(struct device *dev, struct v4l2_pix_format *pix_input,
 		struct v4l2_pix_format *pix_output);
 
-int isp_handle_private(int cmd, void *arg);
+int isp_handle_private(struct device *dev, struct mutex *, int cmd, void *arg);
 
-void isp_save_context(struct isp_reg *);
+void isp_save_context(struct device *dev, struct isp_reg *);
 
-void isp_restore_context(struct isp_reg *);
+void isp_restore_context(struct device *dev, struct isp_reg *);
 
-void isp_print_status(void);
+void isp_print_status(struct device *dev);
 
-void isp_set_hs_vs(int);
+void isp_set_hs_vs(struct device *dev, int hs_vs);
 
-int __init isp_ccdc_init(void);
-int __init isp_hist_init(void);
-int __init isph3a_aewb_init(void);
-int __init isp_preview_init(void);
-int __init isp_resizer_init(void);
-int __init isp_af_init(void);
-int __init isp_csi2_init(void);
+unsigned long isp_get_buf_offset(struct device *dev);
 
-void isp_ccdc_cleanup(void);
-void isp_hist_cleanup(void);
-void isph3a_aewb_cleanup(void);
-void isp_preview_cleanup(void);
-void isp_hist_cleanup(void);
-void isp_resizer_cleanup(void);
-void isp_af_exit(void);
-void isp_csi2_cleanup(void);
+int __init isp_ccdc_init(struct device *dev);
+int __init isp_hist_init(struct device *dev);
+int __init isph3a_aewb_init(struct device *dev);
+int __init isp_preview_init(struct device *dev);
+int __init isp_resizer_init(struct device *dev);
+int __init isp_af_init(struct device *dev);
+int __init isp_csi2_init(struct device *dev);
+
+void isp_ccdc_cleanup(struct device *dev);
+void isp_hist_cleanup(struct device *dev);
+void isph3a_aewb_cleanup(struct device *dev);
+void isp_resizer_cleanup(struct device *dev);
+void isp_af_exit(struct device *dev);
+void isp_csi2_cleanup(struct device *dev);
+
+/* FIXME: Remove these when iommu supports these directly. */
+dma_addr_t ispmmu_vmap(struct device *dev, const struct scatterlist *sglist,
+		       int sglen);
+void ispmmu_vunmap(struct device *dev, dma_addr_t da);
+
+/**
+ * isp_reg_readl - Read value of an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to read from.
+ *
+ * Returns an unsigned 32 bit value with the required register contents.
+ **/
+static inline
+u32 isp_reg_readl(struct device *dev, enum isp_mem_resources isp_mmio_range,
+		  u32 reg_offset)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	return __raw_readl(isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/**
+ * isp_reg_writel - Write value to an OMAP3 ISP register
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @reg_value: 32 bit value to write to the register.
+ * @isp_mmio_range: Range to which the register offset refers to.
+ * @reg_offset: Register offset to write into.
+ **/
+static inline
+void isp_reg_writel(struct device *dev, u32 reg_value,
+		    enum isp_mem_resources isp_mmio_range, u32 reg_offset)
+{
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	__raw_writel(reg_value, isp->mmio_base[isp_mmio_range] + reg_offset);
+}
+
+/**
+ * isp_reg_and - Do AND binary operation within an OMAP3 ISP register value
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @and_bits: 32 bit value which would be 'ANDed' with current register value.
+ **/
+static inline
+void isp_reg_and(struct device *dev, enum isp_mem_resources mmio_range, u32 reg,
+		 u32 and_bits)
+{
+	u32 v = isp_reg_readl(dev, mmio_range, reg);
+
+	isp_reg_writel(dev, v & and_bits, mmio_range, reg);
+}
+
+/**
+ * isp_reg_or - Do OR binary operation within an OMAP3 ISP register value
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @or_bits: 32 bit value which would be 'ORed' with current register value.
+ **/
+static inline
+void isp_reg_or(struct device *dev, enum isp_mem_resources mmio_range, u32 reg,
+		u32 or_bits)
+{
+	u32 v = isp_reg_readl(dev, mmio_range, reg);
+
+	isp_reg_writel(dev, v | or_bits, mmio_range, reg);
+}
+
+/**
+ * isp_reg_and_or - Do AND and OR binary ops within an OMAP3 ISP register value
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ * @mmio_range: Range to which the register offset refers to.
+ * @reg: Register offset to work on.
+ * @and_bits: 32 bit value which would be 'ANDed' with current register value.
+ * @or_bits: 32 bit value which would be 'ORed' with current register value.
+ *
+ * The AND operation is done first, and then the OR operation. Mostly useful
+ * when clearing a group of bits before setting a value.
+ **/
+static inline
+void isp_reg_and_or(struct device *dev, enum isp_mem_resources mmio_range,
+		    u32 reg, u32 and_bits, u32 or_bits)
+{
+	u32 v = isp_reg_readl(dev, mmio_range, reg);
+
+	isp_reg_writel(dev, (v & and_bits) | or_bits, mmio_range, reg);
+}
 
 #endif	/* OMAP_ISP_TOP_H */
diff --git a/drivers/media/video/isp/isp_af.c b/drivers/media/video/isp/isp_af.c
index a607b97..c7fdb6f 100644
--- a/drivers/media/video/isp/isp_af.c
+++ b/drivers/media/video/isp/isp_af.c
@@ -8,6 +8,7 @@
  * Contributors:
  *	Sergio Aguirre <saaguirre@ti.com>
  *	Troy Laramy
+ * 	David Cohen <david.cohen@nokia.com>
  *
  * This package is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,766 +20,457 @@
  */
 
 /* Linux specific include files */
-#include <asm/cacheflush.h>
-
-#include <linux/uaccess.h>
-#include <linux/dma-mapping.h>
-#include <asm/atomic.h>
+#include <linux/device.h>
 
 #include "isp.h"
 #include "ispreg.h"
 #include "isph3a.h"
 #include "isp_af.h"
-#include "ispmmu.h"
-
-/**
- * struct isp_af_buffer - AF frame stats buffer.
- * @virt_addr: Virtual address to mmap the buffer.
- * @phy_addr: Physical address of the buffer.
- * @addr_align: Virtual Address 32 bytes aligned.
- * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
- * @mmap_addr: Mapped memory area of buffer. For userspace access.
- * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten.
- * @frame_num: Frame number from which the statistics are taken.
- * @lens_position: Lens position currently set in the DW9710 Coil motor driver.
- * @next: Pointer to link next buffer.
- */
-struct isp_af_buffer {
-	unsigned long virt_addr;
-	unsigned long phy_addr;
-	unsigned long addr_align;
-	unsigned long ispmmu_addr;
-	unsigned long mmap_addr;
-
-	u8 locked;
-	u16 frame_num;
-	u32 config_counter;
-	struct isp_af_xtrastats xtrastats;
-	struct isp_af_buffer *next;
-};
-
-/**
- * struct isp_af_status - AF status.
- * @initialized: 1 - Buffers initialized.
- * @update: 1 - Update registers.
- * @stats_req: 1 - Future stats requested.
- * @stats_done: 1 - Stats ready for user.
- * @frame_req: Number of frame requested for statistics.
- * @af_buff: Array of statistics buffers to access.
- * @stats_buf_size: Statistics buffer size.
- * @curr_cfg_buf_size: Current user configured stats buff size.
- * @min_buf_size: Minimum statisitics buffer size.
- * @frame_count: Frame Count.
- * @stats_wait: Wait primitive for locking/unlocking the stats request.
- * @buffer_lock: Spinlock for statistics buffers access.
- */
-static struct isp_af_status {
-	u8 initialized;
-	u8 update;
-	u8 stats_req;
-	u8 stats_done;
-	u16 frame_req;
-
-	struct isp_af_buffer af_buff[H3A_MAX_BUFF];
-	unsigned int stats_buf_size;
-	unsigned int min_buf_size;
-	unsigned int curr_cfg_buf_size;
-
-	int pm_state;
-	u32 frame_count;
-	wait_queue_head_t stats_wait;
-	atomic_t config_counter;
-	spinlock_t buffer_lock;		/* For stats buffers read/write sync */
-} afstat;
-
-struct af_device *af_dev_configptr;
-static struct isp_af_buffer *active_buff;
-static int af_major = -1;
-static int camnotify;
-
-/**
- * isp_af_setxtrastats - Receives extra statistics from prior frames.
- * @xtrastats: Pointer to structure containing extra statistics fields like
- *             field count and timestamp of frame.
- *
- * Called from update_vbq in camera driver
- **/
-void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag)
-{
-	int i, past_i;
-
-	if (active_buff == NULL)
-		return;
-
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		if (afstat.af_buff[i].frame_num == active_buff->frame_num)
-			break;
-	}
-
-	if (i == H3A_MAX_BUFF)
-		return;
-
-	if (i == 0) {
-		if (afstat.af_buff[H3A_MAX_BUFF - 1].locked == 0)
-			past_i = H3A_MAX_BUFF - 1;
-		else
-			past_i = H3A_MAX_BUFF - 2;
-	} else if (i == 1) {
-		if (afstat.af_buff[0].locked == 0)
-			past_i = 0;
-		else
-			past_i = H3A_MAX_BUFF - 1;
-	} else {
-		if (afstat.af_buff[i - 1].locked == 0)
-			past_i = i - 1;
-		else
-			past_i = i - 2;
-	}
-
-	if (updateflag & AF_UPDATEXS_TS)
-		afstat.af_buff[past_i].xtrastats.ts = xtrastats->ts;
-
-	if (updateflag & AF_UPDATEXS_FIELDCOUNT)
-		afstat.af_buff[past_i].xtrastats.field_count =
-			xtrastats->field_count;
-}
-EXPORT_SYMBOL(isp_af_setxtrastats);
-
-/*
- * Helper function to update buffer cache pages
- */
-static void isp_af_update_req_buffer(struct isp_af_buffer *buffer)
-{
-	int size = afstat.stats_buf_size;
-
-	size = PAGE_ALIGN(size);
-	/* Update the kernel pages of the requested buffer */
-	dmac_inv_range((void *)buffer->addr_align, (void *)buffer->addr_align +
-		       size);
-}
 
 #define IS_OUT_OF_BOUNDS(value, min, max)		\
 	(((value) < (min)) || ((value) > (max)))
 
 /* Function to check paxel parameters */
-int isp_af_check_paxel(void)
+static int isp_af_check_params(struct isp_af_device *isp_af,
+			       struct af_configuration *afconfig)
 {
-	struct af_paxel *paxel_cfg = &af_dev_configptr->config->paxel_config;
-	struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config;
+	struct af_paxel *paxel_cfg = &afconfig->paxel_config;
+	struct af_iir *iir_cfg = &afconfig->iir_config;
+	int index;
 
 	/* Check horizontal Count */
 	if (IS_OUT_OF_BOUNDS(paxel_cfg->hz_cnt, AF_PAXEL_HORIZONTAL_COUNT_MIN,
-			     AF_PAXEL_HORIZONTAL_COUNT_MAX)) {
-		DPRINTK_ISP_AF("Error : Horizontal Count is incorrect");
+			     AF_PAXEL_HORIZONTAL_COUNT_MAX))
 		return -AF_ERR_HZ_COUNT;
-	}
 
-	/*Check Vertical Count */
+	/* Check Vertical Count */
 	if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_cnt, AF_PAXEL_VERTICAL_COUNT_MIN,
-			     AF_PAXEL_VERTICAL_COUNT_MAX)) {
-		DPRINTK_ISP_AF("Error : Vertical Count is incorrect");
+			     AF_PAXEL_VERTICAL_COUNT_MAX))
 		return -AF_ERR_VT_COUNT;
-	}
 
-	/*Check Height */
+	/* Check Height */
 	if (IS_OUT_OF_BOUNDS(paxel_cfg->height, AF_PAXEL_HEIGHT_MIN,
-			     AF_PAXEL_HEIGHT_MAX)) {
-		DPRINTK_ISP_AF("Error : Height is incorrect");
+			     AF_PAXEL_HEIGHT_MAX))
 		return -AF_ERR_HEIGHT;
-	}
 
-	/*Check width */
+	/* Check width */
 	if (IS_OUT_OF_BOUNDS(paxel_cfg->width, AF_PAXEL_WIDTH_MIN,
-			     AF_PAXEL_WIDTH_MAX)) {
-		DPRINTK_ISP_AF("Error : Width is incorrect");
+			     AF_PAXEL_WIDTH_MAX))
 		return -AF_ERR_WIDTH;
-	}
 
-	/*Check Line Increment */
+	/* Check Line Increment */
 	if (IS_OUT_OF_BOUNDS(paxel_cfg->line_incr, AF_PAXEL_INCREMENT_MIN,
-			     AF_PAXEL_INCREMENT_MAX)) {
-		DPRINTK_ISP_AF("Error : Line Increment is incorrect");
+			     AF_PAXEL_INCREMENT_MAX))
 		return -AF_ERR_INCR;
-	}
 
-	/*Check Horizontal Start */
+	/* Check Horizontal Start */
 	if ((paxel_cfg->hz_start % 2 != 0) ||
 	    (paxel_cfg->hz_start < (iir_cfg->hz_start_pos + 2)) ||
 	    IS_OUT_OF_BOUNDS(paxel_cfg->hz_start,
-			     AF_PAXEL_HZSTART_MIN, AF_PAXEL_HZSTART_MAX)) {
-		DPRINTK_ISP_AF("Error : Horizontal Start is incorrect");
+			     AF_PAXEL_HZSTART_MIN, AF_PAXEL_HZSTART_MAX))
 		return -AF_ERR_HZ_START;
-	}
 
-	/*Check Vertical Start */
+	/* Check Vertical Start */
 	if (IS_OUT_OF_BOUNDS(paxel_cfg->vt_start, AF_PAXEL_VTSTART_MIN,
-			     AF_PAXEL_VTSTART_MAX)) {
-		DPRINTK_ISP_AF("Error : Vertical Start is incorrect");
+			     AF_PAXEL_VTSTART_MAX))
 		return -AF_ERR_VT_START;
-	}
-	return 0;
-}
 
-/**
- * isp_af_check_iir - Function to check IIR Coefficient.
- **/
-int isp_af_check_iir(void)
-{
-	struct af_iir *iir_cfg = &af_dev_configptr->config->iir_config;
-	int index;
-
+	/* Check IIR */
 	for (index = 0; index < AF_NUMBER_OF_COEF; index++) {
-		if ((iir_cfg->coeff_set0[index]) > AF_COEF_MAX) {
-			DPRINTK_ISP_AF("Error : Coefficient for set 0 is "
-				       "incorrect");
+		if ((iir_cfg->coeff_set0[index]) > AF_COEF_MAX)
 			return -AF_ERR_IIR_COEF;
-		}
 
-		if ((iir_cfg->coeff_set1[index]) > AF_COEF_MAX) {
-			DPRINTK_ISP_AF("Error : Coefficient for set 1 is "
-				       "incorrect");
+		if ((iir_cfg->coeff_set1[index]) > AF_COEF_MAX)
 			return -AF_ERR_IIR_COEF;
-		}
 	}
 
 	if (IS_OUT_OF_BOUNDS(iir_cfg->hz_start_pos, AF_IIRSH_MIN,
-			     AF_IIRSH_MAX)) {
-		DPRINTK_ISP_AF("Error : IIRSH is incorrect");
+			     AF_IIRSH_MAX))
 		return -AF_ERR_IIRSH;
-	}
-
-	return 0;
-}
-/**
- * isp_af_unlock_buffers - Helper function to unlock all buffers.
- **/
-static void isp_af_unlock_buffers(void)
-{
-	int i;
-	unsigned long irqflags;
-
-	spin_lock_irqsave(&afstat.buffer_lock, irqflags);
-	for (i = 0; i < H3A_MAX_BUFF; i++)
-		afstat.af_buff[i].locked = 0;
-
-	spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
-}
-
-/*
- * Helper function to link allocated buffers
- */
-static void isp_af_link_buffers(void)
-{
-	int i;
-
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		if ((i + 1) < H3A_MAX_BUFF)
-			afstat.af_buff[i].next = &afstat.af_buff[i + 1];
-		else
-			afstat.af_buff[i].next = &afstat.af_buff[0];
-	}
-}
-
-/* Function to perform hardware set up */
-int isp_af_configure(struct af_configuration *afconfig)
-{
-	int result;
-	int buff_size, i;
-	unsigned int busyaf;
-	struct af_configuration *af_curr_cfg = af_dev_configptr->config;
-
-	if (NULL == afconfig) {
-		printk(KERN_ERR "Null argument in configuration. \n");
-		return -EINVAL;
-	}
-
-	memcpy(af_curr_cfg, afconfig, sizeof(struct af_configuration));
-	/* Get the value of PCR register */
-	busyaf = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
-
-	if ((busyaf & AF_BUSYAF) == AF_BUSYAF) {
-		DPRINTK_ISP_AF("AF_register_setup_ERROR : Engine Busy");
-		DPRINTK_ISP_AF("\n Configuration cannot be done ");
-		return -AF_ERR_ENGINE_BUSY;
-	}
-
-	/* Check IIR Coefficient and start Values */
-	result = isp_af_check_iir();
-	if (result < 0)
-		return result;
-
-	/* Check Paxel Values */
-	result = isp_af_check_paxel();
-	if (result < 0)
-		return result;
 
 	/* Check HMF Threshold Values */
-	if (af_curr_cfg->hmf_config.threshold > AF_THRESHOLD_MAX) {
-		DPRINTK_ISP_AF("Error : HMF Threshold is incorrect");
+	if (afconfig->hmf_config.threshold > AF_THRESHOLD_MAX)
 		return -AF_ERR_THRESHOLD;
-	}
 
-	/* Compute buffer size */
-	buff_size = (af_curr_cfg->paxel_config.hz_cnt + 1) *
-		(af_curr_cfg->paxel_config.vt_cnt + 1) * AF_PAXEL_SIZE;
-
-	afstat.curr_cfg_buf_size = buff_size;
-	/* Deallocate the previous buffers */
-	if (afstat.stats_buf_size && buff_size > afstat.stats_buf_size) {
-		isp_af_enable(0);
-		for (i = 0; i < H3A_MAX_BUFF; i++) {
-			ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr);
-			dma_free_coherent(
-				NULL, afstat.min_buf_size,
-				(void *)afstat.af_buff[i].virt_addr,
-				(dma_addr_t)afstat.af_buff[i].phy_addr);
-			afstat.af_buff[i].virt_addr = 0;
-		}
-		afstat.stats_buf_size = 0;
-	}
-
-	if (!afstat.af_buff[0].virt_addr) {
-		afstat.stats_buf_size = buff_size;
-		afstat.min_buf_size = PAGE_ALIGN(afstat.stats_buf_size);
-
-		for (i = 0; i < H3A_MAX_BUFF; i++) {
-			afstat.af_buff[i].virt_addr =
-				(unsigned long)dma_alloc_coherent(
-					NULL,
-					afstat.min_buf_size,
-					(dma_addr_t *)
-					&afstat.af_buff[i].phy_addr,
-					GFP_KERNEL | GFP_DMA);
-			if (afstat.af_buff[i].virt_addr == 0) {
-				printk(KERN_ERR "Can't acquire memory for "
-				       "buffer[%d]\n", i);
-				return -ENOMEM;
-			}
-			afstat.af_buff[i].addr_align =
-				afstat.af_buff[i].virt_addr;
-			while ((afstat.af_buff[i].addr_align & 0xFFFFFFC0) !=
-			       afstat.af_buff[i].addr_align)
-				afstat.af_buff[i].addr_align++;
-			afstat.af_buff[i].ispmmu_addr =
-				ispmmu_kmap(afstat.af_buff[i].phy_addr,
-					    afstat.min_buf_size);
-		}
-		isp_af_unlock_buffers();
-		isp_af_link_buffers();
-
-		/* First active buffer */
-		if (active_buff == NULL)
-			active_buff = &afstat.af_buff[0];
-		isp_af_set_address(active_buff->ispmmu_addr);
-	}
-
-	result = isp_af_register_setup(af_dev_configptr);
-	if (result < 0)
-		return result;
-	af_dev_configptr->size_paxel = buff_size;
-	atomic_inc(&afstat.config_counter);
-	afstat.initialized = 1;
-	afstat.frame_count = 1;
-	active_buff->frame_num = 1;
-	/* Set configuration flag to indicate HW setup done */
-	if (af_curr_cfg->af_config)
-		isp_af_enable(1);
-	else
-		isp_af_enable(0);
-
-	/* Success */
 	return 0;
 }
-EXPORT_SYMBOL(isp_af_configure);
 
-int isp_af_register_setup(struct af_device *af_dev)
+void isp_af_config_registers(struct isp_af_device *isp_af)
 {
+	struct device *dev = to_device(isp_af);
 	unsigned int pcr = 0, pax1 = 0, pax2 = 0, paxstart = 0;
 	unsigned int coef = 0;
 	unsigned int base_coef_set0 = 0;
 	unsigned int base_coef_set1 = 0;
 	int index;
+	unsigned long irqflags;
+
+	if (!isp_af->config.af_config)
+		return;
+
+	spin_lock_irqsave(isp_af->lock, irqflags);
+
+	isp_reg_writel(dev, isp_af->buf_next->iommu_addr, OMAP3_ISP_IOMEM_H3A,
+		       ISPH3A_AFBUFST);
+
+	if (!isp_af->update) {
+		spin_unlock_irqrestore(isp_af->lock, irqflags);
+		return;
+	}
 
 	/* Configure Hardware Registers */
-	/* Read PCR Register */
-	pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
-
-	/* Set Accumulator Mode */
-	if (af_dev->config->mode == ACCUMULATOR_PEAK)
-		pcr |= FVMODE;
-	else
-		pcr &= ~FVMODE;
-
-	/* Set A-law */
-	if (af_dev->config->alaw_enable == H3A_AF_ALAW_ENABLE)
-		pcr |= AF_ALAW_EN;
-	else
-		pcr &= ~AF_ALAW_EN;
-
-	/* Set RGB Position */
-	pcr &= ~RGBPOS;
-	pcr |= af_dev->config->rgb_pos << AF_RGBPOS_SHIFT;
-
-	/* HMF Configurations */
-	if (af_dev->config->hmf_config.enable == H3A_AF_HMF_ENABLE) {
-		pcr &= ~AF_MED_EN;
-		/* Enable HMF */
-		pcr |= AF_MED_EN;
-
-		/* Set Median Threshold */
-		pcr &= ~MED_TH;
-		pcr |= af_dev->config->hmf_config.threshold << AF_MED_TH_SHIFT;
-	} else
-		pcr &= ~AF_MED_EN;
-
-	/* Set PCR Register */
-	isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
-
-	pax1 &= ~PAXW;
-	pax1 |= af_dev->config->paxel_config.width << AF_PAXW_SHIFT;
-
+	pax1 |= isp_af->config.paxel_config.width << AF_PAXW_SHIFT;
 	/* Set height in AFPAX1 */
-	pax1 &= ~PAXH;
-	pax1 |= af_dev->config->paxel_config.height;
-
-	isp_reg_writel(pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
+	pax1 |= isp_af->config.paxel_config.height;
+	isp_reg_writel(dev, pax1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX1);
 
 	/* Configure AFPAX2 Register */
 	/* Set Line Increment in AFPAX2 Register */
-	pax2 &= ~AFINCV;
-	pax2 |= af_dev->config->paxel_config.line_incr << AF_LINE_INCR_SHIFT;
+	pax2 |= isp_af->config.paxel_config.line_incr << AF_LINE_INCR_SHIFT;
 	/* Set Vertical Count */
-	pax2 &= ~PAXVC;
-	pax2 |= af_dev->config->paxel_config.vt_cnt << AF_VT_COUNT_SHIFT;
+	pax2 |= isp_af->config.paxel_config.vt_cnt << AF_VT_COUNT_SHIFT;
 	/* Set Horizontal Count */
-	pax2 &= ~PAXHC;
-	pax2 |= af_dev->config->paxel_config.hz_cnt;
-	isp_reg_writel(pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
+	pax2 |= isp_af->config.paxel_config.hz_cnt;
+	isp_reg_writel(dev, pax2, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAX2);
 
 	/* Configure PAXSTART Register */
 	/*Configure Horizontal Start */
-	paxstart &= ~PAXSH;
-	paxstart |= af_dev->config->paxel_config.hz_start << AF_HZ_START_SHIFT;
+	paxstart |= isp_af->config.paxel_config.hz_start << AF_HZ_START_SHIFT;
 	/* Configure Vertical Start */
-	paxstart &= ~PAXSV;
-	paxstart |= af_dev->config->paxel_config.vt_start;
-	isp_reg_writel(paxstart, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFPAXSTART);
+	paxstart |= isp_af->config.paxel_config.vt_start;
+	isp_reg_writel(dev, paxstart, OMAP3_ISP_IOMEM_H3A,
+		       ISPH3A_AFPAXSTART);
 
 	/*SetIIRSH Register */
-	isp_reg_writel(af_dev->config->iir_config.hz_start_pos,
+	isp_reg_writel(dev, isp_af->config.iir_config.hz_start_pos,
 		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFIIRSH);
 
-	/*Set IIR Filter0 Coefficients */
 	base_coef_set0 = ISPH3A_AFCOEF010;
-	for (index = 0; index <= 8; index += 2) {
-		coef &= ~COEF_MASK0;
-		coef |= af_dev->config->iir_config.coeff_set0[index];
-		coef &= ~COEF_MASK1;
-		coef |= af_dev->config->iir_config.coeff_set0[index + 1] <<
-			AF_COEF_SHIFT;
-		isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set0);
-		base_coef_set0 = base_coef_set0 + AFCOEF_OFFSET;
-	}
-
-	/* set AFCOEF0010 Register */
-	isp_reg_writel(af_dev->config->iir_config.coeff_set0[10],
-		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF010);
-
-	/*Set IIR Filter1 Coefficients */
-
 	base_coef_set1 = ISPH3A_AFCOEF110;
 	for (index = 0; index <= 8; index += 2) {
-		coef &= ~COEF_MASK0;
-		coef |= af_dev->config->iir_config.coeff_set1[index];
-		coef &= ~COEF_MASK1;
-		coef |= af_dev->config->iir_config.coeff_set1[index + 1] <<
-			AF_COEF_SHIFT;
-		isp_reg_writel(coef, OMAP3_ISP_IOMEM_H3A, base_coef_set1);
+		/*Set IIR Filter0 Coefficients */
+		coef = 0;
+		coef |= isp_af->config.iir_config.coeff_set0[index] &
+			COEF_MASK0;
+		coef |= (isp_af->config.iir_config.coeff_set0[index + 1] <<
+			AF_COEF_SHIFT) & COEF_MASK1;
+		isp_reg_writel(dev, coef, OMAP3_ISP_IOMEM_H3A,
+			       base_coef_set0);
+		base_coef_set0 += AFCOEF_OFFSET;
 
-		base_coef_set1 = base_coef_set1 + AFCOEF_OFFSET;
+		/*Set IIR Filter1 Coefficients */
+		coef = 0;
+		coef |= isp_af->config.iir_config.coeff_set1[index] &
+			COEF_MASK0;
+		coef |= (isp_af->config.iir_config.coeff_set1[index + 1] <<
+			AF_COEF_SHIFT) & COEF_MASK1;
+		isp_reg_writel(dev, coef, OMAP3_ISP_IOMEM_H3A,
+			       base_coef_set1);
+		base_coef_set1 += AFCOEF_OFFSET;
 	}
-	isp_reg_writel(af_dev->config->iir_config.coeff_set1[10],
+	/* set AFCOEF0010 Register */
+	isp_reg_writel(dev, isp_af->config.iir_config.coeff_set0[10],
+		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF0010);
+	/* set AFCOEF1010 Register */
+	isp_reg_writel(dev, isp_af->config.iir_config.coeff_set1[10],
 		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AFCOEF1010);
 
-	return 0;
+	/* PCR Register */
+	/* Set Accumulator Mode */
+	if (isp_af->config.mode == ACCUMULATOR_PEAK)
+		pcr |= FVMODE;
+	/* Set A-law */
+	if (isp_af->config.alaw_enable == H3A_AF_ALAW_ENABLE)
+		pcr |= AF_ALAW_EN;
+	/* Set RGB Position */
+	pcr |= isp_af->config.rgb_pos << AF_RGBPOS_SHIFT;
+	/* HMF Configurations */
+	if (isp_af->config.hmf_config.enable == H3A_AF_HMF_ENABLE) {
+		/* Enable HMF */
+		pcr |= AF_MED_EN;
+		/* Set Median Threshold */
+		pcr |= isp_af->config.hmf_config.threshold << AF_MED_TH_SHIFT;
+	}
+	/* Set PCR Register */
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+		       ~AF_PCR_MASK, pcr);
+
+	isp_af->update = 0;
+
+	spin_unlock_irqrestore(isp_af->lock, irqflags);
 }
 
-/* Function to set address */
-void isp_af_set_address(unsigned long address)
+/* Update local parameters */
+static void isp_af_update_params(struct isp_af_device *isp_af,
+				 struct af_configuration *afconfig)
 {
-	isp_reg_writel(address, OMAP3_ISP_IOMEM_H3A, ISPH3A_AFBUFST);
-}
+	int update = 0;
+	int index;
 
-static int isp_af_stats_available(struct isp_af_data *afdata)
-{
-	int i, ret;
-	unsigned long irqflags;
+	/* alaw */
+	if (isp_af->config.alaw_enable != afconfig->alaw_enable) {
+		update = 1;
+		goto out;
+	}
 
-	spin_lock_irqsave(&afstat.buffer_lock, irqflags);
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		DPRINTK_ISP_AF("Checking Stats buff[%d] (%d) for %d\n",
-			       i, afstat.af_buff[i].frame_num,
-			       afdata->frame_number);
-		if (afdata->frame_number == afstat.af_buff[i].frame_num
-		    && afstat.af_buff[i].frame_num != active_buff->frame_num) {
-			afstat.af_buff[i].locked = 1;
-			spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
-			isp_af_update_req_buffer(&afstat.af_buff[i]);
-			afstat.af_buff[i].frame_num = 0;
-			ret = copy_to_user((void *)afdata->af_statistics_buf,
-					   (void *)afstat.af_buff[i].virt_addr,
-					   afstat.curr_cfg_buf_size);
-			if (ret) {
-				printk(KERN_ERR "Failed copy_to_user for "
-				       "H3A stats buff, %d\n", ret);
-			}
-			afdata->xtrastats.ts = afstat.af_buff[i].xtrastats.ts;
-			afdata->xtrastats.field_count =
-				afstat.af_buff[i].xtrastats.field_count;
-			return 0;
+	/* hmf */
+	if (isp_af->config.hmf_config.enable != afconfig->hmf_config.enable) {
+		update = 1;
+		goto out;
+	}
+	if (isp_af->config.hmf_config.threshold !=
+					afconfig->hmf_config.threshold) {
+		update = 1;
+		goto out;
+	}
+
+	/* rgbpos */
+	if (isp_af->config.rgb_pos != afconfig->rgb_pos) {
+		update = 1;
+		goto out;
+	}
+
+	/* iir */
+	if (isp_af->config.iir_config.hz_start_pos !=
+					afconfig->iir_config.hz_start_pos) {
+		update = 1;
+		goto out;
+	}
+	for (index = 0; index < AF_NUMBER_OF_COEF; index++) {
+		if (isp_af->config.iir_config.coeff_set0[index] !=
+				afconfig->iir_config.coeff_set0[index]) {
+			update = 1;
+			goto out;
+		}
+		if (isp_af->config.iir_config.coeff_set1[index] !=
+				afconfig->iir_config.coeff_set1[index]) {
+			update = 1;
+			goto out;
 		}
 	}
-	spin_unlock_irqrestore(&afstat.buffer_lock, irqflags);
-	/* Stats unavailable */
 
-	return -1;
-}
+	/* paxel */
+	if ((isp_af->config.paxel_config.width !=
+				afconfig->paxel_config.width) ||
+	    (isp_af->config.paxel_config.height !=
+				afconfig->paxel_config.height) ||
+	    (isp_af->config.paxel_config.hz_start !=
+				afconfig->paxel_config.hz_start) ||
+	    (isp_af->config.paxel_config.vt_start !=
+				afconfig->paxel_config.vt_start) ||
+	    (isp_af->config.paxel_config.hz_cnt !=
+				afconfig->paxel_config.hz_cnt) ||
+	    (isp_af->config.paxel_config.line_incr !=
+				afconfig->paxel_config.line_incr)) {
+		update = 1;
+		goto out;
+	}
 
-void isp_af_notify(int notify)
-{
-	camnotify = notify;
-	if (camnotify && afstat.initialized) {
-		printk(KERN_DEBUG "Warning Camera Off \n");
-		afstat.stats_req = 0;
-		afstat.stats_done = 1;
-		wake_up_interruptible(&afstat.stats_wait);
+	/* af_mode */
+	if (isp_af->config.mode != afconfig->mode) {
+		update = 1;
+		goto out;
+	}
+
+	isp_af->config.af_config = afconfig->af_config;
+
+out:
+	if (update) {
+		memcpy(&isp_af->config, afconfig, sizeof(*afconfig));
+		isp_af->update = 1;
 	}
 }
-EXPORT_SYMBOL(isp_af_notify);
+
+void isp_af_try_enable(struct isp_af_device *isp_af)
+{
+	unsigned long irqflags;
+
+	if (!isp_af->config.af_config)
+		return;
+
+	spin_lock_irqsave(isp_af->lock, irqflags);
+	if (unlikely(!isp_af->enabled && isp_af->config.af_config)) {
+		isp_af->update = 1;
+		isp_af->buf_next = ispstat_buf_next(&isp_af->stat);
+		spin_unlock_irqrestore(isp_af->lock, irqflags);
+		isp_af_config_registers(isp_af);
+		isp_af_enable(isp_af, 1);
+	} else
+		spin_unlock_irqrestore(isp_af->lock, irqflags);
+}
+
+/* Function to perform hardware set up */
+int isp_af_config(struct isp_af_device *isp_af,
+		  struct af_configuration *afconfig)
+{
+	struct device *dev = to_device(isp_af);
+	int result;
+	int buf_size;
+	unsigned long irqflags;
+
+	if (!afconfig) {
+		dev_dbg(dev, "af: Null argument in configuration.\n");
+		return -EINVAL;
+	}
+
+	/* Check Parameters */
+	spin_lock_irqsave(isp_af->lock, irqflags);
+	result = isp_af_check_params(isp_af, afconfig);
+	spin_unlock_irqrestore(isp_af->lock, irqflags);
+	if (result) {
+		dev_dbg(dev, "af: wrong configure params received.\n");
+		return result;
+	}
+
+	/* Compute buffer size */
+	buf_size = (afconfig->paxel_config.hz_cnt + 1) *
+		   (afconfig->paxel_config.vt_cnt + 1) * AF_PAXEL_SIZE;
+
+	result = ispstat_bufs_alloc(&isp_af->stat, buf_size, 0);
+	if (result)
+		return result;
+
+	spin_lock_irqsave(isp_af->lock, irqflags);
+	isp_af_update_params(isp_af, afconfig);
+	spin_unlock_irqrestore(isp_af->lock, irqflags);
+
+	/* Success */
+	return 0;
+}
+EXPORT_SYMBOL(isp_af_config);
+
 /*
  * This API allows the user to update White Balance gains, as well as
  * exposure time and analog gain. It is also used to request frame
  * statistics.
  */
-int isp_af_request_statistics(struct isp_af_data *afdata)
+int isp_af_request_statistics(struct isp_af_device *isp_af,
+			      struct isp_af_data *afdata)
 {
-	int ret = 0;
-	u16 frame_diff = 0;
-	u16 frame_cnt = afstat.frame_count;
-	wait_queue_t wqt;
+	struct device *dev = to_device(isp_af);
+	struct ispstat_buffer *buf;
 
-	if (!af_dev_configptr->config->af_config) {
-		printk(KERN_ERR "AF engine not enabled\n");
+	if (!isp_af->config.af_config) {
+		dev_dbg(dev, "af: statistics requested while af engine"
+			     " is not configured\n");
 		return -EINVAL;
 	}
 
-	if (!(afdata->update & REQUEST_STATISTICS)) {
-		afdata->af_statistics_buf = NULL;
-		goto out;
+	if (afdata->update & REQUEST_STATISTICS) {
+		buf = ispstat_buf_get(&isp_af->stat,
+			      (void *)afdata->af_statistics_buf,
+			      afdata->frame_number);
+		if (IS_ERR(buf))
+			return PTR_ERR(buf);
+
+		afdata->xtrastats.ts = buf->ts;
+		afdata->config_counter = buf->config_counter;
+		afdata->frame_number = buf->frame_number;
+
+		ispstat_buf_release(&isp_af->stat);
 	}
 
-	isp_af_unlock_buffers();
-	/* Stats available? */
-	DPRINTK_ISP_AF("Stats available?\n");
-	ret = isp_af_stats_available(afdata);
-	if (!ret)
-		goto out;
-
-	/* Stats in near future? */
-	DPRINTK_ISP_AF("Stats in near future?\n");
-	if (afdata->frame_number > frame_cnt)
-		frame_diff = afdata->frame_number - frame_cnt;
-	else if (afdata->frame_number < frame_cnt) {
-		if (frame_cnt > MAX_FRAME_COUNT - MAX_FUTURE_FRAMES
-		    && afdata->frame_number < MAX_FRAME_COUNT) {
-			frame_diff = afdata->frame_number + MAX_FRAME_COUNT -
-				frame_cnt;
-		} else {
-			/* Frame unavailable */
-			frame_diff = MAX_FUTURE_FRAMES + 1;
-		}
-	}
-
-	if (frame_diff > MAX_FUTURE_FRAMES) {
-		printk(KERN_ERR "Invalid frame requested, returning current"
-		       " frame stats\n");
-		afdata->frame_number = frame_cnt;
-	}
-	if (!camnotify) {
-		/* Block until frame in near future completes */
-		afstat.frame_req = afdata->frame_number;
-		afstat.stats_req = 1;
-		afstat.stats_done = 0;
-		init_waitqueue_entry(&wqt, current);
-		ret = wait_event_interruptible(afstat.stats_wait,
-					       afstat.stats_done == 1);
-		if (ret < 0) {
-			afdata->af_statistics_buf = NULL;
-			return ret;
-		}
-		DPRINTK_ISP_AF("ISP AF request status interrupt raised\n");
-
-		/* Stats now available */
-		ret = isp_af_stats_available(afdata);
-		if (ret) {
-			printk(KERN_ERR "After waiting for stats, stats not"
-			       " available!!\n");
-			afdata->af_statistics_buf = NULL;
-		}
-	}
-
-out:
-	afdata->curr_frame = afstat.frame_count;
+	afdata->curr_frame = isp_af->stat.frame_number;
 
 	return 0;
 }
 EXPORT_SYMBOL(isp_af_request_statistics);
 
-/* This function will handle the H3A interrupt. */
-static void isp_af_isr(unsigned long status, isp_vbq_callback_ptr arg1,
-		       void *arg2)
+/* This function will handle the AF buffer. */
+int isp_af_buf_process(struct isp_af_device *isp_af)
 {
-	u16 frame_align;
+	if (likely(!isp_af->buf_err && isp_af->config.af_config)) {
+		int ret;
 
-	if ((H3A_AF_DONE & status) != H3A_AF_DONE)
-		return;
-
-	/* timestamp stats buffer */
-	do_gettimeofday(&active_buff->xtrastats.ts);
-	active_buff->config_counter = atomic_read(&afstat.config_counter);
-
-	/* Exchange buffers */
-	active_buff = active_buff->next;
-	if (active_buff->locked == 1)
-		active_buff = active_buff->next;
-	isp_af_set_address(active_buff->ispmmu_addr);
-
-	/* Update frame counter */
-	afstat.frame_count++;
-	frame_align = afstat.frame_count;
-	if (afstat.frame_count > MAX_FRAME_COUNT) {
-		afstat.frame_count = 1;
-		frame_align++;
-	}
-	active_buff->frame_num = afstat.frame_count;
-
-	/* Future Stats requested? */
-	if (afstat.stats_req) {
-		/* Is the frame we want already done? */
-		if (frame_align >= afstat.frame_req + 1) {
-			afstat.stats_req = 0;
-			afstat.stats_done = 1;
-			wake_up_interruptible(&afstat.stats_wait);
-		}
+		ret = ispstat_buf_queue(&isp_af->stat);
+		isp_af->buf_next = ispstat_buf_next(&isp_af->stat);
+		return ret;
+	} else {
+		isp_af->buf_err = 0;
+		return -1;
 	}
 }
 
-int __isp_af_enable(int enable)
+static void __isp_af_enable(struct isp_af_device *isp_af, int enable)
 {
+	struct device *dev = to_device(isp_af);
 	unsigned int pcr;
 
-	pcr = isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
+	pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
 
 	/* Set AF_EN bit in PCR Register */
-	if (enable) {
-		if (isp_set_callback(CBK_H3A_AF_DONE, isp_af_isr,
-				     (void *)NULL, (void *)NULL)) {
-			printk(KERN_ERR "No callback for AF\n");
-			return -EINVAL;
-		}
-
+	if (enable)
 		pcr |= AF_EN;
-	} else {
-		isp_unset_callback(CBK_H3A_AF_DONE);
+	else
 		pcr &= ~AF_EN;
-	}
-	isp_reg_writel(pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
-	return 0;
+
+	isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
 }
 
 /* Function to Enable/Disable AF Engine */
-int isp_af_enable(int enable)
+void isp_af_enable(struct isp_af_device *isp_af, int enable)
 {
-	int rval;
+	unsigned long irqflags;
 
-	rval = __isp_af_enable(enable);
+	spin_lock_irqsave(isp_af->lock, irqflags);
 
-	if (!rval)
-		afstat.pm_state = enable;
+	if (!isp_af->config.af_config && enable) {
+		spin_unlock_irqrestore(isp_af->lock, irqflags);
+		return;
+	}
 
-	return rval;
+	__isp_af_enable(isp_af, enable);
+	isp_af->enabled = enable;
+
+	spin_unlock_irqrestore(isp_af->lock, irqflags);
 }
 
 /* Function to Suspend AF Engine */
-void isp_af_suspend(void)
+void isp_af_suspend(struct isp_af_device *isp_af)
 {
-	if (afstat.pm_state)
-		__isp_af_enable(0);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(isp_af->lock, irqflags);
+	if (isp_af->enabled)
+		__isp_af_enable(isp_af, 0);
+	spin_unlock_irqrestore(isp_af->lock, irqflags);
 }
 
 /* Function to Resume AF Engine */
-void isp_af_resume(void)
+void isp_af_resume(struct isp_af_device *isp_af)
 {
-	if (afstat.pm_state)
-		__isp_af_enable(1);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(isp_af->lock, irqflags);
+	if (isp_af->enabled)
+		__isp_af_enable(isp_af, 1);
+	spin_unlock_irqrestore(isp_af->lock, irqflags);
 }
 
-int isp_af_busy(void)
+int isp_af_busy(struct isp_af_device *isp_af)
 {
-	return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+	struct device *dev = to_device(isp_af);
+
+	return isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
 		& ISPH3A_PCR_BUSYAF;
 }
 
 /* Function to register the AF character device driver. */
-int __init isp_af_init(void)
+int __init isp_af_init(struct device *dev)
 {
-	/*allocate memory for device structure and initialize it with 0 */
-	af_dev_configptr = kzalloc(sizeof(struct af_device), GFP_KERNEL);
-	if (!af_dev_configptr)
-		goto err_nomem1;
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_af_device *isp_af = &isp->isp_af;
 
-	active_buff = NULL;
-
-	af_dev_configptr->config = (struct af_configuration *)
-		kzalloc(sizeof(struct af_configuration), GFP_KERNEL);
-
-	if (af_dev_configptr->config == NULL)
-		goto err_nomem2;
-
-	memset(&afstat, 0, sizeof(afstat));
-
-	init_waitqueue_head(&afstat.stats_wait);
-	spin_lock_init(&afstat.buffer_lock);
+	isp_af->lock = &isp->h3a_lock;
+	ispstat_init(dev, "AF", &isp_af->stat, H3A_MAX_BUFF, MAX_FRAME_COUNT);
 
 	return 0;
-
-err_nomem2:
-	kfree(af_dev_configptr);
-err_nomem1:
-	printk(KERN_ERR "Error: kmalloc fail");
-	return -ENOMEM;
 }
 
-void isp_af_exit(void)
+void isp_af_exit(struct device *dev)
 {
-	int i;
+	struct isp_device *isp = dev_get_drvdata(dev);
 
 	/* Free buffers */
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		if (!afstat.af_buff[i].phy_addr)
-			continue;
-
-		ispmmu_kunmap(afstat.af_buff[i].ispmmu_addr);
-
-		dma_free_coherent(NULL,
-				  afstat.min_buf_size,
-				  (void *)afstat.af_buff[i].virt_addr,
-				  (dma_addr_t)afstat.af_buff[i].phy_addr);
-	}
-	kfree(af_dev_configptr->config);
-	kfree(af_dev_configptr);
-
-	memset(&afstat, 0, sizeof(afstat));
-
-	af_major = -1;
+	ispstat_free(&isp->isp_af.stat);
 }
diff --git a/drivers/media/video/isp/isp_af.h b/drivers/media/video/isp/isp_af.h
index ee2b89f..fbdafdb 100644
--- a/drivers/media/video/isp/isp_af.h
+++ b/drivers/media/video/isp/isp_af.h
@@ -24,6 +24,9 @@
 
 #include <mach/isp_user.h>
 
+#include "isph3a.h"
+#include "ispstat.h"
+
 #define AF_MAJOR_NUMBER			0
 #define ISPAF_NAME			"OMAPISP_AF"
 #define AF_NR_DEVS			1
@@ -64,6 +67,8 @@
 #define AF_MED_EN			(1 << 2)
 #define AF_ALAW_EN			(1 << 1)
 #define AF_EN				(1 << 0)
+#define AF_PCR_MASK			(FVMODE | RGBPOS | MED_TH | \
+					 AF_MED_EN | AF_ALAW_EN)
 
 /*
  * AFPAX1 fields
@@ -104,22 +109,29 @@
 #define AF_UPDATEXS_FIELDCOUNT	(1 << 1)
 #define AF_UPDATEXS_LENSPOS		(1 << 2)
 
-/* Structure for device of AF Engine */
-struct af_device {
-	struct af_configuration *config; /*Device configuration structure */
-	int size_paxel;		/*Paxel size in bytes */
+/**
+ * struct isp_af_status - AF status.
+ * @update: 1 - Update registers.
+ */
+struct isp_af_device {
+	u8 update;
+	u8 buf_err;
+	int enabled;
+	struct ispstat stat;
+	struct af_configuration config; /*Device configuration structure */
+	struct ispstat_buffer *buf_next;
+	spinlock_t *lock;
 };
 
-int isp_af_check_paxel(void);
-int isp_af_check_iir(void);
-int isp_af_register_setup(struct af_device *af_dev);
-int isp_af_enable(int);
-void isp_af_suspend(void);
-void isp_af_resume(void);
-int isp_af_busy(void);
-void isp_af_notify(int notify);
-int isp_af_request_statistics(struct isp_af_data *afdata);
-int isp_af_configure(struct af_configuration *afconfig);
-void isp_af_set_address(unsigned long);
-void isp_af_setxtrastats(struct isp_af_xtrastats *xtrastats, u8 updateflag);
+int isp_af_buf_process(struct isp_af_device *isp_af);
+void isp_af_enable(struct isp_af_device *, int);
+void isp_af_try_enable(struct isp_af_device *isp_af);
+void isp_af_suspend(struct isp_af_device *);
+void isp_af_resume(struct isp_af_device *);
+int isp_af_busy(struct isp_af_device *);
+void isp_af_config_registers(struct isp_af_device *isp_af);
+int isp_af_request_statistics(struct isp_af_device *,
+			      struct isp_af_data *afdata);
+int isp_af_config(struct isp_af_device *, struct af_configuration *afconfig);
+
 #endif	/* OMAP_ISP_AF_H */
diff --git a/drivers/media/video/isp/ispccdc.c b/drivers/media/video/isp/ispccdc.c
index 557db28..bde91ab 100644
--- a/drivers/media/video/isp/ispccdc.c
+++ b/drivers/media/video/isp/ispccdc.c
@@ -22,70 +22,15 @@
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/delay.h>
+#include <linux/device.h>
 
 #include "isp.h"
 #include "ispreg.h"
 #include "ispccdc.h"
-#include "ispmmu.h"
 
 #define LSC_TABLE_INIT_SIZE	50052
-
-static u32 *fpc_table_add;
-static unsigned long fpc_table_add_m;
-
-/**
- * struct isp_ccdc - Structure for the CCDC module to store its own information
- * @ccdc_inuse: Flag to determine if CCDC has been reserved or not (0 or 1).
- * @ccdcout_w: CCDC output width.
- * @ccdcout_h: CCDC output height.
- * @ccdcin_w: CCDC input width.
- * @ccdcin_h: CCDC input height.
- * @ccdcin_woffset: CCDC input horizontal offset.
- * @ccdcin_hoffset: CCDC input vertical offset.
- * @crop_w: Crop width.
- * @crop_h: Crop weight.
- * @ccdc_inpfmt: CCDC input format.
- * @ccdc_outfmt: CCDC output format.
- * @vpout_en: Video port output enable.
- * @wen: Data write enable.
- * @exwen: External data write enable.
- * @refmt_en: Reformatter enable.
- * @ccdcslave: CCDC slave mode enable.
- * @syncif_ipmod: Image
- * @obclamp_en: Data input format.
- * @mutexlock: Mutex used to get access to the CCDC.
- */
-static struct isp_ccdc {
-	u8 ccdc_inuse;
-	u32 ccdcout_w;
-	u32 ccdcout_h;
-	u32 ccdcin_w;
-	u32 ccdcin_h;
-	u32 ccdcin_woffset;
-	u32 ccdcin_hoffset;
-	u32 crop_w;
-	u32 crop_h;
-	u8 ccdc_inpfmt;
-	u8 ccdc_outfmt;
-	u8 vpout_en;
-	u8 wen;
-	u8 exwen;
-	u8 refmt_en;
-	u8 ccdcslave;
-	u8 syncif_ipmod;
-	u8 obclamp_en;
-	u8 pm_state;
-	u8 lsc_enable;
-	int lsc_state;
-	struct mutex mutexlock; /* For checking/modifying ccdc_inuse */
-	u32 wenlog;
-} ispccdc_obj;
-
-static struct ispccdc_lsc_config lsc_config;
-static u8 *lsc_gain_table;
-static unsigned long lsc_ispmmu_addr;
-static int lsc_initialized;
-static u8 *lsc_gain_table_tmp;
+#define PTR_FREE		((u32)(-ENOMEM))
 
 /* Structure for saving/restoring CCDC module registers*/
 static struct isp_reg ispccdc_reg_list[] = {
@@ -103,8 +48,8 @@
 	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB, 0},
 	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN, 0},
 	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP, 0},
-	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, 0},
 	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR, 0},
+	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC, 0},
 	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VDINT, 0},
 	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW, 0},
 	{OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF, 0},
@@ -133,420 +78,617 @@
 };
 
 /**
- * omap34xx_isp_ccdc_config - Sets CCDC configuration from userspace
- * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ * ispccdc_print_status - Print current CCDC Module register values.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to current ISP pipeline structure.
  *
- * Returns 0 if successful, -EINVAL if the pointer to the configuration
- * structure is null, or the copy_from_user function fails to copy user space
- * memory to kernel space memory.
+ * Also prints other debug information stored in the CCDC module.
  **/
-int omap34xx_isp_ccdc_config(void *userspace_add)
+static void ispccdc_print_status(struct isp_ccdc_device *isp_ccdc,
+				 struct isp_pipeline *pipe)
 {
-	struct ispccdc_bclamp bclamp_t;
-	struct ispccdc_blcomp blcomp_t;
-	struct ispccdc_fpc fpc_t;
-	struct ispccdc_culling cull_t;
-	struct ispccdc_update_config *ccdc_struct;
+#ifdef OMAP_ISPCCDC_DEBUG
+	struct device *dev = to_device(isp_ccdc);
+#endif
 
-	if (userspace_add == NULL)
-		return -EINVAL;
+	if (!is_ispccdc_debug_enabled())
+		return;
 
-	ccdc_struct = userspace_add;
+	DPRINTK_ISPCCDC("Module in use =%d\n", isp_ccdc->ccdc_inuse);
+	DPRINTK_ISPCCDC("Accepted CCDC Input (width = %d,Height = %d)\n",
+			pipe->ccdc_in_w,
+			pipe->ccdc_in_h);
+	DPRINTK_ISPCCDC("Accepted CCDC Output (width = %d,Height = %d)\n",
+			pipe->ccdc_out_w,
+			pipe->ccdc_out_h);
+	DPRINTK_ISPCCDC("###CCDC PCR=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_PCR));
+	DPRINTK_ISPCCDC("ISP_CTRL =0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_CTRL));
+	switch (pipe->ccdc_in) {
+	case CCDC_RAW_GRBG:
+	case CCDC_RAW_RGGB:
+	case CCDC_RAW_BGGR:
+	case CCDC_RAW_GBRG:
+		DPRINTK_ISPCCDC("ccdc input format is CCDC_RAW\n");
+		break;
+	case CCDC_YUV_SYNC:
+		DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_SYNC\n");
+		break;
+	case CCDC_YUV_BT:
+		DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_BT\n");
+		break;
+	default:
+		break;
+	}
 
-	if (ISP_ABS_CCDC_ALAW & ccdc_struct->flag) {
-		if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
-			ispccdc_config_alaw(ccdc_struct->alawip);
-		ispccdc_enable_alaw(1);
-	} else if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
-		ispccdc_enable_alaw(0);
+	switch (pipe->ccdc_out) {
+	case CCDC_OTHERS_VP:
+		DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_VP\n");
+		break;
+	case CCDC_OTHERS_MEM:
+		DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_MEM\n");
+		break;
+	case CCDC_YUV_RSZ:
+		DPRINTK_ISPCCDC("ccdc output format is CCDC_YUV_RSZ\n");
+		break;
+	default:
+		break;
+	}
 
-	if (ISP_ABS_CCDC_LPF & ccdc_struct->flag)
-		ispccdc_enable_lpf(1);
-	else
-		ispccdc_enable_lpf(0);
+	DPRINTK_ISPCCDC("###ISP_CTRL in ccdc =0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_CTRL));
+	DPRINTK_ISPCCDC("###ISP_IRQ0ENABLE in ccdc =0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_IRQ0ENABLE));
+	DPRINTK_ISPCCDC("###ISP_IRQ0STATUS in ccdc =0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_IRQ0STATUS));
+	DPRINTK_ISPCCDC("###CCDC SYN_MODE=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_SYN_MODE));
+	DPRINTK_ISPCCDC("###CCDC HORZ_INFO=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_HORZ_INFO));
+	DPRINTK_ISPCCDC("###CCDC VERT_START=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_VERT_START));
+	DPRINTK_ISPCCDC("###CCDC VERT_LINES=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_VERT_LINES));
+	DPRINTK_ISPCCDC("###CCDC CULLING=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_CULLING));
+	DPRINTK_ISPCCDC("###CCDC HSIZE_OFF=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_HSIZE_OFF));
+	DPRINTK_ISPCCDC("###CCDC SDOFST=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_SDOFST));
+	DPRINTK_ISPCCDC("###CCDC SDR_ADDR=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_SDR_ADDR));
+	DPRINTK_ISPCCDC("###CCDC CLAMP=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_CLAMP));
+	DPRINTK_ISPCCDC("###CCDC COLPTN=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_COLPTN));
+	DPRINTK_ISPCCDC("###CCDC CFG=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_CFG));
+	DPRINTK_ISPCCDC("###CCDC VP_OUT=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_VP_OUT));
+	DPRINTK_ISPCCDC("###CCDC_SDR_ADDR= 0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_SDR_ADDR));
+	DPRINTK_ISPCCDC("###CCDC FMTCFG=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_FMTCFG));
+	DPRINTK_ISPCCDC("###CCDC FMT_HORZ=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_FMT_HORZ));
+	DPRINTK_ISPCCDC("###CCDC FMT_VERT=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_FMT_VERT));
+	DPRINTK_ISPCCDC("###CCDC LSC_CONFIG=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_LSC_CONFIG));
+	DPRINTK_ISPCCDC("###CCDC LSC_INIT=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_LSC_INITIAL));
+	DPRINTK_ISPCCDC("###CCDC LSC_TABLE BASE=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_LSC_TABLE_BASE));
+	DPRINTK_ISPCCDC("###CCDC LSC TABLE OFFSET=0x%x\n",
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_LSC_TABLE_OFFSET));
+}
 
-	if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->flag) {
-		if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
-			if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
-					   ccdc_struct->bclamp,
-					   sizeof(struct ispccdc_bclamp)))
-				goto copy_from_user_err;
+/**
+ * ispccdc_config_black_clamp - Configures the clamp parameters in CCDC.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @bclamp: Structure containing the optical black average gain, optical black
+ *          sample length, sample lines, and the start pixel position of the
+ *          samples w.r.t the HS pulse.
+ *
+ * Configures the clamp parameters in CCDC. Either if its being used the
+ * optical black clamp, or the digital clamp. If its a digital clamp, then
+ * assures to put a valid DC substraction level.
+ *
+ * Returns always 0 when completed.
+ **/
+static int ispccdc_config_black_clamp(struct isp_ccdc_device *isp_ccdc,
+				      struct ispccdc_bclamp bclamp)
+{
+	struct device *dev = to_device(isp_ccdc);
+	u32 bclamp_val = 0;
 
-			ispccdc_enable_black_clamp(1);
-			ispccdc_config_black_clamp(bclamp_t);
-		} else
-			ispccdc_enable_black_clamp(1);
+	if (isp_ccdc->obclamp_en) {
+		bclamp_val |= bclamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
+		bclamp_val |= bclamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
+		bclamp_val |= bclamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
+		bclamp_val |= bclamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
+		isp_reg_writel(dev, bclamp_val,
+			       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP);
 	} else {
-		if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
-			if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
-					   ccdc_struct->bclamp,
-					   sizeof(struct ispccdc_bclamp)))
-				goto copy_from_user_err;
-
-			ispccdc_enable_black_clamp(0);
-			ispccdc_config_black_clamp(bclamp_t);
-		}
+		if (omap_rev() < OMAP3430_REV_ES2_0)
+			if (isp_ccdc->syncif_ipmod == YUV16 ||
+			    isp_ccdc->syncif_ipmod == YUV8 ||
+			    isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+					  ISPCCDC_REC656IF) &
+			    ISPCCDC_REC656IF_R656ON)
+				bclamp.dcsubval = 0;
+		isp_reg_writel(dev, bclamp.dcsubval,
+			       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_DCSUB);
 	}
-
-	if (ISP_ABS_CCDC_BCOMP & ccdc_struct->update) {
-		if (copy_from_user(&blcomp_t, (struct ispccdc_blcomp *)
-				   ccdc_struct->blcomp,
-				   sizeof(blcomp_t)))
-			goto copy_from_user_err;
-
-		ispccdc_config_black_comp(blcomp_t);
-	}
-
-	if (ISP_ABS_CCDC_FPC & ccdc_struct->flag) {
-		if (ISP_ABS_CCDC_FPC & ccdc_struct->update) {
-			if (copy_from_user(&fpc_t, (struct ispccdc_fpc *)
-					   ccdc_struct->fpc,
-					   sizeof(fpc_t)))
-				goto copy_from_user_err;
-			fpc_table_add = kmalloc(64 + fpc_t.fpnum * 4,
-						GFP_KERNEL | GFP_DMA);
-			if (!fpc_table_add) {
-				printk(KERN_ERR "Cannot allocate memory for"
-				       " FPC table");
-				return -ENOMEM;
-			}
-			while (((unsigned long)fpc_table_add & 0xFFFFFFC0)
-			       != (unsigned long)fpc_table_add)
-				fpc_table_add++;
-
-			fpc_table_add_m = ispmmu_kmap(virt_to_phys
-						      (fpc_table_add),
-						      fpc_t.fpnum * 4);
-
-			if (copy_from_user(fpc_table_add, (u32 *)fpc_t.fpcaddr,
-					   fpc_t.fpnum * 4))
-				goto copy_from_user_err;
-
-			fpc_t.fpcaddr = fpc_table_add_m;
-			ispccdc_config_fpc(fpc_t);
-		}
-		ispccdc_enable_fpc(1);
-	} else if (ISP_ABS_CCDC_FPC & ccdc_struct->update)
-		ispccdc_enable_fpc(0);
-
-	if (ISP_ABS_CCDC_CULL & ccdc_struct->update) {
-		if (copy_from_user(&cull_t, (struct ispccdc_culling *)
-				   ccdc_struct->cull,
-				   sizeof(cull_t)))
-			goto copy_from_user_err;
-		ispccdc_config_culling(cull_t);
-	}
-
-	if (is_isplsc_activated()) {
-		if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->flag) {
-			if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) {
-				if (copy_from_user(
-					    &lsc_config,
-					    (struct ispccdc_lsc_config *)
-					    ccdc_struct->lsc_cfg,
-					    sizeof(struct ispccdc_lsc_config)))
-					goto copy_from_user_err;
-				ispccdc_config_lsc(&lsc_config);
-			}
-			ispccdc_enable_lsc(1);
-		} else if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) {
-			ispccdc_enable_lsc(0);
-		}
-		if (ISP_ABS_TBL_LSC & ccdc_struct->update) {
-			if (copy_from_user(lsc_gain_table,
-					   ccdc_struct->lsc, lsc_config.size))
-				goto copy_from_user_err;
-			ispccdc_load_lsc(lsc_gain_table, lsc_config.size);
-		}
-	}
-
-	if (ISP_ABS_CCDC_COLPTN & ccdc_struct->update)
-		ispccdc_config_imgattr(ccdc_struct->colptn);
-
-	return 0;
-
-copy_from_user_err:
-	printk(KERN_ERR "CCDC Config:Copy From User Error");
-	return -EINVAL ;
-}
-EXPORT_SYMBOL(omap34xx_isp_ccdc_config);
-
-/**
- * Set the value to be used for CCDC_CFG.WENLOG.
- *  w - Value of wenlog.
- */
-void ispccdc_set_wenlog(u32 wenlog)
-{
-	ispccdc_obj.wenlog = wenlog;
-}
-EXPORT_SYMBOL(ispccdc_set_wenlog);
-
-/**
- * ispccdc_set_crop_offset - Store the component order as component offset.
- * @raw_fmt: Input data component order.
- *
- * Turns the component order into a horizontal & vertical offset and store
- * offsets to be used later.
- **/
-void ispccdc_set_crop_offset(enum ispccdc_raw_fmt raw_fmt)
-{
-	switch (raw_fmt) {
-	case ISPCCDC_INPUT_FMT_GR_BG:
-		ispccdc_obj.ccdcin_woffset = 1;
-		ispccdc_obj.ccdcin_hoffset = 0;
-		break;
-	case ISPCCDC_INPUT_FMT_BG_GR:
-		ispccdc_obj.ccdcin_woffset = 1;
-		ispccdc_obj.ccdcin_hoffset = 1;
-		break;
-	case ISPCCDC_INPUT_FMT_RG_GB:
-		ispccdc_obj.ccdcin_woffset = 0;
-		ispccdc_obj.ccdcin_hoffset = 0;
-		break;
-	case ISPCCDC_INPUT_FMT_GB_RG:
-		ispccdc_obj.ccdcin_woffset = 0;
-		ispccdc_obj.ccdcin_hoffset = 1;
-		break;
-	}
-}
-EXPORT_SYMBOL(ispccdc_set_crop_offset);
-
-/**
- * ispccdc_request - Reserves the CCDC module.
- *
- * Reserves the CCDC module and assures that is used only once at a time.
- *
- * Returns 0 if successful, or -EBUSY if CCDC module is busy.
- **/
-int ispccdc_request(void)
-{
-	mutex_lock(&ispccdc_obj.mutexlock);
-	if (ispccdc_obj.ccdc_inuse) {
-		mutex_unlock(&ispccdc_obj.mutexlock);
-		DPRINTK_ISPCCDC("ISP_ERR : CCDC Module Busy\n");
-		return -EBUSY;
-	}
-
-	ispccdc_obj.ccdc_inuse = 1;
-	mutex_unlock(&ispccdc_obj.mutexlock);
-	isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_CCDC_RAM_EN |
-		   ISPCTRL_CCDC_CLK_EN |
-		   ISPCTRL_SBL_WR1_RAM_EN);
-	isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG, ISPCCDC_CFG_VDLC);
 	return 0;
 }
-EXPORT_SYMBOL(ispccdc_request);
 
 /**
- * ispccdc_free - Frees the CCDC module.
+ * ispccdc_enable_black_clamp - Enables/Disables the optical black clamp.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables optical black clamp, 1 Enables optical black clamp.
  *
- * Frees the CCDC module so it can be used by another process.
- *
- * Returns 0 if successful, or -EINVAL if module has been already freed.
+ * Enables or disables the optical black clamp. When disabled, the digital
+ * clamp operates.
  **/
-int ispccdc_free(void)
+static void ispccdc_enable_black_clamp(struct isp_ccdc_device *isp_ccdc,
+				       u8 enable)
 {
-	mutex_lock(&ispccdc_obj.mutexlock);
-	if (!ispccdc_obj.ccdc_inuse) {
-		mutex_unlock(&ispccdc_obj.mutexlock);
-		DPRINTK_ISPCCDC("ISP_ERR: CCDC Module already freed\n");
+	struct device *dev = to_device(isp_ccdc);
+
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
+		       ~ISPCCDC_CLAMP_CLAMPEN,
+		       enable ? ISPCCDC_CLAMP_CLAMPEN : 0);
+	isp_ccdc->obclamp_en = enable;
+}
+
+/**
+ * ispccdc_config_fpc - Configures the Faulty Pixel Correction parameters.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @fpc: Structure containing the number of faulty pixels corrected in the
+ *       frame, address of the FPC table.
+ *
+ * Returns 0 if successful, or -EINVAL if FPC Address is not on the 64 byte
+ * boundary.
+ **/
+static int ispccdc_config_fpc(struct isp_ccdc_device *isp_ccdc,
+			      struct ispccdc_fpc fpc)
+{
+	struct device *dev = to_device(isp_ccdc);
+	u32 fpc_val = 0;
+
+	fpc_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				ISPCCDC_FPC);
+
+	if ((fpc.fpcaddr & 0xFFFFFFC0) == fpc.fpcaddr) {
+		isp_reg_writel(dev, fpc_val & (~ISPCCDC_FPC_FPCEN),
+			       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+		isp_reg_writel(dev, fpc.fpcaddr,
+			       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR);
+	} else {
+		DPRINTK_ISPCCDC("FPC Address should be on 64byte boundary\n");
+		return -EINVAL;
+	}
+	isp_reg_writel(dev, fpc_val |
+		       (fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+	return 0;
+}
+
+/**
+ * ispccdc_enable_fpc - Enable Faulty Pixel Correction.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables FPC, 1 Enables FPC.
+ **/
+static void ispccdc_enable_fpc(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC,
+		       ~ISPCCDC_FPC_FPCEN,
+		       enable ? ISPCCDC_FPC_FPCEN : 0);
+}
+
+/**
+ * ispccdc_config_black_comp - Configure Black Level Compensation.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @blcomp: Structure containing the black level compensation value for RGrGbB
+ *          pixels. in 2's complement.
+ **/
+static void ispccdc_config_black_comp(struct isp_ccdc_device *isp_ccdc,
+				      struct ispccdc_blcomp blcomp)
+{
+	struct device *dev = to_device(isp_ccdc);
+	u32 blcomp_val = 0;
+
+	blcomp_val |= blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
+	blcomp_val |= blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
+	blcomp_val |= blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
+	blcomp_val |= blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
+
+	isp_reg_writel(dev, blcomp_val, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_BLKCMP);
+}
+
+/**
+ * ispccdc_config_vp - Configure the Video Port.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @vpcfg: Structure containing the Video Port input frequency, and the 10 bit
+ *         format.
+ **/
+static void ispccdc_config_vp(struct isp_ccdc_device *isp_ccdc,
+			      struct ispccdc_vp vpcfg)
+{
+	struct device *dev = to_device(isp_ccdc);
+	u32 fmtcfg_vp = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				      ISPCCDC_FMTCFG);
+
+	fmtcfg_vp &= ISPCCDC_FMTCFG_VPIN_MASK & ISPCCDC_FMTCFG_VPIF_FRQ_MASK;
+
+	switch (vpcfg.bitshift_sel) {
+	case BIT9_0:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
+		break;
+	case BIT10_1:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
+		break;
+	case BIT11_2:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
+		break;
+	case BIT12_3:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
+		break;
+	};
+	switch (vpcfg.freq_sel) {
+	case PIXCLKBY2:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY2;
+		break;
+	case PIXCLKBY3_5:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY3;
+		break;
+	case PIXCLKBY4_5:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY4;
+		break;
+	case PIXCLKBY5_5:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY5;
+		break;
+	case PIXCLKBY6_5:
+		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIF_FRQ_BY6;
+		break;
+	};
+	isp_reg_writel(dev, fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_FMTCFG);
+}
+
+/**
+ * ispccdc_enable_vp - Enable Video Port.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables VP, 1 Enables VP
+ *
+ * This is needed for outputting image to Preview, H3A and HIST ISP submodules.
+ **/
+static void ispccdc_enable_vp(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
+		       ~ISPCCDC_FMTCFG_VPEN,
+		       enable ? ISPCCDC_FMTCFG_VPEN : 0);
+}
+
+/**
+ * ispccdc_config_culling - Configure culling parameters.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @cull: Structure containing the vertical culling pattern, and horizontal
+ *        culling pattern for odd and even lines.
+ **/
+static void ispccdc_config_culling(struct isp_ccdc_device *isp_ccdc,
+				   struct ispccdc_culling cull)
+{
+	struct device *dev = to_device(isp_ccdc);
+	u32 culling_val = 0;
+
+	culling_val |= cull.v_pattern << ISPCCDC_CULLING_CULV_SHIFT;
+	culling_val |= cull.h_even << ISPCCDC_CULLING_CULHEVN_SHIFT;
+	culling_val |= cull.h_odd << ISPCCDC_CULLING_CULHODD_SHIFT;
+
+	isp_reg_writel(dev, culling_val, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_CULLING);
+}
+
+/**
+ * ispccdc_enable_lpf - Enable Low-Pass Filter (LPF).
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 Disables LPF, 1 Enables LPF
+ **/
+static void ispccdc_enable_lpf(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
+		       ~ISPCCDC_SYN_MODE_LPF,
+		       enable ? ISPCCDC_SYN_MODE_LPF : 0);
+}
+
+/**
+ * ispccdc_config_alaw - Configure the input width for A-law compression.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @ipwidth: Input width for A-law
+ **/
+static void ispccdc_config_alaw(struct isp_ccdc_device *isp_ccdc,
+				enum alaw_ipwidth ipwidth)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	isp_reg_writel(dev, ipwidth << ISPCCDC_ALAW_GWDI_SHIFT,
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
+}
+
+/**
+ * ispccdc_enable_alaw - Enable A-law compression.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @enable: 0 - Disables A-law, 1 - Enables A-law
+ **/
+static void ispccdc_enable_alaw(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW,
+		       ~ISPCCDC_ALAW_CCDTBL,
+		       enable ? ISPCCDC_ALAW_CCDTBL : 0);
+}
+
+/**
+ * ispccdc_config_imgattr - Configure sensor image specific attributes.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @colptn: Color pattern of the sensor.
+ **/
+static void ispccdc_config_imgattr(struct isp_ccdc_device *isp_ccdc, u32 colptn)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	isp_reg_writel(dev, colptn, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_COLPTN);
+}
+
+/**
+ * ispccdc_validate_config_lsc - Check that LSC configuration is valid.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @lsc_cfg: the LSC configuration to check.
+ * @pipe: if not NULL, verify the table size against CCDC input size.
+ *
+ * Returns 0 if the LSC configuration is valid, or -EINVAL if invalid.
+ **/
+static int ispccdc_validate_config_lsc(struct isp_ccdc_device *isp_ccdc,
+				       struct ispccdc_lsc_config *lsc_cfg)
+{
+	struct isp_device *isp = to_isp_device(isp_ccdc);
+	struct device *dev = to_device(isp_ccdc);
+	unsigned int paxel_width, paxel_height;
+	unsigned int paxel_shift_x, paxel_shift_y;
+	unsigned int min_width, min_height, min_size;
+	unsigned int input_width, input_height;
+
+	paxel_shift_x = lsc_cfg->gain_mode_m;
+	paxel_shift_y = lsc_cfg->gain_mode_n;
+
+	if ((paxel_shift_x < 2) || (paxel_shift_x > 6) ||
+	    (paxel_shift_y < 2) || (paxel_shift_y > 6)) {
+		dev_err(dev, "CCDC: LSC: Invalid paxel size\n");
 		return -EINVAL;
 	}
 
-	ispccdc_obj.ccdc_inuse = 0;
-	mutex_unlock(&ispccdc_obj.mutexlock);
-	isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
-		    ~(ISPCTRL_CCDC_CLK_EN |
-		      ISPCTRL_CCDC_RAM_EN |
-		      ISPCTRL_SBL_WR1_RAM_EN));
-	return 0;
-}
-EXPORT_SYMBOL(ispccdc_free);
-
-/**
- * ispccdc_free_lsc - Frees Lens Shading Compensation table
- *
- * Always returns 0.
- **/
-static int ispccdc_free_lsc(void)
-{
-	if (!lsc_ispmmu_addr)
-		return 0;
-
-	ispccdc_enable_lsc(0);
-	lsc_initialized = 0;
-	isp_reg_writel(0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
-	ispmmu_kunmap(lsc_ispmmu_addr);
-	kfree(lsc_gain_table);
-	return 0;
-}
-
-/**
- * ispccdc_allocate_lsc - Allocate space for Lens Shading Compensation table
- * @table_size: LSC gain table size.
- *
- * Returns 0 if successful, -ENOMEM of its no memory available, or -EINVAL if
- * table_size is zero.
- **/
-static int ispccdc_allocate_lsc(u32 table_size)
-{
-	if (table_size == 0)
+	if (lsc_cfg->offset & 3) {
+		dev_err(dev,
+			"CCDC: LSC: Offset must be a multiple of 4\n");
 		return -EINVAL;
-
-	if ((lsc_config.size >= table_size) && lsc_gain_table)
-		return 0;
-
-	ispccdc_free_lsc();
-
-	lsc_gain_table = kmalloc(table_size, GFP_KERNEL | GFP_DMA);
-
-	if (!lsc_gain_table) {
-		printk(KERN_ERR "Cannot allocate memory for gain tables \n");
-		return -ENOMEM;
 	}
 
-	lsc_ispmmu_addr = ispmmu_kmap(virt_to_phys(lsc_gain_table), table_size);
-	if (lsc_ispmmu_addr <= 0) {
-		printk(KERN_ERR "Cannot map memory for gain tables \n");
-		kfree(lsc_gain_table);
-		return -ENOMEM;
+	if ((lsc_cfg->initial_x & 1) || (lsc_cfg->initial_y & 1)) {
+		dev_err(dev,
+			"CCDC: LSC: initial_x and y must be even\n");
+		return -EINVAL;
 	}
 
+	input_width = isp->pipeline.ccdc_in_w;
+	input_height = isp->pipeline.ccdc_in_h;
+
+	/* Calculate minimum bytesize for validation */
+	paxel_width = 1 << paxel_shift_x;
+	min_width = ((input_width + lsc_cfg->initial_x + paxel_width - 1)
+		     >> paxel_shift_x) + 1;
+
+	paxel_height = 1 << paxel_shift_y;
+	min_height = ((input_height + lsc_cfg->initial_y + paxel_height - 1)
+		     >> paxel_shift_y) + 1;
+
+	min_size = 4 * min_width * min_height;
+	if (min_size > lsc_cfg->size) {
+		dev_err(dev, "CCDC: LSC: too small table\n");
+		return -EINVAL;
+	}
+	if (lsc_cfg->offset < (min_width * 4)) {
+		dev_err(dev, "CCDC: LSC: Offset is too small\n");
+		return -EINVAL;
+	}
+	if ((lsc_cfg->size / lsc_cfg->offset) < min_height) {
+		dev_err(dev, "CCDC: LSC: Wrong size/offset combination\n");
+		return -EINVAL;
+	}
 	return 0;
 }
 
 /**
- * ispccdc_program_lsc - Program Lens Shading Compensation table.
- * @table_size: LSC gain table size.
- *
- * Returns 0 if successful, or -EINVAL if there's no mapped address for the
- * table yet.
+ * ispccdc_program_lsc - Program Lens Shading Compensation table address.
+ * @isp_ccdc: Pointer to ISP CCDC device.
  **/
-static int ispccdc_program_lsc(void)
+static void ispccdc_program_lsc(struct isp_ccdc_device *isp_ccdc)
 {
-	if (!lsc_ispmmu_addr)
-		return -EINVAL;
+	struct device *dev = to_device(isp_ccdc);
 
-	if (lsc_initialized)
-		return 0;
-
-	isp_reg_writel(lsc_ispmmu_addr, OMAP3_ISP_IOMEM_CCDC,
-		       ISPCCDC_LSC_TABLE_BASE);
-	lsc_initialized = 1;
-	return 0;
+	isp_reg_writel(dev, isp_ccdc->lsc_table_inuse,
+		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_TABLE_BASE);
 }
 
 /**
- * ispccdc_load_lsc - Load Lens Shading Compensation table.
- * @table_addr: LSC gain table MMU Mapped address.
- * @table_size: LSC gain table size.
- *
- * Returns 0 if successful, -ENOMEM of its no memory available, or -EINVAL if
- * table_size is zero.
- **/
-int ispccdc_load_lsc(u8 *table_addr, u32 table_size)
-{
-	int ret;
-
-	if (!is_isplsc_activated())
-		return 0;
-
-	if (!table_addr)
-		return -EINVAL;
-
-	ret = ispccdc_allocate_lsc(table_size);
-	if (ret)
-		return ret;
-
-	if (table_addr != lsc_gain_table)
-		memcpy(lsc_gain_table, table_addr, table_size);
-	ret = ispccdc_program_lsc();
-	if (ret)
-		return ret;
-	return 0;
-}
-EXPORT_SYMBOL(ispccdc_load_lsc);
-
-/**
  * ispccdc_config_lsc - Configures the lens shading compensation module
- * @lsc_cfg: LSC configuration structure
+ * @isp_ccdc: Pointer to ISP CCDC device.
  **/
-void ispccdc_config_lsc(struct ispccdc_lsc_config *lsc_cfg)
+static void ispccdc_config_lsc(struct isp_ccdc_device *isp_ccdc)
 {
+	struct device *dev = to_device(isp_ccdc);
+	struct ispccdc_lsc_config *lsc_cfg = &isp_ccdc->lsc_config;
 	int reg;
 
-	if (!is_isplsc_activated())
-		return;
-
-	ispccdc_enable_lsc(0);
-	isp_reg_writel(lsc_cfg->offset, OMAP3_ISP_IOMEM_CCDC,
+	isp_reg_writel(dev, lsc_cfg->offset, OMAP3_ISP_IOMEM_CCDC,
 		       ISPCCDC_LSC_TABLE_OFFSET);
 
 	reg = 0;
 	reg |= lsc_cfg->gain_mode_n << ISPCCDC_LSC_GAIN_MODE_N_SHIFT;
 	reg |= lsc_cfg->gain_mode_m << ISPCCDC_LSC_GAIN_MODE_M_SHIFT;
 	reg |= lsc_cfg->gain_format << ISPCCDC_LSC_GAIN_FORMAT_SHIFT;
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG);
+	isp_reg_writel(dev, reg, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_LSC_CONFIG);
 
 	reg = 0;
 	reg &= ~ISPCCDC_LSC_INITIAL_X_MASK;
 	reg |= lsc_cfg->initial_x << ISPCCDC_LSC_INITIAL_X_SHIFT;
 	reg &= ~ISPCCDC_LSC_INITIAL_Y_MASK;
 	reg |= lsc_cfg->initial_y << ISPCCDC_LSC_INITIAL_Y_SHIFT;
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_INITIAL);
+	isp_reg_writel(dev, reg, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_LSC_INITIAL);
 }
-EXPORT_SYMBOL(ispccdc_config_lsc);
 
-int __ispccdc_enable_lsc(u8 enable)
+void ispccdc_lsc_state_handler(struct isp_ccdc_device *isp_ccdc,
+		unsigned long status)
 {
-	if (!is_isplsc_activated())
-		return -ENODEV;
+	if (!isp_ccdc->lsc_enable)
+		return;
 
-	if (enable) {
-		if (!ispccdc_busy()) {
-			isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
-				   ISPCTRL_SBL_SHARED_RPORTB
-				   | ISPCTRL_SBL_RD_RAM_EN);
+	if (status & CCDC_VD1)
+		isp_ccdc->lsc_delay_stop = 0;
 
-			isp_reg_or(OMAP3_ISP_IOMEM_CCDC,
-				   ISPCCDC_LSC_CONFIG, 0x1);
+	if (status & LSC_DONE)
+		isp_ccdc->lsc_delay_stop = 1;
 
-			ispccdc_obj.lsc_state = 1;
-		} else {
-			/* Postpone enabling LSC */
-			ispccdc_obj.lsc_enable = 1;
-			return -EBUSY;
-		}
-	} else {
-		isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_LSC_CONFIG, 0xFFFE);
-		ispccdc_obj.lsc_state = ispccdc_obj.lsc_enable = 0;
+	if (status & LSC_PRE_ERR) {
+		/* If we have LSC prefetch error, LSC engine is blocked
+		 * and the only way it can recover is to do isp sw reset */
+		ispccdc_enable_lsc(isp_ccdc, 0);
+		isp_ccdc->lsc_delay_stop = 1;
 	}
+}
 
-	return 0;
+static void __ispccdc_enable_lsc(struct isp_ccdc_device *isp_ccdc, u8 enable)
+{
+	isp_reg_and_or(to_device(isp_ccdc), OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_LSC_CONFIG,
+		       ~ISPCCDC_LSC_ENABLE,
+		       enable ? ISPCCDC_LSC_ENABLE : 0);
 }
 
 /**
  * ispccdc_enable_lsc - Enables/Disables the Lens Shading Compensation module.
+ * @isp_ccdc: Pointer to ISP CCDC device.
  * @enable: 0 Disables LSC, 1 Enables LSC.
  **/
-void ispccdc_enable_lsc(u8 enable)
+void ispccdc_enable_lsc(struct isp_ccdc_device *isp_ccdc, u8 enable)
 {
-	if (__ispccdc_enable_lsc(enable)) {
-		if (enable)
-			ispccdc_obj.lsc_state = 1;
-		else
-			ispccdc_obj.lsc_state = ispccdc_obj.lsc_enable = 0;
+	struct device *dev = to_device(isp_ccdc);
+
+	if (enable) {
+		isp_reg_writel(dev, IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ |
+			       IRQ0ENABLE_CCDC_LSC_DONE_IRQ,
+			       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+			IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ |
+			IRQ0ENABLE_CCDC_LSC_DONE_IRQ);
+
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN,
+			   ISP_CTRL, ISPCTRL_SBL_SHARED_RPORTB
+			   | ISPCTRL_SBL_RD_RAM_EN);
+
+		__ispccdc_enable_lsc(isp_ccdc, 1);
+		isp_ccdc->lsc_request_enable = 0;
+	} else {
+		__ispccdc_enable_lsc(isp_ccdc, 0);
+
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+			    ~(IRQ0ENABLE_CCDC_LSC_PREF_ERR_IRQ |
+			      IRQ0ENABLE_CCDC_LSC_DONE_IRQ));
 	}
+	isp_ccdc->lsc_enable = enable;
 }
-EXPORT_SYMBOL(ispccdc_enable_lsc);
 
-void ispccdc_lsc_error_handler(void)
+/**
+ * ispccdc_setup_lsc - apply user LSC settings
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to ISP pipeline structure.
+ *
+ * Consume the new LSC configuration and table set by user space application
+ * and program to CCDC.  This function must be called from process context
+ * before streamon when ISP is not yet running.
+ */
+static void ispccdc_setup_lsc(struct isp_ccdc_device *isp_ccdc,
+			      struct isp_pipeline *pipe)
 {
-	int lsc_enable = ispccdc_obj.lsc_state;
+	struct isp_device *isp = to_isp_device(isp_ccdc);
 
-	ispccdc_enable_lsc(0);
+	ispccdc_enable_lsc(isp_ccdc, 0);	/* Disable LSC */
+	if (((pipe->ccdc_in == CCDC_RAW_GRBG) ||
+	     (pipe->ccdc_in == CCDC_RAW_RGGB) ||
+	     (pipe->ccdc_in == CCDC_RAW_BGGR) ||
+	     (pipe->ccdc_in == CCDC_RAW_GBRG)) &&
+	     isp_ccdc->lsc_request_enable) {
+		/* LSC is requested to be enabled, so configure it */
+		if (isp_ccdc->update_lsc_table) {
+			BUG_ON(isp_ccdc->lsc_table_new == PTR_FREE);
+			iommu_vfree(isp->iommu, isp_ccdc->lsc_table_inuse);
+			isp_ccdc->lsc_table_inuse = isp_ccdc->lsc_table_new;
+			isp_ccdc->lsc_table_new = PTR_FREE;
+			isp_ccdc->update_lsc_table = 0;
+		}
+		ispccdc_config_lsc(isp_ccdc);
+		ispccdc_program_lsc(isp_ccdc);
+	}
+	isp_ccdc->update_lsc_config = 0;
+}
 
-	ispccdc_obj.lsc_enable = lsc_enable;
+/**
+ * ispccdc_lsc_error_handler - Handle LSC prefetch error scenario.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ *
+ * Disables LSC, and defers enablement to shadow registers update time.
+ **/
+void ispccdc_lsc_error_handler(struct isp_ccdc_device *isp_ccdc)
+{
+	ispccdc_enable_lsc(isp_ccdc, 0);
 }
 
 /**
@@ -565,191 +707,138 @@
  * 3) Crop height is always even.
  * 4) Crop width is always a multiple of 16 pixels
  **/
-void ispccdc_config_crop(u32 left, u32 top, u32 height, u32 width)
+static void ispccdc_config_crop(struct isp_ccdc_device *isp_ccdc, u32 left,
+				u32 top, u32 height, u32 width)
 {
-	ispccdc_obj.ccdcin_woffset = left + (left % 2);
-	ispccdc_obj.ccdcin_hoffset = top + (top % 2);
+	isp_ccdc->ccdcin_woffset = left + (left % 2);
+	isp_ccdc->ccdcin_hoffset = top + (top % 2);
 
-	ispccdc_obj.crop_w = width - (width % 16);
-	ispccdc_obj.crop_h = height + (height % 2);
+	isp_ccdc->crop_w = width - (width % 16);
+	isp_ccdc->crop_h = height + (height % 2);
 
 	DPRINTK_ISPCCDC("\n\tOffsets L %d T %d W %d H %d\n",
-			ispccdc_obj.ccdcin_woffset,
-			ispccdc_obj.ccdcin_hoffset,
-			ispccdc_obj.crop_w,
-			ispccdc_obj.crop_h);
+			isp_ccdc->ccdcin_woffset,
+			isp_ccdc->ccdcin_hoffset,
+			isp_ccdc->crop_w,
+			isp_ccdc->crop_h);
 }
 
 /**
- * ispccdc_config_datapath - Specifies the input and output modules for CCDC.
- * @input: Indicates the module that inputs the image to the CCDC.
- * @output: Indicates the module to which the CCDC outputs the image.
+ * ispccdc_config_outlineoffset - Configure memory saving output line offset
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @offset: Address offset to start a new line. Must be twice the
+ *          Output width and aligned on 32 byte boundary
+ * @oddeven: Specifies the odd/even line pattern to be chosen to store the
+ *           output.
+ * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
  *
- * Configures the default configuration for the CCDC to work with.
+ * - Configures the output line offset when stored in memory
+ * - Sets the odd/even line pattern to store the output
+ *    (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
+ * - Configures the number of even and odd line fields in case of rearranging
+ * the lines.
  *
- * The valid values for the input are CCDC_RAW (0), CCDC_YUV_SYNC (1),
- * CCDC_YUV_BT (2), and CCDC_OTHERS (3).
- *
- * The valid values for the output are CCDC_YUV_RSZ (0), CCDC_YUV_MEM_RSZ (1),
- * CCDC_OTHERS_VP (2), CCDC_OTHERS_MEM (3), CCDC_OTHERS_VP_MEM (4).
- *
- * Returns 0 if successful, or -EINVAL if wrong I/O combination or wrong input
- * or output values.
+ * Returns 0 if successful, or -EINVAL if the offset is not in 32 byte
+ * boundary.
  **/
-int ispccdc_config_datapath(enum ccdc_input input, enum ccdc_output output)
+static int ispccdc_config_outlineoffset(struct isp_ccdc_device *isp_ccdc,
+					u32 offset, u8 oddeven, u8 numlines)
 {
-	u32 syn_mode = 0;
-	struct ispccdc_vp vpcfg;
-	struct ispccdc_syncif syncif;
-	struct ispccdc_bclamp blkcfg;
+	struct device *dev = to_device(isp_ccdc);
 
-	u32 colptn = ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
-		ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
-		ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
-		ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
-		ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
-		ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
-		ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
-		ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
-		ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
-		ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
-		ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
-		ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
-		ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
-		ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
-		ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
-		ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
-
-	/* CCDC does not convert the image format */
-	if ((input == CCDC_RAW || input == CCDC_OTHERS) &&
-	    output == CCDC_YUV_RSZ) {
-		DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC I/O Combination\n");
+	if ((offset & ISP_32B_BOUNDARY_OFFSET) == offset) {
+		isp_reg_writel(dev, (offset & 0xFFFF),
+			       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF);
+	} else {
+		DPRINTK_ISPCCDC("ISP_ERR : Offset should be in 32 byte"
+				" boundary\n");
 		return -EINVAL;
 	}
 
-	syn_mode = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+	isp_reg_and(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+		    ~ISPCCDC_SDOFST_FINV);
 
-	switch (output) {
-	case CCDC_YUV_RSZ:
-		syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
-		syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+	isp_reg_and(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
+		    ~ISPCCDC_SDOFST_FOFST_4L);
+
+	switch (oddeven) {
+	case EVENEVEN:
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC,
+			   ISPCCDC_SDOFST,
+			   (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
 		break;
-
-	case CCDC_YUV_MEM_RSZ:
-		syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
-		ispccdc_obj.wen = 1;
-		syn_mode |= ISPCCDC_SYN_MODE_WEN;
+	case ODDEVEN:
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC,
+			   ISPCCDC_SDOFST,
+			   (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
 		break;
-
-	case CCDC_OTHERS_VP:
-		syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
-		syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
-		syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
-		vpcfg.bitshift_sel = BIT9_0;
-		vpcfg.freq_sel = PIXCLKBY2;
-		ispccdc_config_vp(vpcfg);
-		ispccdc_enable_vp(1);
+	case EVENODD:
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC,
+			   ISPCCDC_SDOFST,
+			   (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
 		break;
-
-	case CCDC_OTHERS_MEM:
-		syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
-		syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
-		syn_mode |= ISPCCDC_SYN_MODE_WEN;
-		syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
-		isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
-			    ~ISPCCDC_CFG_WENLOG);
-		vpcfg.bitshift_sel = BIT11_2;
-		vpcfg.freq_sel = PIXCLKBY2;
-		ispccdc_config_vp(vpcfg);
-		ispccdc_enable_vp(0);
-		break;
-
-	case CCDC_OTHERS_VP_MEM:
-		syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
-		syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
-		syn_mode |= ISPCCDC_SYN_MODE_WEN;
-		syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
-
-		isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
-			       ~ISPCCDC_CFG_WENLOG,
-			       ispccdc_obj.wenlog);
-		vpcfg.bitshift_sel = BIT9_0;
-		vpcfg.freq_sel = PIXCLKBY2;
-		ispccdc_config_vp(vpcfg);
-		ispccdc_enable_vp(1);
+	case ODDODD:
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC,
+			   ISPCCDC_SDOFST,
+			   (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
 		break;
 	default:
-		DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Output\n");
-		return -EINVAL;
-	};
-
-	isp_reg_writel(syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
-
-	switch (input) {
-	case CCDC_RAW:
-		syncif.ccdc_mastermode = 0;
-		syncif.datapol = 0;
-		syncif.datsz = DAT10;
-		syncif.fldmode = 0;
-		syncif.fldout = 0;
-		syncif.fldpol = 0;
-		syncif.fldstat = 0;
-		syncif.hdpol = 0;
-		syncif.ipmod = RAW;
-		syncif.vdpol = 0;
-		ispccdc_config_sync_if(syncif);
-		ispccdc_config_imgattr(colptn);
-		blkcfg.dcsubval = 64;
-		ispccdc_config_black_clamp(blkcfg);
-		if (is_isplsc_activated()) {
-			ispccdc_config_lsc(&lsc_config);
-			ispccdc_load_lsc(lsc_gain_table_tmp,
-					 LSC_TABLE_INIT_SIZE);
-		}
-
 		break;
-	case CCDC_YUV_SYNC:
-		syncif.ccdc_mastermode = 0;
-		syncif.datapol = 0;
-		syncif.datsz = DAT8;
-		syncif.fldmode = 0;
-		syncif.fldout = 0;
-		syncif.fldpol = 0;
-		syncif.fldstat = 0;
-		syncif.hdpol = 0;
-		syncif.ipmod = YUV16;
-		syncif.vdpol = 1;
-		ispccdc_config_imgattr(0);
-		ispccdc_config_sync_if(syncif);
-		blkcfg.dcsubval = 0;
-		ispccdc_config_black_clamp(blkcfg);
-		break;
-	case CCDC_YUV_BT:
-		break;
-	case CCDC_OTHERS:
-		break;
-	default:
-		DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Input\n");
-		return -EINVAL;
 	}
-
-	ispccdc_obj.ccdc_inpfmt = input;
-	ispccdc_obj.ccdc_outfmt = output;
-	ispccdc_print_status();
-	isp_print_status();
 	return 0;
 }
-EXPORT_SYMBOL(ispccdc_config_datapath);
 
 /**
- * ispccdc_config_sync_if - Sets the sync i/f params between sensor and CCDC.
+ * ispccdc_set_outaddr - Set memory address to save output image
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @addr: ISP MMU Mapped 32-bit memory address aligned on 32 byte boundary.
+ *
+ * Sets the memory address where the output will be saved.
+ *
+ * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
+ * boundary.
+ **/
+int ispccdc_set_outaddr(struct isp_ccdc_device *isp_ccdc, u32 addr)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	if ((addr & ISP_32B_BOUNDARY_BUF) == addr) {
+		isp_reg_writel(dev, addr, OMAP3_ISP_IOMEM_CCDC,
+			       ISPCCDC_SDR_ADDR);
+		return 0;
+	} else {
+		DPRINTK_ISPCCDC("ISP_ERR : Address should be in 32 byte"
+				" boundary\n");
+		return -EINVAL;
+	}
+
+}
+
+void ispccdc_lsc_pref_comp_handler(struct isp_ccdc_device *isp_ccdc)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	if (!isp_ccdc->lsc_enable)
+		return;
+	isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+		    ~IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ);
+
+	ispccdc_enable(isp_ccdc, 1);
+}
+
+/**
+ * ispccdc_config_sync_if - Set CCDC sync interface params between sensor and CCDC.
+ * @isp_ccdc: Pointer to ISP CCDC device.
  * @syncif: Structure containing the sync parameters like field state, CCDC in
  *          master/slave mode, raw/yuv data, polarity of data, field, hs, vs
  *          signals.
  **/
-void ispccdc_config_sync_if(struct ispccdc_syncif syncif)
+static void ispccdc_config_sync_if(struct isp_ccdc_device *isp_ccdc,
+				   struct ispccdc_syncif syncif)
 {
-	u32 syn_mode = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+	struct device *dev = to_device(isp_ccdc);
+	u32 syn_mode = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				     ISPCCDC_SYN_MODE);
 
 	syn_mode |= ISPCCDC_SYN_MODE_VDHDEN;
 
@@ -759,7 +848,7 @@
 		syn_mode &= ~ISPCCDC_SYN_MODE_FLDSTAT;
 
 	syn_mode &= ISPCCDC_SYN_MODE_INPMOD_MASK;
-	ispccdc_obj.syncif_ipmod = syncif.ipmod;
+	isp_ccdc->syncif_ipmod = syncif.ipmod;
 
 	switch (syncif.ipmod) {
 	case RAW:
@@ -815,12 +904,14 @@
 
 	if (syncif.ccdc_mastermode) {
 		syn_mode |= ISPCCDC_SYN_MODE_FLDOUT | ISPCCDC_SYN_MODE_VDHDOUT;
-		isp_reg_writel(syncif.hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
+		isp_reg_writel(dev,
+			       syncif.hs_width << ISPCCDC_HD_VD_WID_HDW_SHIFT
 			       | syncif.vs_width << ISPCCDC_HD_VD_WID_VDW_SHIFT,
 			       OMAP3_ISP_IOMEM_CCDC,
 			       ISPCCDC_HD_VD_WID);
 
-		isp_reg_writel(syncif.ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
+		isp_reg_writel(dev,
+			       syncif.ppln << ISPCCDC_PIX_LINES_PPLN_SHIFT
 			       | syncif.hlprf << ISPCCDC_PIX_LINES_HLPRF_SHIFT,
 			       OMAP3_ISP_IOMEM_CCDC,
 			       ISPCCDC_PIX_LINES);
@@ -828,391 +919,260 @@
 		syn_mode &= ~(ISPCCDC_SYN_MODE_FLDOUT |
 			      ISPCCDC_SYN_MODE_VDHDOUT);
 
-	isp_reg_writel(syn_mode, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE);
+	isp_reg_writel(dev, syn_mode, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_SYN_MODE);
 
 	if (!(syncif.bt_r656_en)) {
-		isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_REC656IF,
-			    ~ISPCCDC_REC656IF_R656ON);
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_CCDC,
+			    ISPCCDC_REC656IF, ~ISPCCDC_REC656IF_R656ON);
 	}
 }
-EXPORT_SYMBOL(ispccdc_config_sync_if);
 
 /**
- * ispccdc_config_black_clamp - Configures the clamp parameters in CCDC.
- * @bclamp: Structure containing the optical black average gain, optical black
- *          sample length, sample lines, and the start pixel position of the
- *          samples w.r.t the HS pulse.
- * Configures the clamp parameters in CCDC. Either if its being used the
- * optical black clamp, or the digital clamp. If its a digital clamp, then
- * assures to put a valid DC substraction level.
- *
- * Returns always 0 when completed.
- **/
-int ispccdc_config_black_clamp(struct ispccdc_bclamp bclamp)
+ * ispccdc_set_wenlog - Set the CCDC Write Enable valid region.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @wenlog: Write enable logic to apply against valid area. 0 - AND, 1 - OR.
+ */
+void ispccdc_set_wenlog(struct isp_ccdc_device *isp_ccdc, u32 wenlog)
 {
-	u32 bclamp_val = 0;
-
-	if (ispccdc_obj.obclamp_en) {
-		bclamp_val |= bclamp.obgain << ISPCCDC_CLAMP_OBGAIN_SHIFT;
-		bclamp_val |= bclamp.oblen << ISPCCDC_CLAMP_OBSLEN_SHIFT;
-		bclamp_val |= bclamp.oblines << ISPCCDC_CLAMP_OBSLN_SHIFT;
-		bclamp_val |= bclamp.obstpixel << ISPCCDC_CLAMP_OBST_SHIFT;
-		isp_reg_writel(bclamp_val, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_CLAMP);
-	} else {
-		if (omap_rev() < OMAP3430_REV_ES2_0)
-			if (ispccdc_obj.syncif_ipmod == YUV16 ||
-			    ispccdc_obj.syncif_ipmod == YUV8 ||
-			    isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
-					  ISPCCDC_REC656IF) &
-			    ISPCCDC_REC656IF_R656ON)
-				bclamp.dcsubval = 0;
-		isp_reg_writel(bclamp.dcsubval, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_DCSUB);
-	}
-	return 0;
+	isp_ccdc->wenlog = wenlog;
 }
-EXPORT_SYMBOL(ispccdc_config_black_clamp);
 
 /**
- * ispccdc_enable_black_clamp - Enables/Disables the optical black clamp.
- * @enable: 0 Disables optical black clamp, 1 Enables optical black clamp.
+ * ispccdc_config_datapath - Specify the input and output modules for CCDC.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to ISP pipeline structure to base on for config.
  *
- * Enables or disables the optical black clamp. When disabled, the digital
- * clamp operates.
- **/
-void ispccdc_enable_black_clamp(u8 enable)
-{
-	isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP,
-		       ~ISPCCDC_CLAMP_CLAMPEN,
-		       enable ? ISPCCDC_CLAMP_CLAMPEN : 0);
-	ispccdc_obj.obclamp_en = enable;
-}
-EXPORT_SYMBOL(ispccdc_enable_black_clamp);
-
-/**
- * ispccdc_config_fpc - Configures the Faulty Pixel Correction parameters.
- * @fpc: Structure containing the number of faulty pixels corrected in the
- *       frame, address of the FPC table.
+ * Configures the default configuration for the CCDC to work with.
  *
- * Returns 0 if successful, or -EINVAL if FPC Address is not on the 64 byte
- * boundary.
+ * The valid values for the input are CCDC_RAW (0), CCDC_YUV_SYNC (1),
+ * CCDC_YUV_BT (2), and CCDC_OTHERS (3).
+ *
+ * The valid values for the output are CCDC_YUV_RSZ (0), CCDC_YUV_MEM_RSZ (1),
+ * CCDC_OTHERS_VP (2), CCDC_OTHERS_MEM (3), CCDC_OTHERS_VP_MEM (4).
+ *
+ * Returns 0 if successful, or -EINVAL if wrong I/O combination or wrong input
+ * or output values.
  **/
-int ispccdc_config_fpc(struct ispccdc_fpc fpc)
+static int ispccdc_config_datapath(struct isp_ccdc_device *isp_ccdc,
+				   struct isp_pipeline *pipe)
 {
-	u32 fpc_val = 0;
+	struct device *dev = to_device(isp_ccdc);
+	u32 syn_mode = 0;
+	struct ispccdc_vp vpcfg;
+	struct ispccdc_syncif syncif;
+	struct ispccdc_bclamp blkcfg;
 
-	fpc_val = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+	u32 colptn = ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC0_SHIFT |
+		ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC1_SHIFT |
+		ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP0PLC2_SHIFT |
+		ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP0PLC3_SHIFT |
+		ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC0_SHIFT |
+		ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC1_SHIFT |
+		ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP1PLC2_SHIFT |
+		ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP1PLC3_SHIFT |
+		ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC0_SHIFT |
+		ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC1_SHIFT |
+		ISPCCDC_COLPTN_Gr_Cy << ISPCCDC_COLPTN_CP2PLC2_SHIFT |
+		ISPCCDC_COLPTN_R_Ye << ISPCCDC_COLPTN_CP2PLC3_SHIFT |
+		ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC0_SHIFT |
+		ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC1_SHIFT |
+		ISPCCDC_COLPTN_B_Mg << ISPCCDC_COLPTN_CP3PLC2_SHIFT |
+		ISPCCDC_COLPTN_Gb_G << ISPCCDC_COLPTN_CP3PLC3_SHIFT;
 
-	if ((fpc.fpcaddr & 0xFFFFFFC0) == fpc.fpcaddr) {
-		isp_reg_writel(fpc_val & (~ISPCCDC_FPC_FPCEN),
-			       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
-		isp_reg_writel(fpc.fpcaddr,
-			       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC_ADDR);
-	} else {
-		DPRINTK_ISPCCDC("FPC Address should be on 64byte boundary\n");
+	syn_mode = isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+				 ISPCCDC_SYN_MODE);
+
+	switch (pipe->ccdc_out) {
+	case CCDC_YUV_RSZ:
+		syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
+		syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+		break;
+
+	case CCDC_YUV_MEM_RSZ:
+		syn_mode |= ISPCCDC_SYN_MODE_SDR2RSZ;
+		isp_ccdc->wen = 1;
+		syn_mode |= ISPCCDC_SYN_MODE_WEN;
+		break;
+
+	case CCDC_OTHERS_VP:
+		syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+		syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+		syn_mode &= ~ISPCCDC_SYN_MODE_WEN;
+		vpcfg.bitshift_sel = BIT9_0;
+		vpcfg.freq_sel = PIXCLKBY2;
+		ispccdc_config_vp(isp_ccdc, vpcfg);
+		ispccdc_enable_vp(isp_ccdc, 1);
+		break;
+
+	case CCDC_OTHERS_MEM:
+		syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+		syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+		syn_mode |= ISPCCDC_SYN_MODE_WEN;
+		syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+			    ~ISPCCDC_CFG_WENLOG);
+		vpcfg.bitshift_sel = BIT9_0;
+		vpcfg.freq_sel = PIXCLKBY2;
+		ispccdc_config_vp(isp_ccdc, vpcfg);
+		ispccdc_enable_vp(isp_ccdc, 0);
+		break;
+
+	case CCDC_OTHERS_VP_MEM:
+		syn_mode &= ~ISPCCDC_SYN_MODE_VP2SDR;
+		syn_mode &= ~ISPCCDC_SYN_MODE_SDR2RSZ;
+		syn_mode |= ISPCCDC_SYN_MODE_WEN;
+		syn_mode &= ~ISPCCDC_SYN_MODE_EXWEN;
+
+		isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC,
+			       ISPCCDC_CFG, ~ISPCCDC_CFG_WENLOG,
+			       isp_ccdc->wenlog);
+		vpcfg.bitshift_sel = BIT9_0;
+		vpcfg.freq_sel = PIXCLKBY2;
+		ispccdc_config_vp(isp_ccdc, vpcfg);
+		ispccdc_enable_vp(isp_ccdc, 1);
+		break;
+	default:
+		DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Output\n");
+		return -EINVAL;
+	};
+
+	isp_reg_writel(dev, syn_mode, OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_SYN_MODE);
+
+	switch (pipe->ccdc_in) {
+	case CCDC_RAW_GRBG:
+	case CCDC_RAW_RGGB:
+	case CCDC_RAW_BGGR:
+	case CCDC_RAW_GBRG:
+		syncif.ccdc_mastermode = 0;
+		syncif.datapol = 0;
+		syncif.datsz = DAT10;
+		syncif.fldmode = 0;
+		syncif.fldout = 0;
+		syncif.fldpol = 0;
+		syncif.fldstat = 0;
+		syncif.hdpol = 0;
+		syncif.ipmod = RAW;
+		syncif.vdpol = 0;
+		ispccdc_config_sync_if(isp_ccdc, syncif);
+		ispccdc_config_imgattr(isp_ccdc, colptn);
+		blkcfg.oblen = 0;
+		blkcfg.dcsubval = 64;
+		ispccdc_config_black_clamp(isp_ccdc, blkcfg);
+		break;
+	case CCDC_YUV_SYNC:
+		syncif.ccdc_mastermode = 0;
+		syncif.datapol = 0;
+		syncif.datsz = DAT8;
+		syncif.fldmode = 0;
+		syncif.fldout = 0;
+		syncif.fldpol = 0;
+		syncif.fldstat = 0;
+		syncif.hdpol = 0;
+		syncif.ipmod = YUV16;
+		syncif.vdpol = 1;
+		ispccdc_config_imgattr(isp_ccdc, 0);
+		ispccdc_config_sync_if(isp_ccdc, syncif);
+		blkcfg.oblen = 0;
+		blkcfg.dcsubval = 0;
+		ispccdc_config_black_clamp(isp_ccdc, blkcfg);
+		break;
+	case CCDC_YUV_BT:
+		break;
+	case CCDC_OTHERS:
+		break;
+	default:
+		DPRINTK_ISPCCDC("ISP_ERR: Wrong CCDC Input\n");
 		return -EINVAL;
 	}
-	isp_reg_writel(fpc_val | (fpc.fpnum << ISPCCDC_FPC_FPNUM_SHIFT),
-		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC);
+
+	ispccdc_config_crop(isp_ccdc, 0, 0, 0, 0);
+	ispccdc_print_status(isp_ccdc, pipe);
+	isp_print_status(dev);
 	return 0;
 }
-EXPORT_SYMBOL(ispccdc_config_fpc);
 
 /**
- * ispccdc_enable_fpc - Enables the Faulty Pixel Correction.
- * @enable: 0 Disables FPC, 1 Enables FPC.
- **/
-void ispccdc_enable_fpc(u8 enable)
-{
-	isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FPC,
-		       ~ISPCCDC_FPC_FPCEN,
-		       enable ? ISPCCDC_FPC_FPCEN : 0);
-}
-EXPORT_SYMBOL(ispccdc_enable_fpc);
-
-/**
- * ispccdc_config_black_comp - Configures Black Level Compensation parameters.
- * @blcomp: Structure containing the black level compensation value for RGrGbB
- *          pixels. in 2's complement.
- **/
-void ispccdc_config_black_comp(struct ispccdc_blcomp blcomp)
-{
-	u32 blcomp_val = 0;
-
-	blcomp_val |= blcomp.b_mg << ISPCCDC_BLKCMP_B_MG_SHIFT;
-	blcomp_val |= blcomp.gb_g << ISPCCDC_BLKCMP_GB_G_SHIFT;
-	blcomp_val |= blcomp.gr_cy << ISPCCDC_BLKCMP_GR_CY_SHIFT;
-	blcomp_val |= blcomp.r_ye << ISPCCDC_BLKCMP_R_YE_SHIFT;
-
-	isp_reg_writel(blcomp_val, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_BLKCMP);
-}
-EXPORT_SYMBOL(ispccdc_config_black_comp);
-
-/**
- * ispccdc_config_vp - Configures the Video Port Configuration parameters.
- * @vpcfg: Structure containing the Video Port input frequency, and the 10 bit
- *         format.
- **/
-void ispccdc_config_vp(struct ispccdc_vp vpcfg)
-{
-	u32 fmtcfg_vp = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-
-	fmtcfg_vp &= ISPCCDC_FMTCFG_VPIN_MASK & ISPCCDC_FMTCF_VPIF_FRQ_MASK;
-
-	switch (vpcfg.bitshift_sel) {
-	case BIT9_0:
-		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_9_0;
-		break;
-	case BIT10_1:
-		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_10_1;
-		break;
-	case BIT11_2:
-		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_11_2;
-		break;
-	case BIT12_3:
-		fmtcfg_vp |= ISPCCDC_FMTCFG_VPIN_12_3;
-		break;
-	};
-	switch (vpcfg.freq_sel) {
-	case PIXCLKBY2:
-		fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY2;
-		break;
-	case PIXCLKBY3_5:
-		fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY3;
-		break;
-	case PIXCLKBY4_5:
-		fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY4;
-		break;
-	case PIXCLKBY5_5:
-		fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY5;
-		break;
-	case PIXCLKBY6_5:
-		fmtcfg_vp |= ISPCCDC_FMTCF_VPIF_FRQ_BY6;
-		break;
-	};
-	isp_reg_writel(fmtcfg_vp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-}
-EXPORT_SYMBOL(ispccdc_config_vp);
-
-/**
- * ispccdc_enable_vp - Enables the Video Port.
- * @enable: 0 Disables VP, 1 Enables VP
- **/
-void ispccdc_enable_vp(u8 enable)
-{
-	isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
-		       ~ISPCCDC_FMTCFG_VPEN,
-		       enable ? ISPCCDC_FMTCFG_VPEN : 0);
-}
-EXPORT_SYMBOL(ispccdc_enable_vp);
-
-/**
- * ispccdc_config_reformatter - Configures the Reformatter.
- * @refmt: Structure containing the memory address to format and the bit fields
- *         for the reformatter registers.
- *
- * Configures the Reformatter register values if line alternating is disabled.
- * Else, just enabling line alternating is enough.
- **/
-void ispccdc_config_reformatter(struct ispccdc_refmt refmt)
-{
-	u32 fmtcfg_val = 0;
-
-	fmtcfg_val = isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-
-	if (refmt.lnalt)
-		fmtcfg_val |= ISPCCDC_FMTCFG_LNALT;
-	else {
-		fmtcfg_val &= ~ISPCCDC_FMTCFG_LNALT;
-		fmtcfg_val &= 0xFFFFF003;
-		fmtcfg_val |= refmt.lnum << ISPCCDC_FMTCFG_LNUM_SHIFT;
-		fmtcfg_val |= refmt.plen_even <<
-			ISPCCDC_FMTCFG_PLEN_EVEN_SHIFT;
-		fmtcfg_val |= refmt.plen_odd << ISPCCDC_FMTCFG_PLEN_ODD_SHIFT;
-
-		isp_reg_writel(refmt.prgeven0, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_PRGEVEN0);
-		isp_reg_writel(refmt.prgeven1, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_PRGEVEN1);
-		isp_reg_writel(refmt.prgodd0, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_PRGODD0);
-		isp_reg_writel(refmt.prgodd1, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_PRGODD1);
-		isp_reg_writel(refmt.fmtaddr0, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_ADDR0);
-		isp_reg_writel(refmt.fmtaddr1, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_ADDR1);
-		isp_reg_writel(refmt.fmtaddr2, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_ADDR2);
-		isp_reg_writel(refmt.fmtaddr3, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_ADDR3);
-		isp_reg_writel(refmt.fmtaddr4, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_ADDR4);
-		isp_reg_writel(refmt.fmtaddr5, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_ADDR5);
-		isp_reg_writel(refmt.fmtaddr6, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_ADDR6);
-		isp_reg_writel(refmt.fmtaddr7, OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_ADDR7);
-	}
-	isp_reg_writel(fmtcfg_val, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG);
-}
-EXPORT_SYMBOL(ispccdc_config_reformatter);
-
-/**
- * ispccdc_enable_reformatter - Enables the Reformatter.
- * @enable: 0 Disables Reformatter, 1- Enables Data Reformatter
- **/
-void ispccdc_enable_reformatter(u8 enable)
-{
-	isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG,
-		       ~ISPCCDC_FMTCFG_FMTEN,
-		       enable ? ISPCCDC_FMTCFG_FMTEN : 0);
-	ispccdc_obj.refmt_en = enable;
-}
-EXPORT_SYMBOL(ispccdc_enable_reformatter);
-
-/**
- * ispccdc_config_culling - Configures the culling parameters.
- * @cull: Structure containing the vertical culling pattern, and horizontal
- *        culling pattern for odd and even lines.
- **/
-void ispccdc_config_culling(struct ispccdc_culling cull)
-{
-	u32 culling_val = 0;
-
-	culling_val |= cull.v_pattern << ISPCCDC_CULLING_CULV_SHIFT;
-	culling_val |= cull.h_even << ISPCCDC_CULLING_CULHEVN_SHIFT;
-	culling_val |= cull.h_odd << ISPCCDC_CULLING_CULHODD_SHIFT;
-
-	isp_reg_writel(culling_val, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CULLING);
-}
-EXPORT_SYMBOL(ispccdc_config_culling);
-
-/**
- * ispccdc_enable_lpf - Enables the Low-Pass Filter (LPF).
- * @enable: 0 Disables LPF, 1 Enables LPF
- **/
-void ispccdc_enable_lpf(u8 enable)
-{
-	isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE,
-		       ~ISPCCDC_SYN_MODE_LPF,
-		       enable ? ISPCCDC_SYN_MODE_LPF : 0);
-}
-EXPORT_SYMBOL(ispccdc_enable_lpf);
-
-/**
- * ispccdc_config_alaw - Configures the input width for A-law.
- * @ipwidth: Input width for A-law
- **/
-void ispccdc_config_alaw(enum alaw_ipwidth ipwidth)
-{
-	isp_reg_writel(ipwidth << ISPCCDC_ALAW_GWDI_SHIFT,
-		       OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW);
-}
-EXPORT_SYMBOL(ispccdc_config_alaw);
-
-/**
- * ispccdc_enable_alaw - Enables the A-law compression.
- * @enable: 0 - Disables A-law, 1 - Enables A-law
- **/
-void ispccdc_enable_alaw(u8 enable)
-{
-	isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_ALAW,
-		       ~ISPCCDC_ALAW_CCDTBL,
-		       enable ? ISPCCDC_ALAW_CCDTBL : 0);
-}
-EXPORT_SYMBOL(ispccdc_enable_alaw);
-
-/**
- * ispccdc_config_imgattr - Configures the sensor image specific attributes.
- * @colptn: Color pattern of the sensor.
- **/
-void ispccdc_config_imgattr(u32 colptn)
-{
-	isp_reg_writel(colptn, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN);
-}
-EXPORT_SYMBOL(ispccdc_config_imgattr);
-
-void ispccdc_config_shadow_registers(void)
-{
-	if (ispccdc_obj.lsc_enable) {
-		ispccdc_enable_lsc(1);
-		ispccdc_obj.lsc_enable = 0;
-	}
-}
-
-/**
- * ispccdc_try_size - Checks if requested Input/output dimensions are valid
- * @input_w: input width for the CCDC in number of pixels per line
- * @input_h: input height for the CCDC in number of lines
- * @output_w: output width from the CCDC in number of pixels per line
- * @output_h: output height for the CCDC in number of lines
+ * ispccdc_try_pipeline - Checks if requested Input/output dimensions are valid
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to ISP pipeline structure to fill back.
  *
  * Calculates the number of pixels cropped if the reformater is disabled,
  * Fills up the output width and height variables in the isp_ccdc structure.
  *
  * Returns 0 if successful, or -EINVAL if the input width is less than 2 pixels
  **/
-int ispccdc_try_size(u32 input_w, u32 input_h, u32 *output_w, u32 *output_h)
+int ispccdc_try_pipeline(struct isp_ccdc_device *isp_ccdc,
+			 struct isp_pipeline *pipe)
 {
-	if (input_w < 32 || input_h < 32) {
+	struct isp_device *isp = to_isp_device(isp_ccdc);
+
+	if (pipe->ccdc_in_w < 32 || pipe->ccdc_in_h < 32) {
 		DPRINTK_ISPCCDC("ISP_ERR: CCDC cannot handle input width less"
 				" than 32 pixels or height less than 32\n");
 		return -EINVAL;
 	}
 
-	if (ispccdc_obj.crop_w)
-		*output_w = ispccdc_obj.crop_w;
-	else
-		*output_w = input_w;
-
-	if (ispccdc_obj.crop_h)
-		*output_h = ispccdc_obj.crop_h;
-	else
-		*output_h = input_h;
-
-	if (!ispccdc_obj.refmt_en
-	    && ispccdc_obj.ccdc_outfmt != CCDC_OTHERS_MEM
-	    && ispccdc_obj.ccdc_outfmt != CCDC_OTHERS_VP_MEM)
-		*output_h -= 1;
-
-	if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP) {
-		*output_h -= ispccdc_obj.ccdcin_hoffset;
-		*output_w -= ispccdc_obj.ccdcin_woffset;
-		*output_h &= 0xFFFFFFFE;
-		*output_w &= 0xFFFFFFFE;
+	/* CCDC does not convert the image format */
+	if ((pipe->ccdc_in == CCDC_RAW_GRBG ||
+	     pipe->ccdc_in == CCDC_RAW_RGGB ||
+	     pipe->ccdc_in == CCDC_RAW_BGGR ||
+	     pipe->ccdc_in == CCDC_RAW_GBRG ||
+	     pipe->ccdc_in == CCDC_OTHERS) &&
+	    pipe->ccdc_out == CCDC_YUV_RSZ) {
+		dev_info(isp->dev, "wrong CCDC I/O Combination\n");
+		return -EINVAL;
 	}
 
-	if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_MEM
-	    || ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP_MEM) {
-		if (*output_w % 32)
-			*output_w -= (*output_w % 32);
+	pipe->ccdc_in_h_st = 0;
+	pipe->ccdc_in_v_st = 0;
+	pipe->ccdc_out_w = pipe->ccdc_in_w;
+	pipe->ccdc_out_h = pipe->ccdc_in_h;
+
+	if (!isp_ccdc->refmt_en
+	    && pipe->ccdc_out != CCDC_OTHERS_MEM
+	    && pipe->ccdc_out != CCDC_OTHERS_VP_MEM)
+		pipe->ccdc_out_h -= 1;
+
+	if (pipe->ccdc_out == CCDC_OTHERS_VP) {
+		switch (pipe->ccdc_in) {
+		case CCDC_RAW_GRBG:
+			pipe->ccdc_in_h_st = 1;
+			pipe->ccdc_in_v_st = 0;
+			break;
+		case CCDC_RAW_BGGR:
+			pipe->ccdc_in_h_st = 1;
+			pipe->ccdc_in_v_st = 1;
+			break;
+		case CCDC_RAW_RGGB:
+			pipe->ccdc_in_h_st = 0;
+			pipe->ccdc_in_v_st = 0;
+			break;
+		case CCDC_RAW_GBRG:
+			pipe->ccdc_in_h_st = 0;
+			pipe->ccdc_in_v_st = 1;
+			break;
+		default:
+			break;
+		}
+		pipe->ccdc_out_h -= pipe->ccdc_in_v_st;
+		pipe->ccdc_out_w -= pipe->ccdc_in_h_st;
+		pipe->ccdc_out_h -= (pipe->ccdc_out_h % 2);
+		pipe->ccdc_out_w -= (pipe->ccdc_out_w % 2);
 	}
 
-	ispccdc_obj.ccdcout_w = *output_w;
-	ispccdc_obj.ccdcout_h = *output_h;
-	ispccdc_obj.ccdcin_w = input_w;
-	ispccdc_obj.ccdcin_h = input_h;
-
-	DPRINTK_ISPCCDC("try size: ccdcin_w=%u,ccdcin_h=%u,ccdcout_w=%u,"
-			" ccdcout_h=%u\n",
-			ispccdc_obj.ccdcin_w,
-			ispccdc_obj.ccdcin_h,
-			ispccdc_obj.ccdcout_w,
-			ispccdc_obj.ccdcout_h);
+	pipe->ccdc_out_w_img = pipe->ccdc_out_w;
+	/* Round up to nearest 32 pixels. */
+	pipe->ccdc_out_w = ALIGN(pipe->ccdc_out_w, 0x20);
 
 	return 0;
 }
-EXPORT_SYMBOL(ispccdc_try_size);
 
 /**
- * ispccdc_config_size - Configure the dimensions of the CCDC input/output
- * @input_w: input width for the CCDC in number of pixels per line
- * @input_h: input height for the CCDC in number of lines
- * @output_w: output width from the CCDC in number of pixels per line
- * @output_h: output height for the CCDC in number of lines
+ * ispccdc_s_pipeline - Configure the CCDC based on overall ISP pipeline.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @pipe: Pointer to ISP pipeline structure to configure.
  *
  * Configures the appropriate values stored in the isp_ccdc structure to
  * HORZ/VERT_INFO registers and the VP_OUT depending on whether the image
@@ -1221,460 +1181,559 @@
  * Returns 0 if successful, or -EINVAL if try_size was not called before to
  * validate the requested dimensions.
  **/
-int ispccdc_config_size(u32 input_w, u32 input_h, u32 output_w, u32 output_h)
+int ispccdc_s_pipeline(struct isp_ccdc_device *isp_ccdc,
+		       struct isp_pipeline *pipe)
 {
-	DPRINTK_ISPCCDC("config size: input_w=%u, input_h=%u, output_w=%u,"
-			" output_h=%u\n",
-			input_w, input_h,
-			output_w, output_h);
-	if (output_w != ispccdc_obj.ccdcout_w
-	    || output_h != ispccdc_obj.ccdcout_h) {
-		DPRINTK_ISPCCDC("ISP_ERR : ispccdc_try_size should"
-				" be called before config size\n");
-		return -EINVAL;
-	}
+	struct device *dev = to_device(isp_ccdc);
+	int rval;
 
-	if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP) {
-		isp_reg_writel((ispccdc_obj.ccdcin_woffset <<
-				ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
-			((ispccdc_obj.ccdcin_w-ispccdc_obj.ccdcin_woffset) <<
-				ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_HORZ);
-		isp_reg_writel((ispccdc_obj.ccdcin_hoffset <<
-				ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
-			((ispccdc_obj.ccdcin_h-ispccdc_obj.ccdcin_hoffset) <<
-				ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_VERT);
-		isp_reg_writel((ispccdc_obj.ccdcout_w <<
-				ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
-			       (ispccdc_obj.ccdcout_h <<
-					ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
+	rval = ispccdc_config_datapath(isp_ccdc, pipe);
+	if (rval)
+		return rval;
+
+	isp_reg_writel(dev,
+		(pipe->ccdc_in_h_st << ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
+		((pipe->ccdc_in_w - pipe->ccdc_in_h_st) <<
+		ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
+		OMAP3_ISP_IOMEM_CCDC,
+		ISPCCDC_FMT_HORZ);
+	isp_reg_writel(dev,
+		(pipe->ccdc_in_v_st << ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
+		((pipe->ccdc_in_h - pipe->ccdc_in_v_st) <<
+		ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
+		OMAP3_ISP_IOMEM_CCDC,
+		ISPCCDC_FMT_VERT);
+	isp_reg_writel(dev,
+		pipe->ccdc_in_v_st << ISPCCDC_VERT_START_SLV0_SHIFT,
+		OMAP3_ISP_IOMEM_CCDC,
+		ISPCCDC_VERT_START);
+	isp_reg_writel(dev, (pipe->ccdc_out_h - pipe->ccdc_in_v_st - 1) <<
+		ISPCCDC_VERT_LINES_NLV_SHIFT,
+		OMAP3_ISP_IOMEM_CCDC,
+		ISPCCDC_VERT_LINES);
+	isp_reg_writel(dev,
+		(pipe->ccdc_in_h_st << ISPCCDC_HORZ_INFO_SPH_SHIFT)
+		| ((pipe->ccdc_out_w - pipe->ccdc_in_h_st)
+		<< ISPCCDC_HORZ_INFO_NPH_SHIFT),
+		OMAP3_ISP_IOMEM_CCDC,
+		ISPCCDC_HORZ_INFO);
+	ispccdc_config_outlineoffset(isp_ccdc, pipe->ccdc_out_w * 2, 0, 0);
+	isp_reg_writel(dev, (((pipe->ccdc_out_h - 2) &
+			 ISPCCDC_VDINT_0_MASK) <<
+			ISPCCDC_VDINT_0_SHIFT) |
+		       ((50 & ISPCCDC_VDINT_1_MASK) <<
+			ISPCCDC_VDINT_1_SHIFT),
+		       OMAP3_ISP_IOMEM_CCDC,
+		       ISPCCDC_VDINT);
+
+	if (pipe->ccdc_out == CCDC_OTHERS_MEM) {
+		isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_CCDC,
 			       ISPCCDC_VP_OUT);
-		isp_reg_writel((((ispccdc_obj.ccdcout_h - 25) &
-				 ISPCCDC_VDINT_0_MASK) <<
-				ISPCCDC_VDINT_0_SHIFT) |
-			       ((50 & ISPCCDC_VDINT_1_MASK) <<
-				ISPCCDC_VDINT_1_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_VDINT);
+        } else {
+                isp_reg_writel(dev,
+			((pipe->ccdc_out_w - pipe->ccdc_in_h_st)
+			<< ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
+			((pipe->ccdc_out_h - pipe->ccdc_in_v_st - 1) <<
+			ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
+			OMAP3_ISP_IOMEM_CCDC,
+			ISPCCDC_VP_OUT);
+        }
 
-	} else if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_MEM) {
-		isp_reg_writel(0, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT);
-		if (ispccdc_obj.ccdc_inpfmt == CCDC_RAW) {
-			isp_reg_writel(ispccdc_obj.ccdcin_woffset <<
-					ISPCCDC_HORZ_INFO_SPH_SHIFT
-				       | ((ispccdc_obj.ccdcout_w - 1)
-					  << ISPCCDC_HORZ_INFO_NPH_SHIFT),
-				       OMAP3_ISP_IOMEM_CCDC,
-				       ISPCCDC_HORZ_INFO);
-		} else {
-			isp_reg_writel(0 << ISPCCDC_HORZ_INFO_SPH_SHIFT
-				       | ((ispccdc_obj.ccdcout_w - 1)
-					  << ISPCCDC_HORZ_INFO_NPH_SHIFT),
-				       OMAP3_ISP_IOMEM_CCDC,
-				       ISPCCDC_HORZ_INFO);
-		}
-		isp_reg_writel(ispccdc_obj.ccdcin_hoffset <<
-				ISPCCDC_VERT_START_SLV0_SHIFT,
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_VERT_START);
-		isp_reg_writel((ispccdc_obj.ccdcout_h - 1) <<
-			       ISPCCDC_VERT_LINES_NLV_SHIFT,
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_VERT_LINES);
-
-		ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, 0, 0);
-		isp_reg_writel((((ispccdc_obj.ccdcout_h - 2) &
-				 ISPCCDC_VDINT_0_MASK) <<
-				ISPCCDC_VDINT_0_SHIFT) |
-			       ((100 & ISPCCDC_VDINT_1_MASK) <<
-				ISPCCDC_VDINT_1_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_VDINT);
-	} else if (ispccdc_obj.ccdc_outfmt == CCDC_OTHERS_VP_MEM) {
-		isp_reg_writel((ispccdc_obj.ccdcin_woffset <<
-				ISPCCDC_FMT_HORZ_FMTSPH_SHIFT) |
-			((ispccdc_obj.ccdcin_w - ispccdc_obj.ccdcin_woffset) <<
-				ISPCCDC_FMT_HORZ_FMTLNH_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_HORZ);
-		isp_reg_writel((ispccdc_obj.ccdcin_hoffset <<
-				ISPCCDC_FMT_VERT_FMTSLV_SHIFT) |
-			((ispccdc_obj.ccdcin_h - ispccdc_obj.ccdcin_hoffset) <<
-				ISPCCDC_FMT_VERT_FMTLNV_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_FMT_VERT);
-
-		isp_reg_writel((ispccdc_obj.ccdcout_w
-				<< ISPCCDC_VP_OUT_HORZ_NUM_SHIFT) |
-			       ((ispccdc_obj.ccdcout_h - 1) <<
-				ISPCCDC_VP_OUT_VERT_NUM_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_VP_OUT);
-		isp_reg_writel((ispccdc_obj.ccdcin_woffset
-				<< ISPCCDC_HORZ_INFO_SPH_SHIFT) |
-			       ((ispccdc_obj.ccdcout_w - 1) <<
-				ISPCCDC_HORZ_INFO_NPH_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_HORZ_INFO);
-		isp_reg_writel(ispccdc_obj.ccdcin_hoffset
-				<< ISPCCDC_VERT_START_SLV0_SHIFT,
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_VERT_START);
-		isp_reg_writel((ispccdc_obj.ccdcout_h - 1) <<
-			       ISPCCDC_VERT_LINES_NLV_SHIFT,
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_VERT_LINES);
-		ispccdc_config_outlineoffset(ispccdc_obj.ccdcout_w * 2, 0, 0);
-		isp_reg_writel((((ispccdc_obj.ccdcout_h - 2) &
-				 ISPCCDC_VDINT_0_MASK) <<
-				ISPCCDC_VDINT_0_SHIFT) |
-			       ((100 & ISPCCDC_VDINT_1_MASK) <<
-				ISPCCDC_VDINT_1_SHIFT),
-			       OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_VDINT);
-	}
-
-	if (is_isplsc_activated()) {
-		if (ispccdc_obj.ccdc_inpfmt == CCDC_RAW) {
-			ispccdc_config_lsc(&lsc_config);
-			ispccdc_load_lsc(lsc_gain_table, lsc_config.size);
-		}
-	}
+	ispccdc_setup_lsc(isp_ccdc, pipe);
 
 	return 0;
 }
-EXPORT_SYMBOL(ispccdc_config_size);
 
 /**
- * ispccdc_config_outlineoffset - Configures the output line offset
- * @offset: Must be twice the Output width and aligned on 32 byte boundary
- * @oddeven: Specifies the odd/even line pattern to be chosen to store the
- *           output.
- * @numlines: Set the value 0-3 for +1-4lines, 4-7 for -1-4lines.
+ * ispccdc_set_raw_offset - Store the component order as component offset.
+ * @raw_fmt: Input data component order.
  *
- * - Configures the output line offset when stored in memory
- * - Sets the odd/even line pattern to store the output
- *    (EVENEVEN (1), ODDEVEN (2), EVENODD (3), ODDODD (4))
- * - Configures the number of even and odd line fields in case of rearranging
- * the lines.
- *
- * Returns 0 if successful, or -EINVAL if the offset is not in 32 byte
- * boundary.
+ * Turns the component order into a horizontal & vertical offset and store
+ * offsets to be used later.
  **/
-int ispccdc_config_outlineoffset(u32 offset, u8 oddeven, u8 numlines)
+void ispccdc_set_raw_offset(struct isp_ccdc_device *isp_ccdc,
+			    enum ispccdc_raw_fmt raw_fmt)
 {
-	if ((offset & ISP_32B_BOUNDARY_OFFSET) == offset) {
-		isp_reg_writel((offset & 0xFFFF), OMAP3_ISP_IOMEM_CCDC,
-			       ISPCCDC_HSIZE_OFF);
-	} else {
-		DPRINTK_ISPCCDC("ISP_ERR : Offset should be in 32 byte"
-				" boundary\n");
-		return -EINVAL;
-	}
-
-	isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-		    ~ISPCCDC_SDOFST_FINV);
-
-	isp_reg_and(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-		    ~ISPCCDC_SDOFST_FOFST_4L);
-
-	switch (oddeven) {
-	case EVENEVEN:
-		isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-			   (numlines & 0x7) << ISPCCDC_SDOFST_LOFST0_SHIFT);
-		break;
-	case ODDEVEN:
-		isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-			   (numlines & 0x7) << ISPCCDC_SDOFST_LOFST1_SHIFT);
-		break;
-	case EVENODD:
-		isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-			   (numlines & 0x7) << ISPCCDC_SDOFST_LOFST2_SHIFT);
-		break;
-	case ODDODD:
-		isp_reg_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST,
-			   (numlines & 0x7) << ISPCCDC_SDOFST_LOFST3_SHIFT);
-		break;
-	default:
-		break;
-	}
-	return 0;
+	isp_ccdc->raw_fmt_in = raw_fmt;
 }
-EXPORT_SYMBOL(ispccdc_config_outlineoffset);
+EXPORT_SYMBOL(ispccdc_set_raw_offset);
 
 /**
- * ispccdc_set_outaddr - Sets the memory address where the output will be saved
- * @addr: 32-bit memory address aligned on 32 byte boundary.
- *
- * Sets the memory address where the output will be saved.
- *
- * Returns 0 if successful, or -EINVAL if the address is not in the 32 byte
- * boundary.
- **/
-int ispccdc_set_outaddr(u32 addr)
-{
-	if ((addr & ISP_32B_BOUNDARY_BUF) == addr) {
-		isp_reg_writel(addr, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR);
-		return 0;
-	} else {
-		DPRINTK_ISPCCDC("ISP_ERR : Address should be in 32 byte"
-				" boundary\n");
-		return -EINVAL;
-	}
-
-}
-EXPORT_SYMBOL(ispccdc_set_outaddr);
-
-void __ispccdc_enable(u8 enable)
-{
-	if (enable) {
-		if (ispccdc_obj.lsc_enable
-		    && ispccdc_obj.ccdc_inpfmt == CCDC_RAW)
-			ispccdc_enable_lsc(1);
-
-	} else {
-		ispccdc_obj.lsc_enable = ispccdc_obj.lsc_state;
-	}
-
-	isp_reg_and_or(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR, ~ISPCCDC_PCR_EN,
-		       enable ? ISPCCDC_PCR_EN : 0);
-}
-
-/**
- * ispccdc_enable - Enables the CCDC module.
+ * ispccdc_enable - Enable the CCDC module.
+ * @isp_ccdc: Pointer to ISP CCDC device.
  * @enable: 0 Disables CCDC, 1 Enables CCDC
  *
  * Client should configure all the sub modules in CCDC before this.
  **/
-void ispccdc_enable(u8 enable)
+void ispccdc_enable(struct isp_ccdc_device *isp_ccdc, u8 enable)
 {
-	__ispccdc_enable(enable);
-	ispccdc_obj.pm_state = enable;
-}
-EXPORT_SYMBOL(ispccdc_enable);
+	struct isp_device *isp = to_isp_device(isp_ccdc);
+	struct device *dev = to_device(isp_ccdc);
+	int enable_lsc;
 
-/**
- * ispccdc_suspend - Suspend the CCDC module.
- **/
-void ispccdc_suspend(void)
-{
-	if (ispccdc_obj.pm_state) {
-		if (ispccdc_obj.lsc_state)
-			__ispccdc_enable_lsc(0);
-		else if (ispccdc_obj.lsc_enable) {
-			ispccdc_obj.lsc_state = 1;
-			ispccdc_obj.lsc_enable = 0;
+	if (enable) {
+		enable_lsc = enable &&
+		((isp->pipeline.ccdc_in == CCDC_RAW_GRBG) ||
+		 (isp->pipeline.ccdc_in == CCDC_RAW_RGGB) ||
+		 (isp->pipeline.ccdc_in == CCDC_RAW_BGGR) ||
+		 (isp->pipeline.ccdc_in == CCDC_RAW_GBRG)) &&
+		     isp_ccdc->lsc_request_enable &&
+		     ispccdc_validate_config_lsc(isp_ccdc,
+					&isp_ccdc->lsc_config) == 0;
+
+		if (enable_lsc) {
+			/* Defer CCDC enablement for
+			 * when the prefetch is completed. */
+			isp_reg_writel(dev, IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ,
+				       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+			isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+				   IRQ0ENABLE_CCDC_LSC_PREF_COMP_IRQ);
+			ispccdc_enable_lsc(isp_ccdc, 1);
+			return;
 		}
-		__ispccdc_enable(0);
+		isp_reg_writel(dev, IRQ0ENABLE_CCDC_VD1_IRQ,
+			OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS);
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+			IRQ0ENABLE_CCDC_VD1_IRQ);
+	} else {
+		ispccdc_enable_lsc(isp_ccdc, 0);
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
+			    ~IRQ0ENABLE_CCDC_VD1_IRQ);
+		isp_ccdc->lsc_request_enable = isp_ccdc->lsc_enable;
 	}
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR,
+		       ~ISPCCDC_PCR_EN, enable ? ISPCCDC_PCR_EN : 0);
 }
-EXPORT_SYMBOL(ispccdc_suspend);
 
 /**
- * ispccdc_resume - Resume the CCDC module.
- **/
-void ispccdc_resume(void)
-{
-	if (ispccdc_obj.pm_state) {
-		if (ispccdc_obj.lsc_state)
-			__ispccdc_enable_lsc(1);
-		__ispccdc_enable(1);
-	}
-}
-EXPORT_SYMBOL(ispccdc_resume);
-
-/*
+ * ispccdc_sbl_busy - Poll idle state of CCDC and related SBL memory write bits
+ * @_isp_ccdc: Pointer to ISP CCDC device.
+ *
  * Returns zero if the CCDC is idle and the image has been written to
  * memory, too.
- */
-int ispccdc_sbl_busy(void)
+ **/
+int ispccdc_sbl_busy(void *_isp_ccdc)
 {
-	return ispccdc_busy()
-		| (isp_reg_readl(OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_0) &
+	struct isp_ccdc_device *isp_ccdc = _isp_ccdc;
+	struct device *dev = to_device(isp_ccdc);
+
+	return ispccdc_busy(isp_ccdc)
+		| (isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL,
+				 ISPSBL_CCDC_WR_0) &
 		   ISPSBL_CCDC_WR_0_DATA_READY)
-		| (isp_reg_readl(OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_1) &
+		| (isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL,
+				 ISPSBL_CCDC_WR_1) &
 		   ISPSBL_CCDC_WR_0_DATA_READY)
-		| (isp_reg_readl(OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_2) &
+		| (isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL,
+				 ISPSBL_CCDC_WR_2) &
 		   ISPSBL_CCDC_WR_0_DATA_READY)
-		| (isp_reg_readl(OMAP3_ISP_IOMEM_SBL, ISPSBL_CCDC_WR_3) &
+		| (isp_reg_readl(dev, OMAP3_ISP_IOMEM_SBL,
+				 ISPSBL_CCDC_WR_3) &
 		   ISPSBL_CCDC_WR_0_DATA_READY);
 }
-EXPORT_SYMBOL(ispccdc_sbl_busy);
 
 /**
- * ispccdc_busy - Gets busy state of the CCDC.
+ * ispccdc_busy - Get busy state of the CCDC.
+ * @isp_ccdc: Pointer to ISP CCDC device.
  **/
-int ispccdc_busy(void)
+int ispccdc_busy(struct isp_ccdc_device *isp_ccdc)
 {
-	return isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR) &
+	struct device *dev = to_device(isp_ccdc);
+
+	return isp_reg_readl(dev, OMAP3_ISP_IOMEM_CCDC,
+			     ISPCCDC_PCR) &
 		ISPCCDC_PCR_BUSY;
 }
-EXPORT_SYMBOL(ispccdc_busy);
 
 /**
- * ispccdc_save_context - Saves the values of the CCDC module registers
+ * ispccdc_lsc_can_stop - Indicate if ccdc lsc module can be stopped corectly.
+ * @isp_ccdc: Pointer to ISP CCDC device.
  **/
-void ispccdc_save_context(void)
+int ispccdc_lsc_delay_stop(struct isp_ccdc_device *isp_ccdc)
+{
+	return isp_ccdc->lsc_delay_stop;
+}
+EXPORT_SYMBOL(ispccdc_lsc_delay_stop);
+
+/**
+ * ispccdc_config_shadow_registers - Configure CCDC during interframe time.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ *
+ * Executes LSC deferred enablement before next frame starts.
+ **/
+void ispccdc_config_shadow_registers(struct isp_ccdc_device *isp_ccdc)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&isp_ccdc->lock, flags);
+	if (isp_ccdc->shadow_update)
+		goto skip;
+
+	if (isp_ccdc->lsc_defer_setup) {
+		__ispccdc_enable_lsc(isp_ccdc, 0);
+		isp_ccdc->lsc_defer_setup = 0;
+		goto skip;
+	}
+
+	if (isp_ccdc->update_lsc_table) {
+		unsigned long n = isp_ccdc->lsc_table_new;
+		/* Swap tables--no need to vfree in interrupt context */
+		isp_ccdc->lsc_table_new = isp_ccdc->lsc_table_inuse;
+		isp_ccdc->lsc_table_inuse = n;
+		ispccdc_program_lsc(isp_ccdc);
+		isp_ccdc->update_lsc_table = 0;
+	}
+
+	if (isp_ccdc->update_lsc_config) {
+		ispccdc_config_lsc(isp_ccdc);
+		__ispccdc_enable_lsc(isp_ccdc, isp_ccdc->lsc_request_enable);
+		isp_ccdc->update_lsc_config = 0;
+	}
+
+skip:
+	spin_unlock_irqrestore(&isp_ccdc->lock, flags);
+}
+
+/**
+ * ispccdc_config - Set CCDC configuration from userspace
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * @userspace_add: Structure containing CCDC configuration sent from userspace.
+ *
+ * Returns 0 if successful, -EINVAL if the pointer to the configuration
+ * structure is null, or the copy_from_user function fails to copy user space
+ * memory to kernel space memory.
+ **/
+int ispccdc_config(struct isp_ccdc_device *isp_ccdc,
+			     void *userspace_add)
+{
+	struct isp_device *isp = to_isp_device(isp_ccdc);
+	struct device *dev = to_device(isp_ccdc);
+	struct ispccdc_bclamp bclamp_t;
+	struct ispccdc_blcomp blcomp_t;
+	struct ispccdc_fpc fpc_t;
+	struct ispccdc_culling cull_t;
+	struct ispccdc_update_config *ccdc_struct;
+	unsigned long flags;
+	int ret = 0;
+
+	if (userspace_add == NULL)
+		return -EINVAL;
+
+	ccdc_struct = userspace_add;
+
+	spin_lock_irqsave(&isp_ccdc->lock, flags);
+	isp_ccdc->shadow_update = 1;
+	spin_unlock_irqrestore(&isp_ccdc->lock, flags);
+
+	if (ISP_ABS_CCDC_ALAW & ccdc_struct->flag) {
+		if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
+			ispccdc_config_alaw(isp_ccdc, ccdc_struct->alawip);
+		ispccdc_enable_alaw(isp_ccdc, 1);
+	} else if (ISP_ABS_CCDC_ALAW & ccdc_struct->update)
+		ispccdc_enable_alaw(isp_ccdc, 0);
+
+	if (ISP_ABS_CCDC_LPF & ccdc_struct->flag)
+		ispccdc_enable_lpf(isp_ccdc, 1);
+	else
+		ispccdc_enable_lpf(isp_ccdc, 0);
+
+	if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->flag) {
+		if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
+			if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
+					   ccdc_struct->bclamp,
+					   sizeof(struct ispccdc_bclamp))) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			ispccdc_enable_black_clamp(isp_ccdc, 1);
+			ispccdc_config_black_clamp(isp_ccdc, bclamp_t);
+		} else
+			ispccdc_enable_black_clamp(isp_ccdc, 1);
+	} else {
+		if (ISP_ABS_CCDC_BLCLAMP & ccdc_struct->update) {
+			if (copy_from_user(&bclamp_t, (struct ispccdc_bclamp *)
+					   ccdc_struct->bclamp,
+					   sizeof(struct ispccdc_bclamp))) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			ispccdc_enable_black_clamp(isp_ccdc, 0);
+			ispccdc_config_black_clamp(isp_ccdc, bclamp_t);
+		}
+	}
+
+	if (ISP_ABS_CCDC_BCOMP & ccdc_struct->update) {
+		if (copy_from_user(&blcomp_t, (struct ispccdc_blcomp *)
+				   ccdc_struct->blcomp,
+				   sizeof(blcomp_t))) {
+			ret = -EFAULT;
+			goto out;
+		}
+
+		ispccdc_config_black_comp(isp_ccdc, blcomp_t);
+	}
+
+	if (ISP_ABS_CCDC_FPC & ccdc_struct->flag) {
+		if (ISP_ABS_CCDC_FPC & ccdc_struct->update) {
+			if (copy_from_user(&fpc_t, (struct ispccdc_fpc *)
+					   ccdc_struct->fpc,
+					   sizeof(fpc_t))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			isp_ccdc->fpc_table_add = kmalloc(64 + fpc_t.fpnum * 4,
+						GFP_KERNEL | GFP_DMA);
+			if (!isp_ccdc->fpc_table_add) {
+				ret = -ENOMEM;
+				goto out;
+			}
+			while (((unsigned long)isp_ccdc->fpc_table_add
+				& 0xFFFFFFC0)
+			       != (unsigned long)isp_ccdc->fpc_table_add)
+				isp_ccdc->fpc_table_add++;
+
+			isp_ccdc->fpc_table_add_m = iommu_kmap(
+				isp->iommu,
+				0,
+				virt_to_phys(isp_ccdc->fpc_table_add),
+				fpc_t.fpnum * 4,
+				IOMMU_FLAG);
+			/* FIXME: Correct unwinding */
+			BUG_ON(IS_ERR_VALUE(isp_ccdc->fpc_table_add_m));
+
+			if (copy_from_user(isp_ccdc->fpc_table_add,
+					   (u32 *)fpc_t.fpcaddr,
+					   fpc_t.fpnum * 4)) {
+				ret = -EFAULT;
+				goto out;
+			}
+
+			fpc_t.fpcaddr = isp_ccdc->fpc_table_add_m;
+			ispccdc_config_fpc(isp_ccdc, fpc_t);
+		}
+		ispccdc_enable_fpc(isp_ccdc, 1);
+	} else if (ISP_ABS_CCDC_FPC & ccdc_struct->update)
+		ispccdc_enable_fpc(isp_ccdc, 0);
+
+	if (ISP_ABS_CCDC_CULL & ccdc_struct->update) {
+		if (copy_from_user(&cull_t, (struct ispccdc_culling *)
+				   ccdc_struct->cull,
+				   sizeof(cull_t))) {
+			ret = -EFAULT;
+			goto out;
+		}
+		ispccdc_config_culling(isp_ccdc, cull_t);
+	}
+
+	if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->update) {
+		if (ISP_ABS_CCDC_CONFIG_LSC & ccdc_struct->flag) {
+			struct ispccdc_lsc_config cfg;
+			if (copy_from_user(&cfg, ccdc_struct->lsc_cfg,
+					   sizeof(cfg))) {
+				ret = -EFAULT;
+				goto out;
+			}
+			ret = ispccdc_validate_config_lsc(isp_ccdc, &cfg);
+			if (ret)
+				goto out;
+			memcpy(&isp_ccdc->lsc_config, &cfg,
+			       sizeof(isp_ccdc->lsc_config));
+			isp_ccdc->lsc_request_enable = 1;
+		} else {
+			isp_ccdc->lsc_request_enable = 0;
+		}
+		isp_ccdc->update_lsc_config = 1;
+	}
+
+	if (ISP_ABS_TBL_LSC & ccdc_struct->update) {
+		void *n;
+		if (isp_ccdc->lsc_table_new != PTR_FREE)
+			iommu_vfree(isp->iommu, isp_ccdc->lsc_table_new);
+		isp_ccdc->lsc_table_new = iommu_vmalloc(isp->iommu, 0,
+						isp_ccdc->lsc_config.size,
+						IOMMU_FLAG);
+		if (IS_ERR_VALUE(isp_ccdc->lsc_table_new)) {
+			/* Disable LSC if table can not be allocated */
+			isp_ccdc->lsc_table_new = PTR_FREE;
+			isp_ccdc->lsc_request_enable = 0;
+			isp_ccdc->update_lsc_config = 1;
+			ret = -ENOMEM;
+			goto out;
+		}
+		n = da_to_va(isp->iommu, isp_ccdc->lsc_table_new);
+		if (copy_from_user(n, ccdc_struct->lsc,
+				   isp_ccdc->lsc_config.size)) {
+			ret = -EFAULT;
+			goto out;
+		}
+		isp_ccdc->update_lsc_table = 1;
+	}
+
+	if (isp_ccdc->update_lsc_table || isp_ccdc->update_lsc_config) {
+		if (isp->running != ISP_RUNNING)
+			ispccdc_setup_lsc(isp_ccdc, &isp->pipeline);
+		else if (isp_ccdc->lsc_enable)
+			isp_ccdc->lsc_defer_setup = 1;
+		else if (isp_ccdc->lsc_request_enable) {
+			ispccdc_setup_lsc(isp_ccdc, &isp->pipeline);
+			ispccdc_enable_lsc(isp_ccdc, 1);
+		}
+	}
+
+	if (ISP_ABS_CCDC_COLPTN & ccdc_struct->update)
+		ispccdc_config_imgattr(isp_ccdc, ccdc_struct->colptn);
+
+out:
+	if (ret == -EFAULT)
+		dev_err(dev,
+		       "ccdc: user provided bad configuration data address");
+
+	if (ret == -ENOMEM)
+		dev_err(dev,
+		       "ccdc: can not allocate memory");
+
+	isp_ccdc->shadow_update = 0;
+	return ret;
+}
+
+/**
+ * ispccdc_request - Reserve the CCDC module.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ * Reserves the CCDC module and assures that is used only once at a time.
+ *
+ * Returns 0 if successful, or -EBUSY if CCDC module is busy.
+ **/
+int ispccdc_request(struct isp_ccdc_device *isp_ccdc)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	mutex_lock(&isp_ccdc->mutexlock);
+	if (isp_ccdc->ccdc_inuse) {
+		mutex_unlock(&isp_ccdc->mutexlock);
+		DPRINTK_ISPCCDC("ISP_ERR : CCDC Module Busy\n");
+		return -EBUSY;
+	}
+
+	isp_ccdc->ccdc_inuse = 1;
+	mutex_unlock(&isp_ccdc->mutexlock);
+	isp_reg_or(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+		   ISPCTRL_CCDC_RAM_EN | ISPCTRL_CCDC_CLK_EN |
+		   ISPCTRL_SBL_WR1_RAM_EN);
+	isp_reg_or(dev, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
+		   ISPCCDC_CFG_VDLC);
+	return 0;
+}
+
+/**
+ * ispccdc_free - Free the CCDC module.
+ * @isp_ccdc: Pointer to ISP CCDC device.
+ *
+ * Frees the CCDC module so it can be used by another process.
+ *
+ * Returns 0 if successful, or -EINVAL if module has been already freed.
+ **/
+int ispccdc_free(struct isp_ccdc_device *isp_ccdc)
+{
+	struct device *dev = to_device(isp_ccdc);
+
+	mutex_lock(&isp_ccdc->mutexlock);
+	if (!isp_ccdc->ccdc_inuse) {
+		mutex_unlock(&isp_ccdc->mutexlock);
+		DPRINTK_ISPCCDC("ISP_ERR: CCDC Module already freed\n");
+		return -EINVAL;
+	}
+
+	isp_ccdc->ccdc_inuse = 0;
+	mutex_unlock(&isp_ccdc->mutexlock);
+	isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+		    ~(ISPCTRL_CCDC_CLK_EN |
+		      ISPCTRL_CCDC_RAM_EN |
+		      ISPCTRL_SBL_WR1_RAM_EN));
+	return 0;
+}
+
+/**
+ * ispccdc_save_context - Save values of the CCDC module registers
+ * @dev: Device pointer specific to the OMAP3 ISP.
+ **/
+void ispccdc_save_context(struct device *dev)
 {
 	DPRINTK_ISPCCDC("Saving context\n");
-	isp_save_context(ispccdc_reg_list);
+	isp_save_context(dev, ispccdc_reg_list);
 }
-EXPORT_SYMBOL(ispccdc_save_context);
 
 /**
- * ispccdc_restore_context - Restores the values of the CCDC module registers
+ * ispccdc_restore_context - Restore values of the CCDC module registers
+ * @dev: Pointer to ISP device
  **/
-void ispccdc_restore_context(void)
+void ispccdc_restore_context(struct device *dev)
 {
 	DPRINTK_ISPCCDC("Restoring context\n");
-	isp_restore_context(ispccdc_reg_list);
+	isp_restore_context(dev, ispccdc_reg_list);
 }
-EXPORT_SYMBOL(ispccdc_restore_context);
-
-/**
- * ispccdc_print_status - Prints the values of the CCDC Module registers
- *
- * Also prints other debug information stored in the CCDC module.
- **/
-void ispccdc_print_status(void)
-{
-	if (!is_ispccdc_debug_enabled())
-		return;
-
-	DPRINTK_ISPCCDC("Module in use =%d\n", ispccdc_obj.ccdc_inuse);
-	DPRINTK_ISPCCDC("Accepted CCDC Input (width = %d,Height = %d)\n",
-			ispccdc_obj.ccdcin_w,
-			ispccdc_obj.ccdcin_h);
-	DPRINTK_ISPCCDC("Accepted CCDC Output (width = %d,Height = %d)\n",
-			ispccdc_obj.ccdcout_w,
-			ispccdc_obj.ccdcout_h);
-	DPRINTK_ISPCCDC("###CCDC PCR=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_PCR));
-	DPRINTK_ISPCCDC("ISP_CTRL =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
-	switch (ispccdc_obj.ccdc_inpfmt) {
-	case CCDC_RAW:
-		DPRINTK_ISPCCDC("ccdc input format is CCDC_RAW\n");
-		break;
-	case CCDC_YUV_SYNC:
-		DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_SYNC\n");
-		break;
-	case CCDC_YUV_BT:
-		DPRINTK_ISPCCDC("ccdc input format is CCDC_YUV_BT\n");
-		break;
-	}
-
-	switch (ispccdc_obj.ccdc_outfmt) {
-	case CCDC_OTHERS_VP:
-		DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_VP\n");
-		break;
-	case CCDC_OTHERS_MEM:
-		DPRINTK_ISPCCDC("ccdc output format is CCDC_OTHERS_MEM\n");
-		break;
-	case CCDC_YUV_RSZ:
-		DPRINTK_ISPCCDC("ccdc output format is CCDC_YUV_RSZ\n");
-		break;
-	}
-
-	DPRINTK_ISPCCDC("###ISP_CTRL in ccdc =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
-	DPRINTK_ISPCCDC("###ISP_IRQ0ENABLE in ccdc =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
-	DPRINTK_ISPCCDC("###ISP_IRQ0STATUS in ccdc =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
-	DPRINTK_ISPCCDC("###CCDC SYN_MODE=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE));
-	DPRINTK_ISPCCDC("###CCDC HORZ_INFO=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO));
-	DPRINTK_ISPCCDC("###CCDC VERT_START=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
-				      ISPCCDC_VERT_START));
-	DPRINTK_ISPCCDC("###CCDC VERT_LINES=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
-				      ISPCCDC_VERT_LINES));
-	DPRINTK_ISPCCDC("###CCDC CULLING=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CULLING));
-	DPRINTK_ISPCCDC("###CCDC HSIZE_OFF=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF));
-	DPRINTK_ISPCCDC("###CCDC SDOFST=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDOFST));
-	DPRINTK_ISPCCDC("###CCDC SDR_ADDR=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR));
-	DPRINTK_ISPCCDC("###CCDC CLAMP=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CLAMP));
-	DPRINTK_ISPCCDC("###CCDC COLPTN=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_COLPTN));
-	DPRINTK_ISPCCDC("###CCDC CFG=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG));
-	DPRINTK_ISPCCDC("###CCDC VP_OUT=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_VP_OUT));
-	DPRINTK_ISPCCDC("###CCDC_SDR_ADDR= 0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR));
-	DPRINTK_ISPCCDC("###CCDC FMTCFG=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG));
-	DPRINTK_ISPCCDC("###CCDC FMT_HORZ=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_HORZ));
-	DPRINTK_ISPCCDC("###CCDC FMT_VERT=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMT_VERT));
-	DPRINTK_ISPCCDC("###CCDC LSC_CONFIG=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
-				      ISPCCDC_LSC_CONFIG));
-	DPRINTK_ISPCCDC("###CCDC LSC_INIT=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
-				      ISPCCDC_LSC_INITIAL));
-	DPRINTK_ISPCCDC("###CCDC LSC_TABLE BASE=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
-				      ISPCCDC_LSC_TABLE_BASE));
-	DPRINTK_ISPCCDC("###CCDC LSC TABLE OFFSET=0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
-				      ISPCCDC_LSC_TABLE_OFFSET));
-}
-EXPORT_SYMBOL(ispccdc_print_status);
 
 /**
  * isp_ccdc_init - CCDC module initialization.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  *
  * Always returns 0
  **/
-int __init isp_ccdc_init(void)
+int __init isp_ccdc_init(struct device *dev)
 {
-	ispccdc_obj.ccdc_inuse = 0;
-	ispccdc_config_crop(0, 0, 0, 0);
-	mutex_init(&ispccdc_obj.mutexlock);
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_ccdc_device *isp_ccdc = &isp->isp_ccdc;
+	void *p;
 
-	if (is_isplsc_activated()) {
-		lsc_gain_table_tmp = kmalloc(LSC_TABLE_INIT_SIZE, GFP_KERNEL |
-					     GFP_DMA);
-		memset(lsc_gain_table_tmp, 0x40, LSC_TABLE_INIT_SIZE);
-		lsc_config.initial_x = 0;
-		lsc_config.initial_y = 0;
-		lsc_config.gain_mode_n = 0x6;
-		lsc_config.gain_mode_m = 0x6;
-		lsc_config.gain_format = 0x4;
-		lsc_config.offset = 0x60;
-		lsc_config.size = LSC_TABLE_INIT_SIZE;
-		ispccdc_obj.lsc_enable = 1;
-	}
+	isp_ccdc->ccdc_inuse = 0;
+	ispccdc_config_crop(isp_ccdc, 0, 0, 0, 0);
+	mutex_init(&isp_ccdc->mutexlock);
+
+	isp_ccdc->update_lsc_config = 0;
+	isp_ccdc->lsc_request_enable = 1;
+	isp_ccdc->lsc_defer_setup = 0;
+	isp_ccdc->lsc_delay_stop = 0;
+
+	isp_ccdc->lsc_config.initial_x = 0;
+	isp_ccdc->lsc_config.initial_y = 0;
+	isp_ccdc->lsc_config.gain_mode_n = 0x6;
+	isp_ccdc->lsc_config.gain_mode_m = 0x6;
+	isp_ccdc->lsc_config.gain_format = 0x4;
+	isp_ccdc->lsc_config.offset = 0x60;
+	isp_ccdc->lsc_config.size = LSC_TABLE_INIT_SIZE;
+
+	isp_ccdc->update_lsc_table = 0;
+	isp_ccdc->lsc_table_new = PTR_FREE;
+	isp_ccdc->lsc_table_inuse = iommu_vmalloc(isp->iommu, 0,
+						  LSC_TABLE_INIT_SIZE,
+						  IOMMU_FLAG);
+	if (IS_ERR_VALUE(isp_ccdc->lsc_table_inuse))
+		return -ENOMEM;
+	p = da_to_va(isp->iommu, isp_ccdc->lsc_table_inuse);
+	memset(p, 0x40, LSC_TABLE_INIT_SIZE);
+
+	isp_ccdc->shadow_update = 0;
+	spin_lock_init(&isp_ccdc->lock);
 
 	return 0;
 }
 
 /**
  * isp_ccdc_cleanup - CCDC module cleanup.
+ * @dev: Device pointer specific to the OMAP3 ISP.
  **/
-void isp_ccdc_cleanup(void)
+void isp_ccdc_cleanup(struct device *dev)
 {
-	if (is_isplsc_activated()) {
-		ispccdc_free_lsc();
-		kfree(lsc_gain_table_tmp);
-	}
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_ccdc_device *isp_ccdc = &isp->isp_ccdc;
 
-	if (fpc_table_add_m != 0) {
-		ispmmu_kunmap(fpc_table_add_m);
-		kfree(fpc_table_add);
+	iommu_vfree(isp->iommu, isp_ccdc->lsc_table_inuse);
+	if (isp_ccdc->lsc_table_new != PTR_FREE)
+		iommu_vfree(isp->iommu, isp_ccdc->lsc_table_new);
+
+	if (isp_ccdc->fpc_table_add_m != 0) {
+		iommu_kunmap(isp->iommu, isp_ccdc->fpc_table_add_m);
+		kfree(isp_ccdc->fpc_table_add);
 	}
 }
diff --git a/drivers/media/video/isp/ispccdc.h b/drivers/media/video/isp/ispccdc.h
index 606857a..9cfbc5c 100644
--- a/drivers/media/video/isp/ispccdc.h
+++ b/drivers/media/video/isp/ispccdc.h
@@ -28,7 +28,10 @@
 
 /* Enumeration constants for CCDC input output format */
 enum ccdc_input {
-	CCDC_RAW,
+	CCDC_RAW_GRBG,
+	CCDC_RAW_RGGB,
+	CCDC_RAW_BGGR,
+	CCDC_RAW_GBRG,
 	CCDC_YUV_SYNC,
 	CCDC_YUV_BT,
 	CCDC_OTHERS
@@ -130,82 +133,97 @@
 	u32 fmtaddr7;
 };
 
-int ispccdc_request(void);
+enum ispccdc_raw_fmt {
+	ISPCCDC_INPUT_FMT_GR_BG,
+	ISPCCDC_INPUT_FMT_RG_GB,
+	ISPCCDC_INPUT_FMT_BG_GR,
+	ISPCCDC_INPUT_FMT_GB_RG,
+};
 
-int ispccdc_free(void);
+/**
+ * struct isp_ccdc_device - Structure for the CCDC module to store its own
+ *			    information
+ * @ccdc_inuse: Flag to determine if CCDC has been reserved or not (0 or 1).
+ * @ccdcin_woffset: CCDC input horizontal offset.
+ * @ccdcin_hoffset: CCDC input vertical offset.
+ * @crop_w: Crop width.
+ * @crop_h: Crop weight.
+ * @vpout_en: Video port output enable.
+ * @wen: Data write enable.
+ * @exwen: External data write enable.
+ * @refmt_en: Reformatter enable.
+ * @ccdcslave: CCDC slave mode enable.
+ * @syncif_ipmod: Image
+ * @obclamp_en: Data input format.
+ * @mutexlock: Mutex used to get access to the CCDC.
+ * @wenlog: Write Enable logic to use against valid data signal.
+ * @fpc_table_add_m: ISP MMU mapped address of the current used FPC table.
+ * @fpc_table_add: Virtual address of the current used FPC table.
+ * @update_lsc_config: Set when user changes lsc_config
+ * @lsc_request_enable: Whether LSC is requested to be enabled
+ * @lsc_config: LSC config set by user
+ * @update_lsc_table: Set when user provides a new LSC table to lsc_table_new
+ * @lsc_table_new: LSC table set by user, ISP address
+ * @lsc_table_inuse: LSC table currently in use, ISP address
+ * @shadow_update: non-zero when user is updating CCDC configuration
+ * @lock: serializes shadow_update with interrupt handler
+ */
+struct isp_ccdc_device {
+	u8 ccdc_inuse;
+	u32 ccdcin_woffset;
+	u32 ccdcin_hoffset;
+	u32 crop_w;
+	u32 crop_h;
+	u8 vpout_en;
+	u8 wen;
+	u8 exwen;
+	u8 refmt_en;
+	u8 ccdcslave;
+	u8 syncif_ipmod;
+	u8 obclamp_en;
+	struct mutex mutexlock; /* For checking/modifying ccdc_inuse */
+	u32 wenlog;
+	unsigned long fpc_table_add_m;
+	u32 *fpc_table_add;
+	enum ispccdc_raw_fmt raw_fmt_in;
 
-int ispccdc_config_datapath(enum ccdc_input input, enum ccdc_output output);
+	/* LSC related fields */
+	u8 lsc_delay_stop;
+	u8 lsc_enable;
+	u8 update_lsc_config;
+	u8 lsc_request_enable;
+	u8 lsc_defer_setup;
+	struct ispccdc_lsc_config lsc_config;
+	u8 update_lsc_table;
+	u32 lsc_table_new;
+	u32 lsc_table_inuse;
 
-void ispccdc_config_crop(u32 left, u32 top, u32 height, u32 width);
+	int shadow_update;
+	spinlock_t lock;
+};
 
-void ispccdc_config_sync_if(struct ispccdc_syncif syncif);
-
-int ispccdc_config_black_clamp(struct ispccdc_bclamp bclamp);
-
-void ispccdc_enable_black_clamp(u8 enable);
-
-int ispccdc_config_fpc(struct ispccdc_fpc fpc);
-
-void ispccdc_enable_fpc(u8 enable);
-
-void ispccdc_config_black_comp(struct ispccdc_blcomp blcomp);
-
-void ispccdc_config_vp(struct ispccdc_vp vp);
-
-void ispccdc_enable_vp(u8 enable);
-
-void ispccdc_config_reformatter(struct ispccdc_refmt refmt);
-
-void ispccdc_enable_reformatter(u8 enable);
-
-void ispccdc_config_culling(struct ispccdc_culling culling);
-
-void ispccdc_enable_lpf(u8 enable);
-
-void ispccdc_config_alaw(enum alaw_ipwidth ipwidth);
-
-void ispccdc_enable_alaw(u8 enable);
-
-int ispccdc_load_lsc(u8 *table_addr, u32 table_size);
-
-void ispccdc_config_lsc(struct ispccdc_lsc_config *lsc_cfg);
-
-void ispccdc_enable_lsc(u8 enable);
-
-void ispccdc_lsc_error_handler(void);
-
-void ispccdc_config_imgattr(u32 colptn);
-
-void ispccdc_config_shadow_registers(void);
-
-int ispccdc_try_size(u32 input_w, u32 input_h, u32 *output_w, u32 *output_h);
-
-int ispccdc_config_size(u32 input_w, u32 input_h, u32 output_w, u32 output_h);
-
-int ispccdc_config_outlineoffset(u32 offset, u8 oddeven, u8 numlines);
-
-int ispccdc_set_outaddr(u32 addr);
-
-void ispccdc_enable(u8 enable);
-
-void ispccdc_suspend(void);
-
-void ispccdc_resume(void);
-
-int ispccdc_sbl_busy(void);
-
-int ispccdc_busy(void);
-
-void ispccdc_save_context(void);
-
-void ispccdc_restore_context(void);
-
-void ispccdc_print_status(void);
-
-int omap34xx_isp_ccdc_config(void *userspace_add);
-
-void ispccdc_set_wenlog(u32 wenlog);
-
-void ispccdc_set_crop_offset(enum ispccdc_raw_fmt);
+int ispccdc_set_outaddr(struct isp_ccdc_device *isp_ccdc, u32 addr);
+void ispccdc_set_wenlog(struct isp_ccdc_device *isp_ccdc, u32 wenlog);
+int ispccdc_try_pipeline(struct isp_ccdc_device *isp_ccdc,
+			 struct isp_pipeline *pipe);
+int ispccdc_s_pipeline(struct isp_ccdc_device *isp_ccdc,
+		       struct isp_pipeline *pipe);
+void ispccdc_set_raw_offset(struct isp_ccdc_device *isp_ccdc,
+			    enum ispccdc_raw_fmt raw_fmt);
+void ispccdc_enable(struct isp_ccdc_device *isp_ccdc, u8 enable);
+int ispccdc_sbl_busy(void *_isp_ccdc);
+int ispccdc_busy(struct isp_ccdc_device *isp_ccdc);
+void ispccdc_config_shadow_registers(struct isp_ccdc_device *isp_ccdc);
+int ispccdc_config(struct isp_ccdc_device *isp_ccdc,
+			     void *userspace_add);
+int ispccdc_request(struct isp_ccdc_device *isp_ccdc);
+int ispccdc_free(struct isp_ccdc_device *isp_ccdc);
+void ispccdc_save_context(struct device *dev);
+void ispccdc_restore_context(struct device *dev);
+void ispccdc_enable_lsc(struct isp_ccdc_device *isp_ccdc, u8 enable);
+int ispccdc_lsc_delay_stop(struct isp_ccdc_device *isp_ccdc);
+void ispccdc_lsc_state_handler(struct isp_ccdc_device *isp_ccdc,
+			unsigned long status);
+void ispccdc_lsc_pref_comp_handler(struct isp_ccdc_device *isp_ccdc);
 
 #endif		/* OMAP_ISP_CCDC_H */
diff --git a/drivers/media/video/isp/ispcsi2.c b/drivers/media/video/isp/ispcsi2.c
index 00aa362..cc8fa39 100644
--- a/drivers/media/video/isp/ispcsi2.c
+++ b/drivers/media/video/isp/ispcsi2.c
@@ -26,19 +26,6 @@
 #include "ispreg.h"
 #include "ispcsi2.h"
 
-static struct isp_csi2_cfg current_csi2_cfg;
-static struct isp_csi2_cfg_update current_csi2_cfg_update;
-
-static bool update_complexio_cfg1;
-static bool update_phy_cfg0;
-static bool update_phy_cfg1;
-static bool update_ctx_ctrl1[8];
-static bool update_ctx_ctrl2[8];
-static bool update_ctx_ctrl3[8];
-static bool update_timing;
-static bool update_ctrl;
-static bool uses_videoport;
-
 /* Structure for saving/restoring CSI2 module registers*/
 static struct isp_reg ispcsi2_reg_list[] = {
 	{OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG, 0},
@@ -75,13 +62,14 @@
  * position. To apply this settings, use the isp_csi2_complexio_lanes_update()
  * function just after calling this function.
  **/
-int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg)
+int isp_csi2_complexio_lanes_config(struct isp_csi2_device *isp_csi2,
+				    struct isp_csi2_lanes_cfg *reqcfg)
 {
 	int i;
 	bool pos_occupied[5] = {false, false, false, false, false};
-	struct isp_csi2_lanes_cfg *currlanes = &current_csi2_cfg.lanes;
+	struct isp_csi2_lanes_cfg *currlanes = &isp_csi2->current_cfg.lanes;
 	struct isp_csi2_lanes_cfg_update *currlanes_u =
-		&current_csi2_cfg_update.lanes;
+		&isp_csi2->current_cfg_update.lanes;
 
 	/* Validating parameters sent by driver */
 	if (reqcfg == NULL) {
@@ -97,8 +85,10 @@
 			       " parameters for data lane #%d\n", i);
 			goto err_einval;
 		}
-		if (pos_occupied[reqcfg->data[i].pos - 1] &&
-		    reqcfg->data[i].pos > 0) {
+		if (!reqcfg->data[i].pos)
+			continue;
+
+		if (pos_occupied[reqcfg->data[i].pos - 1]) {
 			printk(KERN_ERR "Lane #%d already occupied\n",
 			       reqcfg->data[i].pos);
 			goto err_einval;
@@ -124,12 +114,12 @@
 		if (currlanes->data[i].pos != reqcfg->data[i].pos) {
 			currlanes->data[i].pos = reqcfg->data[i].pos;
 			currlanes_u->data[i] = true;
-			update_complexio_cfg1 = true;
+			isp_csi2->update_complexio_cfg1 = true;
 		}
 		if (currlanes->data[i].pol != reqcfg->data[i].pol) {
 			currlanes->data[i].pol = reqcfg->data[i].pol;
 			currlanes_u->data[i] = true;
-			update_complexio_cfg1 = true;
+			isp_csi2->update_complexio_cfg1 = true;
 		}
 		/* If the lane position is non zero then we can assume that
 		 * the initial lane state is on.
@@ -141,12 +131,12 @@
 	if (currlanes->clk.pos != reqcfg->clk.pos) {
 		currlanes->clk.pos = reqcfg->clk.pos;
 		currlanes_u->clk = true;
-		update_complexio_cfg1 = true;
+		isp_csi2->update_complexio_cfg1 = true;
 	}
 	if (currlanes->clk.pol != reqcfg->clk.pol) {
 		currlanes->clk.pol = reqcfg->clk.pol;
 		currlanes_u->clk = true;
-		update_complexio_cfg1 = true;
+		isp_csi2->update_complexio_cfg1 = true;
 	}
 	return 0;
 err_einval:
@@ -163,18 +153,20 @@
  * set to true.
  * Always returns 0.
  **/
-int isp_csi2_complexio_lanes_update(bool force_update)
+int isp_csi2_complexio_lanes_update(struct isp_csi2_device *isp_csi2,
+				    bool force_update)
 {
-	struct isp_csi2_lanes_cfg *currlanes = &current_csi2_cfg.lanes;
+	struct isp_csi2_lanes_cfg *currlanes = &isp_csi2->current_cfg.lanes;
 	struct isp_csi2_lanes_cfg_update *currlanes_u =
-		&current_csi2_cfg_update.lanes;
+		&isp_csi2->current_cfg_update.lanes;
 	u32 reg;
 	int i;
 
-	if (!update_complexio_cfg1 && !force_update)
+	if (!isp_csi2->update_complexio_cfg1 && !force_update)
 		return 0;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_COMPLEXIO_CFG1);
 	for (i = 0; i < 4; i++) {
 		if (currlanes_u->data[i] || force_update) {
 			reg &= ~(ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1) |
@@ -199,9 +191,10 @@
 			ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT);
 		currlanes_u->clk = false;
 	}
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+		       ISPCSI2_COMPLEXIO_CFG1);
 
-	update_complexio_cfg1 = false;
+	isp_csi2->update_complexio_cfg1 = false;
 	return 0;
 }
 
@@ -211,9 +204,9 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_complexio_lanes_count(int cnt)
+int isp_csi2_complexio_lanes_count(struct isp_csi2_device *isp_csi2, int cnt)
 {
-	struct isp_csi2_lanes_cfg *currlanes = &current_csi2_cfg.lanes;
+	struct isp_csi2_lanes_cfg *currlanes = &isp_csi2->current_cfg.lanes;
 	int i;
 
 	for (i = 0; i < 4; i++) {
@@ -223,7 +216,7 @@
 			currlanes->data[i].state = ISP_CSI2_LANE_OFF;
 	}
 
-	isp_csi2_complexio_lanes_update(true);
+	isp_csi2_complexio_lanes_update(isp_csi2, true);
 	return 0;
 }
 EXPORT_SYMBOL(isp_csi2_complexio_lanes_count);
@@ -234,15 +227,16 @@
  * Gets settings from HW registers and fills in the internal driver memory
  * Always returns 0.
  **/
-int isp_csi2_complexio_lanes_get(void)
+int isp_csi2_complexio_lanes_get(struct isp_csi2_device *isp_csi2)
 {
-	struct isp_csi2_lanes_cfg *currlanes = &current_csi2_cfg.lanes;
+	struct isp_csi2_lanes_cfg *currlanes = &isp_csi2->current_cfg.lanes;
 	struct isp_csi2_lanes_cfg_update *currlanes_u =
-		&current_csi2_cfg_update.lanes;
+		&isp_csi2->current_cfg_update.lanes;
 	u32 reg;
 	int i;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_COMPLEXIO_CFG1);
 	for (i = 0; i < 4; i++) {
 		currlanes->data[i].pol = (reg &
 					  ISPCSI2_COMPLEXIO_CFG1_DATA_POL_MASK(i + 1)) >>
@@ -259,7 +253,7 @@
 		ISPCSI2_COMPLEXIO_CFG1_CLOCK_POSITION_SHIFT;
 	currlanes_u->clk = false;
 
-	update_complexio_cfg1 = false;
+	isp_csi2->update_complexio_cfg1 = false;
 	return 0;
 }
 
@@ -269,12 +263,14 @@
  * Returns 3 possible valid states: ISP_CSI2_POWER_OFF, ISP_CSI2_POWER_ON,
  * and ISP_CSI2_POWER_ULPW.
  **/
-static enum isp_csi2_power_cmds isp_csi2_complexio_power_status(void)
+static enum isp_csi2_power_cmds isp_csi2_complexio_power_status(
+					struct isp_csi2_device *isp_csi2)
 {
 	enum isp_csi2_power_cmds ret;
 	u32 reg;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1) &
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_COMPLEXIO_CFG1) &
 		ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_MASK;
 	switch (reg) {
 	case ISPCSI2_COMPLEXIO_CFG1_PWR_STATUS_OFF:
@@ -298,11 +294,13 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_complexio_power_autoswitch(bool enable)
+int isp_csi2_complexio_power_autoswitch(struct isp_csi2_device *isp_csi2,
+					bool enable)
 {
 	u32 reg;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_COMPLEXIO_CFG1);
 	reg &= ~ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_MASK;
 
 	if (enable)
@@ -310,7 +308,8 @@
 	else
 		reg |= ISPCSI2_COMPLEXIO_CFG1_PWR_AUTO_DISABLE;
 
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+		       ISPCSI2_COMPLEXIO_CFG1);
 	return 0;
 }
 
@@ -320,13 +319,15 @@
  *
  * Returns 0 if successful, or -EBUSY if the retry count is exceeded.
  **/
-int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd)
+int isp_csi2_complexio_power(struct isp_csi2_device *isp_csi2,
+			     enum isp_csi2_power_cmds power_cmd)
 {
 	enum isp_csi2_power_cmds current_state;
 	u32 reg;
 	u8 retry_count;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1) &
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_COMPLEXIO_CFG1) &
 		~ISPCSI2_COMPLEXIO_CFG1_PWR_CMD_MASK;
 	switch (power_cmd) {
 	case ISP_CSI2_POWER_OFF:
@@ -342,12 +343,13 @@
 		printk(KERN_ERR "CSI2: ERROR - Wrong Power command!\n");
 		return -EINVAL;
 	}
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_COMPLEXIO_CFG1);
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+		       ISPCSI2_COMPLEXIO_CFG1);
 
 	retry_count = 0;
 	do {
 		udelay(50);
-		current_state = isp_csi2_complexio_power_status();
+		current_state = isp_csi2_complexio_power_status(isp_csi2);
 
 		if (current_state != power_cmd) {
 			printk(KERN_DEBUG "CSI2: Complex IO power command not"
@@ -376,16 +378,17 @@
  * Validates and saves to internal driver memory the passed configuration.
  * Always returns 0.
  **/
-int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode)
+int isp_csi2_ctrl_config_frame_mode(struct isp_csi2_device *isp_csi2,
+				    enum isp_csi2_frame_mode frame_mode)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 
 	if (currctrl->frame_mode != frame_mode) {
 		currctrl->frame_mode = frame_mode;
 		currctrl_u->frame_mode = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -397,16 +400,17 @@
  * Validates and saves to internal driver memory the passed configuration.
  * Always returns 0.
  **/
-int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable)
+int isp_csi2_ctrl_config_vp_clk_enable(struct isp_csi2_device *isp_csi2,
+				       bool vp_clk_enable)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 
 	if (currctrl->vp_clk_enable != vp_clk_enable) {
 		currctrl->vp_clk_enable = vp_clk_enable;
 		currctrl_u->vp_clk_enable = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -419,16 +423,17 @@
  * Validates and saves to internal driver memory the passed configuration.
  * Always returns 0.
  **/
-int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable)
+int isp_csi2_ctrl_config_vp_only_enable(struct isp_csi2_device *isp_csi2,
+					bool vp_only_enable)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 
 	if (currctrl->vp_only_enable != vp_only_enable) {
 		currctrl->vp_only_enable = vp_only_enable;
 		currctrl_u->vp_only_enable = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -441,11 +446,12 @@
  * Validates and saves to internal driver memory the passed configuration.
  * Returns 0 if successful, or -EINVAL if wrong divider value is passed.
  **/
-int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl)
+int isp_csi2_ctrl_config_vp_out_ctrl(struct isp_csi2_device *isp_csi2,
+				     u8 vp_out_ctrl)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 
 	if ((vp_out_ctrl == 0) || (vp_out_ctrl > 4)) {
 		printk(KERN_ERR "CSI2: Wrong divisor value. Must be between"
@@ -456,7 +462,7 @@
 	if (currctrl->vp_out_ctrl != vp_out_ctrl) {
 		currctrl->vp_out_ctrl = vp_out_ctrl;
 		currctrl_u->vp_out_ctrl = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -467,16 +473,17 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctrl_config_debug_enable(bool debug_enable)
+int isp_csi2_ctrl_config_debug_enable(struct isp_csi2_device *isp_csi2,
+				      bool debug_enable)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 
 	if (currctrl->debug_enable != debug_enable) {
 		currctrl->debug_enable = debug_enable;
 		currctrl_u->debug_enable = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -487,11 +494,12 @@
  *
  * Returns 0 if successful, or -EINVAL if burst size is wrong.
  **/
-int isp_csi2_ctrl_config_burst_size(u8 burst_size)
+int isp_csi2_ctrl_config_burst_size(struct isp_csi2_device *isp_csi2,
+				    u8 burst_size)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 	if (burst_size > 3) {
 		printk(KERN_ERR "CSI2: Wrong burst size. Must be between"
 		       " 0 and 3");
@@ -501,7 +509,7 @@
 	if (currctrl->burst_size != burst_size) {
 		currctrl->burst_size = burst_size;
 		currctrl_u->burst_size = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -512,16 +520,17 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable)
+int isp_csi2_ctrl_config_ecc_enable(struct isp_csi2_device *isp_csi2,
+				    bool ecc_enable)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 
 	if (currctrl->ecc_enable != ecc_enable) {
 		currctrl->ecc_enable = ecc_enable;
 		currctrl_u->ecc_enable = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -532,16 +541,17 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctrl_config_secure_mode(bool secure_mode)
+int isp_csi2_ctrl_config_secure_mode(struct isp_csi2_device *isp_csi2,
+				     bool secure_mode)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 
 	if (currctrl->secure_mode != secure_mode) {
 		currctrl->secure_mode = secure_mode;
 		currctrl_u->secure_mode = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -552,16 +562,17 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctrl_config_if_enable(bool if_enable)
+int isp_csi2_ctrl_config_if_enable(struct isp_csi2_device *isp_csi2,
+				   bool if_enable)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 
 	if (currctrl->if_enable != if_enable) {
 		currctrl->if_enable = if_enable;
 		currctrl_u->if_enable = true;
-		update_ctrl = true;
+		isp_csi2->update_ctrl = true;
 	}
 	return 0;
 }
@@ -576,15 +587,16 @@
  * set to true.
  * Always returns 0.
  **/
-int isp_csi2_ctrl_update(bool force_update)
+int isp_csi2_ctrl_update(struct isp_csi2_device *isp_csi2, bool force_update)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 	u32 reg;
 
-	if (update_ctrl || force_update) {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL);
+	if (isp_csi2->update_ctrl || force_update) {
+		reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+				    ISPCSI2_CTRL);
 		if (currctrl_u->frame_mode || force_update) {
 			reg &= ~ISPCSI2_CTRL_FRAME_MASK;
 			if (currctrl->frame_mode)
@@ -603,7 +615,7 @@
 		}
 		if (currctrl_u->vp_only_enable || force_update) {
 			reg &= ~ISPCSI2_CTRL_VP_ONLY_EN_MASK;
-			uses_videoport = currctrl->vp_only_enable;
+			isp_csi2->uses_videoport = currctrl->vp_only_enable;
 			if (currctrl->vp_only_enable)
 				reg |= ISPCSI2_CTRL_VP_ONLY_EN_ENABLE;
 			else
@@ -654,8 +666,9 @@
 				reg |= ISPCSI2_CTRL_IF_EN_DISABLE;
 			currctrl_u->if_enable = false;
 		}
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL);
-		update_ctrl = false;
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+			       ISPCSI2_CTRL);
+		isp_csi2->update_ctrl = false;
 	}
 	return 0;
 }
@@ -665,14 +678,15 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctrl_get(void)
+int isp_csi2_ctrl_get(struct isp_csi2_device *isp_csi2)
 {
-	struct isp_csi2_ctrl_cfg *currctrl = &current_csi2_cfg.ctrl;
+	struct isp_csi2_ctrl_cfg *currctrl = &isp_csi2->current_cfg.ctrl;
 	struct isp_csi2_ctrl_cfg_update *currctrl_u =
-		&current_csi2_cfg_update.ctrl;
+		&isp_csi2->current_cfg_update.ctrl;
 	u32 reg;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL);
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_CTRL);
 	currctrl->frame_mode = (reg & ISPCSI2_CTRL_FRAME_MASK) >>
 		ISPCSI2_CTRL_FRAME_SHIFT;
 	currctrl_u->frame_mode = false;
@@ -689,7 +703,7 @@
 		currctrl->vp_only_enable = true;
 	else
 		currctrl->vp_only_enable = false;
-	uses_videoport = currctrl->vp_only_enable;
+	isp_csi2->uses_videoport = currctrl->vp_only_enable;
 	currctrl_u->vp_only_enable = false;
 
 	currctrl->vp_out_ctrl = ((reg & ISPCSI2_CTRL_VP_OUT_CTRL_MASK) >>
@@ -724,7 +738,7 @@
 		currctrl->if_enable = false;
 	currctrl_u->if_enable = false;
 
-	update_ctrl = false;
+	isp_csi2->update_ctrl = false;
 	return 0;
 }
 
@@ -751,7 +765,8 @@
  *
  * Returns 0 if successful, or -EINVAL if Virtual ID is not in range (0-3).
  **/
-int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id)
+int isp_csi2_ctx_config_virtual_id(struct isp_csi2_device *isp_csi2, u8 ctxnum,
+				   u8 virtual_id)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -763,13 +778,13 @@
 		return -EINVAL;
 	}
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->virtual_id != virtual_id) {
 		selected_ctx->virtual_id = virtual_id;
 		selected_ctx_u->virtual_id = true;
-		update_ctx_ctrl2[ctxnum] = true;
+		isp_csi2->update_ctx_ctrl2[ctxnum] = true;
 	}
 
 	return 0;
@@ -782,20 +797,21 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count)
+int isp_csi2_ctx_config_frame_count(struct isp_csi2_device *isp_csi2, u8 ctxnum,
+				    u8 frame_count)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
 
 	isp_csi2_ctx_validate(&ctxnum);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->frame_count != frame_count) {
 		selected_ctx->frame_count = frame_count;
 		selected_ctx_u->frame_count = true;
-		update_ctx_ctrl1[ctxnum] = true;
+		isp_csi2->update_ctx_ctrl1[ctxnum] = true;
 	}
 
 	return 0;
@@ -809,7 +825,8 @@
  * Returns 0 if successful, or -EINVAL if the format is not supported by the
  * receiver.
  **/
-int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat)
+int isp_csi2_ctx_config_format(struct isp_csi2_device *isp_csi2, u8 ctxnum,
+			       u32 pixformat)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -832,12 +849,12 @@
 		return -EINVAL;
 	}
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	selected_ctx->format = pix;
 	selected_ctx_u->format = true;
-	update_ctx_ctrl2[ctxnum] = true;
+	isp_csi2->update_ctx_ctrl2[ctxnum] = true;
 
 	return 0;
 }
@@ -849,7 +866,8 @@
  *
  * Returns 0 if successful, or -EINVAL if the alpha value is bigger than 16383.
  **/
-int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha)
+int isp_csi2_ctx_config_alpha(struct isp_csi2_device *isp_csi2, u8 ctxnum,
+			      u16 alpha)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -861,13 +879,13 @@
 		return -EINVAL;
 	}
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->alpha != alpha) {
 		selected_ctx->alpha = alpha;
 		selected_ctx_u->alpha = true;
-		update_ctx_ctrl3[ctxnum] = true;
+		isp_csi2->update_ctx_ctrl3[ctxnum] = true;
 	}
 	return 0;
 }
@@ -879,7 +897,8 @@
  *
  * Returns 0 if successful, or -EINVAL if the line offset is bigger than 1023.
  **/
-int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset)
+int isp_csi2_ctx_config_data_offset(struct isp_csi2_device *isp_csi2,
+				    u8 ctxnum, u16 data_offset)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -891,8 +910,8 @@
 		return -EINVAL;
 	}
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->data_offset != data_offset) {
 		selected_ctx->data_offset = data_offset;
@@ -908,7 +927,8 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr)
+int isp_csi2_ctx_config_ping_addr(struct isp_csi2_device *isp_csi2,
+				  u8 ctxnum, u32 ping_addr)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -917,8 +937,8 @@
 
 	ping_addr &= ~(0x1F);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->ping_addr != ping_addr) {
 		selected_ctx->ping_addr = ping_addr;
@@ -934,7 +954,8 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr)
+int isp_csi2_ctx_config_pong_addr(struct isp_csi2_device *isp_csi2,
+				  u8 ctxnum, u32 pong_addr)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -943,8 +964,8 @@
 
 	pong_addr &= ~(0x1F);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->pong_addr != pong_addr) {
 		selected_ctx->pong_addr = pong_addr;
@@ -961,20 +982,21 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled)
+int isp_csi2_ctx_config_eof_enabled(struct isp_csi2_device *isp_csi2,
+				    u8 ctxnum, bool eof_enabled)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
 
 	isp_csi2_ctx_validate(&ctxnum);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->eof_enabled != eof_enabled) {
 		selected_ctx->eof_enabled = eof_enabled;
 		selected_ctx_u->eof_enabled = true;
-		update_ctx_ctrl1[ctxnum] = true;
+		isp_csi2->update_ctx_ctrl1[ctxnum] = true;
 	}
 	return 0;
 }
@@ -987,20 +1009,21 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled)
+int isp_csi2_ctx_config_eol_enabled(struct isp_csi2_device *isp_csi2,
+				    u8 ctxnum, bool eol_enabled)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
 
 	isp_csi2_ctx_validate(&ctxnum);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->eol_enabled != eol_enabled) {
 		selected_ctx->eol_enabled = eol_enabled;
 		selected_ctx_u->eol_enabled = true;
-		update_ctx_ctrl1[ctxnum] = true;
+		isp_csi2->update_ctx_ctrl1[ctxnum] = true;
 	}
 	return 0;
 }
@@ -1013,20 +1036,21 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled)
+int isp_csi2_ctx_config_checksum_enabled(struct isp_csi2_device *isp_csi2,
+					 u8 ctxnum, bool checksum_enabled)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
 
 	isp_csi2_ctx_validate(&ctxnum);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->checksum_enabled != checksum_enabled) {
 		selected_ctx->checksum_enabled = checksum_enabled;
 		selected_ctx_u->checksum_enabled = true;
-		update_ctx_ctrl1[ctxnum] = true;
+		isp_csi2->update_ctx_ctrl1[ctxnum] = true;
 	}
 	return 0;
 }
@@ -1038,20 +1062,21 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled)
+int isp_csi2_ctx_config_enabled(struct isp_csi2_device *isp_csi2,
+				u8 ctxnum, bool enabled)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
 
 	isp_csi2_ctx_validate(&ctxnum);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
 	if (selected_ctx->enabled != enabled) {
 		selected_ctx->enabled = enabled;
 		selected_ctx_u->enabled = true;
-		update_ctx_ctrl1[ctxnum] = true;
+		isp_csi2->update_ctx_ctrl1[ctxnum] = true;
 	}
 	return 0;
 }
@@ -1067,7 +1092,8 @@
  * set to true.
  * Always returns 0.
  **/
-int isp_csi2_ctx_update(u8 ctxnum, bool force_update)
+int isp_csi2_ctx_update(struct isp_csi2_device *isp_csi2,
+			u8 ctxnum, bool force_update)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -1075,11 +1101,11 @@
 
 	isp_csi2_ctx_validate(&ctxnum);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
-	if (update_ctx_ctrl1[ctxnum] || force_update) {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	if (isp_csi2->update_ctx_ctrl1[ctxnum] || force_update) {
+		reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 				    ISPCSI2_CTX_CTRL1(ctxnum));
 		if (selected_ctx_u->frame_count || force_update) {
 			reg &= ~(ISPCSI2_CTX_CTRL1_COUNT_MASK);
@@ -1119,13 +1145,13 @@
 				reg |= ISPCSI2_CTX_CTRL1_CTX_EN_DISABLE;
 			selected_ctx_u->enabled = false;
 		}
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_CTX_CTRL1(ctxnum));
-		update_ctx_ctrl1[ctxnum] = false;
+		isp_csi2->update_ctx_ctrl1[ctxnum] = false;
 	}
 
-	if (update_ctx_ctrl2[ctxnum] || force_update) {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	if (isp_csi2->update_ctx_ctrl2[ctxnum] || force_update) {
+		reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 				    ISPCSI2_CTX_CTRL2(ctxnum));
 		if (selected_ctx_u->virtual_id || force_update) {
 			reg &= ~(ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK);
@@ -1147,7 +1173,7 @@
 				break;
 			case V4L2_PIX_FMT_YUYV:
 			case V4L2_PIX_FMT_UYVY:
-				if (uses_videoport)
+				if (isp_csi2->uses_videoport)
 					new_format = 0x9E;
 				else
 					new_format = 0x1E;
@@ -1157,7 +1183,7 @@
 				new_format = 0xA1;
 				break;
 			case V4L2_PIX_FMT_SGRBG10:
-				if (uses_videoport)
+				if (isp_csi2->uses_videoport)
 					new_format = 0x12F;
 				else
 					new_format = 0xAB;
@@ -1166,13 +1192,13 @@
 			reg |= (new_format << ISPCSI2_CTX_CTRL2_FORMAT_SHIFT);
 			selected_ctx_u->format = false;
 		}
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_CTX_CTRL2(ctxnum));
-		update_ctx_ctrl2[ctxnum] = false;
+		isp_csi2->update_ctx_ctrl2[ctxnum] = false;
 	}
 
-	if (update_ctx_ctrl3[ctxnum] || force_update) {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	if (isp_csi2->update_ctx_ctrl3[ctxnum] || force_update) {
+		reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 				    ISPCSI2_CTX_CTRL3(ctxnum));
 		if (selected_ctx_u->alpha || force_update) {
 			reg &= ~(ISPCSI2_CTX_CTRL3_ALPHA_MASK);
@@ -1180,32 +1206,32 @@
 				ISPCSI2_CTX_CTRL3_ALPHA_SHIFT);
 			selected_ctx_u->alpha = false;
 		}
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_CTX_CTRL3(ctxnum));
-		update_ctx_ctrl3[ctxnum] = false;
+		isp_csi2->update_ctx_ctrl3[ctxnum] = false;
 	}
 
 	if (selected_ctx_u->data_offset) {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+		reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 				    ISPCSI2_CTX_DAT_OFST(ctxnum));
 		reg &= ~ISPCSI2_CTX_DAT_OFST_OFST_MASK;
 		reg |= selected_ctx->data_offset <<
 			ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_CTX_DAT_OFST(ctxnum));
 		selected_ctx_u->data_offset = false;
 	}
 
 	if (selected_ctx_u->ping_addr) {
 		reg = selected_ctx->ping_addr;
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_CTX_DAT_PING_ADDR(ctxnum));
 		selected_ctx_u->ping_addr = false;
 	}
 
 	if (selected_ctx_u->pong_addr) {
 		reg = selected_ctx->pong_addr;
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum));
 		selected_ctx_u->pong_addr = false;
 	}
@@ -1218,7 +1244,7 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_get(u8 ctxnum)
+int isp_csi2_ctx_get(struct isp_csi2_device *isp_csi2, u8 ctxnum)
 {
 	struct isp_csi2_ctx_cfg *selected_ctx;
 	struct isp_csi2_ctx_cfg_update *selected_ctx_u;
@@ -1226,10 +1252,11 @@
 
 	isp_csi2_ctx_validate(&ctxnum);
 
-	selected_ctx = &current_csi2_cfg.contexts[ctxnum];
-	selected_ctx_u = &current_csi2_cfg_update.contexts[ctxnum];
+	selected_ctx = &isp_csi2->current_cfg.contexts[ctxnum];
+	selected_ctx_u = &isp_csi2->current_cfg_update.contexts[ctxnum];
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTX_CTRL1(ctxnum));
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_CTX_CTRL1(ctxnum));
 	selected_ctx->frame_count = (reg & ISPCSI2_CTX_CTRL1_COUNT_MASK) >>
 		ISPCSI2_CTX_CTRL1_COUNT_SHIFT;
 	selected_ctx_u->frame_count = false;
@@ -1261,9 +1288,10 @@
 	else
 		selected_ctx->enabled = false;
 	selected_ctx_u->enabled = false;
-	update_ctx_ctrl1[ctxnum] = false;
+	isp_csi2->update_ctx_ctrl1[ctxnum] = false;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTX_CTRL2(ctxnum));
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_CTX_CTRL2(ctxnum));
 
 	selected_ctx->virtual_id = (reg & ISPCSI2_CTX_CTRL2_VIRTUAL_ID_MASK) >>
 		ISPCSI2_CTX_CTRL2_VIRTUAL_ID_SHIFT;
@@ -1287,26 +1315,30 @@
 		break;
 	}
 	selected_ctx_u->format = false;
-	update_ctx_ctrl2[ctxnum] = false;
+	isp_csi2->update_ctx_ctrl2[ctxnum] = false;
 
-	selected_ctx->alpha = (isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	selected_ctx->alpha = (isp_reg_readl(isp_csi2->dev,
+					     OMAP3_ISP_IOMEM_CSI2A,
 					     ISPCSI2_CTX_CTRL3(ctxnum)) &
 			       ISPCSI2_CTX_CTRL3_ALPHA_MASK) >>
 		ISPCSI2_CTX_CTRL3_ALPHA_SHIFT;
 	selected_ctx_u->alpha = false;
-	update_ctx_ctrl3[ctxnum] = false;
+	isp_csi2->update_ctx_ctrl3[ctxnum] = false;
 
-	selected_ctx->data_offset = (isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	selected_ctx->data_offset = (isp_reg_readl(isp_csi2->dev,
+						   OMAP3_ISP_IOMEM_CSI2A,
 						   ISPCSI2_CTX_DAT_OFST(ctxnum)) &
 				     ISPCSI2_CTX_DAT_OFST_OFST_MASK) >>
 		ISPCSI2_CTX_DAT_OFST_OFST_SHIFT;
 	selected_ctx_u->data_offset = false;
 
-	selected_ctx->ping_addr = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	selected_ctx->ping_addr = isp_reg_readl(isp_csi2->dev,
+						OMAP3_ISP_IOMEM_CSI2A,
 						ISPCSI2_CTX_DAT_PING_ADDR(ctxnum));
 	selected_ctx_u->ping_addr = false;
 
-	selected_ctx->pong_addr = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	selected_ctx->pong_addr = isp_reg_readl(isp_csi2->dev,
+						OMAP3_ISP_IOMEM_CSI2A,
 						ISPCSI2_CTX_DAT_PONG_ADDR(ctxnum));
 	selected_ctx_u->pong_addr = false;
 	return 0;
@@ -1322,12 +1354,12 @@
  * set to true.
  * Always returns 0.
  **/
-int isp_csi2_ctx_update_all(bool force_update)
+int isp_csi2_ctx_update_all(struct isp_csi2_device *isp_csi2, bool force_update)
 {
 	u8 ctxnum;
 
 	for (ctxnum = 0; ctxnum < 8; ctxnum++)
-		isp_csi2_ctx_update(ctxnum, force_update);
+		isp_csi2_ctx_update(isp_csi2, ctxnum, force_update);
 
 	return 0;
 }
@@ -1337,21 +1369,22 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_ctx_get_all(void)
+int isp_csi2_ctx_get_all(struct isp_csi2_device *isp_csi2)
 {
 	u8 ctxnum;
 
 	for (ctxnum = 0; ctxnum < 8; ctxnum++)
-		isp_csi2_ctx_get(ctxnum);
+		isp_csi2_ctx_get(isp_csi2, ctxnum);
 
 	return 0;
 }
 
-int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig)
+int isp_csi2_phy_config(struct isp_csi2_device *isp_csi2,
+			struct isp_csi2_phy_cfg *desiredphyconfig)
 {
-	struct isp_csi2_phy_cfg *currphy = &current_csi2_cfg.phy;
+	struct isp_csi2_phy_cfg *currphy = &isp_csi2->current_cfg.phy;
 	struct isp_csi2_phy_cfg_update *currphy_u =
-						&current_csi2_cfg_update.phy;
+						&isp_csi2->current_cfg_update.phy;
 
 	if ((desiredphyconfig->tclk_term > 0x7f) ||
 				(desiredphyconfig->tclk_miss > 0x3)) {
@@ -1363,27 +1396,27 @@
 	if (currphy->ths_term != desiredphyconfig->ths_term) {
 		currphy->ths_term = desiredphyconfig->ths_term;
 		currphy_u->ths_term = true;
-		update_phy_cfg0 = true;
+		isp_csi2->update_phy_cfg0 = true;
 	}
 	if (currphy->ths_settle != desiredphyconfig->ths_settle) {
 		currphy->ths_settle = desiredphyconfig->ths_settle;
 		currphy_u->ths_settle = true;
-		update_phy_cfg0 = true;
+		isp_csi2->update_phy_cfg0 = true;
 	}
 	if (currphy->tclk_term != desiredphyconfig->tclk_term) {
 		currphy->tclk_term = desiredphyconfig->tclk_term;
 		currphy_u->tclk_term = true;
-		update_phy_cfg1 = true;
+		isp_csi2->update_phy_cfg1 = true;
 	}
 	if (currphy->tclk_miss != desiredphyconfig->tclk_miss) {
 		currphy->tclk_miss = desiredphyconfig->tclk_miss;
 		currphy_u->tclk_miss = true;
-		update_phy_cfg1 = true;
+		isp_csi2->update_phy_cfg1 = true;
 	}
 	if (currphy->tclk_settle != desiredphyconfig->tclk_settle) {
 		currphy->tclk_settle = desiredphyconfig->tclk_settle;
 		currphy_u->tclk_settle = true;
-		update_phy_cfg1 = true;
+		isp_csi2->update_phy_cfg1 = true;
 	}
 	return 0;
 }
@@ -1402,12 +1435,13 @@
  *
  * Always returns 0.
  */
-int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle,
-							u32 ubound_hs_settle)
+int isp_csi2_calc_phy_cfg0(struct isp_csi2_device *isp_csi2,
+			   u32 mipiclk, u32 lbound_hs_settle,
+			   u32 ubound_hs_settle)
 {
-	struct isp_csi2_phy_cfg *currphy = &current_csi2_cfg.phy;
+	struct isp_csi2_phy_cfg *currphy = &isp_csi2->current_cfg.phy;
 	struct isp_csi2_phy_cfg_update *currphy_u =
-						&current_csi2_cfg_update.phy;
+						&isp_csi2->current_cfg_update.phy;
 	u32 tmp, ddrclk = mipiclk >> 1;
 
 	/* Calculate THS_TERM */
@@ -1421,7 +1455,7 @@
 	currphy->ths_settle = (ubound_hs_settle + lbound_hs_settle) / 2;
 
 	currphy_u->ths_settle = true;
-	isp_csi2_phy_update(true);
+	isp_csi2_phy_update(isp_csi2, true);
 	return 0;
 }
 EXPORT_SYMBOL(isp_csi2_calc_phy_cfg0);
@@ -1436,15 +1470,17 @@
 	* set to true.
 	* Always returns 0.
 	**/
-int isp_csi2_phy_update(bool force_update)
+int isp_csi2_phy_update(struct isp_csi2_device *isp_csi2, bool force_update)
 {
-	struct isp_csi2_phy_cfg *currphy = &current_csi2_cfg.phy;
+	struct isp_csi2_phy_cfg *currphy = &isp_csi2->current_cfg.phy;
 	struct isp_csi2_phy_cfg_update *currphy_u =
-		&current_csi2_cfg_update.phy;
+		&isp_csi2->current_cfg_update.phy;
 	u32 reg;
 
-	if (update_phy_cfg0 || force_update) {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0);
+	if (isp_csi2->update_phy_cfg0 || force_update) {
+		reg = isp_reg_readl(isp_csi2->dev,
+				    OMAP3_ISP_IOMEM_CSI2PHY,
+				    ISPCSI2PHY_CFG0);
 		if (currphy_u->ths_term || force_update) {
 			reg &= ~ISPCSI2PHY_CFG0_THS_TERM_MASK;
 			reg |= (currphy->ths_term <<
@@ -1457,12 +1493,14 @@
 				ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT);
 			currphy_u->ths_settle = false;
 		}
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0);
-		update_phy_cfg0 = false;
+		isp_reg_writel(isp_csi2->dev, reg,
+			       OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0);
+		isp_csi2->update_phy_cfg0 = false;
 	}
 
-	if (update_phy_cfg1 || force_update) {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
+	if (isp_csi2->update_phy_cfg1 || force_update) {
+		reg = isp_reg_readl(isp_csi2->dev,
+				    OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
 		if (currphy_u->tclk_term || force_update) {
 			reg &= ~ISPCSI2PHY_CFG1_TCLK_TERM_MASK;
 			reg |= (currphy->tclk_term <<
@@ -1481,8 +1519,9 @@
 				ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT);
 			currphy_u->tclk_settle = false;
 		}
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
-		update_phy_cfg1 = false;
+		isp_reg_writel(isp_csi2->dev, reg,
+			       OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
+		isp_csi2->update_phy_cfg1 = false;
 	}
 	return 0;
 }
@@ -1493,14 +1532,15 @@
  * Gets settings from HW registers and fills in the internal driver memory
  * Always returns 0.
  **/
-int isp_csi2_phy_get(void)
+int isp_csi2_phy_get(struct isp_csi2_device *isp_csi2)
 {
-	struct isp_csi2_phy_cfg *currphy = &current_csi2_cfg.phy;
+	struct isp_csi2_phy_cfg *currphy = &isp_csi2->current_cfg.phy;
 	struct isp_csi2_phy_cfg_update *currphy_u =
-		&current_csi2_cfg_update.phy;
+		&isp_csi2->current_cfg_update.phy;
 	u32 reg;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG0);
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2PHY,
+			    ISPCSI2PHY_CFG0);
 	currphy->ths_term = (reg & ISPCSI2PHY_CFG0_THS_TERM_MASK) >>
 		ISPCSI2PHY_CFG0_THS_TERM_SHIFT;
 	currphy_u->ths_term = false;
@@ -1508,9 +1548,10 @@
 	currphy->ths_settle = (reg & ISPCSI2PHY_CFG0_THS_SETTLE_MASK) >>
 		ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT;
 	currphy_u->ths_settle = false;
-	update_phy_cfg0 = false;
+	isp_csi2->update_phy_cfg0 = false;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY, ISPCSI2PHY_CFG1);
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2PHY,
+			    ISPCSI2PHY_CFG1);
 
 	currphy->tclk_term = (reg & ISPCSI2PHY_CFG1_TCLK_TERM_MASK) >>
 		ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT;
@@ -1524,7 +1565,7 @@
 		ISPCSI2PHY_CFG1_TCLK_SETTLE_SHIFT;
 	currphy_u->tclk_settle = false;
 
-	update_phy_cfg1 = false;
+	isp_csi2->update_phy_cfg1 = false;
 	return 0;
 }
 
@@ -1534,7 +1575,8 @@
  *
  * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
  **/
-int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode)
+int isp_csi2_timings_config_forcerxmode(struct isp_csi2_device *isp_csi2,
+					u8 io, bool force_rx_mode)
 {
 	struct isp_csi2_timings_cfg *currtimings;
 	struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1544,12 +1586,12 @@
 		return -EINVAL;
 	}
 
-	currtimings = &current_csi2_cfg.timings[io - 1];
-	currtimings_u = &current_csi2_cfg_update.timings[io - 1];
+	currtimings = &isp_csi2->current_cfg.timings[io - 1];
+	currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
 	if (currtimings->force_rx_mode != force_rx_mode) {
 		currtimings->force_rx_mode = force_rx_mode;
 		currtimings_u->force_rx_mode = true;
-		update_timing = true;
+		isp_csi2->update_timing = true;
 	}
 	return 0;
 }
@@ -1560,7 +1602,8 @@
  *
  * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
  **/
-int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x)
+int isp_csi2_timings_config_stopstate_16x(struct isp_csi2_device *isp_csi2,
+					  u8 io, bool stop_state_16x)
 {
 	struct isp_csi2_timings_cfg *currtimings;
 	struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1570,12 +1613,12 @@
 		return -EINVAL;
 	}
 
-	currtimings = &current_csi2_cfg.timings[io - 1];
-	currtimings_u = &current_csi2_cfg_update.timings[io - 1];
+	currtimings = &isp_csi2->current_cfg.timings[io - 1];
+	currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
 	if (currtimings->stop_state_16x != stop_state_16x) {
 		currtimings->stop_state_16x = stop_state_16x;
 		currtimings_u->stop_state_16x = true;
-		update_timing = true;
+		isp_csi2->update_timing = true;
 	}
 	return 0;
 }
@@ -1586,7 +1629,8 @@
  *
  * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
  **/
-int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x)
+int isp_csi2_timings_config_stopstate_4x(struct isp_csi2_device *isp_csi2,
+					 u8 io, bool stop_state_4x)
 {
 	struct isp_csi2_timings_cfg *currtimings;
 	struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1596,12 +1640,12 @@
 		return -EINVAL;
 	}
 
-	currtimings = &current_csi2_cfg.timings[io - 1];
-	currtimings_u = &current_csi2_cfg_update.timings[io - 1];
+	currtimings = &isp_csi2->current_cfg.timings[io - 1];
+	currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
 	if (currtimings->stop_state_4x != stop_state_4x) {
 		currtimings->stop_state_4x = stop_state_4x;
 		currtimings_u->stop_state_4x = true;
-		update_timing = true;
+		isp_csi2->update_timing = true;
 	}
 	return 0;
 }
@@ -1612,7 +1656,8 @@
  *
  * Returns 0 if successful, or -EINVAL if wrong ComplexIO number is selected.
  **/
-int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter)
+int isp_csi2_timings_config_stopstate_cnt(struct isp_csi2_device *isp_csi2,
+					  u8 io, u16 stop_state_counter)
 {
 	struct isp_csi2_timings_cfg *currtimings;
 	struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1622,12 +1667,12 @@
 		return -EINVAL;
 	}
 
-	currtimings = &current_csi2_cfg.timings[io - 1];
-	currtimings_u = &current_csi2_cfg_update.timings[io - 1];
+	currtimings = &isp_csi2->current_cfg.timings[io - 1];
+	currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
 	if (currtimings->stop_state_counter != stop_state_counter) {
 		currtimings->stop_state_counter = (stop_state_counter & 0x1FFF);
 		currtimings_u->stop_state_counter = true;
-		update_timing = true;
+		isp_csi2->update_timing = true;
 	}
 	return 0;
 }
@@ -1643,7 +1688,8 @@
  * set to true.
  * Returns 0 if successful, or -EINVAL if invalid IO number is passed.
  **/
-int isp_csi2_timings_update(u8 io, bool force_update)
+int isp_csi2_timings_update(struct isp_csi2_device *isp_csi2,
+			    u8 io, bool force_update)
 {
 	struct isp_csi2_timings_cfg *currtimings;
 	struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1654,11 +1700,12 @@
 		return -EINVAL;
 	}
 
-	currtimings = &current_csi2_cfg.timings[io - 1];
-	currtimings_u = &current_csi2_cfg_update.timings[io - 1];
+	currtimings = &isp_csi2->current_cfg.timings[io - 1];
+	currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
 
-	if (update_timing || force_update) {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING);
+	if (isp_csi2->update_timing || force_update) {
+		reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+				    ISPCSI2_TIMING);
 		if (currtimings_u->force_rx_mode || force_update) {
 			reg &= ~ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io);
 			if (currtimings->force_rx_mode)
@@ -1696,8 +1743,9 @@
 				ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io);
 			currtimings_u->stop_state_counter = false;
 		}
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING);
-		update_timing = false;
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+			       ISPCSI2_TIMING);
+		isp_csi2->update_timing = false;
 	}
 	return 0;
 }
@@ -1709,7 +1757,7 @@
  * Gets settings from HW registers and fills in the internal driver memory
  * Returns 0 if successful, or -EINVAL if invalid IO number is passed.
  **/
-int isp_csi2_timings_get(u8 io)
+int isp_csi2_timings_get(struct isp_csi2_device *isp_csi2, u8 io)
 {
 	struct isp_csi2_timings_cfg *currtimings;
 	struct isp_csi2_timings_cfg_update *currtimings_u;
@@ -1720,10 +1768,11 @@
 		return -EINVAL;
 	}
 
-	currtimings = &current_csi2_cfg.timings[io - 1];
-	currtimings_u = &current_csi2_cfg_update.timings[io - 1];
+	currtimings = &isp_csi2->current_cfg.timings[io - 1];
+	currtimings_u = &isp_csi2->current_cfg_update.timings[io - 1];
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING);
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_TIMING);
 	if ((reg & ISPCSI2_TIMING_FORCE_RX_MODE_IO_MASK(io)) ==
 	    ISPCSI2_TIMING_FORCE_RX_MODE_IO_ENABLE(io))
 		currtimings->force_rx_mode = true;
@@ -1749,7 +1798,7 @@
 					   ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_MASK(io)) >>
 		ISPCSI2_TIMING_STOP_STATE_COUNTER_IO_SHIFT(io);
 	currtimings_u->stop_state_counter = false;
-	update_timing = false;
+	isp_csi2->update_timing = false;
 	return 0;
 }
 
@@ -1763,12 +1812,13 @@
  * set to true.
  * Always returns 0.
  **/
-int isp_csi2_timings_update_all(bool force_update)
+int isp_csi2_timings_update_all(struct isp_csi2_device *isp_csi2,
+				bool force_update)
 {
 	int i;
 
 	for (i = 1; i < 3; i++)
-		isp_csi2_timings_update(i, force_update);
+		isp_csi2_timings_update(isp_csi2, i, force_update);
 	return 0;
 }
 
@@ -1777,62 +1827,83 @@
  *
  * Always returns 0.
  **/
-int isp_csi2_timings_get_all(void)
+int isp_csi2_timings_get_all(struct isp_csi2_device *isp_csi2)
 {
 	int i;
 
 	for (i = 1; i < 3; i++)
-		isp_csi2_timings_get(i);
+		isp_csi2_timings_get(isp_csi2, i);
 	return 0;
 }
 
 /**
  * isp_csi2_isr - CSI2 interrupt handling.
+ *
+ * Return -EIO on Transmission error
  **/
-void isp_csi2_isr(void)
+int isp_csi2_isr(struct isp_csi2_device *isp_csi2)
 {
+	int retval = 0;
 	u32 csi2_irqstatus, cpxio1_irqstatus, ctxirqstatus;
 
-	csi2_irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	csi2_irqstatus = isp_reg_readl(isp_csi2->dev,
+				       OMAP3_ISP_IOMEM_CSI2A,
 				       ISPCSI2_IRQSTATUS);
-	isp_reg_writel(csi2_irqstatus, OMAP3_ISP_IOMEM_CSI2A,
-		       ISPCSI2_IRQSTATUS);
+	isp_reg_writel(isp_csi2->dev, csi2_irqstatus,
+		       OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQSTATUS);
 
+	/* Failure Cases */
 	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ) {
-		cpxio1_irqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+		cpxio1_irqstatus = isp_reg_readl(isp_csi2->dev,
+						 OMAP3_ISP_IOMEM_CSI2A,
 						 ISPCSI2_COMPLEXIO1_IRQSTATUS);
-		isp_reg_writel(cpxio1_irqstatus, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, cpxio1_irqstatus,
+			       OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_COMPLEXIO1_IRQSTATUS);
-		printk(KERN_ERR "CSI2: ComplexIO Error IRQ %x\n",
-		       cpxio1_irqstatus);
+		dev_dbg(isp_csi2->dev, "CSI2: ComplexIO Error IRQ %x\n",
+			cpxio1_irqstatus);
+		retval = -EIO;
 	}
 
+	if (csi2_irqstatus & (ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
+			      ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ |
+			      ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ |
+			      ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ |
+			      ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)) {
+		dev_dbg(isp_csi2->dev, "CSI2 Err:"
+			" OCP:%d,"
+			" Short_pack:%d,"
+			" ECC:%d,"
+			" CPXIO2:%d,"
+			" FIFO_OVF:%d,"
+			"\n",
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_OCP_ERR_IRQ) ? 1 : 0,
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ) ? 1 : 0,
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ) ? 1 : 0,
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ) ? 1 : 0,
+			(csi2_irqstatus &
+			 ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ) ? 1 : 0);
+		retval = -EIO;
+	}
+
+	/* Successful cases */
 	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_CONTEXT(0)) {
-		ctxirqstatus = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+		ctxirqstatus = isp_reg_readl(isp_csi2->dev,
+					     OMAP3_ISP_IOMEM_CSI2A,
 					     ISPCSI2_CTX_IRQSTATUS(0));
-		isp_reg_writel(ctxirqstatus, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, ctxirqstatus,
+			       OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_CTX_IRQSTATUS(0));
 	}
 
-	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_OCP_ERR_IRQ)
-		printk(KERN_ERR "CSI2: OCP Transmission Error\n");
-
-	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_SHORT_PACKET_IRQ)
-		printk(KERN_ERR "CSI2: Short packet receive error\n");
-
 	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_CORRECTION_IRQ)
-		printk(KERN_DEBUG "CSI2: ECC correction done\n");
+		dev_dbg(isp_csi2->dev, "CSI2: ECC correction done\n");
 
-	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_ECC_NO_CORRECTION_IRQ)
-		printk(KERN_ERR "CSI2: ECC correction failed\n");
-
-	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_COMPLEXIO2_ERR_IRQ)
-		printk(KERN_ERR "CSI2: ComplexIO #2 failed\n");
-
-	if (csi2_irqstatus & ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ)
-		printk(KERN_ERR "CSI2: FIFO overflow error\n");
-
-	return;
+	return retval;
 }
 EXPORT_SYMBOL(isp_csi2_isr);
 
@@ -1840,7 +1911,7 @@
  * isp_csi2_irq_complexio1_set - Enables CSI2 ComplexIO IRQs.
  * @enable: Enable/disable CSI2 ComplexIO #1 interrupts
  **/
-void isp_csi2_irq_complexio1_set(int enable)
+void isp_csi2_irq_complexio1_set(struct isp_csi2_device *isp_csi2, int enable)
 {
 	u32 reg;
 	reg = ISPCSI2_COMPLEXIO1_IRQENABLE_STATEALLULPMEXIT |
@@ -1870,14 +1941,15 @@
 		ISPCSI2_COMPLEXIO1_IRQENABLE_ERRESC1 |
 		ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTSYNCHS1 |
 		ISPCSI2_COMPLEXIO1_IRQENABLE_ERRSOTHS1;
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 		       ISPCSI2_COMPLEXIO1_IRQSTATUS);
 	if (enable) {
-		reg |= isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+		reg |= isp_reg_readl(isp_csi2->dev,
+				     OMAP3_ISP_IOMEM_CSI2A,
 				     ISPCSI2_COMPLEXIO1_IRQENABLE);
 	} else
 		reg = 0;
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 		       ISPCSI2_COMPLEXIO1_IRQENABLE);
 }
 EXPORT_SYMBOL(isp_csi2_irq_complexio1_set);
@@ -1886,20 +1958,21 @@
  * isp_csi2_irq_ctx_set - Enables CSI2 Context IRQs.
  * @enable: Enable/disable CSI2 Context interrupts
  **/
-void isp_csi2_irq_ctx_set(int enable)
+void isp_csi2_irq_ctx_set(struct isp_csi2_device *isp_csi2, int enable)
 {
 	u32 reg;
 	int i;
 
 	reg = ISPCSI2_CTX_IRQSTATUS_FS_IRQ | ISPCSI2_CTX_IRQSTATUS_FE_IRQ;
 	for (i = 0; i < 8; i++) {
-		isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A,
+		isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
 			       ISPCSI2_CTX_IRQSTATUS(i));
 		if (enable) {
-			isp_reg_or(OMAP3_ISP_IOMEM_CSI2A,
+			isp_reg_or(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 				   ISPCSI2_CTX_IRQENABLE(i), reg);
 		} else {
-			isp_reg_writel(0, OMAP3_ISP_IOMEM_CSI2A,
+			isp_reg_writel(isp_csi2->dev, 0,
+				       OMAP3_ISP_IOMEM_CSI2A,
 				       ISPCSI2_CTX_IRQENABLE(i));
 		}
 	}
@@ -1911,7 +1984,7 @@
  * isp_csi2_irq_status_set - Enables CSI2 Status IRQs.
  * @enable: Enable/disable CSI2 Status interrupts
  **/
-void isp_csi2_irq_status_set(int enable)
+void isp_csi2_irq_status_set(struct isp_csi2_device *isp_csi2, int enable)
 {
 	u32 reg;
 	reg = ISPCSI2_IRQSTATUS_OCP_ERR_IRQ |
@@ -1922,46 +1995,34 @@
 		ISPCSI2_IRQSTATUS_COMPLEXIO1_ERR_IRQ |
 		ISPCSI2_IRQSTATUS_FIFO_OVF_IRQ |
 		ISPCSI2_IRQSTATUS_CONTEXT(0);
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQSTATUS);
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+		       ISPCSI2_IRQSTATUS);
 	if (enable)
-		reg |= isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQENABLE);
+		reg |= isp_reg_readl(isp_csi2->dev,
+				     OMAP3_ISP_IOMEM_CSI2A,
+				     ISPCSI2_IRQENABLE);
 	else
 		reg = 0;
 
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_IRQENABLE);
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+		       ISPCSI2_IRQENABLE);
 }
 EXPORT_SYMBOL(isp_csi2_irq_status_set);
 
 /**
- * isp_csi2_irq_status_set - Enables main CSI2 IRQ.
- * @enable: Enable/disable main CSI2 interrupt
- **/
-void isp_csi2_irq_set(int enable)
-{
-	isp_reg_writel(IRQ0STATUS_CSIA_IRQ, OMAP3_ISP_IOMEM_MAIN,
-		       ISP_IRQ0STATUS);
-	isp_reg_and_or(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE,
-		       ~IRQ0ENABLE_CSIA_IRQ,
-		       (enable ? IRQ0ENABLE_CSIA_IRQ : 0));
-}
-EXPORT_SYMBOL(isp_csi2_irq_set);
-
-/**
  * isp_csi2_irq_all_set - Enable/disable CSI2 interrupts.
  * @enable: 0-Disable, 1-Enable.
  **/
-void isp_csi2_irq_all_set(int enable)
+void isp_csi2_irq_all_set(struct isp_csi2_device *isp_csi2, int enable)
 {
 	if (enable) {
-		isp_csi2_irq_complexio1_set(enable);
-		isp_csi2_irq_ctx_set(enable);
-		isp_csi2_irq_status_set(enable);
-		isp_csi2_irq_set(enable);
+		isp_csi2_irq_complexio1_set(isp_csi2, enable);
+		isp_csi2_irq_ctx_set(isp_csi2, enable);
+		isp_csi2_irq_status_set(isp_csi2, enable);
 	} else {
-		isp_csi2_irq_set(enable);
-		isp_csi2_irq_status_set(enable);
-		isp_csi2_irq_ctx_set(enable);
-		isp_csi2_irq_complexio1_set(enable);
+		isp_csi2_irq_status_set(isp_csi2, enable);
+		isp_csi2_irq_ctx_set(isp_csi2, enable);
+		isp_csi2_irq_complexio1_set(isp_csi2, enable);
 	}
 	return;
 }
@@ -1972,18 +2033,31 @@
  *
  * Returns 0 if successful, or -EBUSY if power command didn't respond.
  **/
-int isp_csi2_reset(void)
+int isp_csi2_reset(struct isp_csi2_device *isp_csi2)
 {
+	struct isp_device *isp = dev_get_drvdata(isp_csi2->dev);
 	u32 reg;
 	u8 soft_reset_retries = 0;
 	int i;
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG);
+	memset(&isp_csi2->current_cfg, 0, sizeof(isp_csi2->current_cfg));
+	memset(&isp_csi2->current_cfg_update, 0,
+	       sizeof(isp_csi2->current_cfg_update));
+
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_SYSCONFIG);
 	reg |= ISPCSI2_SYSCONFIG_SOFT_RESET_RESET;
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG);
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+		       ISPCSI2_SYSCONFIG);
+
+	if (isp->revision > ISP_REVISION_2_0)
+		isp_reg_or(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			   ISPCSI2_COMPLEXIO_CFG1,
+			   ISPCSI2_COMPLEXIO_CFG1_RESET_CTRL_DEASSERTED);
 
 	do {
-		reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSSTATUS) &
+		reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+				    ISPCSI2_SYSSTATUS) &
 			ISPCSI2_SYSSTATUS_RESET_DONE_MASK;
 		if (reg == ISPCSI2_SYSSTATUS_RESET_DONE_DONE)
 			break;
@@ -1997,37 +2071,56 @@
 		return -EBUSY;
 	}
 
-	reg = isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG);
+	i = 100;
+	do {
+		reg = isp_reg_readl(isp_csi2->dev,
+				    OMAP3_ISP_IOMEM_CSI2PHY,
+				    ISPCSI2PHY_CFG1) &
+		      ISPCSI2PHY_CFG1_RESETDONECTRLCLK_MASK;
+		if (reg == ISPCSI2PHY_CFG1_RESETDONECTRLCLK_MASK)
+			break;
+		udelay(100);
+	} while (--i > 0);
+
+	if (i == 0) {
+		printk(KERN_ERR
+			"CSI2: Reset for CSI2_96M_FCLK domain Failed!\n");
+		return -EBUSY;
+	}
+
+	reg = isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			    ISPCSI2_SYSCONFIG);
 	reg &= ~ISPCSI2_SYSCONFIG_MSTANDBY_MODE_MASK;
 	reg |= ISPCSI2_SYSCONFIG_MSTANDBY_MODE_SMART;
 	reg &= ~ISPCSI2_SYSCONFIG_AUTO_IDLE_MASK;
 	reg |= ISPCSI2_SYSCONFIG_AUTO_IDLE_AUTO;
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_SYSCONFIG);
+	isp_reg_writel(isp_csi2->dev, reg, OMAP3_ISP_IOMEM_CSI2A,
+		       ISPCSI2_SYSCONFIG);
 
-	uses_videoport = false;
-	update_complexio_cfg1 = false;
-	update_phy_cfg0 = false;
-	update_phy_cfg1 = false;
+	isp_csi2->uses_videoport = false;
+	isp_csi2->update_complexio_cfg1 = false;
+	isp_csi2->update_phy_cfg0 = false;
+	isp_csi2->update_phy_cfg1 = false;
 	for (i = 0; i < 8; i++) {
-		update_ctx_ctrl1[i] = false;
-		update_ctx_ctrl2[i] = false;
-		update_ctx_ctrl3[i] = false;
+		isp_csi2->update_ctx_ctrl1[i] = false;
+		isp_csi2->update_ctx_ctrl2[i] = false;
+		isp_csi2->update_ctx_ctrl3[i] = false;
 	}
-	update_timing = false;
-	update_ctrl = false;
+	isp_csi2->update_timing = false;
+	isp_csi2->update_ctrl = false;
 
-	isp_csi2_complexio_lanes_get();
-	isp_csi2_ctrl_get();
-	isp_csi2_ctx_get_all();
-	isp_csi2_phy_get();
-	isp_csi2_timings_get_all();
+	isp_csi2_complexio_lanes_get(isp_csi2);
+	isp_csi2_ctrl_get(isp_csi2);
+	isp_csi2_ctx_get_all(isp_csi2);
+	isp_csi2_phy_get(isp_csi2);
+	isp_csi2_timings_get_all(isp_csi2);
 
-	isp_csi2_complexio_power_autoswitch(true);
-	isp_csi2_complexio_power(ISP_CSI2_POWER_ON);
+	isp_csi2_complexio_power(isp_csi2, ISP_CSI2_POWER_ON);
+	isp_csi2_complexio_power_autoswitch(isp_csi2, true);
 
-	isp_csi2_timings_config_forcerxmode(1, true);
-	isp_csi2_timings_config_stopstate_cnt(1, 0x1FF);
-	isp_csi2_timings_update_all(true);
+	isp_csi2_timings_config_forcerxmode(isp_csi2, 1, true);
+	isp_csi2_timings_config_stopstate_cnt(isp_csi2, 1, 0x1FF);
+	isp_csi2_timings_update_all(isp_csi2, true);
 
 	return 0;
 }
@@ -2036,26 +2129,26 @@
  * isp_csi2_enable - Enables the CSI2 module.
  * @enable: Enables/disables the CSI2 module.
  **/
-void isp_csi2_enable(int enable)
+void isp_csi2_enable(struct isp_csi2_device *isp_csi2, int enable)
 {
 	if (enable) {
-		isp_csi2_ctx_config_enabled(0, true);
-		isp_csi2_ctx_config_eof_enabled(0, true);
-		isp_csi2_ctx_config_checksum_enabled(0, true);
-		isp_csi2_ctx_update(0, false);
+		isp_csi2_ctx_config_enabled(isp_csi2, 0, true);
+		isp_csi2_ctx_config_eof_enabled(isp_csi2, 0, true);
+		isp_csi2_ctx_config_checksum_enabled(isp_csi2, 0, true);
+		isp_csi2_ctx_update(isp_csi2, 0, false);
 
-		isp_csi2_ctrl_config_ecc_enable(true);
-		isp_csi2_ctrl_config_if_enable(true);
-		isp_csi2_ctrl_update(false);
+		isp_csi2_ctrl_config_ecc_enable(isp_csi2, true);
+		isp_csi2_ctrl_config_if_enable(isp_csi2, true);
+		isp_csi2_ctrl_update(isp_csi2, false);
 	} else {
-		isp_csi2_ctx_config_enabled(0, false);
-		isp_csi2_ctx_config_eof_enabled(0, false);
-		isp_csi2_ctx_config_checksum_enabled(0, false);
-		isp_csi2_ctx_update(0, false);
+		isp_csi2_ctx_config_enabled(isp_csi2, 0, false);
+		isp_csi2_ctx_config_eof_enabled(isp_csi2, 0, false);
+		isp_csi2_ctx_config_checksum_enabled(isp_csi2, 0, false);
+		isp_csi2_ctx_update(isp_csi2, 0, false);
 
-		isp_csi2_ctrl_config_ecc_enable(false);
-		isp_csi2_ctrl_config_if_enable(false);
-		isp_csi2_ctrl_update(false);
+		isp_csi2_ctrl_config_ecc_enable(isp_csi2, false);
+		isp_csi2_ctrl_config_if_enable(isp_csi2, false);
+		isp_csi2_ctrl_update(isp_csi2, false);
 	}
 }
 EXPORT_SYMBOL(isp_csi2_enable);
@@ -2063,111 +2156,120 @@
 /**
  * isp_csi2_regdump - Prints CSI2 debug information.
  **/
-void isp_csi2_regdump(void)
+void isp_csi2_regdump(struct isp_csi2_device *isp_csi2)
 {
 	printk(KERN_DEBUG "-------------Register dump-------------\n");
 
 	printk(KERN_DEBUG "ISP_CTRL: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_MAIN,
+			     ISP_CTRL));
 	printk(KERN_DEBUG "ISP_TCTRL_CTRL: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_TCTRL_CTRL));
-
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_MAIN,
+			     ISP_TCTRL_CTRL));
 	printk(KERN_DEBUG "ISPCCDC_SDR_ADDR: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SDR_ADDR));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+			     ISPCCDC_SDR_ADDR));
 	printk(KERN_DEBUG "ISPCCDC_SYN_MODE: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_SYN_MODE));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+			     ISPCCDC_SYN_MODE));
 	printk(KERN_DEBUG "ISPCCDC_CFG: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+			     ISPCCDC_CFG));
 	printk(KERN_DEBUG "ISPCCDC_FMTCFG: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_FMTCFG));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+			     ISPCCDC_FMTCFG));
 	printk(KERN_DEBUG "ISPCCDC_HSIZE_OFF: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HSIZE_OFF));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+			     ISPCCDC_HSIZE_OFF));
 	printk(KERN_DEBUG "ISPCCDC_HORZ_INFO: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CCDC, ISPCCDC_HORZ_INFO));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
+			     ISPCCDC_HORZ_INFO));
 	printk(KERN_DEBUG "ISPCCDC_VERT_START: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
 			     ISPCCDC_VERT_START));
 	printk(KERN_DEBUG "ISPCCDC_VERT_LINES: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CCDC,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CCDC,
 			     ISPCCDC_VERT_LINES));
 
 	printk(KERN_DEBUG "ISPCSI2_COMPLEXIO_CFG1: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_COMPLEXIO_CFG1));
 	printk(KERN_DEBUG "ISPCSI2_SYSSTATUS: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_SYSSTATUS));
 	printk(KERN_DEBUG "ISPCSI2_SYSCONFIG: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_SYSCONFIG));
 	printk(KERN_DEBUG "ISPCSI2_IRQENABLE: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_IRQENABLE));
 	printk(KERN_DEBUG "ISPCSI2_IRQSTATUS: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_IRQSTATUS));
 
 	printk(KERN_DEBUG "ISPCSI2_CTX_IRQENABLE(0): %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_CTX_IRQENABLE(0)));
 	printk(KERN_DEBUG "ISPCSI2_CTX_IRQSTATUS(0): %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_CTX_IRQSTATUS(0)));
 	printk(KERN_DEBUG "ISPCSI2_TIMING: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_TIMING));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			     ISPCSI2_TIMING));
 	printk(KERN_DEBUG "ISPCSI2PHY_CFG0: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2PHY,
 			     ISPCSI2PHY_CFG0));
 	printk(KERN_DEBUG "ISPCSI2PHY_CFG1: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2PHY,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2PHY,
 			     ISPCSI2PHY_CFG1));
 	printk(KERN_DEBUG "ISPCSI2_CTX_CTRL1(0): %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_CTX_CTRL1(0)));
 	printk(KERN_DEBUG "ISPCSI2_CTX_CTRL2(0): %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_CTX_CTRL2(0)));
 	printk(KERN_DEBUG "ISPCSI2_CTX_CTRL3(0): %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_CTX_CTRL3(0)));
 	printk(KERN_DEBUG "ISPCSI2_CTX_DAT_OFST(0): %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_CTX_DAT_OFST(0)));
 	printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PING_ADDR(0): %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_CTX_DAT_PING_ADDR(0)));
 	printk(KERN_DEBUG "ISPCSI2_CTX_DAT_PONG_ADDR(0): %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A,
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
 			     ISPCSI2_CTX_DAT_PONG_ADDR(0)));
 	printk(KERN_DEBUG "ISPCSI2_CTRL: %x\n",
-	       isp_reg_readl(OMAP3_ISP_IOMEM_CSI2A, ISPCSI2_CTRL));
+	       isp_reg_readl(isp_csi2->dev, OMAP3_ISP_IOMEM_CSI2A,
+			     ISPCSI2_CTRL));
 	printk(KERN_DEBUG "---------------------------------------\n");
 }
 
 /**
  * ispcsi2_save_context - Saves the values of the CSI1 module registers
  **/
-void ispcsi2_save_context(void)
+void ispcsi2_save_context(struct device *dev)
 {
 	printk(KERN_DEBUG "Saving csi2 context\n");
-	isp_save_context(ispcsi2_reg_list);
+	isp_save_context(dev, ispcsi2_reg_list);
 }
 EXPORT_SYMBOL(ispcsi2_save_context);
 
 /**
  * ispcsi2_restore_context - Restores the values of the CSI2 module registers
  **/
-void ispcsi2_restore_context(void)
+void ispcsi2_restore_context(struct device *dev)
 {
 	printk(KERN_DEBUG "Restoring csi2 context\n");
-	isp_restore_context(ispcsi2_reg_list);
+	isp_restore_context(dev, ispcsi2_reg_list);
 }
 EXPORT_SYMBOL(ispcsi2_restore_context);
 
 /**
  * isp_csi2_cleanup - Routine for module driver cleanup
  **/
-void isp_csi2_cleanup(void)
+void isp_csi2_cleanup(struct device *dev)
 {
 	return;
 }
@@ -2175,23 +2277,26 @@
 /**
  * isp_csi2_init - Routine for module driver init
  **/
-int __init isp_csi2_init(void)
+int __init isp_csi2_init(struct device *dev)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_csi2_device *isp_csi2 = &isp->isp_csi2;
 	int i;
 
-	update_complexio_cfg1 = false;
-	update_phy_cfg0 = false;
-	update_phy_cfg1 = false;
+	isp_csi2->dev = dev;
+	isp_csi2->update_complexio_cfg1 = false;
+	isp_csi2->update_phy_cfg0 = false;
+	isp_csi2->update_phy_cfg1 = false;
 	for (i = 0; i < 8; i++) {
-		update_ctx_ctrl1[i] = false;
-		update_ctx_ctrl2[i] = false;
-		update_ctx_ctrl3[i] = false;
+		isp_csi2->update_ctx_ctrl1[i] = false;
+		isp_csi2->update_ctx_ctrl2[i] = false;
+		isp_csi2->update_ctx_ctrl3[i] = false;
 	}
-	update_timing = false;
-	update_ctrl = false;
+	isp_csi2->update_timing = false;
+	isp_csi2->update_ctrl = false;
 
-	memset(&current_csi2_cfg, 0, sizeof(current_csi2_cfg));
-	memset(&current_csi2_cfg_update, 0, sizeof(current_csi2_cfg_update));
+	memset(&isp_csi2->current_cfg, 0, sizeof(isp_csi2->current_cfg));
+	memset(&isp_csi2->current_cfg_update, 0, sizeof(isp_csi2->current_cfg_update));
 	return 0;
 }
 
diff --git a/drivers/media/video/isp/ispcsi2.h b/drivers/media/video/isp/ispcsi2.h
index 3fc5e55..a6ad66a 100644
--- a/drivers/media/video/isp/ispcsi2.h
+++ b/drivers/media/video/isp/ispcsi2.h
@@ -177,64 +177,112 @@
 	struct isp_csi2_ctrl_cfg_update ctrl;
 };
 
-int isp_csi2_complexio_lanes_config(struct isp_csi2_lanes_cfg *reqcfg);
-int isp_csi2_complexio_lanes_update(bool force_update);
-int isp_csi2_complexio_lanes_count(int cnt);
-int isp_csi2_complexio_lanes_get(void);
-int isp_csi2_complexio_power_autoswitch(bool enable);
-int isp_csi2_complexio_power(enum isp_csi2_power_cmds power_cmd);
-int isp_csi2_ctrl_config_frame_mode(enum isp_csi2_frame_mode frame_mode);
-int isp_csi2_ctrl_config_vp_clk_enable(bool vp_clk_enable);
-int isp_csi2_ctrl_config_vp_only_enable(bool vp_only_enable);
-int isp_csi2_ctrl_config_debug_enable(bool debug_enable);
-int isp_csi2_ctrl_config_burst_size(u8 burst_size);
-int isp_csi2_ctrl_config_ecc_enable(bool ecc_enable);
-int isp_csi2_ctrl_config_secure_mode(bool secure_mode);
-int isp_csi2_ctrl_config_if_enable(bool if_enable);
-int isp_csi2_ctrl_config_vp_out_ctrl(u8 vp_out_ctrl);
-int isp_csi2_ctrl_update(bool force_update);
-int isp_csi2_ctrl_get(void);
-int isp_csi2_ctx_config_virtual_id(u8 ctxnum, u8 virtual_id);
-int isp_csi2_ctx_config_frame_count(u8 ctxnum, u8 frame_count);
-int isp_csi2_ctx_config_format(u8 ctxnum, u32 pixformat);
-int isp_csi2_ctx_config_alpha(u8 ctxnum, u16 alpha);
-int isp_csi2_ctx_config_data_offset(u8 ctxnum, u16 data_offset);
-int isp_csi2_ctx_config_ping_addr(u8 ctxnum, u32 ping_addr);
-int isp_csi2_ctx_config_pong_addr(u8 ctxnum, u32 pong_addr);
-int isp_csi2_ctx_config_eof_enabled(u8 ctxnum, bool eof_enabled);
-int isp_csi2_ctx_config_eol_enabled(u8 ctxnum, bool eol_enabled);
-int isp_csi2_ctx_config_checksum_enabled(u8 ctxnum, bool checksum_enabled);
-int isp_csi2_ctx_config_enabled(u8 ctxnum, bool enabled);
-int isp_csi2_ctx_update(u8 ctxnum, bool force_update);
-int isp_csi2_ctx_get(u8 ctxnum);
-int isp_csi2_ctx_update_all(bool force_update);
-int isp_csi2_ctx_get_all(void);
-int isp_csi2_phy_config(struct isp_csi2_phy_cfg *desiredphyconfig);
-int isp_csi2_calc_phy_cfg0(u32 mipiclk, u32 lbound_hs_settle,
+struct isp_csi2_device {
+	struct device *dev;
+	struct isp_csi2_cfg current_cfg;
+	struct isp_csi2_cfg_update current_cfg_update;
+	bool update_complexio_cfg1;
+	bool update_phy_cfg0;
+	bool update_phy_cfg1;
+	bool update_ctx_ctrl1[8];
+	bool update_ctx_ctrl2[8];
+	bool update_ctx_ctrl3[8];
+	bool update_timing;
+	bool update_ctrl;
+	bool uses_videoport;
+};
+
+int isp_csi2_complexio_lanes_config(struct isp_csi2_device *isp_csi2,
+				    struct isp_csi2_lanes_cfg *reqcfg);
+int isp_csi2_complexio_lanes_update(struct isp_csi2_device *isp_csi2,
+				    bool force_update);
+int isp_csi2_complexio_lanes_count(struct isp_csi2_device *isp_csi2, int cnt);
+int isp_csi2_complexio_lanes_get(struct isp_csi2_device *isp_csi2);
+int isp_csi2_complexio_power_autoswitch(struct isp_csi2_device *isp_csi2,
+					bool enable);
+int isp_csi2_complexio_power(struct isp_csi2_device *isp_csi2,
+			     enum isp_csi2_power_cmds power_cmd);
+int isp_csi2_ctrl_config_frame_mode(struct isp_csi2_device *isp_csi2,
+				    enum isp_csi2_frame_mode frame_mode);
+int isp_csi2_ctrl_config_vp_clk_enable(struct isp_csi2_device *isp_csi2,
+				       bool vp_clk_enable);
+int isp_csi2_ctrl_config_vp_only_enable(struct isp_csi2_device *isp_csi2,
+					bool vp_only_enable);
+int isp_csi2_ctrl_config_debug_enable(struct isp_csi2_device *isp_csi2,
+				      bool debug_enable);
+int isp_csi2_ctrl_config_burst_size(struct isp_csi2_device *isp_csi2,
+				    u8 burst_size);
+int isp_csi2_ctrl_config_ecc_enable(struct isp_csi2_device *isp_csi2,
+				    bool ecc_enable);
+int isp_csi2_ctrl_config_secure_mode(struct isp_csi2_device *isp_csi2,
+				     bool secure_mode);
+int isp_csi2_ctrl_config_if_enable(struct isp_csi2_device *isp_csi2,
+				   bool if_enable);
+int isp_csi2_ctrl_config_vp_out_ctrl(struct isp_csi2_device *isp_csi2,
+				     u8 vp_out_ctrl);
+int isp_csi2_ctrl_update(struct isp_csi2_device *isp_csi2, bool force_update);
+int isp_csi2_ctrl_get(struct isp_csi2_device *isp_csi2);
+int isp_csi2_ctx_config_virtual_id(struct isp_csi2_device *isp_csi2,
+				   u8 ctxnum, u8 virtual_id);
+int isp_csi2_ctx_config_frame_count(struct isp_csi2_device *isp_csi2,
+				    u8 ctxnum, u8 frame_count);
+int isp_csi2_ctx_config_format(struct isp_csi2_device *isp_csi2,
+			       u8 ctxnum, u32 pixformat);
+int isp_csi2_ctx_config_alpha(struct isp_csi2_device *isp_csi2,
+			      u8 ctxnum, u16 alpha);
+int isp_csi2_ctx_config_data_offset(struct isp_csi2_device *isp_csi2,
+				    u8 ctxnum, u16 data_offset);
+int isp_csi2_ctx_config_ping_addr(struct isp_csi2_device *isp_csi2,
+				  u8 ctxnum, u32 ping_addr);
+int isp_csi2_ctx_config_pong_addr(struct isp_csi2_device *isp_csi2,
+				  u8 ctxnum, u32 pong_addr);
+int isp_csi2_ctx_config_eof_enabled(struct isp_csi2_device *isp_csi2,
+				    u8 ctxnum, bool eof_enabled);
+int isp_csi2_ctx_config_eol_enabled(struct isp_csi2_device *isp_csi2,
+				    u8 ctxnum, bool eol_enabled);
+int isp_csi2_ctx_config_checksum_enabled(struct isp_csi2_device *isp_csi2,
+					 u8 ctxnum, bool checksum_enabled);
+int isp_csi2_ctx_config_enabled(struct isp_csi2_device *isp_csi2,
+				u8 ctxnum, bool enabled);
+int isp_csi2_ctx_update(struct isp_csi2_device *isp_csi2,
+			u8 ctxnum, bool force_update);
+int isp_csi2_ctx_get(struct isp_csi2_device *isp_csi2, u8 ctxnum);
+int isp_csi2_ctx_update_all(struct isp_csi2_device *isp_csi2,
+			    bool force_update);
+int isp_csi2_ctx_get_all(struct isp_csi2_device *isp_csi2);
+int isp_csi2_phy_config(struct isp_csi2_device *isp_csi2,
+			struct isp_csi2_phy_cfg *desiredphyconfig);
+int isp_csi2_calc_phy_cfg0(struct isp_csi2_device *isp_csi2,
+			   u32 mipiclk, u32 lbound_hs_settle,
 			   u32 ubound_hs_settle);
-int isp_csi2_phy_update(bool force_update);
-int isp_csi2_phy_get(void);
-int isp_csi2_timings_config_forcerxmode(u8 io, bool force_rx_mode);
-int isp_csi2_timings_config_stopstate_16x(u8 io, bool stop_state_16x);
-int isp_csi2_timings_config_stopstate_4x(u8 io, bool stop_state_4x);
-int isp_csi2_timings_config_stopstate_cnt(u8 io, u16 stop_state_counter);
-int isp_csi2_timings_update(u8 io, bool force_update);
-int isp_csi2_timings_get(u8 io);
-int isp_csi2_timings_update_all(bool force_update);
-int isp_csi2_timings_get_all(void);
-void isp_csi2_irq_complexio1_set(int enable);
-void isp_csi2_irq_ctx_set(int enable);
-void isp_csi2_irq_status_set(int enable);
-void isp_csi2_irq_set(int enable);
-void isp_csi2_irq_all_set(int enable);
+int isp_csi2_phy_update(struct isp_csi2_device *isp_csi2,
+			bool force_update);
+int isp_csi2_phy_get(struct isp_csi2_device *isp_csi2);
+int isp_csi2_timings_config_forcerxmode(struct isp_csi2_device *isp_csi2,
+					u8 io, bool force_rx_mode);
+int isp_csi2_timings_config_stopstate_16x(struct isp_csi2_device *isp_csi2,
+					  u8 io, bool stop_state_16x);
+int isp_csi2_timings_config_stopstate_4x(struct isp_csi2_device *isp_csi2,
+					 u8 io, bool stop_state_4x);
+int isp_csi2_timings_config_stopstate_cnt(struct isp_csi2_device *isp_csi2,
+					  u8 io, u16 stop_state_counter);
+int isp_csi2_timings_update(struct isp_csi2_device *isp_csi2,
+			    u8 io, bool force_update);
+int isp_csi2_timings_get(struct isp_csi2_device *isp_csi2, u8 io);
+int isp_csi2_timings_update_all(struct isp_csi2_device *isp_csi2, bool force_update);
+int isp_csi2_timings_get_all(struct isp_csi2_device *isp_csi2);
+void isp_csi2_irq_complexio1_set(struct isp_csi2_device *isp_csi2, int enable);
+void isp_csi2_irq_ctx_set(struct isp_csi2_device *isp_csi2, int enable);
+void isp_csi2_irq_status_set(struct isp_csi2_device *isp_csi2, int enable);
+void isp_csi2_irq_all_set(struct isp_csi2_device *isp_csi2, int enable);
 
-void isp_csi2_isr(void);
-int isp_csi2_reset(void);
-void isp_csi2_enable(int enable);
-void isp_csi2_regdump(void);
+int isp_csi2_isr(struct isp_csi2_device *isp_csi2);
+int isp_csi2_reset(struct isp_csi2_device *isp_csi2);
+void isp_csi2_enable(struct isp_csi2_device *isp_csi2, int enable);
+void isp_csi2_regdump(struct isp_csi2_device *isp_csi2);
 
-void ispcsi2_save_context(void);
-void ispcsi2_restore_context(void);
+void ispcsi2_save_context(struct device *dev);
+void ispcsi2_restore_context(struct device *dev);
 
 #endif	/* OMAP_ISP_CSI2_H */
 
diff --git a/drivers/media/video/isp/isph3a.c b/drivers/media/video/isp/isph3a.c
index dc38a91..fc4632d 100644
--- a/drivers/media/video/isp/isph3a.c
+++ b/drivers/media/video/isp/isph3a.c
@@ -18,109 +18,10 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#include <asm/cacheflush.h>
-
 #include <linux/dma-mapping.h>
 #include <linux/uaccess.h>
 
 #include "isp.h"
-#include "ispreg.h"
-#include "isph3a.h"
-#include "ispmmu.h"
-#include "isppreview.h"
-
-/**
- * struct isph3a_aewb_buffer - AE, AWB frame stats buffer.
- * @virt_addr: Virtual address to mmap the buffer.
- * @phy_addr: Physical address of the buffer.
- * @addr_align: Virtual Address 32 bytes aligned.
- * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
- * @mmap_addr: Mapped memory area of buffer. For userspace access.
- * @locked: 1 - Buffer locked from write. 0 - Buffer can be overwritten.
- * @frame_num: Frame number from which the statistics are taken.
- * @next: Pointer to link next buffer.
- */
-struct isph3a_aewb_buffer {
-	unsigned long virt_addr;
-	unsigned long phy_addr;
-	unsigned long addr_align;
-	unsigned long ispmmu_addr;
-	unsigned long mmap_addr;	/* For userspace */
-	struct timeval ts;
-	u32 config_counter;
-
-	u8 locked;
-	u16 frame_num;
-	struct isph3a_aewb_buffer *next;
-};
-
-/**
- * struct isph3a_aewb_status - AE, AWB status.
- * @initialized: 1 - Buffers initialized.
- * @update: 1 - Update registers.
- * @stats_req: 1 - Future stats requested.
- * @stats_done: 1 - Stats ready for user.
- * @frame_req: Number of frame requested for statistics.
- * @h3a_buff: Array of statistics buffers to access.
- * @stats_buf_size: Statistics buffer size.
- * @min_buf_size: Minimum statisitics buffer size.
- * @win_count: Window Count.
- * @frame_count: Frame Count.
- * @stats_wait: Wait primitive for locking/unlocking the stats request.
- * @buffer_lock: Spinlock for statistics buffers access.
- */
-static struct isph3a_aewb_status {
-	u8 initialized;
-	u8 update;
-	u8 stats_req;
-	u8 stats_done;
-	u16 frame_req;
-	int pm_state;
-
-	struct isph3a_aewb_buffer h3a_buff[H3A_MAX_BUFF];
-	unsigned int stats_buf_size;
-	unsigned int min_buf_size;
-	unsigned int curr_cfg_buf_size;
-
-	atomic_t config_counter;
-
-	u16 win_count;
-	u32 frame_count;
-	wait_queue_head_t stats_wait;
-	spinlock_t buffer_lock;		/* For stats buffers read/write sync */
-} aewbstat;
-
-/**
- * struct isph3a_aewb_regs - Current value of AE, AWB configuration registers.
- * reg_pcr: Peripheral control register.
- * reg_win1: Control register.
- * reg_start: Start position register.
- * reg_blk: Black line register.
- * reg_subwin: Configuration register.
- */
-static struct isph3a_aewb_regs {
-	u32 reg_pcr;
-	u32 reg_win1;
-	u32 reg_start;
-	u32 reg_blk;
-	u32 reg_subwin;
-} aewb_regs;
-
-static struct isph3a_aewb_config aewb_config_local = {
-	.saturation_limit = 0x3FF,
-	.win_height = 0,
-	.win_width = 0,
-	.ver_win_count = 0,
-	.hor_win_count = 0,
-	.ver_win_start = 0,
-	.hor_win_start = 0,
-	.blk_ver_win_start = 0,
-	.blk_win_height = 0,
-	.subsample_ver_inc = 0,
-	.subsample_hor_inc = 0,
-	.alaw_enable = 0,
-	.aewb_enable = 0,
-};
 
 /* Structure for saving/restoring h3a module registers */
 static struct isp_reg isph3a_reg_list[] = {
@@ -150,72 +51,18 @@
 	{0, ISP_TOK_TERM, 0}
 };
 
-static struct ispprev_wbal h3awb_update;
-static struct isph3a_aewb_buffer *active_buff;
-static struct isph3a_aewb_xtrastats h3a_xtrastats[H3A_MAX_BUFF];
-static int camnotify;
-static int wb_update;
-static void isph3a_print_status(void);
+static void isph3a_print_status(struct isp_h3a_device *isp_h3a);
 
-/**
- * isph3a_aewb_setxtrastats - Receives extra statistics from prior frames.
- * @xtrastats: Pointer to structure containing extra statistics fields like
- *             field count and timestamp of frame.
- *
- * Called from update_vbq in camera driver
- **/
-void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats)
+void __isph3a_aewb_enable(struct isp_h3a_device *isp_h3a, u8 enable)
 {
-	int i;
+	struct device *dev = to_device(isp_h3a);
+	u32 pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
 
-	if (active_buff == NULL)
-		return;
-
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		if (aewbstat.h3a_buff[i].frame_num != active_buff->frame_num)
-			continue;
-
-		if (i == 0) {
-			if (aewbstat.h3a_buff[H3A_MAX_BUFF - 1].locked == 0) {
-				h3a_xtrastats[H3A_MAX_BUFF - 1] =
-					*xtrastats;
-			} else {
-				h3a_xtrastats[H3A_MAX_BUFF - 2] =
-					*xtrastats;
-			}
-		} else if (i == 1) {
-			if (aewbstat.h3a_buff[0].locked == 0)
-				h3a_xtrastats[0] = *xtrastats;
-			else {
-				h3a_xtrastats[H3A_MAX_BUFF - 1] =
-					*xtrastats;
-			}
-		} else {
-			if (aewbstat.h3a_buff[i - 1].locked == 0)
-				h3a_xtrastats[i - 1] = *xtrastats;
-			else
-				h3a_xtrastats[i - 2] = *xtrastats;
-		}
-		return;
-	}
-}
-EXPORT_SYMBOL(isph3a_aewb_setxtrastats);
-
-void __isph3a_aewb_enable(u8 enable)
-{
-	isp_reg_writel(IRQ0STATUS_H3A_AWB_DONE_IRQ, OMAP3_ISP_IOMEM_MAIN,
-		       ISP_IRQ0STATUS);
-
-	if (enable) {
-		aewb_regs.reg_pcr |= ISPH3A_PCR_AEW_EN;
-		DPRINTK_ISPH3A("    H3A enabled \n");
-	} else {
-		aewb_regs.reg_pcr &= ~ISPH3A_PCR_AEW_EN;
-		DPRINTK_ISPH3A("    H3A disabled \n");
-	}
-	isp_reg_and_or(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR, ~ISPH3A_PCR_AEW_EN,
-		       (enable ? ISPH3A_PCR_AEW_EN : 0));
-	aewb_config_local.aewb_enable = enable;
+	if (enable)
+		pcr |= ISPH3A_PCR_AEW_EN;
+	else
+		pcr &= ~ISPH3A_PCR_AEW_EN;
+	isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
 }
 
 /**
@@ -224,46 +71,90 @@
  *
  * Client should configure all the AE & AWB registers in H3A before this.
  **/
-void isph3a_aewb_enable(u8 enable)
+void isph3a_aewb_enable(struct isp_h3a_device *isp_h3a, u8 enable)
 {
-	__isph3a_aewb_enable(enable);
-	aewbstat.pm_state = enable;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(isp_h3a->lock, irqflags);
+
+	if (!isp_h3a->aewb_config_local.aewb_enable && enable) {
+		spin_unlock_irqrestore(isp_h3a->lock, irqflags);
+		return;
+	}
+
+	__isph3a_aewb_enable(isp_h3a, enable);
+	isp_h3a->enabled = enable;
+
+	spin_unlock_irqrestore(isp_h3a->lock, irqflags);
 }
 
 /**
  * isph3a_aewb_suspend - Suspend AE, AWB engine in the H3A module.
  **/
-void isph3a_aewb_suspend(void)
+void isph3a_aewb_suspend(struct isp_h3a_device *isp_h3a)
 {
-	if (aewbstat.pm_state)
-		__isph3a_aewb_enable(0);
+	unsigned long flags;
+
+	spin_lock_irqsave(isp_h3a->lock, flags);
+
+	if (isp_h3a->enabled)
+		__isph3a_aewb_enable(isp_h3a, 0);
+
+	spin_unlock_irqrestore(isp_h3a->lock, flags);
 }
 
 /**
  * isph3a_aewb_resume - Resume AE, AWB engine in the H3A module.
  **/
-void isph3a_aewb_resume(void)
+void isph3a_aewb_resume(struct isp_h3a_device *isp_h3a)
 {
-	if (aewbstat.pm_state)
-		__isph3a_aewb_enable(1);
+	unsigned long flags;
+
+	spin_lock_irqsave(isp_h3a->lock, flags);
+
+	if (isp_h3a->enabled)
+		__isph3a_aewb_enable(isp_h3a, 1);
+
+	spin_unlock_irqrestore(isp_h3a->lock, flags);
 }
 
-int isph3a_aewb_busy(void)
+int isph3a_aewb_busy(struct isp_h3a_device *isp_h3a)
 {
-	return isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
+	struct device *dev = to_device(isp_h3a);
+
+	return isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR)
 		& ISPH3A_PCR_BUSYAEAWB;
 }
 
+void isph3a_aewb_try_enable(struct isp_h3a_device *isp_h3a)
+{
+	unsigned long irqflags;
+
+	spin_lock_irqsave(isp_h3a->lock, irqflags);
+	if (!isp_h3a->enabled && isp_h3a->aewb_config_local.aewb_enable) {
+		isp_h3a->update = 1;
+		isp_h3a->buf_next = ispstat_buf_next(&isp_h3a->stat);
+		spin_unlock_irqrestore(isp_h3a->lock, irqflags);
+		isph3a_aewb_config_registers(isp_h3a);
+		isph3a_aewb_enable(isp_h3a, 1);
+	} else
+		spin_unlock_irqrestore(isp_h3a->lock, irqflags);
+}
+
 /**
  * isph3a_update_wb - Updates WB parameters.
  *
  * Needs to be called when no ISP Preview processing is taking place.
  **/
-void isph3a_update_wb(void)
+void isph3a_update_wb(struct isp_h3a_device *isp_h3a)
 {
-	if (wb_update) {
-		isppreview_config_whitebalance(h3awb_update);
-		wb_update = 0;
+	struct isp_device *isp = to_isp_device(isp_h3a);
+
+	if (isp_h3a->wb_update) {
+		/* FIXME: Get the preview crap out of here!!! */
+		isppreview_config_whitebalance(&isp->isp_prev,
+					       isp_h3a->h3awb_update);
+		isp_h3a->wb_update = 0;
 	}
 	return;
 }
@@ -272,30 +163,38 @@
 /**
  * isph3a_aewb_update_regs - Helper function to update h3a registers.
  **/
-static void isph3a_aewb_update_regs(void)
+void isph3a_aewb_config_registers(struct isp_h3a_device *isp_h3a)
 {
-	isp_reg_writel(aewb_regs.reg_pcr, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR);
-	isp_reg_writel(aewb_regs.reg_win1, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1);
-	isp_reg_writel(aewb_regs.reg_start, OMAP3_ISP_IOMEM_H3A,
+	struct device *dev = to_device(isp_h3a);
+	unsigned long irqflags;
+
+	if (!isp_h3a->aewb_config_local.aewb_enable)
+		return;
+
+	spin_lock_irqsave(isp_h3a->lock, irqflags);
+
+	isp_reg_writel(dev, isp_h3a->buf_next->iommu_addr,
+		       OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST);
+
+	if (!isp_h3a->update) {
+		spin_unlock_irqrestore(isp_h3a->lock, irqflags);
+		return;
+	}
+
+	isp_reg_writel(dev, isp_h3a->regs.win1, OMAP3_ISP_IOMEM_H3A,
+		       ISPH3A_AEWWIN1);
+	isp_reg_writel(dev, isp_h3a->regs.start, OMAP3_ISP_IOMEM_H3A,
 		       ISPH3A_AEWINSTART);
-	isp_reg_writel(aewb_regs.reg_blk, OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK);
-	isp_reg_writel(aewb_regs.reg_subwin, OMAP3_ISP_IOMEM_H3A,
+	isp_reg_writel(dev, isp_h3a->regs.blk, OMAP3_ISP_IOMEM_H3A,
+		       ISPH3A_AEWINBLK);
+	isp_reg_writel(dev, isp_h3a->regs.subwin, OMAP3_ISP_IOMEM_H3A,
 		       ISPH3A_AEWSUBWIN);
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR,
+		       ~ISPH3A_PCR_AEW_MASK, isp_h3a->regs.pcr);
 
-	aewbstat.update = 0;
-}
+	isp_h3a->update = 0;
 
-/**
- * isph3a_aewb_update_req_buffer - Helper function to update buffer cache pages
- * @buffer: Pointer to structure
- **/
-static void isph3a_aewb_update_req_buffer(struct isph3a_aewb_buffer *buffer)
-{
-	int size = aewbstat.stats_buf_size;
-
-	size = PAGE_ALIGN(size);
-	dmac_inv_range((void *)buffer->addr_align,
-		       (void *)buffer->addr_align + size);
+	spin_unlock_irqrestore(isp_h3a->lock, irqflags);
 }
 
 /**
@@ -304,116 +203,95 @@
  *
  * Returns 0 if successful, or -1 if statistics are unavailable.
  **/
-static int isph3a_aewb_stats_available(struct isph3a_aewb_data *aewbdata)
+static int isph3a_aewb_get_stats(struct isp_h3a_device *isp_h3a,
+				 struct isph3a_aewb_data *aewbdata)
 {
-	int i, ret;
-	unsigned long irqflags;
+	struct ispstat_buffer *buf;
 
-	spin_lock_irqsave(&aewbstat.buffer_lock, irqflags);
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		DPRINTK_ISPH3A("Checking Stats buff[%d] (%d) for %d\n",
-			       i, aewbstat.h3a_buff[i].frame_num,
-			       aewbdata->frame_number);
-		if ((aewbdata->frame_number !=
-		     aewbstat.h3a_buff[i].frame_num) ||
-		    (aewbstat.h3a_buff[i].frame_num ==
-		     active_buff->frame_num))
-			continue;
-		aewbstat.h3a_buff[i].locked = 1;
-		spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
-		isph3a_aewb_update_req_buffer(&aewbstat.h3a_buff[i]);
-		aewbstat.h3a_buff[i].frame_num = 0;
-		ret = copy_to_user((void *)aewbdata->h3a_aewb_statistics_buf,
-				   (void *)aewbstat.h3a_buff[i].virt_addr,
-				   aewbstat.curr_cfg_buf_size);
-		if (ret) {
-			printk(KERN_ERR "Failed copy_to_user for "
-			       "H3A stats buff, %d\n", ret);
-		}
-		aewbdata->ts = aewbstat.h3a_buff[i].ts;
-		aewbdata->config_counter = aewbstat.h3a_buff[i].config_counter;
-		aewbdata->field_count = h3a_xtrastats[i].field_count;
-		return 0;
-	}
-	spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
+	buf = ispstat_buf_get(&isp_h3a->stat,
+			      (void *)aewbdata->h3a_aewb_statistics_buf,
+			      aewbdata->frame_number);
 
-	return -1;
+	if (IS_ERR(buf))
+		return PTR_ERR(buf);
+
+	aewbdata->ts = buf->ts;
+	aewbdata->config_counter = buf->config_counter;
+	aewbdata->frame_number = buf->frame_number;
+
+	ispstat_buf_release(&isp_h3a->stat);
+
+	return 0;
 }
 
 /**
- * isph3a_aewb_link_buffers - Helper function to link allocated buffers.
- **/
-static void isph3a_aewb_link_buffers(void)
-{
-	int i;
-
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		if ((i + 1) < H3A_MAX_BUFF) {
-			aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[i + 1];
-			h3a_xtrastats[i].next = &h3a_xtrastats[i + 1];
-		} else {
-			aewbstat.h3a_buff[i].next = &aewbstat.h3a_buff[0];
-			h3a_xtrastats[i].next = &h3a_xtrastats[0];
-		}
-	}
-}
-
-/**
- * isph3a_aewb_unlock_buffers - Helper function to unlock all buffers.
- **/
-static void isph3a_aewb_unlock_buffers(void)
-{
-	int i;
-	unsigned long irqflags;
-
-	spin_lock_irqsave(&aewbstat.buffer_lock, irqflags);
-	for (i = 0; i < H3A_MAX_BUFF; i++)
-		aewbstat.h3a_buff[i].locked = 0;
-
-	spin_unlock_irqrestore(&aewbstat.buffer_lock, irqflags);
-}
-
-/**
- * isph3a_aewb_isr - Callback from ISP driver for H3A AEWB interrupt.
- * @status: IRQ0STATUS in case of MMU error, 0 for H3A interrupt.
- * @arg1: Not used as of now.
- * @arg2: Not used as of now.
+ * isph3a_aewb_buf_process - Process H3A AEWB buffer.
  */
-static void isph3a_aewb_isr(unsigned long status, isp_vbq_callback_ptr arg1,
-			    void *arg2)
+int isph3a_aewb_buf_process(struct isp_h3a_device *isp_h3a)
 {
-	u16 frame_align;
+	isph3a_update_wb(isp_h3a);
+	if (likely(!isp_h3a->buf_err &&
+				isp_h3a->aewb_config_local.aewb_enable)) {
+		int ret;
 
-	if ((H3A_AWB_DONE & status) != H3A_AWB_DONE)
-		return;
-
-	do_gettimeofday(&active_buff->ts);
-	active_buff->config_counter = atomic_read(&aewbstat.config_counter);
-	active_buff = active_buff->next;
-	if (active_buff->locked == 1)
-		active_buff = active_buff->next;
-	isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A,
-		       ISPH3A_AEWBUFST);
-
-	aewbstat.frame_count++;
-	frame_align = aewbstat.frame_count;
-	if (aewbstat.frame_count > MAX_FRAME_COUNT) {
-		aewbstat.frame_count = 1;
-		frame_align++;
+		ret = ispstat_buf_queue(&isp_h3a->stat);
+		isp_h3a->buf_next = ispstat_buf_next(&isp_h3a->stat);
+		return ret;
+	} else {
+		isp_h3a->buf_err = 0;
+		return -1;
 	}
-	active_buff->frame_num = aewbstat.frame_count;
+}
 
-	if (aewbstat.stats_req) {
-		DPRINTK_ISPH3A("waiting for frame %d\n", aewbstat.frame_req);
-		if (frame_align >= aewbstat.frame_req + 1) {
-			aewbstat.stats_req = 0;
-			aewbstat.stats_done = 1;
-			wake_up_interruptible(&aewbstat.stats_wait);
-		}
-	}
+static int isph3a_aewb_validate_params(struct isp_h3a_device *isp_h3a,
+				       struct isph3a_aewb_config *user_cfg)
+{
+	if (unlikely(user_cfg->saturation_limit > MAX_SATURATION_LIM))
+		return -EINVAL;
 
-	if (aewbstat.update)
-		isph3a_aewb_update_regs();
+	if (unlikely(user_cfg->win_height < MIN_WIN_H ||
+		     user_cfg->win_height > MAX_WIN_H ||
+		     user_cfg->win_height & 0x01))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->win_width < MIN_WIN_W ||
+		     user_cfg->win_width > MAX_WIN_W ||
+		     user_cfg->win_width & 0x01))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->ver_win_count < 1 ||
+		     user_cfg->ver_win_count > MAX_WINVC))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->hor_win_count < 1 ||
+		     user_cfg->hor_win_count > MAX_WINHC))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->ver_win_start > MAX_WINSTART))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->hor_win_start > MAX_WINSTART))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->blk_ver_win_start > MAX_WINSTART))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->blk_win_height < MIN_WIN_H ||
+		     user_cfg->blk_win_height > MAX_WIN_H ||
+		     user_cfg->blk_win_height & 0x01))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->subsample_ver_inc < MIN_SUB_INC ||
+		     user_cfg->subsample_ver_inc > MAX_SUB_INC ||
+		     user_cfg->subsample_ver_inc & 0x01))
+		return -EINVAL;
+
+	if (unlikely(user_cfg->subsample_hor_inc < MIN_SUB_INC ||
+		     user_cfg->subsample_hor_inc > MAX_SUB_INC ||
+		     user_cfg->subsample_hor_inc & 0x01))
+		return -EINVAL;
+
+	return 0;
 }
 
 /**
@@ -425,287 +303,156 @@
  *
  * Returns 0 if successful, or -EINVAL if any of the parameters are invalid.
  **/
-static int isph3a_aewb_set_params(struct isph3a_aewb_config *user_cfg)
+static void isph3a_aewb_set_params(struct isp_h3a_device *isp_h3a,
+				   struct isph3a_aewb_config *user_cfg)
 {
-	if (unlikely(user_cfg->saturation_limit > MAX_SATURATION_LIM)) {
-		printk(KERN_ERR "Invalid Saturation_limit: %d\n",
-		       user_cfg->saturation_limit);
-		return -EINVAL;
-	}
-	if (aewb_config_local.saturation_limit != user_cfg->saturation_limit) {
-		WRITE_SAT_LIM(aewb_regs.reg_pcr, user_cfg->saturation_limit);
-		aewb_config_local.saturation_limit =
+	if (isp_h3a->aewb_config_local.saturation_limit !=
+						user_cfg->saturation_limit) {
+		WRITE_SAT_LIM(isp_h3a->regs.pcr, user_cfg->saturation_limit);
+		isp_h3a->aewb_config_local.saturation_limit =
 			user_cfg->saturation_limit;
-		aewbstat.update = 1;
+		isp_h3a->update = 1;
 	}
 
-	if (aewb_config_local.alaw_enable != user_cfg->alaw_enable) {
-		WRITE_ALAW(aewb_regs.reg_pcr, user_cfg->alaw_enable);
-		aewb_config_local.alaw_enable = user_cfg->alaw_enable;
-		aewbstat.update = 1;
+	if (isp_h3a->aewb_config_local.alaw_enable != user_cfg->alaw_enable) {
+		WRITE_ALAW(isp_h3a->regs.pcr, user_cfg->alaw_enable);
+		isp_h3a->aewb_config_local.alaw_enable = user_cfg->alaw_enable;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->win_height < MIN_WIN_H ||
-		     user_cfg->win_height > MAX_WIN_H ||
-		     user_cfg->win_height & 0x01)) {
-		printk(KERN_ERR "Invalid window height: %d\n",
-		       user_cfg->win_height);
-		return -EINVAL;
-	}
-	if (aewb_config_local.win_height != user_cfg->win_height) {
-		WRITE_WIN_H(aewb_regs.reg_win1, user_cfg->win_height);
-		aewb_config_local.win_height = user_cfg->win_height;
-		aewbstat.update = 1;
+	if (isp_h3a->aewb_config_local.win_height != user_cfg->win_height) {
+		WRITE_WIN_H(isp_h3a->regs.win1, user_cfg->win_height);
+		isp_h3a->aewb_config_local.win_height = user_cfg->win_height;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->win_width < MIN_WIN_W ||
-		     user_cfg->win_width > MAX_WIN_W ||
-		     user_cfg->win_width & 0x01)) {
-		printk(KERN_ERR "Invalid window width: %d\n",
-		       user_cfg->win_width);
-		return -EINVAL;
-	}
-	if (aewb_config_local.win_width != user_cfg->win_width) {
-		WRITE_WIN_W(aewb_regs.reg_win1, user_cfg->win_width);
-		aewb_config_local.win_width = user_cfg->win_width;
-		aewbstat.update = 1;
+	if (isp_h3a->aewb_config_local.win_width != user_cfg->win_width) {
+		WRITE_WIN_W(isp_h3a->regs.win1, user_cfg->win_width);
+		isp_h3a->aewb_config_local.win_width = user_cfg->win_width;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->ver_win_count < 1 ||
-		     user_cfg->ver_win_count > MAX_WINVC)) {
-		printk(KERN_ERR "Invalid vertical window count: %d\n",
-		       user_cfg->ver_win_count);
-		return -EINVAL;
-	}
-	if (aewb_config_local.ver_win_count != user_cfg->ver_win_count) {
-		WRITE_VER_C(aewb_regs.reg_win1, user_cfg->ver_win_count);
-		aewb_config_local.ver_win_count = user_cfg->ver_win_count;
-		aewbstat.update = 1;
+	if (isp_h3a->aewb_config_local.ver_win_count !=
+						user_cfg->ver_win_count) {
+		WRITE_VER_C(isp_h3a->regs.win1, user_cfg->ver_win_count);
+		isp_h3a->aewb_config_local.ver_win_count =
+						user_cfg->ver_win_count;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->hor_win_count < 1 ||
-		     user_cfg->hor_win_count > MAX_WINHC)) {
-		printk(KERN_ERR "Invalid horizontal window count: %d\n",
-		       user_cfg->hor_win_count);
-		return -EINVAL;
-	}
-	if (aewb_config_local.hor_win_count != user_cfg->hor_win_count) {
-		WRITE_HOR_C(aewb_regs.reg_win1, user_cfg->hor_win_count);
-		aewb_config_local.hor_win_count	= user_cfg->hor_win_count;
-		aewbstat.update = 1;
+	if (isp_h3a->aewb_config_local.hor_win_count !=
+						user_cfg->hor_win_count) {
+		WRITE_HOR_C(isp_h3a->regs.win1, user_cfg->hor_win_count);
+		isp_h3a->aewb_config_local.hor_win_count =
+						user_cfg->hor_win_count;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->ver_win_start > MAX_WINSTART)) {
-		printk(KERN_ERR "Invalid vertical window start: %d\n",
-		       user_cfg->ver_win_start);
-		return -EINVAL;
-	}
-	if (aewb_config_local.ver_win_start != user_cfg->ver_win_start) {
-		WRITE_VER_WIN_ST(aewb_regs.reg_start, user_cfg->ver_win_start);
-		aewb_config_local.ver_win_start = user_cfg->ver_win_start;
-		aewbstat.update = 1;
+	if (isp_h3a->aewb_config_local.ver_win_start !=
+						user_cfg->ver_win_start) {
+		WRITE_VER_WIN_ST(isp_h3a->regs.start, user_cfg->ver_win_start);
+		isp_h3a->aewb_config_local.ver_win_start =
+						user_cfg->ver_win_start;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->hor_win_start > MAX_WINSTART)) {
-		printk(KERN_ERR "Invalid horizontal window start: %d\n",
-		       user_cfg->hor_win_start);
-		return -EINVAL;
-	}
-	if (aewb_config_local.hor_win_start != user_cfg->hor_win_start) {
-		WRITE_HOR_WIN_ST(aewb_regs.reg_start, user_cfg->hor_win_start);
-		aewb_config_local.hor_win_start	= user_cfg->hor_win_start;
-		aewbstat.update = 1;
+	if (isp_h3a->aewb_config_local.hor_win_start !=
+						user_cfg->hor_win_start) {
+		WRITE_HOR_WIN_ST(isp_h3a->regs.start, user_cfg->hor_win_start);
+		isp_h3a->aewb_config_local.hor_win_start =
+						user_cfg->hor_win_start;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->blk_ver_win_start > MAX_WINSTART)) {
-		printk(KERN_ERR "Invalid black vertical window start: %d\n",
-		       user_cfg->blk_ver_win_start);
-		return -EINVAL;
-	}
-	if (aewb_config_local.blk_ver_win_start !=
+	if (isp_h3a->aewb_config_local.blk_ver_win_start !=
 	    user_cfg->blk_ver_win_start) {
-		WRITE_BLK_VER_WIN_ST(aewb_regs.reg_blk,
+		WRITE_BLK_VER_WIN_ST(isp_h3a->regs.blk,
 				     user_cfg->blk_ver_win_start);
-		aewb_config_local.blk_ver_win_start =
+		isp_h3a->aewb_config_local.blk_ver_win_start =
 			user_cfg->blk_ver_win_start;
-		aewbstat.update = 1;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->blk_win_height < MIN_WIN_H ||
-		     user_cfg->blk_win_height > MAX_WIN_H ||
-		     user_cfg->blk_win_height & 0x01)) {
-		printk(KERN_ERR "Invalid black window height: %d\n",
-		       user_cfg->blk_win_height);
-		return -EINVAL;
-	}
-	if (aewb_config_local.blk_win_height != user_cfg->blk_win_height) {
-		WRITE_BLK_WIN_H(aewb_regs.reg_blk, user_cfg->blk_win_height);
-		aewb_config_local.blk_win_height = user_cfg->blk_win_height;
-		aewbstat.update = 1;
+	if (isp_h3a->aewb_config_local.blk_win_height !=
+						user_cfg->blk_win_height) {
+		WRITE_BLK_WIN_H(isp_h3a->regs.blk, user_cfg->blk_win_height);
+		isp_h3a->aewb_config_local.blk_win_height =
+						user_cfg->blk_win_height;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->subsample_ver_inc < MIN_SUB_INC ||
-		     user_cfg->subsample_ver_inc > MAX_SUB_INC ||
-		     user_cfg->subsample_ver_inc & 0x01)) {
-		printk(KERN_ERR "Invalid vertical subsample increment: %d\n",
-		       user_cfg->subsample_ver_inc);
-		return -EINVAL;
-	}
-	if (aewb_config_local.subsample_ver_inc !=
+	if (isp_h3a->aewb_config_local.subsample_ver_inc !=
 	    user_cfg->subsample_ver_inc) {
-		WRITE_SUB_VER_INC(aewb_regs.reg_subwin,
+		WRITE_SUB_VER_INC(isp_h3a->regs.subwin,
 				  user_cfg->subsample_ver_inc);
-		aewb_config_local.subsample_ver_inc =
+		isp_h3a->aewb_config_local.subsample_ver_inc =
 			user_cfg->subsample_ver_inc;
-		aewbstat.update = 1;
+		isp_h3a->update = 1;
 	}
 
-	if (unlikely(user_cfg->subsample_hor_inc < MIN_SUB_INC ||
-		     user_cfg->subsample_hor_inc > MAX_SUB_INC ||
-		     user_cfg->subsample_hor_inc & 0x01)) {
-		printk(KERN_ERR "Invalid horizontal subsample increment: %d\n",
-		       user_cfg->subsample_hor_inc);
-		return -EINVAL;
-	}
-	if (aewb_config_local.subsample_hor_inc !=
+	if (isp_h3a->aewb_config_local.subsample_hor_inc !=
 	    user_cfg->subsample_hor_inc) {
-		WRITE_SUB_HOR_INC(aewb_regs.reg_subwin,
+		WRITE_SUB_HOR_INC(isp_h3a->regs.subwin,
 				  user_cfg->subsample_hor_inc);
-		aewb_config_local.subsample_hor_inc =
+		isp_h3a->aewb_config_local.subsample_hor_inc =
 			user_cfg->subsample_hor_inc;
-		aewbstat.update = 1;
+		isp_h3a->update = 1;
 	}
 
-	if (!aewbstat.initialized || !aewb_config_local.aewb_enable) {
-		isph3a_aewb_update_regs();
-		aewbstat.initialized = 1;
-	}
-	return 0;
+	isp_h3a->aewb_config_local.aewb_enable = user_cfg->aewb_enable;;
 }
 
 /**
- * isph3a_aewb_configure - Configure AEWB regs, enable/disable H3A engine.
+ * isph3a_aewb_config - Configure AEWB regs, enable/disable H3A engine.
  * @aewbcfg: Pointer to AEWB config structure.
  *
  * Returns 0 if successful, -EINVAL if aewbcfg pointer is NULL, -ENOMEM if
  * was unable to allocate memory for the buffer, of other errors if H3A
  * callback is not set or the parameters for AEWB are invalid.
  **/
-int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg)
+int isph3a_aewb_config(struct isp_h3a_device *isp_h3a,
+				struct isph3a_aewb_config *aewbcfg)
 {
+	struct device *dev = to_device(isp_h3a);
 	int ret = 0;
-	int i;
 	int win_count = 0;
+	unsigned int buf_size;
+	unsigned long irqflags;
 
 	if (NULL == aewbcfg) {
-		printk(KERN_ERR "Null argument in configuration. \n");
+		dev_dbg(dev, "h3a: Null argument in configuration\n");
 		return -EINVAL;
 	}
 
-	if (!aewbstat.initialized) {
-		DPRINTK_ISPH3A("Setting callback for H3A\n");
-		ret = isp_set_callback(CBK_H3A_AWB_DONE, isph3a_aewb_isr,
-				       (void *)NULL, (void *)NULL);
-		if (ret) {
-			printk(KERN_ERR "No callback for H3A\n");
-			return ret;
-		}
-	}
-
-	ret = isph3a_aewb_set_params(aewbcfg);
-	if (ret) {
-		printk(KERN_ERR "Invalid parameters! \n");
+	ret = isph3a_aewb_validate_params(isp_h3a, aewbcfg);
+	if (ret)
 		return ret;
-	}
 
+	/* FIXME: This win_count handling looks really fishy. */
 	win_count = aewbcfg->ver_win_count * aewbcfg->hor_win_count;
 	win_count += aewbcfg->hor_win_count;
 	ret = win_count / 8;
 	win_count += win_count % 8 ? 1 : 0;
 	win_count += ret;
 
-	aewbstat.win_count = win_count;
-	aewbstat.curr_cfg_buf_size = win_count * AEWB_PACKET_SIZE;
+	buf_size = win_count * AEWB_PACKET_SIZE;
 
-	if (aewbstat.stats_buf_size
-	    && win_count * AEWB_PACKET_SIZE > aewbstat.stats_buf_size) {
-		DPRINTK_ISPH3A("There was a previous buffer... "
-			       "Freeing/unmapping current stat busffs\n");
-		isph3a_aewb_enable(0);
-		for (i = 0; i < H3A_MAX_BUFF; i++) {
-			ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr);
-			dma_free_coherent(
-				NULL,
-				aewbstat.min_buf_size,
-				(void *)aewbstat.h3a_buff[i].virt_addr,
-				(dma_addr_t)aewbstat.h3a_buff[i].phy_addr);
-			aewbstat.h3a_buff[i].virt_addr = 0;
-		}
-		aewbstat.stats_buf_size = 0;
-	}
+	ret = ispstat_bufs_alloc(&isp_h3a->stat, buf_size, 0);
+	if (ret)
+		return ret;
 
-	if (!aewbstat.h3a_buff[0].virt_addr) {
-		aewbstat.stats_buf_size = win_count * AEWB_PACKET_SIZE;
-		aewbstat.min_buf_size = PAGE_ALIGN(aewbstat.stats_buf_size);
+	spin_lock_irqsave(isp_h3a->lock, irqflags);
 
-		DPRINTK_ISPH3A("Allocating/mapping new stat buffs\n");
-		for (i = 0; i < H3A_MAX_BUFF; i++) {
-			aewbstat.h3a_buff[i].frame_num = 0;
-			aewbstat.h3a_buff[i].virt_addr =
-				(unsigned long)dma_alloc_coherent(
-					NULL,
-					aewbstat.min_buf_size,
-					(dma_addr_t *)
-					&aewbstat.h3a_buff[i].phy_addr,
-					GFP_KERNEL | GFP_DMA);
-			if (aewbstat.h3a_buff[i].virt_addr == 0) {
-				printk(KERN_ERR "Can't acquire memory for "
-				       "buffer[%d]\n", i);
-				return -ENOMEM;
-			}
-			aewbstat.h3a_buff[i].addr_align =
-				aewbstat.h3a_buff[i].virt_addr;
-			while ((aewbstat.h3a_buff[i].addr_align & 0xFFFFFFC0) !=
-			       aewbstat.h3a_buff[i].addr_align)
-				aewbstat.h3a_buff[i].addr_align++;
-			aewbstat.h3a_buff[i].ispmmu_addr =
-				ispmmu_kmap(aewbstat.h3a_buff[i].phy_addr,
-					    aewbstat.min_buf_size);
-		}
-		isph3a_aewb_unlock_buffers();
-		isph3a_aewb_link_buffers();
+	isp_h3a->win_count = win_count;
+	isph3a_aewb_set_params(isp_h3a, aewbcfg);
 
-		if (active_buff == NULL)
-			active_buff = &aewbstat.h3a_buff[0];
+	spin_unlock_irqrestore(isp_h3a->lock, irqflags);
 
-		isp_reg_writel(active_buff->ispmmu_addr, OMAP3_ISP_IOMEM_H3A,
-			       ISPH3A_AEWBUFST);
-	}
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		DPRINTK_ISPH3A("buff[%d] addr is:\n    virt    0x%lX\n"
-			       "    aligned 0x%lX\n"
-			       "    phys    0x%lX\n"
-			       "    ispmmu  0x%08lX\n"
-			       "    mmapped 0x%lX\n"
-			       "    frame_num %d\n", i,
-			       aewbstat.h3a_buff[i].virt_addr,
-			       aewbstat.h3a_buff[i].addr_align,
-			       aewbstat.h3a_buff[i].phy_addr,
-			       aewbstat.h3a_buff[i].ispmmu_addr,
-			       aewbstat.h3a_buff[i].mmap_addr,
-			       aewbstat.h3a_buff[i].frame_num);
-	}
-
-	active_buff->frame_num = 1;
-	aewbstat.frame_count = 1;
-
-	atomic_inc(&aewbstat.config_counter);
-	isph3a_aewb_enable(aewbcfg->aewb_enable);
-	isph3a_print_status();
+	isph3a_print_status(isp_h3a);
 
 	return 0;
 }
-EXPORT_SYMBOL(isph3a_aewb_configure);
+EXPORT_SYMBOL(isph3a_aewb_config);
 
 /**
  * isph3a_aewb_request_statistics - REquest statistics and update gains in AEWB
@@ -718,22 +465,23 @@
  * Returns 0 if successful, -EINVAL when H3A engine is not enabled, or other
  * errors when setting gains.
  **/
-int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata)
+int isph3a_aewb_request_statistics(struct isp_h3a_device *isp_h3a,
+				   struct isph3a_aewb_data *aewbdata)
 {
+	struct device *dev = to_device(isp_h3a);
+	unsigned long irqflags;
 	int ret = 0;
-	u16 frame_diff = 0;
-	u16 frame_cnt = aewbstat.frame_count;
-	wait_queue_t wqt;
 
-	if (!aewb_config_local.aewb_enable) {
-		printk(KERN_ERR "H3A engine not enabled\n");
+	if (!isp_h3a->aewb_config_local.aewb_enable) {
+		dev_dbg(dev, "h3a: engine not enabled\n");
 		return -EINVAL;
 	}
 
 	DPRINTK_ISPH3A("isph3a_aewb_request_statistics: Enter "
 		       "(frame req. => %d, current frame => %d,"
 		       "update => %d)\n",
-		       aewbdata->frame_number, frame_cnt, aewbdata->update);
+		       aewbdata->frame_number, isp_h3a->stat.frame_number,
+		       aewbdata->update);
 	DPRINTK_ISPH3A("User data received: \n");
 	DPRINTK_ISPH3A("Digital gain = 0x%04x\n", aewbdata->dgain);
 	DPRINTK_ISPH3A("WB gain b *=   0x%04x\n", aewbdata->wb_gain_b);
@@ -741,93 +489,31 @@
 	DPRINTK_ISPH3A("WB gain gb =   0x%04x\n", aewbdata->wb_gain_gb);
 	DPRINTK_ISPH3A("WB gain gr =   0x%04x\n", aewbdata->wb_gain_gr);
 
-	if (!aewbdata->update) {
-		aewbdata->h3a_aewb_statistics_buf = NULL;
-		goto out;
-	}
+	spin_lock_irqsave(isp_h3a->lock, irqflags);
+
 	if (aewbdata->update & SET_DIGITAL_GAIN)
-		h3awb_update.dgain = (u16)aewbdata->dgain;
+		isp_h3a->h3awb_update.dgain = (u16)aewbdata->dgain;
 	if (aewbdata->update & SET_COLOR_GAINS) {
-		h3awb_update.coef0 = (u8)aewbdata->wb_gain_r;
-		h3awb_update.coef1 = (u8)aewbdata->wb_gain_gr;
-		h3awb_update.coef2 = (u8)aewbdata->wb_gain_gb;
-		h3awb_update.coef3 = (u8)aewbdata->wb_gain_b;
+		isp_h3a->h3awb_update.coef0 = (u8)aewbdata->wb_gain_r;
+		isp_h3a->h3awb_update.coef1 = (u8)aewbdata->wb_gain_gr;
+		isp_h3a->h3awb_update.coef2 = (u8)aewbdata->wb_gain_gb;
+		isp_h3a->h3awb_update.coef3 = (u8)aewbdata->wb_gain_b;
 	}
 	if (aewbdata->update & (SET_COLOR_GAINS | SET_DIGITAL_GAIN))
-		wb_update = 1;
+		isp_h3a->wb_update = 1;
 
-	if (!(aewbdata->update & REQUEST_STATISTICS)) {
-		aewbdata->h3a_aewb_statistics_buf = NULL;
-		goto out;
-	}
+	spin_unlock_irqrestore(isp_h3a->lock, irqflags);
 
-	if (aewbdata->frame_number < 1) {
-		printk(KERN_ERR "Illeagal frame number "
-		       "requested (%d)\n",
-		       aewbdata->frame_number);
-		return -EINVAL;
-	}
+	if (aewbdata->update & REQUEST_STATISTICS)
+		ret = isph3a_aewb_get_stats(isp_h3a, aewbdata);
 
-	isph3a_aewb_unlock_buffers();
+	aewbdata->curr_frame = isp_h3a->stat.frame_number;
 
-	DPRINTK_ISPH3A("Stats available?\n");
-	ret = isph3a_aewb_stats_available(aewbdata);
-	if (!ret)
-		goto out;
-
-	DPRINTK_ISPH3A("Stats in near future?\n");
-	if (aewbdata->frame_number > frame_cnt)
-		frame_diff = aewbdata->frame_number - frame_cnt;
-	else if (aewbdata->frame_number < frame_cnt) {
-		if ((frame_cnt > (MAX_FRAME_COUNT - MAX_FUTURE_FRAMES)) &&
-		    (aewbdata->frame_number < MAX_FRAME_COUNT)) {
-			frame_diff = aewbdata->frame_number + MAX_FRAME_COUNT -
-				frame_cnt;
-		} else
-			frame_diff = MAX_FUTURE_FRAMES + 1;
-	}
-
-	if (frame_diff > MAX_FUTURE_FRAMES) {
-		printk(KERN_ERR "Invalid frame requested, returning current"
-		       " frame stats\n");
-		aewbdata->frame_number = frame_cnt;
-	}
-	if (camnotify) {
-		DPRINTK_ISPH3A("NOT Waiting on stats IRQ for frame %d "
-			       "because camnotify set\n",
-			       aewbdata->frame_number);
-		aewbdata->h3a_aewb_statistics_buf = NULL;
-		goto out;
-	}
-	DPRINTK_ISPH3A("Waiting on stats IRQ for frame %d\n",
-		       aewbdata->frame_number);
-	aewbstat.frame_req = aewbdata->frame_number;
-	aewbstat.stats_req = 1;
-	aewbstat.stats_done = 0;
-	init_waitqueue_entry(&wqt, current);
-	ret = wait_event_interruptible(aewbstat.stats_wait,
-				       aewbstat.stats_done == 1);
-	if (ret < 0) {
-		printk(KERN_ERR "isph3a_aewb_request_statistics"
-		       " Error on wait event %d\n", ret);
-		aewbdata->h3a_aewb_statistics_buf = NULL;
-		return ret;
-	}
-
-	DPRINTK_ISPH3A("ISP AEWB request status interrupt raised\n");
-	ret = isph3a_aewb_stats_available(aewbdata);
-	if (ret) {
-		DPRINTK_ISPH3A("After waiting for stats,"
-			       " stats not available!!\n");
-		aewbdata->h3a_aewb_statistics_buf = NULL;
-	}
-out:
 	DPRINTK_ISPH3A("isph3a_aewb_request_statistics: "
 		       "aewbdata->h3a_aewb_statistics_buf => %p\n",
 		       aewbdata->h3a_aewb_statistics_buf);
-	aewbdata->curr_frame = aewbstat.frame_count;
 
-	return 0;
+	return ret;
 }
 EXPORT_SYMBOL(isph3a_aewb_request_statistics);
 
@@ -836,98 +522,77 @@
  *
  * Always returns 0.
  **/
-int __init isph3a_aewb_init(void)
+int __init isph3a_aewb_init(struct device *dev)
 {
-	memset(&aewbstat, 0, sizeof(aewbstat));
-	memset(&aewb_regs, 0, sizeof(aewb_regs));
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_h3a_device *isp_h3a = &isp->isp_h3a;
 
-	init_waitqueue_head(&aewbstat.stats_wait);
-	spin_lock_init(&aewbstat.buffer_lock);
+	isp_h3a->lock = &isp->h3a_lock;
+	isp_h3a->aewb_config_local.saturation_limit = AEWB_SATURATION_LIMIT;
+	ispstat_init(dev, "H3A", &isp_h3a->stat, H3A_MAX_BUFF, MAX_FRAME_COUNT);
+
 	return 0;
 }
 
 /**
  * isph3a_aewb_cleanup - Module exit.
  **/
-void isph3a_aewb_cleanup(void)
+void isph3a_aewb_cleanup(struct device *dev)
 {
-	int i;
+	struct isp_device *isp = dev_get_drvdata(dev);
 
-	for (i = 0; i < H3A_MAX_BUFF; i++) {
-		if (!aewbstat.h3a_buff[i].phy_addr)
-			continue;
-
-		ispmmu_kunmap(aewbstat.h3a_buff[i].ispmmu_addr);
-		dma_free_coherent(NULL,
-				  aewbstat.min_buf_size,
-				  (void *)aewbstat.h3a_buff[i].virt_addr,
-				  (dma_addr_t)aewbstat.h3a_buff[i].phy_addr);
-	}
-	memset(&aewbstat, 0, sizeof(aewbstat));
-	memset(&aewb_regs, 0, sizeof(aewb_regs));
+	ispstat_free(&isp->isp_h3a.stat);
 }
 
 /**
  * isph3a_print_status - Debug print. Values of H3A related registers.
  **/
-static void isph3a_print_status(void)
+static void isph3a_print_status(struct isp_h3a_device *isp_h3a)
 {
-	DPRINTK_ISPH3A("ISPH3A_PCR = 0x%08x\n",
-		       isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_PCR));
-	DPRINTK_ISPH3A("ISPH3A_AEWWIN1 = 0x%08x\n",
-		       isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWWIN1));
-	DPRINTK_ISPH3A("ISPH3A_AEWINSTART = 0x%08x\n",
-		       isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINSTART));
-	DPRINTK_ISPH3A("ISPH3A_AEWINBLK = 0x%08x\n",
-		       isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWINBLK));
-	DPRINTK_ISPH3A("ISPH3A_AEWSUBWIN = 0x%08x\n",
-		       isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWSUBWIN));
-	DPRINTK_ISPH3A("ISPH3A_AEWBUFST = 0x%08x\n",
-		       isp_reg_readl(OMAP3_ISP_IOMEM_H3A, ISPH3A_AEWBUFST));
-	DPRINTK_ISPH3A("stats windows = %d\n", aewbstat.win_count);
-	DPRINTK_ISPH3A("stats buff size = %d\n", aewbstat.stats_buf_size);
-	DPRINTK_ISPH3A("currently configured stats buff size = %d\n",
-		       aewbstat.curr_cfg_buf_size);
-}
+#ifdef OMAP_ISPH3A_DEBUG
+	struct device *dev = to_device(isp_h3a);
+#endif
 
-/**
- * isph3a_notify - Unblocks user request for statistics when camera is off
- * @notify: 1 - Camera is turned off
- *
- * Used when the user has requested statistics about a future frame, but the
- * camera is turned off before it happens, and this function unblocks the
- * request so the user can continue in its program.
- **/
-void isph3a_notify(int notify)
-{
-	camnotify = notify;
-	if (camnotify && aewbstat.initialized) {
-		printk(KERN_DEBUG "Warning Camera Off \n");
-		aewbstat.stats_req = 0;
-		aewbstat.stats_done = 1;
-		wake_up_interruptible(&aewbstat.stats_wait);
-	}
+	DPRINTK_ISPH3A("ISPH3A_PCR = 0x%08x\n",
+		       isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+				     ISPH3A_PCR));
+	DPRINTK_ISPH3A("ISPH3A_AEWWIN1 = 0x%08x\n",
+		       isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+				     ISPH3A_AEWWIN1));
+	DPRINTK_ISPH3A("ISPH3A_AEWINSTART = 0x%08x\n",
+		       isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+				     ISPH3A_AEWINSTART));
+	DPRINTK_ISPH3A("ISPH3A_AEWINBLK = 0x%08x\n",
+		       isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+				     ISPH3A_AEWINBLK));
+	DPRINTK_ISPH3A("ISPH3A_AEWSUBWIN = 0x%08x\n",
+		       isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+				     ISPH3A_AEWSUBWIN));
+	DPRINTK_ISPH3A("ISPH3A_AEWBUFST = 0x%08x\n",
+		       isp_reg_readl(dev, OMAP3_ISP_IOMEM_H3A,
+				     ISPH3A_AEWBUFST));
+	DPRINTK_ISPH3A("stats windows = %d\n", isp_h3a->win_count);
+	DPRINTK_ISPH3A("stats buf size = %d\n", isp_h3a->stat.buf_size);
 }
-EXPORT_SYMBOL(isph3a_notify);
 
 /**
  * isph3a_save_context - Saves the values of the h3a module registers.
  **/
-void isph3a_save_context(void)
+void isph3a_save_context(struct device *dev)
 {
 	DPRINTK_ISPH3A(" Saving context\n");
-	isp_save_context(isph3a_reg_list);
+	isp_save_context(dev, isph3a_reg_list);
 	/* Avoid enable during restore ctx */
-	isph3a_reg_list[0].val &= ~ISPH3A_PCR_AEW_EN;
+	isph3a_reg_list[0].val &= ~(ISPH3A_PCR_AEW_EN | ISPH3A_PCR_AF_EN);
 }
 EXPORT_SYMBOL(isph3a_save_context);
 
 /**
  * isph3a_restore_context - Restores the values of the h3a module registers.
  **/
-void isph3a_restore_context(void)
+void isph3a_restore_context(struct device *dev)
 {
 	DPRINTK_ISPH3A(" Restoring context\n");
-	isp_restore_context(isph3a_reg_list);
+	isp_restore_context(dev, isph3a_reg_list);
 }
 EXPORT_SYMBOL(isph3a_restore_context);
diff --git a/drivers/media/video/isp/isph3a.h b/drivers/media/video/isp/isph3a.h
index 7d4c765..5b0179c 100644
--- a/drivers/media/video/isp/isph3a.h
+++ b/drivers/media/video/isp/isph3a.h
@@ -25,6 +25,7 @@
 
 #define AEWB_PACKET_SIZE	16
 #define H3A_MAX_BUFF		5
+#define AEWB_SATURATION_LIMIT	0x3FF
 
 /* Flags for changed registers */
 #define PCR_CHNG		(1 << 0)
@@ -43,6 +44,8 @@
 #define ISPH3A_PCR_AEW_EN	(1 << 16)
 #define ISPH3A_PCR_AEW_ALAW_EN	(1 << 17)
 #define ISPH3A_PCR_AEW_BUSY	(1 << 18)
+#define ISPH3A_PCR_AEW_MASK 	(ISPH3A_PCR_AEW_ALAW_EN | \
+				 ISPH3A_PCR_AEW_AVE2LMT_MASK)
 
 #define WRITE_SAT_LIM(reg, sat_limit)			\
 	(reg = (reg & (~(ISPH3A_PCR_AEW_AVE2LMT_MASK))) \
@@ -94,34 +97,62 @@
 	 | (((sub_hor_inc >> 1) - 1) << ISPH3A_AEWSUBWIN_AEWINCH_SHIFT))
 
 /**
- * struct isph3a_aewb_xtrastats - Structure with extra statistics sent by cam.
- * @field_count: Sequence number of returned framestats.
- * @isph3a_aewb_xtrastats: Pointer to next buffer with extra stats.
+ * struct isph3a_aewb_regs - Current value of AE, AWB configuration registers.
+ * pcr: Peripheral control register.
+ * win1: Control register.
+ * start: Start position register.
+ * blk: Black line register.
+ * subwin: Configuration register.
  */
-struct isph3a_aewb_xtrastats {
-	unsigned long field_count;
-	struct isph3a_aewb_xtrastats *next;
+struct isph3a_aewb_regs {
+	u32 pcr;
+	u32 win1;
+	u32 start;
+	u32 blk;
+	u32 subwin;
 };
 
-void isph3a_aewb_setxtrastats(struct isph3a_aewb_xtrastats *xtrastats);
+struct isp_h3a_device {
+	spinlock_t *lock;		/* Lock for this struct */
 
-int isph3a_aewb_configure(struct isph3a_aewb_config *aewbcfg);
+	u8 update;
+	u8 buf_err;
+	int enabled;
+	int wb_update;
 
-int isph3a_aewb_request_statistics(struct isph3a_aewb_data *aewbdata);
+	struct isph3a_aewb_regs regs;
+	struct ispprev_wbal h3awb_update;
+	struct isph3a_aewb_config aewb_config_local;
+	struct ispstat_buffer *buf_next;
+	u16 win_count;
 
-void isph3a_save_context(void);
+	struct ispstat stat;
+};
 
-void isph3a_restore_context(void);
+int isph3a_aewb_config(struct isp_h3a_device *isp_h3a,
+		       struct isph3a_aewb_config *aewbcfg);
 
-void isph3a_aewb_enable(u8 enable);
+int isph3a_aewb_request_statistics(struct isp_h3a_device *isp_h3a,
+				   struct isph3a_aewb_data *aewbdata);
 
-int isph3a_aewb_busy(void);
+void isph3a_save_context(struct device *dev);
 
-void isph3a_aewb_suspend(void);
+void isph3a_restore_context(struct device *dev);
 
-void isph3a_aewb_resume(void);
+void isph3a_aewb_enable(struct isp_h3a_device *isp_h3a, u8 enable);
 
-void isph3a_update_wb(void);
+void isph3a_aewb_try_enable(struct isp_h3a_device *isp_h3a);
 
-void isph3a_notify(int notify);
+int isph3a_aewb_busy(struct isp_h3a_device *isp_h3a);
+
+void isph3a_aewb_suspend(struct isp_h3a_device *isp_h3a);
+
+void isph3a_aewb_resume(struct isp_h3a_device *isp_h3a);
+
+void isph3a_update_wb(struct isp_h3a_device *isp_h3a);
+
+int isph3a_aewb_buf_process(struct isp_h3a_device *isp_h3a);
+
+void isph3a_aewb_config_registers(struct isp_h3a_device *isp_h3a);
+
 #endif		/* OMAP_ISP_H3A_H */
diff --git a/drivers/media/video/isp/isphist.c b/drivers/media/video/isp/isphist.c
index c6f6a77..2f89ca3 100644
--- a/drivers/media/video/isp/isphist.c
+++ b/drivers/media/video/isp/isphist.c
@@ -6,6 +6,7 @@
  * Copyright (C) 2009 Texas Instruments, Inc.
  *
  * Contributors:
+ *	David Cohen <david.cohen@nokia.com>
  *	Sergio Aguirre <saaguirre@ti.com>
  *	Troy Laramy
  *
@@ -18,87 +19,15 @@
  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
-#include <asm/cacheflush.h>
-
 #include <linux/delay.h>
-#include <linux/dma-mapping.h>
 #include <linux/uaccess.h>
+#include <linux/device.h>
 
 #include "isp.h"
 #include "ispreg.h"
 #include "isphist.h"
-#include "ispmmu.h"
 
-/**
- * struct isp_hist_status - Histogram status.
- * @hist_enable: Enables the histogram module.
- * @initialized: Flag to indicate that the module is correctly initializated.
- * @frame_cnt: Actual frame count.
- * @frame_req: Frame requested by user.
- * @completed: Flag to indicate if a frame request is completed.
- */
-struct isp_hist_status {
-	u8 hist_enable;
-	u8 pm_state;
-	u8 initialized;
-	u8 frame_cnt;
-	u8 frame_req;
-	u8 completed;
-} histstat;
-
-/**
- * struct isp_hist_buffer - Frame histogram buffer.
- * @virt_addr: Virtual address to mmap the buffer.
- * @phy_addr: Physical address of the buffer.
- * @addr_align: Virtual Address 32 bytes aligned.
- * @ispmmu_addr: Address of the buffer mapped by the ISPMMU.
- * @mmap_addr: Mapped memory area of buffer. For userspace access.
- */
-struct isp_hist_buffer {
-	unsigned long virt_addr;
-	unsigned long phy_addr;
-	unsigned long addr_align;
-	unsigned long ispmmu_addr;
-	unsigned long mmap_addr;
-} hist_buff;
-
-/**
- * struct isp_hist_regs - Current value of Histogram configuration registers.
- * @reg_pcr: Peripheral control register.
- * @reg_cnt: Histogram control register.
- * @reg_wb_gain: Histogram white balance gain register.
- * @reg_r0_h: Region 0 horizontal register.
- * @reg_r0_v: Region 0 vertical register.
- * @reg_r1_h: Region 1 horizontal register.
- * @reg_r1_v: Region 1 vertical register.
- * @reg_r2_h: Region 2 horizontal register.
- * @reg_r2_v: Region 2 vertical register.
- * @reg_r3_h: Region 3 horizontal register.
- * @reg_r3_v: Region 3 vertical register.
- * @reg_hist_addr: Histogram address register.
- * @reg_hist_data: Histogram data.
- * @reg_hist_radd: Address register. When input data comes from mem.
- * @reg_hist_radd_off: Address offset register. When input data comes from mem.
- * @reg_h_v_info: Image size register. When input data comes from mem.
- */
-static struct isp_hist_regs {
-	u32 reg_pcr;
-	u32 reg_cnt;
-	u32 reg_wb_gain;
-	u32 reg_r0_h;
-	u32 reg_r0_v;
-	u32 reg_r1_h;
-	u32 reg_r1_v;
-	u32 reg_r2_h;
-	u32 reg_r2_v;
-	u32 reg_r3_h;
-	u32 reg_r3_v;
-	u32 reg_hist_addr;
-	u32 reg_hist_data;
-	u32 reg_hist_radd;
-	u32 reg_hist_radd_off;
-	u32 reg_h_v_info;
-} hist_regs;
+#define HIST_USE_DMA	1
 
 /* Structure for saving/restoring histogram module registers */
 struct isp_reg isphist_reg_list[] = {
@@ -119,18 +48,22 @@
 	{0, ISP_TOK_TERM, 0}
 };
 
-static void isp_hist_print_status(void);
+static void isp_hist_print_status(struct isp_hist_device *isp_hist);
 
-void __isp_hist_enable(u8 enable)
+static void __isp_hist_enable(struct isp_hist_device *isp_hist, u8 enable)
 {
-	if (enable)
-		DPRINTK_ISPHIST("   histogram enabled \n");
-	else
-		DPRINTK_ISPHIST("   histogram disabled \n");
+	struct device *dev = to_device(isp_hist);
+	unsigned int pcr;
 
-	isp_reg_and_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR, ~ISPHIST_PCR_EN,
-						(enable ? ISPHIST_PCR_EN : 0));
-	histstat.hist_enable = enable;
+	pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR);
+
+	/* Set AF_EN bit in PCR Register */
+	if (enable)
+		pcr |= ISPHIST_PCR_EN;
+	else
+		pcr &= ~ISPHIST_PCR_EN;
+
+	isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR);
 }
 
 /**
@@ -140,314 +73,493 @@
  * Client should configure all the Histogram registers before calling this
  * function.
  **/
-void isp_hist_enable(u8 enable)
+void isp_hist_enable(struct isp_hist_device *isp_hist, u8 enable)
 {
-	__isp_hist_enable(enable);
-	histstat.pm_state = enable;
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+
+	if (!isp_hist->config.enable) {
+		spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+		return;
+	}
+
+	__isp_hist_enable(isp_hist, enable);
+	isp_hist->enabled = enable;
+
+	spin_unlock_irqrestore(&isp_hist->lock, irqflags);
 }
 
 /**
  * isp_hist_suspend - Suspend ISP Histogram submodule.
  **/
-void isp_hist_suspend(void)
+void isp_hist_suspend(struct isp_hist_device *isp_hist)
 {
-	if (histstat.pm_state)
-		__isp_hist_enable(0);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+	if (isp_hist->enabled)
+		__isp_hist_enable(isp_hist, 0);
+	spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+}
+
+void isp_hist_try_enable(struct isp_hist_device *isp_hist)
+{
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+	if (unlikely(!isp_hist->enabled && isp_hist->config.enable &&
+						!isp_hist->waiting_dma)) {
+		isp_hist->update = 1;
+		isp_hist->active_buf = ispstat_buf_next(&isp_hist->stat);
+		spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+		isp_hist_config_registers(isp_hist);
+		isp_hist_enable(isp_hist, 1);
+	} else
+		spin_unlock_irqrestore(&isp_hist->lock, irqflags);
 }
 
 /**
  * isp_hist_resume - Resume ISP Histogram submodule.
  **/
-void isp_hist_resume(void)
+void isp_hist_resume(struct isp_hist_device *isp_hist)
 {
-	if (histstat.pm_state)
-		__isp_hist_enable(1);
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+	if (isp_hist->enabled)
+		__isp_hist_enable(isp_hist, 1);
+	spin_unlock_irqrestore(&isp_hist->lock, irqflags);
 }
 
-int isp_hist_busy(void)
+int isp_hist_busy(struct isp_hist_device *isp_hist)
 {
-	return isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR) &
-		ISPHIST_PCR_BUSY;
-}
+	struct device *dev = to_device(isp_hist);
 
-
-/**
- * isp_hist_update_regs - Helper function to update Histogram registers.
- **/
-static void isp_hist_update_regs(void)
-{
-	isp_reg_writel(hist_regs.reg_pcr, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR);
-	isp_reg_writel(hist_regs.reg_cnt, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT);
-	isp_reg_writel(hist_regs.reg_wb_gain, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_WB_GAIN);
-	isp_reg_writel(hist_regs.reg_r0_h, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_R0_HORZ);
-	isp_reg_writel(hist_regs.reg_r0_v, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_R0_VERT);
-	isp_reg_writel(hist_regs.reg_r1_h, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_R1_HORZ);
-	isp_reg_writel(hist_regs.reg_r1_v, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_R1_VERT);
-	isp_reg_writel(hist_regs.reg_r2_h, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_R2_HORZ);
-	isp_reg_writel(hist_regs.reg_r2_v, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_R2_VERT);
-	isp_reg_writel(hist_regs.reg_r3_h, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_R3_HORZ);
-	isp_reg_writel(hist_regs.reg_r3_v, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_R3_VERT);
-	isp_reg_writel(hist_regs.reg_hist_addr, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_ADDR);
-	isp_reg_writel(hist_regs.reg_hist_data, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_DATA);
-	isp_reg_writel(hist_regs.reg_hist_radd, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_RADD);
-	isp_reg_writel(hist_regs.reg_hist_radd_off, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_RADD_OFF);
-	isp_reg_writel(hist_regs.reg_h_v_info, OMAP3_ISP_IOMEM_HIST,
-		       ISPHIST_H_V_INFO);
-}
-
-/**
- * isp_hist_isr - Callback from ISP driver for HIST interrupt.
- * @status: IRQ0STATUS in case of MMU error, 0 for hist interrupt.
- *          arg1 and arg2 Not used as of now.
- **/
-static void isp_hist_isr(unsigned long status, isp_vbq_callback_ptr arg1,
-			 void *arg2)
-{
-	isp_hist_enable(0);
-
-	if (!(status & HIST_DONE))
-		return;
-
-	if (!histstat.completed) {
-		if (histstat.frame_req == histstat.frame_cnt) {
-			histstat.frame_cnt = 0;
-			histstat.frame_req = 0;
-			histstat.completed = 1;
-		} else {
-			isp_hist_enable(1);
-			histstat.frame_cnt++;
-		}
-	}
+	return isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR)
+			     & ISPHIST_PCR_BUSY;
 }
 
 /**
  * isp_hist_reset_mem - clear Histogram memory before start stats engine.
- *
- * Returns 0 after histogram memory was cleared.
  **/
-static int isp_hist_reset_mem(void)
+static void isp_hist_reset_mem(struct isp_hist_device *isp_hist)
 {
-	int i;
+	struct device *dev = to_device(isp_hist);
+	unsigned int i;
 
-	isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN);
+	isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
 
-	for (i = 0; i < HIST_MEM_SIZE; i++)
-		isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+	/*
+	 * By setting it, the histogram internal buffer is being cleared at the
+	 * same time it's being read. This bit must be cleared afterwards.
+	 */
+	isp_reg_or(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN);
 
-	isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ~ISPHIST_CNT_CLR_EN);
+	/*
+	 * We'll clear 4 words at each iteration for optimization. It avoids
+	 * 3/4 of the jumps. We also know HIST_MEM_SIZE is divisible by 4.
+	 */
+	for (i = HIST_MEM_SIZE / 4; i > 0; i--) {
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+	}
+	isp_reg_and(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+		    ~ISPHIST_CNT_CLR_EN);
+}
+
+static void isp_hist_dma_config(struct isp_hist_device *isp_hist)
+{
+	struct omap_dma_channel_params *dma_config = &isp_hist->dma_config;
+
+	dma_config->data_type = OMAP_DMA_DATA_TYPE_S32;
+	dma_config->sync_mode = OMAP_DMA_SYNC_ELEMENT;
+	dma_config->elem_count = (isp_hist->buf_size / sizeof(u32));
+	dma_config->frame_count = 1;
+	dma_config->src_amode = OMAP_DMA_AMODE_CONSTANT;
+	dma_config->src_start = OMAP3ISP_HIST_REG_BASE + ISPHIST_DATA;
+	dma_config->dst_amode = OMAP_DMA_AMODE_POST_INC;
+	dma_config->src_or_dst_synch = OMAP_DMA_SRC_SYNC;
+}
+
+/**
+ * isp_hist_set_regs - Helper function to update Histogram registers.
+ **/
+void isp_hist_config_registers(struct isp_hist_device *isp_hist)
+{
+	struct device *dev = to_device(isp_hist);
+	unsigned long irqflags;
+
+	if (!isp_hist->update || !isp_hist->config.enable)
+		return;
+
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+	isp_hist->num_acc_frames = isp_hist->config.num_acc_frames;
+	isp_hist_reset_mem(isp_hist);
+
+	isp_reg_writel(dev, isp_hist->regs.cnt, OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_CNT);
+	isp_reg_writel(dev, isp_hist->regs.wb_gain,
+		       OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN);
+	isp_reg_writel(dev, isp_hist->regs.reg_hor[0], OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_R0_HORZ);
+	isp_reg_writel(dev, isp_hist->regs.reg_ver[0], OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_R0_VERT);
+	isp_reg_writel(dev, isp_hist->regs.reg_hor[1], OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_R1_HORZ);
+	isp_reg_writel(dev, isp_hist->regs.reg_ver[1], OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_R1_VERT);
+	isp_reg_writel(dev, isp_hist->regs.reg_hor[2], OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_R2_HORZ);
+	isp_reg_writel(dev, isp_hist->regs.reg_ver[2], OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_R2_VERT);
+	isp_reg_writel(dev, isp_hist->regs.reg_hor[3], OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_R3_HORZ);
+	isp_reg_writel(dev, isp_hist->regs.reg_ver[3], OMAP3_ISP_IOMEM_HIST,
+		       ISPHIST_R3_VERT);
+	isp_reg_writel(dev, isp_hist->regs.hist_radd,
+		       OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD);
+	isp_reg_writel(dev, isp_hist->regs.hist_radd_off,
+		       OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF);
+	isp_reg_writel(dev, isp_hist->regs.h_v_info,
+		       OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO);
+
+	isp_hist_dma_config(isp_hist);
+
+	isp_hist->update = 0;
+	spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+
+	isp_hist_print_status(isp_hist);
+}
+
+static void isp_hist_dma_cb(int lch, u16 ch_status, void *data)
+{
+	struct isp_hist_device *isp_hist = data;
+	struct device *dev = to_device(isp_hist);
+
+	if (ch_status & ~OMAP_DMA_BLOCK_IRQ) {
+		dev_dbg(dev, "hist: DMA error. status = %02x\n", ch_status);
+		omap_stop_dma(lch);
+		isp_hist_reset_mem(isp_hist);
+	} else {
+		int ret;
+
+		ret = ispstat_buf_queue(&isp_hist->stat);
+		isp_hist->active_buf = ispstat_buf_next(&isp_hist->stat);
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+			    ~ISPHIST_CNT_CLR_EN);
+		if (!ret)
+			isp_hist_dma_done(dev);
+	}
+	isp_hist->waiting_dma = 0;
+}
+
+static int isp_hist_buf_dma(struct isp_hist_device *isp_hist)
+{
+	struct device *dev = to_device(isp_hist);
+	dma_addr_t dma_addr = isp_hist->active_buf->dma_addr;
+
+	if (!dma_addr) {
+		dev_dbg(dev, "hist: invalid DMA buffer address\n");
+		isp_hist_reset_mem(isp_hist);
+		return HIST_NO_BUF;
+	}
+
+	isp_hist->waiting_dma = 1;
+	isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+	isp_reg_or(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+		   ISPHIST_CNT_CLR_EN);
+	isp_flush(dev);
+	isp_hist->dma_config.dst_start = dma_addr;
+	omap_set_dma_params(isp_hist->dma_ch, &isp_hist->dma_config);
+	omap_start_dma(isp_hist->dma_ch);
+
+	return HIST_BUF_WAITING_DMA;
+}
+
+static int isp_hist_buf_pio(struct isp_hist_device *isp_hist)
+{
+	struct device *dev = to_device(isp_hist);
+	u32 *buf = isp_hist->active_buf->virt_addr;
+	unsigned int i;
+	int ret;
+
+	if (!buf) {
+		dev_dbg(dev, "hist: invalid PIO buffer address\n");
+		isp_hist_reset_mem(isp_hist);
+		return HIST_NO_BUF;
+	}
+
+	isp_reg_writel(dev, 0, OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR);
+
+	/*
+	 * By setting it, the histogram internal buffer is being cleared at the
+	 * same time it's being read. This bit must be cleared just after all
+	 * data is acquired.
+	 */
+	isp_reg_or(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+		   ISPHIST_CNT_CLR_EN);
+
+	/*
+	 * We'll read 4 times a 4-bytes-word at each iteration for
+	 * optimization. It avoids 3/4 of the jumps. We also know buf_size is
+	 * divisible by 16.
+	 */
+	for (i = isp_hist->buf_size / 16; i > 0; i--) {
+		*buf++ = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		*buf++ = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		*buf++ = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+		*buf++ = isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
+	}
+	isp_reg_and(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
+		    ~ISPHIST_CNT_CLR_EN);
+
+	ret = ispstat_buf_queue(&isp_hist->stat);
+	isp_hist->active_buf = ispstat_buf_next(&isp_hist->stat);
+
+	if (ret)
+		return HIST_NO_BUF;
+	else
+		return HIST_BUF_DONE;
+}
+
+/**
+ * isp_hist_isr - Callback from ISP driver for HIST interrupt.
+ **/
+int isp_hist_buf_process(struct isp_hist_device *isp_hist)
+{
+	unsigned long irqflags;
+	int ret = HIST_NO_BUF;
+
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+
+	if (isp_hist->invalid_buf || !isp_hist->config.enable) {
+		isp_hist->invalid_buf = 0;
+		isp_hist_reset_mem(isp_hist);
+		goto out_invalid;
+	}
+
+	if (--(isp_hist->num_acc_frames))
+		goto out_acc;
+
+	if (isp_hist->use_dma)
+		ret = isp_hist_buf_dma(isp_hist);
+	else
+		ret = isp_hist_buf_pio(isp_hist);
+
+out_invalid:
+	isp_hist->num_acc_frames = isp_hist->config.num_acc_frames;
+out_acc:
+	spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+
+	return ret;
+}
+
+void isp_hist_mark_invalid_buf(struct isp_hist_device *isp_hist)
+{
+	unsigned long irqflags;
+
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+	isp_hist->invalid_buf = 1;
+	spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+}
+
+/**
+ * isp_hist_validate_params - Helper function to check user given params.
+ * @user_cfg: Pointer to user configuration structure.
+ *
+ * Returns 0 on success configuration.
+ **/
+static int isp_hist_validate_params(struct isp_hist_config *user_cfg)
+{
+	int c;
+
+	if (user_cfg->source > HIST_SOURCE_MEM)
+		return -EINVAL;
+
+	if (user_cfg->source == HIST_SOURCE_MEM) {
+		if ((user_cfg->input_bit_width < HIST_MIN_BIT_WIDTH) ||
+			(user_cfg->input_bit_width > HIST_MAX_BIT_WIDTH))
+			return -EINVAL;
+
+		/* Should be in 32 byte boundary if source is mem */
+		if ((user_cfg->hist_radd & ~ISP_32B_BOUNDARY_BUF) ||
+		    (user_cfg->hist_radd_off & ~ISP_32B_BOUNDARY_OFFSET))
+			return -EINVAL;
+	} else if (user_cfg->input_bit_width != 10) /* CCDC must be 10bits */
+		return -EINVAL;
+
+	if (user_cfg->cfa > HIST_CFA_FOVEONX3)
+		return -EINVAL;
+
+	/* Regions size and position */
+
+	if ((user_cfg->num_regions < HIST_MIN_REGIONS) ||
+	    (user_cfg->num_regions > HIST_MAX_REGIONS))
+		return -EINVAL;
+
+	/* Regions */
+	for (c = 0; c < user_cfg->num_regions; c++) {
+		if (user_cfg->reg_hor[c] & ~ISPHIST_REGHORIZ_HEND_MASK &
+		    ~ISPHIST_REGHORIZ_HSTART_MASK)
+			return -EINVAL;
+		if ((user_cfg->reg_hor[c] & ISPHIST_REGHORIZ_HEND_MASK) <=
+		    ((user_cfg->reg_hor[c] & ISPHIST_REGHORIZ_HSTART_MASK) >>
+		     ISPHIST_REGHORIZ_HSTART_SHIFT))
+			return -EINVAL;
+		if (user_cfg->reg_ver[c] & ~ISPHIST_REGVERT_VEND_MASK &
+		    ~ISPHIST_REGVERT_VSTART_MASK)
+			return -EINVAL;
+		if ((user_cfg->reg_ver[c] & ISPHIST_REGVERT_VEND_MASK) <=
+		    ((user_cfg->reg_ver[c] & ISPHIST_REGVERT_VSTART_MASK) >>
+		     ISPHIST_REGVERT_VSTART_SHIFT))
+			return -EINVAL;
+	}
+
+	switch (user_cfg->num_regions) {
+	case 1:
+		if (user_cfg->hist_bins > HIST_BINS_256)
+			return -EINVAL;
+		break;
+	case 2:
+		if (user_cfg->hist_bins > HIST_BINS_128)
+			return -EINVAL;
+		break;
+	default: /* 3 or 4 */
+		if (user_cfg->hist_bins > HIST_BINS_64)
+			return -EINVAL;
+		break;
+	}
+
+	return 0;
+}
+
+static int isp_hist_comp_params(struct isp_hist_device *isp_hist,
+				struct isp_hist_config *user_cfg)
+{
+	struct isp_hist_config *cur_cfg = &isp_hist->config;
+	int c;
+
+	if ((cur_cfg->source && !user_cfg->source) ||
+	    (!cur_cfg->source && user_cfg->source))
+		return 1;
+
+	if (cur_cfg->input_bit_width != user_cfg->input_bit_width)
+		return 1;
+
+	if (user_cfg->source) {
+		if (cur_cfg->hist_h_v_info != user_cfg->hist_h_v_info)
+			return 1;
+		if (cur_cfg->hist_radd != user_cfg->hist_radd)
+			return 1;
+		if (cur_cfg->hist_radd_off != user_cfg->hist_radd_off)
+			return 1;
+	}
+
+	if (cur_cfg->cfa != user_cfg->cfa)
+		return 1;
+
+	if (cur_cfg->num_acc_frames != user_cfg->num_acc_frames)
+		return 1;
+
+	if (cur_cfg->hist_bins != user_cfg->hist_bins)
+		return 1;
+
+	for (c = 0; c < HIST_MAX_WG; c++) {
+		if (c == 3 && user_cfg->cfa == HIST_CFA_FOVEONX3)
+			break;
+		else if (cur_cfg->wg[c] != user_cfg->wg[c])
+			return 1;
+	}
+
+	if (cur_cfg->num_regions != user_cfg->num_regions)
+		return 1;
+
+	/* Regions */
+	for (c = 0; c < user_cfg->num_regions; c++) {
+		if (cur_cfg->reg_hor[c] != user_cfg->reg_hor[c])
+			return 1;
+		if (cur_cfg->reg_ver[c] != user_cfg->reg_ver[c])
+			return 1;
+	}
 
 	return 0;
 }
 
 /**
- * isp_hist_set_params - Helper function to check and store user given params.
+ * isp_hist_update_params - Helper function to check and store user given params.
  * @user_cfg: Pointer to user configuration structure.
  *
  * Returns 0 on success configuration.
  **/
-static int isp_hist_set_params(struct isp_hist_config *user_cfg)
+static void isp_hist_update_params(struct isp_hist_device *isp_hist,
+				   struct isp_hist_config *user_cfg)
 {
+	int bit_shift;
+	int c;
 
-	int reg_num = 0;
-	int bit_shift = 0;
+	if (!isp_hist_comp_params(isp_hist, user_cfg)) {
+		isp_hist->config.enable = user_cfg->enable;
+		return;
+	}
 
+	memcpy(&isp_hist->config, user_cfg, sizeof(*user_cfg));
 
-	if (isp_hist_busy())
-		return -EINVAL;
-
-	if (user_cfg->input_bit_width > MIN_BIT_WIDTH)
-		WRITE_DATA_SIZE(hist_regs.reg_cnt, 0);
+	if (user_cfg->input_bit_width > HIST_MIN_BIT_WIDTH)
+		WRITE_DATA_SIZE(isp_hist->regs.cnt, 0);
 	else
-		WRITE_DATA_SIZE(hist_regs.reg_cnt, 1);
+		WRITE_DATA_SIZE(isp_hist->regs.cnt, 1);
 
-	WRITE_SOURCE(hist_regs.reg_cnt, user_cfg->hist_source);
+	WRITE_SOURCE(isp_hist->regs.cnt, user_cfg->source);
 
-	if (user_cfg->hist_source) {
-		WRITE_HV_INFO(hist_regs.reg_h_v_info, user_cfg->hist_h_v_info);
-
-		if ((user_cfg->hist_radd & ISP_32B_BOUNDARY_BUF) ==
-		    user_cfg->hist_radd) {
-			WRITE_RADD(hist_regs.reg_hist_radd,
-				   user_cfg->hist_radd);
-		} else {
-			printk(KERN_ERR "Address should be in 32 byte boundary"
-			       "\n");
-			return -EINVAL;
-		}
-
-		if ((user_cfg->hist_radd_off & ISP_32B_BOUNDARY_OFFSET) ==
-		    user_cfg->hist_radd_off) {
-			WRITE_RADD_OFF(hist_regs.reg_hist_radd_off,
-				       user_cfg->hist_radd_off);
-		} else {
-			printk(KERN_ERR "Offset should be in 32 byte boundary"
-			       "\n");
-			return -EINVAL;
-		}
-
+	if (user_cfg->source == HIST_SOURCE_MEM) {
+		WRITE_HV_INFO(isp_hist->regs.h_v_info, user_cfg->hist_h_v_info);
+		WRITE_RADD(isp_hist->regs.hist_radd, user_cfg->hist_radd);
+		WRITE_RADD_OFF(isp_hist->regs.hist_radd_off,
+			       user_cfg->hist_radd_off);
 	}
 
-	isp_hist_reset_mem();
-	DPRINTK_ISPHIST("ISPHIST: Memory Cleared\n");
-	histstat.frame_req = user_cfg->hist_frames;
+	WRITE_CFA(isp_hist->regs.cnt, user_cfg->cfa);
 
-	if (unlikely(user_cfg->wb_gain_R > MAX_WB_GAIN ||
-		     user_cfg->wb_gain_RG > MAX_WB_GAIN ||
-		     user_cfg->wb_gain_B > MAX_WB_GAIN ||
-		     user_cfg->wb_gain_BG > MAX_WB_GAIN)) {
-		printk(KERN_ERR "Invalid WB gain\n");
-		return -EINVAL;
-	} else {
-		WRITE_WB_R(hist_regs.reg_wb_gain, user_cfg->wb_gain_R);
-		WRITE_WB_RG(hist_regs.reg_wb_gain, user_cfg->wb_gain_RG);
-		WRITE_WB_B(hist_regs.reg_wb_gain, user_cfg->wb_gain_B);
-		WRITE_WB_BG(hist_regs.reg_wb_gain, user_cfg->wb_gain_BG);
-	}
+	WRITE_WG0(isp_hist->regs.wb_gain, user_cfg->wg[0]);
+	WRITE_WG1(isp_hist->regs.wb_gain, user_cfg->wg[1]);
+	WRITE_WG2(isp_hist->regs.wb_gain, user_cfg->wg[2]);
+	if (user_cfg->cfa == HIST_CFA_BAYER)
+		WRITE_WG3(isp_hist->regs.wb_gain, user_cfg->wg[3]);
 
 	/* Regions size and position */
-
-	if (user_cfg->num_regions > MAX_REGIONS)
-		return -EINVAL;
-
-	if (likely((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HEND_MASK) -
-		   ((user_cfg->reg0_hor & ISPHIST_REGHORIZ_HSTART_MASK) >>
-		    ISPHIST_REGHORIZ_HSTART_SHIFT))) {
-		WRITE_REG_HORIZ(hist_regs.reg_r0_h, user_cfg->reg0_hor);
-		reg_num++;
-	} else {
-		printk(KERN_ERR "Invalid Region parameters\n");
-		return -EINVAL;
-	}
-
-	if (likely((user_cfg->reg0_ver & ISPHIST_REGVERT_VEND_MASK) -
-		   ((user_cfg->reg0_ver & ISPHIST_REGVERT_VSTART_MASK) >>
-		    ISPHIST_REGVERT_VSTART_SHIFT))) {
-		WRITE_REG_VERT(hist_regs.reg_r0_v, user_cfg->reg0_ver);
-	} else {
-		printk(KERN_ERR "Invalid Region parameters\n");
-		return -EINVAL;
-	}
-
-	if (user_cfg->num_regions >= 1) {
-		if (likely((user_cfg->reg1_hor & ISPHIST_REGHORIZ_HEND_MASK) -
-			   ((user_cfg->reg1_hor &
-			     ISPHIST_REGHORIZ_HSTART_MASK) >>
-			    ISPHIST_REGHORIZ_HSTART_SHIFT))) {
-			WRITE_REG_HORIZ(hist_regs.reg_r1_h, user_cfg->reg1_hor);
+	for (c = 0; c < HIST_MAX_REGIONS; c++) {
+		if (c < user_cfg->num_regions) {
+			WRITE_REG_HORIZ(isp_hist->regs.reg_hor[c],
+					user_cfg->reg_hor[c]);
+			WRITE_REG_VERT(isp_hist->regs.reg_ver[c],
+				       user_cfg->reg_ver[c]);
 		} else {
-			printk(KERN_ERR "Invalid Region parameters\n");
-			return -EINVAL;
-		}
-
-		if (likely((user_cfg->reg1_ver & ISPHIST_REGVERT_VEND_MASK) -
-			   ((user_cfg->reg1_ver &
-			     ISPHIST_REGVERT_VSTART_MASK) >>
-			    ISPHIST_REGVERT_VSTART_SHIFT))) {
-			WRITE_REG_VERT(hist_regs.reg_r1_v, user_cfg->reg1_ver);
-		} else {
-			printk(KERN_ERR "Invalid Region parameters\n");
-			return -EINVAL;
+			isp_hist->regs.reg_hor[c] = 0;
+			isp_hist->regs.reg_ver[c] = 0;
 		}
 	}
 
-	if (user_cfg->num_regions >= 2) {
-		if (likely((user_cfg->reg2_hor & ISPHIST_REGHORIZ_HEND_MASK) -
-			   ((user_cfg->reg2_hor &
-			     ISPHIST_REGHORIZ_HSTART_MASK) >>
-			    ISPHIST_REGHORIZ_HSTART_SHIFT))) {
-			WRITE_REG_HORIZ(hist_regs.reg_r2_h, user_cfg->reg2_hor);
-		} else {
-			printk(KERN_ERR "Invalid Region parameters\n");
-			return -EINVAL;
-		}
-
-		if (likely((user_cfg->reg2_ver & ISPHIST_REGVERT_VEND_MASK) -
-			   ((user_cfg->reg2_ver &
-			     ISPHIST_REGVERT_VSTART_MASK) >>
-			    ISPHIST_REGVERT_VSTART_SHIFT))) {
-			WRITE_REG_VERT(hist_regs.reg_r2_v, user_cfg->reg2_ver);
-		} else {
-			printk(KERN_ERR "Invalid Region parameters\n");
-			return -EINVAL;
-		}
+	WRITE_NUM_BINS(isp_hist->regs.cnt, user_cfg->hist_bins);
+	switch (user_cfg->hist_bins) {
+	case HIST_BINS_256:
+		bit_shift = user_cfg->input_bit_width - 8;
+		break;
+	case HIST_BINS_128:
+		bit_shift = user_cfg->input_bit_width - 7;
+		break;
+	case HIST_BINS_64:
+		bit_shift = user_cfg->input_bit_width - 6;
+		break;
+	default: /* HIST_BINS_32 */
+		bit_shift = user_cfg->input_bit_width - 5;
+		break;
 	}
+	WRITE_BIT_SHIFT(isp_hist->regs.cnt, bit_shift);
 
-	if (user_cfg->num_regions >= 3) {
-		if (likely((user_cfg->reg3_hor & ISPHIST_REGHORIZ_HEND_MASK) -
-			   ((user_cfg->reg3_hor &
-			     ISPHIST_REGHORIZ_HSTART_MASK) >>
-			    ISPHIST_REGHORIZ_HSTART_SHIFT))) {
-			WRITE_REG_HORIZ(hist_regs.reg_r3_h, user_cfg->reg3_hor);
-		} else {
-			printk(KERN_ERR "Invalid Region parameters\n");
-			return -EINVAL;
-		}
-
-		if (likely((user_cfg->reg3_ver & ISPHIST_REGVERT_VEND_MASK) -
-			   ((user_cfg->reg3_ver &
-			     ISPHIST_REGVERT_VSTART_MASK) >>
-			    ISPHIST_REGVERT_VSTART_SHIFT))) {
-			WRITE_REG_VERT(hist_regs.reg_r3_v, user_cfg->reg3_ver);
-		} else {
-			printk(KERN_ERR "Invalid Region parameters\n");
-			return -EINVAL;
-		}
-	}
-	reg_num = user_cfg->num_regions;
-	if (unlikely(((user_cfg->hist_bins > BINS_256) &&
-		      (user_cfg->hist_bins != BINS_32)) ||
-		     ((user_cfg->hist_bins == BINS_256) &&
-		      reg_num != 0) || ((user_cfg->hist_bins ==
-					 BINS_128) && reg_num >= 2))) {
-		printk(KERN_ERR "Invalid Bins Number: %d\n",
-		       user_cfg->hist_bins);
-		return -EINVAL;
-	} else {
-		WRITE_NUM_BINS(hist_regs.reg_cnt, user_cfg->hist_bins);
-	}
-
-	if (user_cfg->input_bit_width > MAX_BIT_WIDTH ||
-	    user_cfg->input_bit_width < MIN_BIT_WIDTH) {
-		printk(KERN_ERR "Invalid Bit Width: %d\n",
-		       user_cfg->input_bit_width);
-		return -EINVAL;
-	} else {
-		switch (user_cfg->hist_bins) {
-		case BINS_256:
-			bit_shift = user_cfg->input_bit_width - 8;
-			break;
-		case BINS_128:
-			bit_shift = user_cfg->input_bit_width - 7;
-			break;
-		case BINS_64:
-			bit_shift = user_cfg->input_bit_width - 6;
-			break;
-		case BINS_32:
-			bit_shift = user_cfg->input_bit_width - 5;
-			break;
-		default:
-			return -EINVAL;
-		}
-		WRITE_BIT_SHIFT(hist_regs.reg_cnt, bit_shift);
-	}
-
-	isp_hist_update_regs();
-	histstat.initialized = 1;
-
-	return 0;
+	isp_hist->update = 1;
 }
 
 /**
@@ -456,40 +568,68 @@
  *
  * Returns 0 on success configuration.
  **/
-int isp_hist_configure(struct isp_hist_config *histcfg)
+int isp_hist_config(struct isp_hist_device *isp_hist,
+		    struct isp_hist_config *histcfg)
 {
-
+	struct device *dev = to_device(isp_hist);
+	unsigned long irqflags;
 	int ret = 0;
+	unsigned int size;
+	int use_dma = HIST_USE_DMA;
+	const unsigned int size_bins[] =
+			{ HIST_MEM_SIZE_BINS(32), HIST_MEM_SIZE_BINS(64),
+			  HIST_MEM_SIZE_BINS(128), HIST_MEM_SIZE_BINS(256) };
 
-	if (NULL == histcfg) {
-		printk(KERN_ERR "Null argument in configuration. \n");
+	if (!histcfg) {
+		dev_dbg(dev, "hist: Null argument in configuration.\n");
 		return -EINVAL;
 	}
 
-	if (!histstat.initialized) {
-		DPRINTK_ISPHIST("Setting callback for HISTOGRAM\n");
-		ret = isp_set_callback(CBK_HIST_DONE, isp_hist_isr,
-				       (void *)NULL, (void *)NULL);
-		if (ret) {
-			printk(KERN_ERR "No callback for HIST\n");
-			return ret;
-		}
-	}
-
-	ret = isp_hist_set_params(histcfg);
+	/* Check Parameters */
+	ret = isp_hist_validate_params(histcfg);
 	if (ret) {
-		printk(KERN_ERR "Invalid parameters! \n");
+		dev_dbg(dev, "hist: wrong configure params received.\n");
 		return ret;
 	}
 
-	histstat.frame_cnt = 0;
-	histstat.completed = 0;
-	isp_hist_enable(1);
-	isp_hist_print_status();
+	size = size_bins[histcfg->hist_bins] * histcfg->num_regions;
+
+	/* Cannot use DMA if no channel is available */
+	if (unlikely(HIST_USE_DMA && (isp_hist->dma_ch < 0)))
+		use_dma = 0;
+
+	/* Alloc buffers */
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+	if (isp_hist->waiting_dma) {
+		omap_stop_dma(isp_hist->dma_ch);
+		isp_hist->waiting_dma = 0;
+	}
+	spin_unlock_irqrestore(&isp_hist->lock, irqflags);
+
+	ret = ispstat_bufs_alloc(&isp_hist->stat, size, use_dma);
+	if (ret) {
+		if (use_dma)
+			ret = ispstat_bufs_alloc(&isp_hist->stat, size, 0);
+
+		if (ret) {
+			dev_err(dev, "hist: unable to alloc buffers.\n");
+			isp_hist->config.enable = 0;
+			return ret;
+		} else {
+			use_dma = 0;
+			dev_dbg(dev, "hist: unable to alloc buffers for DMA. "
+				      "PIO will be used.\n");
+		}
+	}
+
+	spin_lock_irqsave(&isp_hist->lock, irqflags);
+	isp_hist->buf_size = size;
+	isp_hist->use_dma = use_dma;
+	isp_hist_update_params(isp_hist, histcfg);
+	spin_unlock_irqrestore(&isp_hist->lock, irqflags);
 
 	return 0;
 }
-EXPORT_SYMBOL(isp_hist_configure);
 
 /**
  * isp_hist_request_statistics - Request statistics in Histogram.
@@ -499,110 +639,135 @@
  *
  * Returns 0 on successful request.
  **/
-int isp_hist_request_statistics(struct isp_hist_data *histdata)
+int isp_hist_request_statistics(struct isp_hist_device *isp_hist,
+				struct isp_hist_data *histdata)
 {
-	int i, ret;
-	u32 curr;
+	struct device *dev = to_device(isp_hist);
+	struct ispstat_buffer *buf;
 
-	if (isp_hist_busy())
-		return -EBUSY;
-
-	if (!histstat.completed && histstat.initialized)
+	if (!isp_hist->config.enable) {
+		dev_dbg(dev, "hist: statistics requested while engine is not "
+			     "configured\n");
 		return -EINVAL;
-
-	isp_reg_or(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT, ISPHIST_CNT_CLR_EN);
-
-	for (i = 0; i < HIST_MEM_SIZE; i++) {
-		curr = isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_DATA);
-		ret = put_user(curr, histdata->hist_statistics_buf + i);
-		if (ret) {
-			printk(KERN_ERR "Failed copy_to_user for "
-			       "HIST stats buff, %d\n", ret);
-		}
 	}
 
-	isp_reg_and(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT,
-		    ~ISPHIST_CNT_CLR_EN);
-	histstat.completed = 0;
+	if (histdata->update & REQUEST_STATISTICS) {
+		buf = ispstat_buf_get(&isp_hist->stat,
+				      (void *)histdata->hist_statistics_buf,
+				      histdata->frame_number);
+		if (IS_ERR(buf))
+			return PTR_ERR(buf);
+
+		histdata->ts = buf->ts;
+		histdata->config_counter = buf->config_counter;
+		histdata->frame_number = buf->frame_number;
+
+		ispstat_buf_release(&isp_hist->stat);
+	}
+
+	histdata->curr_frame = isp_hist->stat.frame_number;
+
 	return 0;
 }
-EXPORT_SYMBOL(isp_hist_request_statistics);
 
 /**
  * isp_hist_init - Module Initialization.
  *
  * Returns 0 if successful.
  **/
-int __init isp_hist_init(void)
+int __init isp_hist_init(struct device *dev)
 {
-	memset(&histstat, 0, sizeof(histstat));
-	memset(&hist_regs, 0, sizeof(hist_regs));
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_hist_device *isp_hist = &isp->isp_hist;
+	int ret = -1;
 
-	return 0;
+	if (HIST_USE_DMA)
+		ret = omap_request_dma(OMAP24XX_DMA_NO_DEVICE, "DMA_ISP_HIST",
+				       isp_hist_dma_cb, isp_hist,
+				       &isp_hist->dma_ch);
+	if (ret) {
+		if (HIST_USE_DMA)
+			dev_info(dev, "hist: DMA request channel failed. Using "
+				      "PIO only.\n");
+		isp_hist->dma_ch = -1;
+	} else {
+		dev_dbg(dev, "hist: DMA channel = %d\n", isp_hist->dma_ch);
+		omap_enable_dma_irq(isp_hist->dma_ch, OMAP_DMA_BLOCK_IRQ);
+	}
+
+	spin_lock_init(&isp_hist->lock);
+	ret = ispstat_init(dev, "HIST", &isp_hist->stat, HIST_MAX_BUFF,
+			    MAX_FRAME_COUNT);
+	if (ret && (isp_hist->dma_ch >= 0))
+		omap_free_dma(isp_hist->dma_ch);
+
+	return ret;
 }
 
 /**
  * isp_hist_cleanup - Module cleanup.
  **/
-void isp_hist_cleanup(void)
+void isp_hist_cleanup(struct device *dev)
 {
-	memset(&histstat, 0, sizeof(histstat));
-	memset(&hist_regs, 0, sizeof(hist_regs));
+	struct isp_device *isp = dev_get_drvdata(dev);
+
+	isp->isp_hist.active_buf = NULL;
+	ispstat_free(&isp->isp_hist.stat);
+	if (isp->isp_hist.dma_ch >= 0)
+		omap_free_dma(isp->isp_hist.dma_ch);
 }
 
 /**
- * isphist_save_context - Saves the values of the histogram module registers.
+ * isp_hist_save_context - Saves the values of the histogram module registers.
  **/
-void isphist_save_context(void)
+void isp_hist_save_context(struct device *dev)
 {
-	DPRINTK_ISPHIST(" Saving context\n");
-	isp_save_context(isphist_reg_list);
+	isp_save_context(dev, isphist_reg_list);
 }
-EXPORT_SYMBOL(isphist_save_context);
 
 /**
- * isphist_restore_context - Restores the values of the histogram module regs.
+ * isp_hist_restore_context - Restores the values of the histogram module regs.
  **/
-void isphist_restore_context(void)
+void isp_hist_restore_context(struct device *dev)
 {
-	DPRINTK_ISPHIST(" Restoring context\n");
-	isp_restore_context(isphist_reg_list);
+	isp_restore_context(dev, isphist_reg_list);
 }
-EXPORT_SYMBOL(isphist_restore_context);
 
 /**
  * isp_hist_print_status - Debug print
  **/
-static void isp_hist_print_status(void)
+static void isp_hist_print_status(struct isp_hist_device *isp_hist)
 {
-	DPRINTK_ISPHIST("ISPHIST_PCR = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR));
-	DPRINTK_ISPHIST("ISPHIST_CNT = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT));
-	DPRINTK_ISPHIST("ISPHIST_WB_GAIN = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN));
-	DPRINTK_ISPHIST("ISPHIST_R0_HORZ = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ));
-	DPRINTK_ISPHIST("ISPHIST_R0_VERT = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT));
-	DPRINTK_ISPHIST("ISPHIST_R1_HORZ = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ));
-	DPRINTK_ISPHIST("ISPHIST_R1_VERT = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT));
-	DPRINTK_ISPHIST("ISPHIST_R2_HORZ = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ));
-	DPRINTK_ISPHIST("ISPHIST_R2_VERT = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT));
-	DPRINTK_ISPHIST("ISPHIST_R3_HORZ = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ));
-	DPRINTK_ISPHIST("ISPHIST_R3_VERT = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT));
-	DPRINTK_ISPHIST("ISPHIST_ADDR = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_ADDR));
-	DPRINTK_ISPHIST("ISPHIST_RADD = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD));
-	DPRINTK_ISPHIST("ISPHIST_RADD_OFF = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF));
-	DPRINTK_ISPHIST("ISPHIST_H_V_INFO = 0x%08x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO));
+#ifdef ISP_HIST_DEBUG
+	struct device *dev = to_device(isp_hist);
+
+	dev_dbg(dev, "hist: ISPHIST_PCR = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_PCR));
+	dev_dbg(dev, "hist: ISPHIST_CNT = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_CNT));
+	dev_dbg(dev, "hist: ISPHIST_WB_GAIN = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_WB_GAIN));
+	dev_dbg(dev, "hist: ISPHIST_R0_HORZ = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_HORZ));
+	dev_dbg(dev, "hist: ISPHIST_R0_VERT = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R0_VERT));
+	dev_dbg(dev, "hist: ISPHIST_R1_HORZ = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_HORZ));
+	dev_dbg(dev, "hist: ISPHIST_R1_VERT = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R1_VERT));
+	dev_dbg(dev, "hist: ISPHIST_R2_HORZ = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_HORZ));
+	dev_dbg(dev, "hist: ISPHIST_R2_VERT = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R2_VERT));
+	dev_dbg(dev, "hist: ISPHIST_R3_HORZ = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_HORZ));
+	dev_dbg(dev, "hist: ISPHIST_R3_VERT = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_R3_VERT));
+	dev_dbg(dev, "hist: ISPHIST_RADD = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD));
+	dev_dbg(dev, "hist: ISPHIST_RADD_OFF = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_RADD_OFF));
+	dev_dbg(dev, "hist: ISPHIST_H_V_INFO = 0x%08x\n",
+		isp_reg_readl(dev, OMAP3_ISP_IOMEM_HIST, ISPHIST_H_V_INFO));
+#endif
 }
diff --git a/drivers/media/video/isp/isphist.h b/drivers/media/video/isp/isphist.h
index 6b17c4e..d726298 100644
--- a/drivers/media/video/isp/isphist.h
+++ b/drivers/media/video/isp/isphist.h
@@ -6,6 +6,7 @@
  * Copyright (C) 2009 Texas Instruments, Inc.
  *
  * Contributors:
+ * 	David Cohen <david.cohen@nokia.com>
  *	Sergio Aguirre <saaguirre@ti.com>
  *	Troy Laramy
  *
@@ -22,15 +23,11 @@
 #define OMAP_ISP_HIST_H
 
 #include <mach/isp_user.h>
+#include <mach/dma.h>
 
-#define MAX_REGIONS		0x4
-#define MAX_WB_GAIN		255
-#define MIN_WB_GAIN		0x0
-#define MAX_BIT_WIDTH		14
-#define MIN_BIT_WIDTH		8
+#include "ispstat.h"
 
 #define ISPHIST_PCR_EN		(1 << 0)
-#define HIST_MEM_SIZE		1024
 #define ISPHIST_CNT_CLR_EN	(1 << 7)
 
 #define WRITE_SOURCE(reg, source)			\
@@ -61,19 +58,23 @@
 	(reg = (reg & ~(ISPHIST_CNT_BINS_MASK))		\
 	 | (num_bins << ISPHIST_CNT_BINS_SHIFT))
 
-#define WRITE_WB_R(reg, reg_wb_gain)				\
+#define WRITE_CFA(reg, cfa)				\
+	(reg = (reg & ~(ISPHIST_CNT_CFA_MASK))		\
+	 | (cfa << ISPHIST_CNT_CFA_SHIFT))
+
+#define WRITE_WG0(reg, reg_wb_gain)				\
 	reg = ((reg & ~(ISPHIST_WB_GAIN_WG00_MASK))		\
 	       | (reg_wb_gain << ISPHIST_WB_GAIN_WG00_SHIFT))
 
-#define WRITE_WB_RG(reg, reg_wb_gain)			\
+#define WRITE_WG1(reg, reg_wb_gain)			\
 	(reg = (reg & ~(ISPHIST_WB_GAIN_WG01_MASK))	\
 	 | (reg_wb_gain << ISPHIST_WB_GAIN_WG01_SHIFT))
 
-#define WRITE_WB_B(reg, reg_wb_gain)			\
+#define WRITE_WG2(reg, reg_wb_gain)			\
 	(reg = (reg & ~(ISPHIST_WB_GAIN_WG02_MASK))	\
 	 | (reg_wb_gain << ISPHIST_WB_GAIN_WG02_SHIFT))
 
-#define WRITE_WB_BG(reg, reg_wb_gain)			\
+#define WRITE_WG3(reg, reg_wb_gain)			\
 	(reg = (reg & ~(ISPHIST_WB_GAIN_WG03_MASK))	\
 	 | (reg_wb_gain << ISPHIST_WB_GAIN_WG03_SHIFT))
 
@@ -85,21 +86,74 @@
 	(reg = ((reg & ~ISPHIST_REGVERT_MASK)		\
 		| (reg_n_vert & ISPHIST_REGVERT_MASK)))
 
+/**
+ * struct isp_hist_regs - Current value of Histogram configuration registers.
+ * @pcr: Peripheral control register.
+ * @cnt: Histogram control register.
+ * @wb_gain: Histogram white balance gain register.
+ * @reg_hor[]: Region N horizontal register.
+ * @reg_ver[]: Region N vertical register.
+ * @hist_radd: Address register. When input data comes from mem.
+ * @hist_radd_off: Address offset register. When input data comes from mem.
+ * @h_v_info: Image size register. When input data comes from mem.
+ */
+struct isp_hist_regs {
+	u32 pcr;
+	u32 cnt;
+	u32 wb_gain;
+	u32 reg_hor[HIST_MAX_REGIONS];
+	u32 reg_ver[HIST_MAX_REGIONS];
+	u32 hist_radd;
+	u32 hist_radd_off;
+	u32 h_v_info;
+};
 
-void isp_hist_enable(u8 enable);
+/**
+ * struct isp_hist_status - Histogram status.
+ * @hist_enable: Enables the histogram module.
+ * @initialized: Flag to indicate that the module is correctly initialized.
+ * @frame_cnt: Actual frame count.
+ * @num_acc_frames: Num accumulated image frames per hist frame
+ * @completed: Flag to indicate if a frame request is completed.
+ */
+struct isp_hist_device {
+	u8 enabled;
+	u8 update;
+	u8 num_acc_frames;
+	u8 waiting_dma;
+	u8 invalid_buf;
+	u8 use_dma;
+	int dma_ch;
+	struct timeval ts;
 
-int isp_hist_busy(void);
+	struct omap_dma_channel_params dma_config;
+	struct isp_hist_regs regs;
+	struct isp_hist_config config;
+	struct ispstat_buffer *active_buf;
+	unsigned int buf_size;
+	struct ispstat stat;
 
-int isp_hist_configure(struct isp_hist_config *histcfg);
+	spinlock_t lock;	/* serialize access to hist device's fields */
+};
 
-int isp_hist_request_statistics(struct isp_hist_data *histdata);
+#define HIST_BUF_DONE		0
+#define HIST_NO_BUF		1
+#define HIST_BUF_WAITING_DMA	2
 
-void isphist_save_context(void);
-
-void isp_hist_suspend(void);
-
-void isp_hist_resume(void);
-
-void isphist_restore_context(void);
+int isp_hist_busy(struct isp_hist_device *isp_hist);
+void isp_hist_enable(struct isp_hist_device *isp_hist, u8 enable);
+void isp_hist_try_enable(struct isp_hist_device *isp_hist);
+int isp_hist_busy(struct isp_hist_device *isp_hist);
+int isp_hist_buf_process(struct isp_hist_device *isp_hist);
+void isp_hist_mark_invalid_buf(struct isp_hist_device *isp_hist);
+void isp_hist_config_registers(struct isp_hist_device *isp_hist);
+void isp_hist_suspend(struct isp_hist_device *isp_hist);
+void isp_hist_resume(struct isp_hist_device *isp_hist);
+void isp_hist_save_context(struct device *dev);
+void isp_hist_restore_context(struct device *dev);
+int isp_hist_config(struct isp_hist_device *isp_hist,
+		    struct isp_hist_config *histcfg);
+int isp_hist_request_statistics(struct isp_hist_device *isp_hist,
+				struct isp_hist_data *histdata);
 
 #endif				/* OMAP_ISP_HIST */
diff --git a/drivers/media/video/isp/ispmmu.c b/drivers/media/video/isp/ispmmu.c
deleted file mode 100644
index f872c71..0000000
--- a/drivers/media/video/isp/ispmmu.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * omap iommu wrapper for TI's OMAP3430 Camera ISP
- *
- * Copyright (C) 2008--2009 Nokia.
- *
- * Contributors:
- *	Hiroshi Doyu <hiroshi.doyu@nokia.com>
- *	Sakari Ailus <sakari.ailus@nokia.com>
- *
- * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#include <linux/module.h>
-
-#include "ispmmu.h"
-#include "isp.h"
-
-#include <mach/iommu.h>
-#include <mach/iovmm.h>
-
-#define IOMMU_FLAG (IOVMF_ENDIAN_LITTLE | IOVMF_ELSZ_8)
-
-static struct iommu *isp_iommu;
-
-dma_addr_t ispmmu_vmalloc(size_t bytes)
-{
-	return (dma_addr_t)iommu_vmalloc(isp_iommu, 0, bytes, IOMMU_FLAG);
-}
-
-void ispmmu_vfree(const dma_addr_t da)
-{
-	iommu_vfree(isp_iommu, (u32)da);
-}
-
-dma_addr_t ispmmu_kmap(u32 pa, int size)
-{
-	void *da;
-
-	da = (void *)iommu_kmap(isp_iommu, 0, pa, size, IOMMU_FLAG);
-	if (IS_ERR(da))
-		return PTR_ERR(da);
-
-	return (dma_addr_t)da;
-}
-
-void ispmmu_kunmap(dma_addr_t da)
-{
-	iommu_kunmap(isp_iommu, (u32)da);
-}
-
-dma_addr_t ispmmu_vmap(const struct scatterlist *sglist,
-		       int sglen)
-{
-	int err;
-	void *da;
-	struct sg_table *sgt;
-	unsigned int i;
-	struct scatterlist *sg, *src = (struct scatterlist *)sglist;
-
-	/*
-	 * convert isp sglist to iommu sgt
-	 * FIXME: should be fixed in the upper layer?
-	 */
-	sgt = kmalloc(sizeof(*sgt), GFP_KERNEL);
-	if (!sgt)
-		return -ENOMEM;
-	err = sg_alloc_table(sgt, sglen, GFP_KERNEL);
-	if (err)
-		goto err_sg_alloc;
-
-	for_each_sg(sgt->sgl, sg, sgt->nents, i)
-		sg_set_buf(sg, phys_to_virt(sg_dma_address(src + i)),
-			   sg_dma_len(src + i));
-
-	da = (void *)iommu_vmap(isp_iommu, 0, sgt, IOMMU_FLAG);
-	if (IS_ERR(da))
-		goto err_vmap;
-
-	return (dma_addr_t)da;
-
-err_vmap:
-	sg_free_table(sgt);
-err_sg_alloc:
-	kfree(sgt);
-	return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(ispmmu_vmap);
-
-void ispmmu_vunmap(dma_addr_t da)
-{
-	struct sg_table *sgt;
-
-	sgt = iommu_vunmap(isp_iommu, (u32)da);
-	if (!sgt)
-		return;
-	sg_free_table(sgt);
-	kfree(sgt);
-}
-EXPORT_SYMBOL_GPL(ispmmu_vunmap);
-
-void ispmmu_save_context(void)
-{
-	if (isp_iommu)
-		iommu_save_ctx(isp_iommu);
-}
-
-void ispmmu_restore_context(void)
-{
-	if (isp_iommu)
-		iommu_restore_ctx(isp_iommu);
-}
-
-int __init ispmmu_init(void)
-{
-	int err = 0;
-
-	isp_get();
-	isp_iommu = iommu_get("isp");
-	if (IS_ERR(isp_iommu)) {
-		err = PTR_ERR(isp_iommu);
-		isp_iommu = NULL;
-	}
-	isp_put();
-
-	return err;
-}
-
-void ispmmu_cleanup(void)
-{
-	isp_get();
-	if (isp_iommu)
-		iommu_put(isp_iommu);
-	isp_put();
-	isp_iommu = NULL;
-}
diff --git a/drivers/media/video/isp/ispmmu.h b/drivers/media/video/isp/ispmmu.h
deleted file mode 100644
index 0bc5bcb..0000000
--- a/drivers/media/video/isp/ispmmu.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * omap iommu wrapper for TI's OMAP3430 Camera ISP
- *
- * Copyright (C) 2008--2009 Nokia.
- *
- * Contributors:
- *	Hiroshi Doyu <hiroshi.doyu@nokia.com>
- *	Sakari Ailus <sakari.ailus@nokia.com>
- *
- * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
- */
-
-#ifndef OMAP_ISP_MMU_H
-#define OMAP_ISP_MMU_H
-
-#include <linux/err.h>
-#include <linux/scatterlist.h>
-
-dma_addr_t ispmmu_vmalloc(size_t bytes);
-void ispmmu_vfree(const dma_addr_t da);
-dma_addr_t ispmmu_kmap(u32 pa, int size);
-void ispmmu_kunmap(dma_addr_t da);
-dma_addr_t ispmmu_vmap(const struct scatterlist *sglist, int sglen);
-void ispmmu_vunmap(dma_addr_t da);
-void ispmmu_save_context(void);
-void ispmmu_restore_context(void);
-int ispmmu_init(void);
-void ispmmu_cleanup(void);
-
-#endif /* OMAP_ISP_MMU_H */
diff --git a/drivers/media/video/isp/isppreview.c b/drivers/media/video/isp/isppreview.c
index 02390e1..4f5da4e 100644
--- a/drivers/media/video/isp/isppreview.c
+++ b/drivers/media/video/isp/isppreview.c
@@ -22,17 +22,15 @@
 #include <linux/mutex.h>
 #include <linux/module.h>
 #include <linux/uaccess.h>
+#include <linux/device.h>
 
 #include "isp.h"
 #include "ispreg.h"
 #include "isppreview.h"
 
-static struct ispprev_nf prev_nf_t;
-static struct prev_params *params;
-static int rg_update, gg_update, bg_update, nf_enable, nf_update;
-
 /* Structure for saving/restoring preview module registers */
 static struct isp_reg ispprev_reg_list[] = {
+	{OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 0x0000}, /* See context saving. */
 	{OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO, 0x0000},
 	{OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO, 0x0000},
 	{OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR, 0x0000},
@@ -67,7 +65,6 @@
 	{OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1, 0x0000},
 	{OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2, 0x0000},
 	{OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3, 0x0000},
-	{OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, 0x0000},
 	{0, ISP_TOK_TERM, 0x0000}
 };
 
@@ -139,61 +136,6 @@
 #define FLR_BLKADJ_GREEN	0x0
 #define FLR_BLKADJ_RED		0x0
 
-static int update_color_matrix;
-
-/**
- * struct isp_prev - Structure for storing ISP Preview module information
- * @prev_inuse: Flag to determine if CCDC has been reserved or not (0 or 1).
- * @prevout_w: Preview output width.
- * @prevout_h: Preview output height.
- * @previn_w: Preview input width.
- * @previn_h: Preview input height.
- * @prev_inpfmt: Preview input format.
- * @prev_outfmt: Preview output format.
- * @hmed_en: Horizontal median filter enable.
- * @nf_en: Noise filter enable.
- * @dcor_en: Defect correction enable.
- * @cfa_en: Color Filter Array (CFA) interpolation enable.
- * @csup_en: Chrominance suppression enable.
- * @yenh_en: Luma enhancement enable.
- * @fmtavg: Number of horizontal pixels to average in input formatter. The
- *          input width should be a multiple of this number.
- * @brightness: Brightness in preview module.
- * @contrast: Contrast in preview module.
- * @color: Color effect in preview module.
- * @cfafmt: Color Filter Array (CFA) Format.
- * @ispprev_mutex: Mutex for isp preview.
- *
- * This structure is used to store the OMAP ISP Preview module Information.
- */
-static struct isp_prev {
-	int pm_state;
-	u8 prev_inuse;
-	u32 prevout_w;
-	u32 prevout_h;
-	u32 previn_w;
-	u32 previn_h;
-	enum preview_input prev_inpfmt;
-	enum preview_output prev_outfmt;
-	u8 hmed_en;
-	u8 nf_en;
-	u8 dcor_en;
-	u8 cfa_en;
-	u8 csup_en;
-	u8 yenh_en;
-	u8 fmtavg;
-	u8 brightness;
-	u8 contrast;
-	enum v4l2_colorfx color;
-	enum cfa_fmt cfafmt;
-	struct mutex ispprev_mutex; /* For checking/modifying prev_inuse */
-	u32 sph;
-	u32 slv;
-} ispprev_obj;
-
-/* Saved parameters */
-static struct prev_params *prev_config_params;
-
 /*
  * Coeficient Tables for the submodules in Preview.
  * Array is initialised with the values from.the tables text file.
@@ -242,208 +184,223 @@
 #include "luma_enhance_table.h"
 };
 
+static int isppreview_tables_update(struct isp_prev_device *isp_prev,
+				    struct isptables_update *isptables_struct);
+
+
 /**
- * omap34xx_isp_preview_config - Abstraction layer Preview configuration.
+ * isppreview_config - Abstraction layer Preview configuration.
  * @userspace_add: Pointer from Userspace to structure with flags and data to
  *                 update.
  **/
-int omap34xx_isp_preview_config(void *userspace_add)
+int isppreview_config(struct isp_prev_device *isp_prev, void *userspace_add)
 {
+	struct device *dev = to_device(isp_prev);
+	struct isp_device *isp = to_isp_device(isp_prev);
 	struct ispprev_hmed prev_hmed_t;
-	struct ispprev_cfa prev_cfa_t;
 	struct ispprev_csup csup_t;
-	struct ispprev_wbal prev_wbal_t;
 	struct ispprev_blkadj prev_blkadj_t;
-	struct ispprev_rgbtorgb rgb2rgb_t;
-	struct ispprev_csc prev_csc_t;
 	struct ispprev_yclimit yclimit_t;
 	struct ispprev_dcor prev_dcor_t;
-	struct ispprv_update_config *preview_struct;
+	struct ispprv_update_config *config;
 	struct isptables_update isp_table_update;
 	int yen_t[ISPPRV_YENH_TBL_SIZE];
+	struct prev_params *params = &isp_prev->params;
+	unsigned long flags;
 
 	if (userspace_add == NULL)
 		return -EINVAL;
 
-	preview_struct = userspace_add;
+	spin_lock_irqsave(&isp_prev->lock, flags);
+	isp_prev->shadow_update = 1;
+	spin_unlock_irqrestore(&isp_prev->lock, flags);
 
-	if (ISP_ABS_PREV_LUMAENH & preview_struct->flag) {
-		if (ISP_ABS_PREV_LUMAENH & preview_struct->update) {
-			if (copy_from_user(yen_t, preview_struct->yen,
+	config = userspace_add;
+
+	if (isp->running != ISP_STOPPED)
+		goto out_config_shadow;
+
+	if (ISP_ABS_PREV_LUMAENH & config->flag) {
+		if (ISP_ABS_PREV_LUMAENH & config->update) {
+			if (copy_from_user(yen_t, config->yen,
 					   sizeof(yen_t)))
 				goto err_copy_from_user;
-			isppreview_config_luma_enhancement(yen_t);
+			isppreview_config_luma_enhancement(isp_prev, yen_t);
 		}
 		params->features |= PREV_LUMA_ENHANCE;
-	} else if (ISP_ABS_PREV_LUMAENH & preview_struct->update)
+	} else if (ISP_ABS_PREV_LUMAENH & config->update)
 		params->features &= ~PREV_LUMA_ENHANCE;
 
-	if (ISP_ABS_PREV_INVALAW & preview_struct->flag) {
-		isppreview_enable_invalaw(1);
+	if (ISP_ABS_PREV_INVALAW & config->flag) {
+		isppreview_enable_invalaw(isp_prev, 1);
 		params->features |= PREV_INVERSE_ALAW;
 	} else {
-		isppreview_enable_invalaw(0);
+		isppreview_enable_invalaw(isp_prev, 0);
 		params->features &= ~PREV_INVERSE_ALAW;
 	}
 
-	if (ISP_ABS_PREV_HRZ_MED & preview_struct->flag) {
-		if (ISP_ABS_PREV_HRZ_MED & preview_struct->update) {
+	if (ISP_ABS_PREV_HRZ_MED & config->flag) {
+		if (ISP_ABS_PREV_HRZ_MED & config->update) {
 			if (copy_from_user(&prev_hmed_t,
 					   (struct ispprev_hmed *)
-					   preview_struct->prev_hmed,
+					   config->prev_hmed,
 					   sizeof(struct ispprev_hmed)))
 				goto err_copy_from_user;
-			isppreview_config_hmed(prev_hmed_t);
+			isppreview_config_hmed(isp_prev, prev_hmed_t);
 		}
-		isppreview_enable_hmed(1);
+		isppreview_enable_hmed(isp_prev, 1);
 		params->features |= PREV_HORZ_MEDIAN_FILTER;
-	} else if (ISP_ABS_PREV_HRZ_MED & preview_struct->update) {
-		isppreview_enable_hmed(0);
+	} else if (ISP_ABS_PREV_HRZ_MED & config->update) {
+		isppreview_enable_hmed(isp_prev, 0);
 		params->features &= ~PREV_HORZ_MEDIAN_FILTER;
 	}
 
-	if (ISP_ABS_PREV_CFA & preview_struct->flag) {
-		if (ISP_ABS_PREV_CFA & preview_struct->update) {
-			if (copy_from_user(&prev_cfa_t,
-					   (struct ispprev_cfa *)
-					   preview_struct->prev_cfa,
-					   sizeof(struct ispprev_cfa)))
-				goto err_copy_from_user;
-
-			isppreview_config_cfa(prev_cfa_t);
-		}
-		isppreview_enable_cfa(1);
-		params->features |= PREV_CFA;
-	} else if (ISP_ABS_PREV_CFA & preview_struct->update) {
-		isppreview_enable_cfa(0);
-		params->features &= ~PREV_CFA;
-	}
-
-	if (ISP_ABS_PREV_CHROMA_SUPP & preview_struct->flag) {
-		if (ISP_ABS_PREV_CHROMA_SUPP & preview_struct->update) {
+	if (ISP_ABS_PREV_CHROMA_SUPP & config->flag) {
+		if (ISP_ABS_PREV_CHROMA_SUPP & config->update) {
 			if (copy_from_user(&csup_t,
 					   (struct ispprev_csup *)
-					   preview_struct->csup,
+					   config->csup,
 					   sizeof(struct ispprev_csup)))
 				goto err_copy_from_user;
-			isppreview_config_chroma_suppression(csup_t);
+			isppreview_config_chroma_suppression(isp_prev, csup_t);
 		}
-		isppreview_enable_chroma_suppression(1);
+		isppreview_enable_chroma_suppression(isp_prev, 1);
 		params->features |= PREV_CHROMA_SUPPRESS;
-	} else if (ISP_ABS_PREV_CHROMA_SUPP & preview_struct->update) {
-		isppreview_enable_chroma_suppression(0);
+	} else if (ISP_ABS_PREV_CHROMA_SUPP & config->update) {
+		isppreview_enable_chroma_suppression(isp_prev, 0);
 		params->features &= ~PREV_CHROMA_SUPPRESS;
 	}
 
-	if (ISP_ABS_PREV_WB & preview_struct->update) {
-		if (copy_from_user(&prev_wbal_t, (struct ispprev_wbal *)
-				   preview_struct->prev_wbal,
-				   sizeof(struct ispprev_wbal)))
-			goto err_copy_from_user;
-		isppreview_config_whitebalance(prev_wbal_t);
-	}
-
-	if (ISP_ABS_PREV_BLKADJ & preview_struct->update) {
+	if (ISP_ABS_PREV_BLKADJ & config->update) {
 		if (copy_from_user(&prev_blkadj_t, (struct ispprev_blkadjl *)
-				   preview_struct->prev_blkadj,
+				   config->prev_blkadj,
 				   sizeof(struct ispprev_blkadj)))
 			goto err_copy_from_user;
-		isppreview_config_blkadj(prev_blkadj_t);
+		isppreview_config_blkadj(isp_prev, prev_blkadj_t);
 	}
 
-	if (ISP_ABS_PREV_RGB2RGB & preview_struct->update) {
-		if (copy_from_user(&rgb2rgb_t, (struct ispprev_rgbtorgb *)
-				   preview_struct->rgb2rgb,
-				   sizeof(struct ispprev_rgbtorgb)))
-			goto err_copy_from_user;
-		isppreview_config_rgb_blending(rgb2rgb_t);
-	}
-
-	if (ISP_ABS_PREV_COLOR_CONV & preview_struct->update) {
-		if (copy_from_user(&prev_csc_t, (struct ispprev_csc *)
-				   preview_struct->prev_csc,
-				   sizeof(struct ispprev_csc)))
-			goto err_copy_from_user;
-		isppreview_config_rgb_to_ycbcr(prev_csc_t);
-	}
-
-	if (ISP_ABS_PREV_YC_LIMIT & preview_struct->update) {
+	if (ISP_ABS_PREV_YC_LIMIT & config->update) {
 		if (copy_from_user(&yclimit_t, (struct ispprev_yclimit *)
-				   preview_struct->yclimit,
+				   config->yclimit,
 				   sizeof(struct ispprev_yclimit)))
 			goto err_copy_from_user;
-		isppreview_config_yc_range(yclimit_t);
+		isppreview_config_yc_range(isp_prev, yclimit_t);
 	}
 
-	if (ISP_ABS_PREV_DEFECT_COR & preview_struct->flag) {
-		if (ISP_ABS_PREV_DEFECT_COR & preview_struct->update) {
+	if (ISP_ABS_PREV_DEFECT_COR & config->flag) {
+		if (ISP_ABS_PREV_DEFECT_COR & config->update) {
 			if (copy_from_user(&prev_dcor_t,
 					   (struct ispprev_dcor *)
-					   preview_struct->prev_dcor,
+					   config->prev_dcor,
 					   sizeof(struct ispprev_dcor)))
 				goto err_copy_from_user;
-			isppreview_config_dcor(prev_dcor_t);
+			isppreview_config_dcor(isp_prev, prev_dcor_t);
 		}
-		isppreview_enable_dcor(1);
+		isppreview_enable_dcor(isp_prev, 1);
 		params->features |= PREV_DEFECT_COR;
-	} else if (ISP_ABS_PREV_DEFECT_COR & preview_struct->update) {
-		isppreview_enable_dcor(0);
+	} else if (ISP_ABS_PREV_DEFECT_COR & config->update) {
+		isppreview_enable_dcor(isp_prev, 0);
 		params->features &= ~PREV_DEFECT_COR;
 	}
 
-	if (ISP_ABS_PREV_GAMMABYPASS & preview_struct->flag) {
-		isppreview_enable_gammabypass(1);
+	if (ISP_ABS_PREV_GAMMABYPASS & config->flag) {
+		isppreview_enable_gammabypass(isp_prev, 1);
 		params->features |= PREV_GAMMA_BYPASS;
 	} else {
-		isppreview_enable_gammabypass(0);
+		isppreview_enable_gammabypass(isp_prev, 0);
 		params->features &= ~PREV_GAMMA_BYPASS;
 	}
 
-	isp_table_update.update = preview_struct->update;
-	isp_table_update.flag = preview_struct->flag;
-	isp_table_update.prev_nf = preview_struct->prev_nf;
-	isp_table_update.red_gamma = preview_struct->red_gamma;
-	isp_table_update.green_gamma = preview_struct->green_gamma;
-	isp_table_update.blue_gamma = preview_struct->blue_gamma;
+out_config_shadow:
+	if (ISP_ABS_PREV_RGB2RGB & config->update) {
+		if (copy_from_user(&params->rgb2rgb,
+				   (struct ispprev_rgbtorgb *)
+				   config->rgb2rgb,
+				   sizeof(struct ispprev_rgbtorgb)))
+			goto err_copy_from_user;
+		/* The function call above prevents compiler from reordering
+		 * writes so that the flag below is always set after
+		 * isp_prev->params.rgb2rgb is written to. */
+		isp_prev->update_rgb_blending = 1;
+	}
 
-	if (omap34xx_isp_tables_update(&isp_table_update))
+	if (ISP_ABS_PREV_COLOR_CONV & config->update) {
+		if (copy_from_user(&params->rgb2ycbcr, (struct ispprev_csc *)
+				   config->prev_csc,
+				   sizeof(struct ispprev_csc)))
+			goto err_copy_from_user;
+		/* Same here... this flag has to be set after rgb2ycbcr
+		 * structure is written to. */
+		isp_prev->update_rgb_to_ycbcr = 1;
+	}
+
+	isp_table_update.update = config->update;
+	isp_table_update.flag = config->flag;
+	isp_table_update.prev_nf = config->prev_nf;
+	isp_table_update.red_gamma = config->red_gamma;
+	isp_table_update.green_gamma = config->green_gamma;
+	isp_table_update.blue_gamma = config->blue_gamma;
+	isp_table_update.prev_cfa = config->prev_cfa;
+	isp_table_update.prev_wbal = config->prev_wbal;
+
+	if (isppreview_tables_update(isp_prev, &isp_table_update))
 		goto err_copy_from_user;
 
+	isp_prev->shadow_update = 0;
+
+	/* If the stream is stopped then update registers immediately */
+	if (isp->running == ISP_STOPPED)
+		isppreview_config_shadow_registers(isp_prev);
+
 	return 0;
 
 err_copy_from_user:
-	printk(KERN_ERR "Preview Config: Copy From User Error\n");
+	isp_prev->shadow_update = 0;
+	dev_err(dev, "preview: Config: Copy From User Error\n");
 	return -EFAULT;
 }
-EXPORT_SYMBOL_GPL(omap34xx_isp_preview_config);
+EXPORT_SYMBOL_GPL(isppreview_config);
 
 /**
- * omap34xx_isp_tables_update - Abstraction layer Tables update.
+ * isppreview_tables_update - Abstraction layer Tables update.
  * @isptables_struct: Pointer from Userspace to structure with flags and table
  *                 data to update.
  **/
-int omap34xx_isp_tables_update(struct isptables_update *isptables_struct)
+static int isppreview_tables_update(struct isp_prev_device *isp_prev,
+				    struct isptables_update *isptables_struct)
 {
+	struct device *dev = to_device(isp_prev);
+	struct prev_params *params = &isp_prev->params;
+
+	if (ISP_ABS_PREV_WB & isptables_struct->update) {
+		if (copy_from_user(&isp_prev->params.wbal,
+				isptables_struct->prev_wbal,
+				sizeof(struct ispprev_wbal)))
+			goto err_copy_from_user;
+
+		isp_prev->wbal_update = 1;
+	}
 
 	if (ISP_ABS_TBL_NF & isptables_struct->flag) {
-		nf_enable = 1;
+		isp_prev->nf_enable = 1;
 		params->features |= PREV_NOISE_FILTER;
 		if (ISP_ABS_TBL_NF & isptables_struct->update) {
-			if (copy_from_user(&prev_nf_t, (struct ispprev_nf *)
+			if (copy_from_user(&isp_prev->prev_nf_t,
+					   (struct ispprev_nf *)
 					   isptables_struct->prev_nf,
 					   sizeof(struct ispprev_nf)))
 				goto err_copy_from_user;
 
-			nf_update = 1;
+			isp_prev->nf_update = 1;
 		} else
-			nf_update = 0;
+			isp_prev->nf_update = 0;
 	} else {
-		nf_enable = 0;
+		isp_prev->nf_enable = 0;
 		params->features &= ~PREV_NOISE_FILTER;
 		if (ISP_ABS_TBL_NF & isptables_struct->update)
-			nf_update = 1;
+			isp_prev->nf_update = 1;
 		else
-			nf_update = 0;
+			isp_prev->nf_update = 0;
 	}
 
 	if (ISP_ABS_TBL_REDGAMMA & isptables_struct->update) {
@@ -451,18 +408,18 @@
 				   sizeof(redgamma_table))) {
 			goto err_copy_from_user;
 		}
-		rg_update = 1;
+		isp_prev->rg_update = 1;
 	} else
-		rg_update = 0;
+		isp_prev->rg_update = 0;
 
 	if (ISP_ABS_TBL_GREENGAMMA & isptables_struct->update) {
 		if (copy_from_user(greengamma_table,
 				   isptables_struct->green_gamma,
 				   sizeof(greengamma_table)))
 			goto err_copy_from_user;
-		gg_update = 1;
+		isp_prev->gg_update = 1;
 	} else
-		gg_update = 0;
+		isp_prev->gg_update = 0;
 
 	if (ISP_ABS_TBL_BLUEGAMMA & isptables_struct->update) {
 		if (copy_from_user(bluegamma_table,
@@ -470,14 +427,40 @@
 				   sizeof(bluegamma_table))) {
 			goto err_copy_from_user;
 		}
-		bg_update = 1;
+		isp_prev->bg_update = 1;
 	} else
-		bg_update = 0;
+		isp_prev->bg_update = 0;
+
+	if (ISP_ABS_PREV_CFA & isptables_struct->update) {
+		struct ispprev_cfa cfa;
+		if (isptables_struct->prev_cfa) {
+			if (copy_from_user(&cfa,
+					   isptables_struct->prev_cfa,
+					   sizeof(struct ispprev_cfa)))
+				goto err_copy_from_user;
+			if (cfa.cfa_table != NULL) {
+				if (copy_from_user(cfa_coef_table,
+						   cfa.cfa_table,
+						   sizeof(cfa_coef_table)))
+					goto err_copy_from_user;
+			}
+			cfa.cfa_table = cfa_coef_table;
+			isp_prev->params.cfa = cfa;
+		}
+		if (ISP_ABS_PREV_CFA & isptables_struct->flag) {
+			isp_prev->cfa_en = 1;
+			isp_prev->params.features |= PREV_CFA;
+		} else {
+			isp_prev->cfa_en = 0;
+			isp_prev->params.features &= ~PREV_CFA;
+		}
+		isp_prev->cfa_update = 1;
+	}
 
 	return 0;
 
 err_copy_from_user:
-	printk(KERN_ERR "Preview Tables:Copy From User Error\n");
+	dev_err(dev, "preview tables: Copy From User Error\n");
 	return -EFAULT;
 }
 
@@ -486,116 +469,131 @@
  *
  * Allows user to program shadow registers associated with preview module.
  **/
-void isppreview_config_shadow_registers()
+void isppreview_config_shadow_registers(struct isp_prev_device *isp_prev)
 {
+	struct device *dev = to_device(isp_prev);
 	u8 current_brightness_contrast;
-	int ctr, prv_disabled;
+	int ctr;
+	unsigned long flags;
 
-	isppreview_query_brightness(&current_brightness_contrast);
+	spin_lock_irqsave(&isp_prev->lock, flags);
+	if (isp_prev->shadow_update) {
+		spin_unlock_irqrestore(&isp_prev->lock, flags);
+		return;
+	}
+
+	isppreview_query_brightness(isp_prev, &current_brightness_contrast);
 	if (current_brightness_contrast !=
-	    ispprev_obj.brightness) {
+	    isp_prev->brightness) {
 		DPRINTK_ISPPREV(" Changing Brightness level to %d\n",
-				ispprev_obj.brightness);
-		isppreview_config_brightness(ispprev_obj.brightness);
+				isp_prev->brightness);
+		isppreview_config_brightness(isp_prev, isp_prev->brightness);
 	}
 
-	isppreview_query_contrast(&current_brightness_contrast);
+	isppreview_query_contrast(isp_prev, &current_brightness_contrast);
 	if (current_brightness_contrast !=
-	    ispprev_obj.contrast) {
+	    isp_prev->contrast) {
 		DPRINTK_ISPPREV(" Changing Contrast level to %d\n",
-				ispprev_obj.contrast);
-		isppreview_config_contrast(ispprev_obj.contrast);
+				isp_prev->contrast);
+		isppreview_config_contrast(isp_prev, isp_prev->contrast);
 	}
-	if (update_color_matrix) {
-		isppreview_config_rgb_to_ycbcr(flr_prev_csc[ispprev_obj.color]);
-		update_color_matrix = 0;
+	if (isp_prev->wbal_update) {
+		isppreview_config_whitebalance(isp_prev,
+					       isp_prev->params.wbal);
+		isp_prev->wbal_update = 0;
 	}
-	if (gg_update || rg_update || bg_update || nf_update) {
-		isppreview_enable(0);
-		prv_disabled = 1;
+	if (isp_prev->update_color_matrix) {
+		isppreview_config_rgb_to_ycbcr(isp_prev,
+					       flr_prev_csc[isp_prev->color]);
+		isp_prev->update_color_matrix = 0;
+	}
+	if (isp_prev->update_rgb_blending) {
+		isp_prev->update_rgb_blending = 0;
+		isppreview_config_rgb_blending(isp_prev,
+					       isp_prev->params.rgb2rgb);
+	}
+	if (isp_prev->update_rgb_to_ycbcr) {
+		isp_prev->update_rgb_to_ycbcr = 0;
+		isppreview_config_rgb_to_ycbcr(isp_prev,
+					       isp_prev->params.rgb2ycbcr);
 	}
 
-	if (gg_update) {
-		isp_reg_writel(ISPPRV_TBL_ADDR_GREEN_G_START,
+	if (isp_prev->gg_update) {
+		isp_reg_writel(dev, ISPPRV_TBL_ADDR_GREEN_G_START,
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 
 		for (ctr = 0; ctr < ISP_GAMMA_TABLE_SIZE; ctr++) {
-			isp_reg_writel(greengamma_table[ctr],
+			isp_reg_writel(dev, greengamma_table[ctr],
 				       OMAP3_ISP_IOMEM_PREV,
 				       ISPPRV_SET_TBL_DATA);
 		}
-		gg_update = 0;
+		isp_prev->gg_update = 0;
 	}
 
-	if (rg_update) {
-		isp_reg_writel(ISPPRV_TBL_ADDR_RED_G_START,
+	if (isp_prev->rg_update) {
+		isp_reg_writel(dev, ISPPRV_TBL_ADDR_RED_G_START,
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 
 		for (ctr = 0; ctr < ISP_GAMMA_TABLE_SIZE; ctr++) {
-			isp_reg_writel(redgamma_table[ctr],
+			isp_reg_writel(dev, redgamma_table[ctr],
 				       OMAP3_ISP_IOMEM_PREV,
 				       ISPPRV_SET_TBL_DATA);
 		}
-		rg_update = 0;
+		isp_prev->rg_update = 0;
 	}
 
-	if (bg_update) {
-		isp_reg_writel(ISPPRV_TBL_ADDR_BLUE_G_START,
+	if (isp_prev->bg_update) {
+		isp_reg_writel(dev, ISPPRV_TBL_ADDR_BLUE_G_START,
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 
 		for (ctr = 0; ctr < ISP_GAMMA_TABLE_SIZE; ctr++) {
-			isp_reg_writel(bluegamma_table[ctr],
+			isp_reg_writel(dev, bluegamma_table[ctr],
 				       OMAP3_ISP_IOMEM_PREV,
 				       ISPPRV_SET_TBL_DATA);
 		}
-		bg_update = 0;
+		isp_prev->bg_update = 0;
 	}
 
-	if (nf_update && nf_enable) {
-		isp_reg_writel(0xC00,
+	if (isp_prev->cfa_update) {
+		isp_prev->cfa_update = 0;
+		isppreview_config_cfa(isp_prev, isp_prev->params.cfa);
+		isppreview_enable_cfa(isp_prev, isp_prev->cfa_en);
+	}
+
+	if (isp_prev->nf_update && isp_prev->nf_enable) {
+		isppreview_enable_noisefilter(isp_prev, 0);
+		isp_reg_writel(dev, 0xC00,
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
-		isp_reg_writel(prev_nf_t.spread,
+		isp_reg_writel(dev, isp_prev->prev_nf_t.spread,
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
 		for (ctr = 0; ctr < ISPPRV_NF_TBL_SIZE; ctr++) {
-			isp_reg_writel(prev_nf_t.table[ctr],
+			isp_reg_writel(dev,
+				       isp_prev->prev_nf_t.table[ctr],
 				       OMAP3_ISP_IOMEM_PREV,
 				       ISPPRV_SET_TBL_DATA);
 		}
-		isppreview_enable_noisefilter(1);
-		nf_update = 0;
+		isppreview_enable_noisefilter(isp_prev, 1);
+		isp_prev->nf_update = 0;
 	}
 
-	if (~nf_update && nf_enable)
-		isppreview_enable_noisefilter(1);
+	if (isp_prev->nf_update && ~isp_prev->nf_enable)
+		isppreview_enable_noisefilter(isp_prev, 0);
 
-	if (nf_update && ~nf_enable)
-		isppreview_enable_noisefilter(0);
-
-	if (prv_disabled) {
-		isppreview_enable(1);
-		prv_disabled = 0;
-	}
+	spin_unlock_irqrestore(&isp_prev->lock, flags);
 }
-EXPORT_SYMBOL_GPL(isppreview_config_shadow_registers);
 
 /**
  * isppreview_request - Reserves the preview module.
  *
  * Returns 0 if successful, or -EBUSY if the module was already reserved.
  **/
-int isppreview_request()
+int isppreview_request(struct isp_prev_device *isp_prev)
 {
-	mutex_lock(&ispprev_obj.ispprev_mutex);
-	if (ispprev_obj.prev_inuse) {
-		mutex_unlock(&ispprev_obj.ispprev_mutex);
-		printk(KERN_ERR "ISP_ERR : Preview Module Busy\n");
-		return -EBUSY;
-	}
-	ispprev_obj.prev_inuse = 1;
-	mutex_unlock(&ispprev_obj.ispprev_mutex);
-	isp_reg_or(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_PREV_RAM_EN |
-		   ISPCTRL_PREV_CLK_EN |
-		   ISPCTRL_SBL_WR1_RAM_EN);
+	struct device *dev = to_device(isp_prev);
+
+	isp_reg_or(dev,
+		   OMAP3_ISP_IOMEM_MAIN, ISP_CTRL, ISPCTRL_PREV_RAM_EN |
+		   ISPCTRL_PREV_CLK_EN | ISPCTRL_SBL_WR1_RAM_EN);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_request);
@@ -605,23 +603,14 @@
  *
  * Returns 0 if successful, or -EINVAL if the module was already freed.
  **/
-int isppreview_free()
+void isppreview_free(struct isp_prev_device *isp_prev)
 {
-	mutex_lock(&ispprev_obj.ispprev_mutex);
-	if (ispprev_obj.prev_inuse) {
-		ispprev_obj.prev_inuse = 0;
-		mutex_unlock(&ispprev_obj.ispprev_mutex);
-		isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+	struct device *dev = to_device(isp_prev);
+
+	isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
 			    ~(ISPCTRL_PREV_CLK_EN |
 			      ISPCTRL_PREV_RAM_EN |
 			      ISPCTRL_SBL_WR1_RAM_EN));
-		return 0;
-	} else {
-		mutex_unlock(&ispprev_obj.ispprev_mutex);
-		DPRINTK_ISPPREV("ISP_ERR : Preview Module already freed\n");
-		return -EINVAL;
-	}
-
 }
 EXPORT_SYMBOL_GPL(isppreview_free);
 
@@ -639,47 +628,39 @@
  * Returns 0 if successful, or -EINVAL if wrong input or output values are
  * specified.
  **/
-int isppreview_config_datapath(enum preview_input input,
-			       enum preview_output output)
+int isppreview_config_datapath(struct isp_prev_device *isp_prev,
+			       struct isp_pipeline *pipe)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 pcr = 0;
 	u8 enable = 0;
-	struct prev_params *params = prev_config_params;
+	struct prev_params *params = &isp_prev->params;
 	struct ispprev_yclimit yclimit;
 
-	pcr = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+	pcr = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
 
-	switch (input) {
+	switch (pipe->prv_in) {
 	case PRV_RAW_CCDC:
 		pcr &= ~ISPPRV_PCR_SOURCE;
-		pcr &= ~ISPPRV_PCR_ONESHOT;
-		ispprev_obj.prev_inpfmt = PRV_RAW_CCDC;
 		break;
 	case PRV_RAW_MEM:
 		pcr |= ISPPRV_PCR_SOURCE;
-		pcr |= ISPPRV_PCR_ONESHOT;
-		ispprev_obj.prev_inpfmt = PRV_RAW_MEM;
 		break;
 	case PRV_CCDC_DRKF:
 		pcr |= ISPPRV_PCR_DRKFCAP;
-		pcr |= ISPPRV_PCR_ONESHOT;
-		ispprev_obj.prev_inpfmt = PRV_CCDC_DRKF;
 		break;
 	case PRV_COMPCFA:
-		ispprev_obj.prev_inpfmt = PRV_COMPCFA;
 		break;
 	case PRV_OTHERS:
-		ispprev_obj.prev_inpfmt = PRV_OTHERS;
 		break;
 	case PRV_RGBBAYERCFA:
-		ispprev_obj.prev_inpfmt = PRV_RGBBAYERCFA;
 		break;
 	default:
-		printk(KERN_ERR "ISP_ERR : Wrong Input\n");
+		dev_err(dev, "preview: Wrong Input\n");
 		return -EINVAL;
 	};
 
-	switch (output) {
+	switch (pipe->prv_out) {
 	case PREVIEW_RSZ:
 		pcr |= ISPPRV_PCR_RSZPORT;
 		pcr &= ~ISPPRV_PCR_SDRPORT;
@@ -689,60 +670,60 @@
 		pcr |= ISPPRV_PCR_SDRPORT;
 		break;
 	default:
-		printk(KERN_ERR "ISP_ERR : Wrong Output\n");
+		dev_err(dev, "preview: Wrong Output\n");
 		return -EINVAL;
 	}
-	ispprev_obj.prev_outfmt = output;
 
-	isp_reg_writel(pcr, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+	isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
 
-	isppreview_config_ycpos(params->pix_fmt);
-
-	if (params->cfa.cfa_table != NULL)
-		isppreview_config_cfa(params->cfa);
 	if (params->csup.hypf_en == 1)
-		isppreview_config_chroma_suppression(params->csup);
+		isppreview_config_chroma_suppression(isp_prev, params->csup);
 	if (params->ytable != NULL)
-		isppreview_config_luma_enhancement(params->ytable);
+		isppreview_config_luma_enhancement(isp_prev, params->ytable);
 
 	if (params->gtable.redtable != NULL)
-		isppreview_config_gammacorrn(params->gtable);
+		isppreview_config_gammacorrn(isp_prev, params->gtable);
+
+	isp_prev->cfa_update = 0;
+	isppreview_config_cfa(isp_prev, params->cfa);
 
 	enable = (params->features & PREV_CFA) ? 1 : 0;
-	isppreview_enable_cfa(enable);
+	isppreview_enable_cfa(isp_prev, enable);
 
 	enable = (params->features & PREV_CHROMA_SUPPRESS) ? 1 : 0;
-	isppreview_enable_chroma_suppression(enable);
+	isppreview_enable_chroma_suppression(isp_prev, enable);
 
 	enable = (params->features & PREV_LUMA_ENHANCE) ? 1 : 0;
-	isppreview_enable_luma_enhancement(enable);
+	isppreview_enable_luma_enhancement(isp_prev, enable);
 
 	enable = (params->features & PREV_NOISE_FILTER) ? 1 : 0;
 	if (enable)
-		isppreview_config_noisefilter(params->nf);
-	isppreview_enable_noisefilter(enable);
+		isppreview_config_noisefilter(isp_prev, params->nf);
+	isppreview_enable_noisefilter(isp_prev, enable);
 
 	enable = (params->features & PREV_DEFECT_COR) ? 1 : 0;
 	if (enable)
-		isppreview_config_dcor(params->dcor);
-	isppreview_enable_dcor(enable);
+		isppreview_config_dcor(isp_prev, params->dcor);
+	isppreview_enable_dcor(isp_prev, enable);
 
 	enable = (params->features & PREV_GAMMA_BYPASS) ? 1 : 0;
-	isppreview_enable_gammabypass(enable);
+	isppreview_enable_gammabypass(isp_prev, enable);
 
-	isppreview_config_whitebalance(params->wbal);
-	isppreview_config_blkadj(params->blk_adj);
-	isppreview_config_rgb_blending(params->rgb2rgb);
-	isppreview_config_rgb_to_ycbcr(params->rgb2ycbcr);
+	isppreview_config_whitebalance(isp_prev, params->wbal);
+	isp_prev->wbal_update = 0;
 
-	isppreview_config_contrast(params->contrast);
-	isppreview_config_brightness(params->brightness);
+	isppreview_config_blkadj(isp_prev, params->blk_adj);
+	isppreview_config_rgb_blending(isp_prev, params->rgb2rgb);
+	isppreview_config_rgb_to_ycbcr(isp_prev, params->rgb2ycbcr);
+
+	isppreview_config_contrast(isp_prev, params->contrast);
+	isppreview_config_brightness(isp_prev, params->brightness);
 
 	yclimit.minC = ISPPRV_YC_MIN;
 	yclimit.maxC = ISPPRV_YC_MAX;
 	yclimit.minY = ISPPRV_YC_MIN;
 	yclimit.maxY = ISPPRV_YC_MAX;
-	isppreview_config_yc_range(yclimit);
+	isppreview_config_yc_range(isp_prev, yclimit);
 
 	return 0;
 }
@@ -753,10 +734,10 @@
  *  h - Start Pixel Horizontal.
  *  v - Start Line Vertical.
  **/
-void isppreview_set_skip(u32 h, u32 v)
+void isppreview_set_skip(struct isp_prev_device *isp_prev, u32 h, u32 v)
 {
-	ispprev_obj.sph = h;
-	ispprev_obj.slv = v;
+	isp_prev->sph = h;
+	isp_prev->slv = v;
 }
 EXPORT_SYMBOL_GPL(isppreview_set_skip);
 
@@ -764,12 +745,16 @@
  * isppreview_config_ycpos - Configure byte layout of YUV image.
  * @mode: Indicates the required byte layout.
  **/
-void isppreview_config_ycpos(enum preview_ycpos_mode mode)
+void isppreview_config_ycpos(struct isp_prev_device *isp_prev,
+			     enum preview_ycpos_mode mode)
 {
-	u32 pcr = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+	struct device *dev = to_device(isp_prev);
+	u32 pcr = isp_reg_readl(dev,
+				OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+
 	pcr &= ~ISPPRV_PCR_YCPOS_CrYCbY;
 	pcr |= (mode << ISPPRV_PCR_YCPOS_SHIFT);
-	isp_reg_writel(pcr, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+	isp_reg_writel(dev, pcr, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
 }
 EXPORT_SYMBOL_GPL(isppreview_config_ycpos);
 
@@ -777,12 +762,13 @@
  * isppreview_config_averager - Enable / disable / configure averager
  * @average: Average value to be configured.
  **/
-void isppreview_config_averager(u8 average)
+void isppreview_config_averager(struct isp_prev_device *isp_prev, u8 average)
 {
+	struct device *dev = to_device(isp_prev);
 	int reg = 0;
 
 	reg = AVE_ODD_PIXEL_DIST | AVE_EVEN_PIXEL_DIST | average;
-	isp_reg_writel(reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
+	isp_reg_writel(dev, reg, OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
 }
 EXPORT_SYMBOL_GPL(isppreview_config_averager);
 
@@ -790,16 +776,19 @@
  * isppreview_enable_invalaw - Enable/Disable Inverse A-Law module in Preview.
  * @enable: 1 - Reverse the A-Law done in CCDC.
  **/
-void isppreview_enable_invalaw(u8 enable)
+void isppreview_enable_invalaw(struct isp_prev_device *isp_prev, u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 pcr_val = 0;
-	pcr_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+	pcr_val = isp_reg_readl(dev,
+				OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
 
 	if (enable) {
-		isp_reg_writel(pcr_val | ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW,
+		isp_reg_writel(dev,
+			       pcr_val | ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW,
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
 	} else {
-		isp_reg_writel(pcr_val &
+		isp_reg_writel(dev, pcr_val &
 			       ~(ISPPRV_PCR_WIDTH | ISPPRV_PCR_INVALAW),
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
 	}
@@ -813,12 +802,15 @@
  *
  * The proccess is applied for each captured frame.
  **/
-void isppreview_enable_drkframe(u8 enable)
+void isppreview_enable_drkframe(struct isp_prev_device *isp_prev, u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (enable)
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_DRKFEN);
+		isp_reg_or(dev,
+			   OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_DRKFEN);
 	else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_DRKFEN);
 	}
 }
@@ -831,15 +823,16 @@
  * If dark frame subtract won't be used, then enable this shading
  * compensation.
  **/
-void isppreview_enable_shadcomp(u8 enable)
+void isppreview_enable_shadcomp(struct isp_prev_device *isp_prev, u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
 
 	if (enable) {
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			   ISPPRV_PCR_SCOMP_EN);
-		isppreview_enable_drkframe(1);
+		isppreview_enable_drkframe(isp_prev, 1);
 	} else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_SCOMP_EN);
 	}
 }
@@ -849,12 +842,16 @@
  * isppreview_config_drkf_shadcomp - Configures shift value in shading comp.
  * @scomp_shtval: 3bit value of shift used in shading compensation.
  **/
-void isppreview_config_drkf_shadcomp(u8 scomp_shtval)
+void isppreview_config_drkf_shadcomp(struct isp_prev_device *isp_prev,
+				     u8 scomp_shtval)
 {
-	u32 pcr_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
+	struct device *dev = to_device(isp_prev);
+	u32 pcr_val = isp_reg_readl(dev,
+				    OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
 
 	pcr_val &= ISPPRV_PCR_SCOMP_SFT_MASK;
-	isp_reg_writel(pcr_val | (scomp_shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT),
+	isp_reg_writel(dev,
+		       pcr_val | (scomp_shtval << ISPPRV_PCR_SCOMP_SFT_SHIFT),
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR);
 }
 EXPORT_SYMBOL_GPL(isppreview_config_drkf_shadcomp);
@@ -863,15 +860,18 @@
  * isppreview_enable_hmed - Enables/Disables of the Horizontal Median Filter.
  * @enable: 1 - Enables Horizontal Median Filter.
  **/
-void isppreview_enable_hmed(u8 enable)
+void isppreview_enable_hmed(struct isp_prev_device *isp_prev, u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (enable)
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_HMEDEN);
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			   ISPPRV_PCR_HMEDEN);
 	else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_HMEDEN);
 	}
-	ispprev_obj.hmed_en = enable ? 1 : 0;
+	isp_prev->hmed_en = enable ? 1 : 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_enable_hmed);
 
@@ -880,9 +880,10 @@
  * @prev_hmed: Structure containing the odd and even distance between the
  *             pixels in the image along with the filter threshold.
  **/
-void isppreview_config_hmed(struct ispprev_hmed prev_hmed)
+void isppreview_config_hmed(struct isp_prev_device *isp_prev,
+			    struct ispprev_hmed prev_hmed)
 {
-
+	struct device *dev = to_device(isp_prev);
 	u32 odddist = 0;
 	u32 evendist = 0;
 
@@ -896,7 +897,7 @@
 	else
 		evendist = ISPPRV_HMED_EVENDIST;
 
-	isp_reg_writel(odddist | evendist | (prev_hmed.thres <<
+	isp_reg_writel(dev, odddist | evendist | (prev_hmed.thres <<
 					     ISPPRV_HMED_THRESHOLD_SHIFT),
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED);
 
@@ -908,16 +909,19 @@
  * @prev_nf: Structure containing the noisefilter table, strength to be used
  *           for the noise filter and the defect correction enable flag.
  **/
-void isppreview_config_noisefilter(struct ispprev_nf prev_nf)
+void isppreview_config_noisefilter(struct isp_prev_device *isp_prev,
+				   struct ispprev_nf prev_nf)
 {
+	struct device *dev = to_device(isp_prev);
 	int i = 0;
 
-	isp_reg_writel(prev_nf.spread, OMAP3_ISP_IOMEM_PREV, ISPPRV_NF);
-	isp_reg_writel(ISPPRV_NF_TABLE_ADDR, OMAP3_ISP_IOMEM_PREV,
-		       ISPPRV_SET_TBL_ADDR);
+	isp_reg_writel(dev, prev_nf.spread, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_NF);
+	isp_reg_writel(dev, ISPPRV_NF_TABLE_ADDR,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 	for (i = 0; i < ISPPRV_NF_TBL_SIZE; i++) {
-		isp_reg_writel(prev_nf.table[i], OMAP3_ISP_IOMEM_PREV,
-			       ISPPRV_SET_TBL_DATA);
+		isp_reg_writel(dev, prev_nf.table[i],
+			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
 	}
 }
 EXPORT_SYMBOL_GPL(isppreview_config_noisefilter);
@@ -926,20 +930,24 @@
  * isppreview_config_dcor - Configures the defect correction
  * @prev_nf: Structure containing the defect correction structure
  **/
-void isppreview_config_dcor(struct ispprev_dcor prev_dcor)
+void isppreview_config_dcor(struct isp_prev_device *isp_prev,
+			    struct ispprev_dcor prev_dcor)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (prev_dcor.couplet_mode_en) {
-		isp_reg_writel(prev_dcor.detect_correct[0],
+		isp_reg_writel(dev, prev_dcor.detect_correct[0],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR0);
-		isp_reg_writel(prev_dcor.detect_correct[1],
+		isp_reg_writel(dev, prev_dcor.detect_correct[1],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR1);
-		isp_reg_writel(prev_dcor.detect_correct[2],
+		isp_reg_writel(dev, prev_dcor.detect_correct[2],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR2);
-		isp_reg_writel(prev_dcor.detect_correct[3],
+		isp_reg_writel(dev, prev_dcor.detect_correct[3],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_CDC_THR3);
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_DCCOUP);
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			   ISPPRV_PCR_DCCOUP);
 	} else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_DCCOUP);
 	}
 }
@@ -950,25 +958,28 @@
  * @prev_cfa: Structure containing the CFA interpolation table, CFA format
  *            in the image, vertical and horizontal gradient threshold.
  **/
-void isppreview_config_cfa(struct ispprev_cfa prev_cfa)
+void isppreview_config_cfa(struct isp_prev_device *isp_prev,
+			   struct ispprev_cfa prev_cfa)
 {
+	struct device *dev = to_device(isp_prev);
 	int i = 0;
 
-	ispprev_obj.cfafmt = prev_cfa.cfafmt;
+	isp_prev->cfafmt = prev_cfa.cfafmt;
 
-	isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
-		   (prev_cfa.cfafmt << ISPPRV_PCR_CFAFMT_SHIFT));
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		       ~ISPPRV_PCR_CFAFMT_MASK,
+		       (prev_cfa.cfafmt << ISPPRV_PCR_CFAFMT_SHIFT));
 
-	isp_reg_writel(
+	isp_reg_writel(dev,
 		(prev_cfa.cfa_gradthrs_vert << ISPPRV_CFA_GRADTH_VER_SHIFT) |
 		(prev_cfa.cfa_gradthrs_horz << ISPPRV_CFA_GRADTH_HOR_SHIFT),
 		OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA);
 
-	isp_reg_writel(ISPPRV_CFA_TABLE_ADDR, OMAP3_ISP_IOMEM_PREV,
-		       ISPPRV_SET_TBL_ADDR);
+	isp_reg_writel(dev, ISPPRV_CFA_TABLE_ADDR,
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 
 	for (i = 0; i < ISPPRV_CFA_TBL_SIZE; i++) {
-		isp_reg_writel(prev_cfa.cfa_table[i],
+		isp_reg_writel(dev, prev_cfa.cfa_table[i],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
 	}
 }
@@ -978,58 +989,49 @@
  * isppreview_config_gammacorrn - Configures the Gamma Correction table values
  * @gtable: Structure containing the table for red, blue, green gamma table.
  **/
-void isppreview_config_gammacorrn(struct ispprev_gtable gtable)
+void isppreview_config_gammacorrn(struct isp_prev_device *isp_prev,
+				  struct ispprev_gtable gtable)
 {
+	struct device *dev = to_device(isp_prev);
 	int i = 0;
 
-	isp_reg_writel(ISPPRV_REDGAMMA_TABLE_ADDR,
+	isp_reg_writel(dev, ISPPRV_REDGAMMA_TABLE_ADDR,
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 	for (i = 0; i < ISPPRV_GAMMA_TBL_SIZE; i++) {
-		isp_reg_writel(gtable.redtable[i],
+		isp_reg_writel(dev, gtable.redtable[i],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
 	}
 
-	isp_reg_writel(ISPPRV_GREENGAMMA_TABLE_ADDR,
+	isp_reg_writel(dev, ISPPRV_GREENGAMMA_TABLE_ADDR,
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 	for (i = 0; i < ISPPRV_GAMMA_TBL_SIZE; i++) {
-		isp_reg_writel(gtable.greentable[i],
+		isp_reg_writel(dev, gtable.greentable[i],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
 	}
 
-	isp_reg_writel(ISPPRV_BLUEGAMMA_TABLE_ADDR,
+	isp_reg_writel(dev, ISPPRV_BLUEGAMMA_TABLE_ADDR,
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 	for (i = 0; i < ISPPRV_GAMMA_TBL_SIZE; i++) {
-		isp_reg_writel(gtable.bluetable[i],
+		isp_reg_writel(dev, gtable.bluetable[i],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
 	}
 }
 EXPORT_SYMBOL_GPL(isppreview_config_gammacorrn);
 
 /**
- * isppreview_set_luma_enhancement - Stores the Luminance Enhancement table.
+ * isppreview_config_luma_enhancement - Sets the Luminance Enhancement table.
  * @ytable: Structure containing the table for Luminance Enhancement table.
  **/
-void isppreview_set_luma_enhancement(u32 *ytable)
+void isppreview_config_luma_enhancement(struct isp_prev_device *isp_prev,
+					u32 *ytable)
 {
-	int i;
-
-	for (i = 0; i < ISPPRV_YENH_TBL_SIZE; i++)
-		params->ytable[i] = ytable[i];
-}
-EXPORT_SYMBOL_GPL(isppreview_set_luma_enhancement);
-
-/**
- * isppreview_config_luma_enhancement - Writes the Luminance Enhancement table.
- * @ytable: Structure containing the table for Luminance Enhancement table.
- **/
-void isppreview_config_luma_enhancement(u32 *ytable)
-{
+	struct device *dev = to_device(isp_prev);
 	int i = 0;
 
-	isp_reg_writel(ISPPRV_YENH_TABLE_ADDR,
+	isp_reg_writel(dev, ISPPRV_YENH_TABLE_ADDR,
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_ADDR);
 	for (i = 0; i < ISPPRV_YENH_TBL_SIZE; i++) {
-		isp_reg_writel(ytable[i],
+		isp_reg_writel(dev, ytable[i],
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_SET_TBL_DATA);
 	}
 }
@@ -1040,9 +1042,13 @@
  * @csup: Structure containing the threshold value for suppression
  *        and the hypass filter enable flag.
  **/
-void isppreview_config_chroma_suppression(struct ispprev_csup csup)
+void isppreview_config_chroma_suppression(struct isp_prev_device *isp_prev,
+					  struct ispprev_csup csup)
 {
-	isp_reg_writel(csup.gain | (csup.thres << ISPPRV_CSUP_THRES_SHIFT) |
+	struct device *dev = to_device(isp_prev);
+
+	isp_reg_writel(dev,
+		       csup.gain | (csup.thres << ISPPRV_CSUP_THRES_SHIFT) |
 		       (csup.hypf_en << ISPPRV_CSUP_HPYF_SHIFT),
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP);
 }
@@ -1052,13 +1058,17 @@
  * isppreview_enable_noisefilter - Enables/Disables the Noise Filter.
  * @enable: 1 - Enables the Noise Filter.
  **/
-void isppreview_enable_noisefilter(u8 enable)
+void isppreview_enable_noisefilter(struct isp_prev_device *isp_prev, u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (enable)
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_NFEN);
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			   ISPPRV_PCR_NFEN);
 	else
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ~ISPPRV_PCR_NFEN);
-	ispprev_obj.nf_en = enable ? 1 : 0;
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ~ISPPRV_PCR_NFEN);
+	isp_prev->nf_en = enable ? 1 : 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_enable_noisefilter);
 
@@ -1066,15 +1076,18 @@
  * isppreview_enable_dcor - Enables/Disables the defect correction.
  * @enable: 1 - Enables the defect correction.
  **/
-void isppreview_enable_dcor(u8 enable)
+void isppreview_enable_dcor(struct isp_prev_device *isp_prev, u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (enable)
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_DCOREN);
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			   ISPPRV_PCR_DCOREN);
 	else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_DCOREN);
 	}
-	ispprev_obj.dcor_en = enable ? 1 : 0;
+	isp_prev->dcor_en = enable ? 1 : 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_enable_dcor);
 
@@ -1082,15 +1095,18 @@
  * isppreview_enable_cfa - Enable/Disable the CFA Interpolation.
  * @enable: 1 - Enables the CFA.
  **/
-void isppreview_enable_cfa(u8 enable)
+void isppreview_enable_cfa(struct isp_prev_device *isp_prev, u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (enable)
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_CFAEN);
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			   ISPPRV_PCR_CFAEN);
 	else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_CFAEN);
 	}
-	ispprev_obj.cfa_en = enable ? 1 : 0;
+	isp_prev->cfa_en = enable ? 1 : 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_enable_cfa);
 
@@ -1099,13 +1115,15 @@
  * @enable: 1 - Bypasses Gamma - 10bit input is cropped to 8MSB.
  *          0 - Goes through Gamma Correction. input and output is 10bit.
  **/
-void isppreview_enable_gammabypass(u8 enable)
+void isppreview_enable_gammabypass(struct isp_prev_device *isp_prev, u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (enable) {
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			   ISPPRV_PCR_GAMMA_BYPASS);
 	} else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_GAMMA_BYPASS);
 	}
 }
@@ -1115,16 +1133,19 @@
  * isppreview_enable_luma_enhancement - Enables/Disables Luminance Enhancement
  * @enable: 1 - Enable the Luminance Enhancement.
  **/
-void isppreview_enable_luma_enhancement(u8 enable)
+void isppreview_enable_luma_enhancement(struct isp_prev_device *isp_prev,
+					u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (enable) {
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			   ISPPRV_PCR_YNENHEN);
 	} else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_YNENHEN);
 	}
-	ispprev_obj.yenh_en = enable ? 1 : 0;
+	isp_prev->yenh_en = enable ? 1 : 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_enable_luma_enhancement);
 
@@ -1132,15 +1153,19 @@
  * isppreview_enable_chroma_suppression - Enables/Disables Chrominance Suppr.
  * @enable: 1 - Enable the Chrominance Suppression.
  **/
-void isppreview_enable_chroma_suppression(u8 enable)
+void isppreview_enable_chroma_suppression(struct isp_prev_device *isp_prev,
+					  u8 enable)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if (enable)
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_SUPEN);
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			   ISPPRV_PCR_SUPEN);
 	else {
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
 			    ~ISPPRV_PCR_SUPEN);
 	}
-	ispprev_obj.csup_en = enable ? 1 : 0;
+	isp_prev->csup_en = enable ? 1 : 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_enable_chroma_suppression);
 
@@ -1151,19 +1176,24 @@
  *
  * Coefficient matrix always with default values.
  **/
-void isppreview_config_whitebalance(struct ispprev_wbal prev_wbal)
+void isppreview_config_whitebalance(struct isp_prev_device *isp_prev,
+				    struct ispprev_wbal prev_wbal)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 val;
 
-	isp_reg_writel(prev_wbal.dgain, OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
+	isp_reg_writel(dev, prev_wbal.dgain, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_WB_DGAIN);
 
 	val = prev_wbal.coef0 << ISPPRV_WBGAIN_COEF0_SHIFT;
 	val |= prev_wbal.coef1 << ISPPRV_WBGAIN_COEF1_SHIFT;
 	val |= prev_wbal.coef2 << ISPPRV_WBGAIN_COEF2_SHIFT;
 	val |= prev_wbal.coef3 << ISPPRV_WBGAIN_COEF3_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_WBGAIN);
 
-	isp_reg_writel(ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
+	isp_reg_writel(dev,
+		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_0_SHIFT |
 		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_1_SHIFT |
 		       ISPPRV_WBSEL_COEF0 << ISPPRV_WBSEL_N0_2_SHIFT |
 		       ISPPRV_WBSEL_COEF1 << ISPPRV_WBSEL_N0_3_SHIFT |
@@ -1190,17 +1220,20 @@
  *
  * Coefficient matrix can be changed.
  **/
-void isppreview_config_whitebalance2(struct prev_white_balance prev_wbal)
+void isppreview_config_whitebalance2(struct isp_prev_device *isp_prev,
+				     struct prev_white_balance prev_wbal)
 {
-	isp_reg_writel(prev_wbal.wb_dgain,
+	struct device *dev = to_device(isp_prev);
+
+	isp_reg_writel(dev, prev_wbal.wb_dgain,
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN);
-	isp_reg_writel(prev_wbal.wb_gain[0] |
+	isp_reg_writel(dev, prev_wbal.wb_gain[0] |
 		       prev_wbal.wb_gain[1] << ISPPRV_WBGAIN_COEF1_SHIFT |
 		       prev_wbal.wb_gain[2] << ISPPRV_WBGAIN_COEF2_SHIFT |
 		       prev_wbal.wb_gain[3] << ISPPRV_WBGAIN_COEF3_SHIFT,
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN);
 
-	isp_reg_writel(
+	isp_reg_writel(dev,
 		prev_wbal.wb_coefmatrix[0][0] << ISPPRV_WBSEL_N0_0_SHIFT |
 		prev_wbal.wb_coefmatrix[0][1] << ISPPRV_WBSEL_N0_1_SHIFT |
 		prev_wbal.wb_coefmatrix[0][2] << ISPPRV_WBSEL_N0_2_SHIFT |
@@ -1226,9 +1259,12 @@
  * @prev_blkadj: Structure containing the black adjustment towards red, green,
  *               blue.
  **/
-void isppreview_config_blkadj(struct ispprev_blkadj prev_blkadj)
+void isppreview_config_blkadj(struct isp_prev_device *isp_prev,
+			      struct ispprev_blkadj prev_blkadj)
 {
-	isp_reg_writel(prev_blkadj.blue |
+	struct device *dev = to_device(isp_prev);
+
+	isp_reg_writel(dev, prev_blkadj.blue |
 		       (prev_blkadj.green << ISPPRV_BLKADJOFF_G_SHIFT) |
 		       (prev_blkadj.red << ISPPRV_BLKADJOFF_R_SHIFT),
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF);
@@ -1240,35 +1276,44 @@
  * @rgb2rgb: Structure containing the rgb to rgb blending matrix and the rgb
  *           offset.
  **/
-void isppreview_config_rgb_blending(struct ispprev_rgbtorgb rgb2rgb)
+void isppreview_config_rgb_blending(struct isp_prev_device *isp_prev,
+				    struct ispprev_rgbtorgb rgb2rgb)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 val = 0;
 
 	val = (rgb2rgb.matrix[0][0] & 0xfff) << ISPPRV_RGB_MAT1_MTX_RR_SHIFT;
 	val |= (rgb2rgb.matrix[0][1] & 0xfff) << ISPPRV_RGB_MAT1_MTX_GR_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_RGB_MAT1);
 
 	val = (rgb2rgb.matrix[0][2] & 0xfff) << ISPPRV_RGB_MAT2_MTX_BR_SHIFT;
 	val |= (rgb2rgb.matrix[1][0] & 0xfff) << ISPPRV_RGB_MAT2_MTX_RG_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_RGB_MAT2);
 
 	val = (rgb2rgb.matrix[1][1] & 0xfff) << ISPPRV_RGB_MAT3_MTX_GG_SHIFT;
 	val |= (rgb2rgb.matrix[1][2] & 0xfff) << ISPPRV_RGB_MAT3_MTX_BG_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_RGB_MAT3);
 
 	val = (rgb2rgb.matrix[2][0] & 0xfff) << ISPPRV_RGB_MAT4_MTX_RB_SHIFT;
 	val |= (rgb2rgb.matrix[2][1] & 0xfff) << ISPPRV_RGB_MAT4_MTX_GB_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_RGB_MAT4);
 
 	val = (rgb2rgb.matrix[2][2] & 0xfff) << ISPPRV_RGB_MAT5_MTX_BB_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_RGB_MAT5);
 
-	val = (rgb2rgb.offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
-	val |= (rgb2rgb.offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1);
+	val = (rgb2rgb.offset[0] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFR_SHIFT;
+	val |= (rgb2rgb.offset[1] & 0x3ff) << ISPPRV_RGB_OFF1_MTX_OFFG_SHIFT;
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_RGB_OFF1);
 
 	val = (rgb2rgb.offset[2] & 0x3ff) << ISPPRV_RGB_OFF2_MTX_OFFB_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_RGB_OFF2);
 }
 EXPORT_SYMBOL_GPL(isppreview_config_rgb_blending);
 
@@ -1277,29 +1322,32 @@
  * @prev_csc: Structure containing the RGB to YCbYCr matrix and the
  *            YCbCr offset.
  **/
-void isppreview_config_rgb_to_ycbcr(struct ispprev_csc prev_csc)
+void isppreview_config_rgb_to_ycbcr(struct isp_prev_device *isp_prev,
+				    struct ispprev_csc prev_csc)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 val = 0;
 
 	val = (prev_csc.matrix[0][0] & 0x3ff) << ISPPRV_CSC0_RY_SHIFT;
 	val |= (prev_csc.matrix[0][1] & 0x3ff) << ISPPRV_CSC0_GY_SHIFT;
 	val |= (prev_csc.matrix[0][2] & 0x3ff) << ISPPRV_CSC0_BY_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0);
 
 	val = (prev_csc.matrix[1][0] & 0x3ff) << ISPPRV_CSC1_RCB_SHIFT;
 	val |= (prev_csc.matrix[1][1] & 0x3ff) << ISPPRV_CSC1_GCB_SHIFT;
 	val |= (prev_csc.matrix[1][2] & 0x3ff) << ISPPRV_CSC1_BCB_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1);
 
 	val = (prev_csc.matrix[2][0] & 0x3ff) << ISPPRV_CSC2_RCR_SHIFT;
 	val |= (prev_csc.matrix[2][1] & 0x3ff) << ISPPRV_CSC2_GCR_SHIFT;
 	val |= (prev_csc.matrix[2][2] & 0x3ff) << ISPPRV_CSC2_BCR_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2);
 
-	val = (prev_csc.offset[0] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
+	val = (prev_csc.offset[0] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
 	val |= (prev_csc.offset[1] & 0xff) << ISPPRV_CSC_OFFSET_CB_SHIFT;
-	val |= (prev_csc.offset[2] & 0xff) << ISPPRV_CSC_OFFSET_Y_SHIFT;
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET);
+	val |= (prev_csc.offset[2] & 0xff) << ISPPRV_CSC_OFFSET_CR_SHIFT;
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_CSC_OFFSET);
 }
 EXPORT_SYMBOL_GPL(isppreview_config_rgb_to_ycbcr);
 
@@ -1307,11 +1355,13 @@
  * isppreview_query_contrast - Query the contrast.
  * @contrast: Pointer to hold the current programmed contrast value.
  **/
-void isppreview_query_contrast(u8 *contrast)
+void isppreview_query_contrast(struct isp_prev_device *isp_prev, u8 *contrast)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 brt_cnt_val = 0;
 
-	brt_cnt_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
+	brt_cnt_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				    ISPPRV_CNT_BRT);
 	*contrast = (brt_cnt_val >> ISPPRV_CNT_BRT_CNT_SHIFT) & 0xff;
 	DPRINTK_ISPPREV(" Current brt cnt value in hw is %x\n", brt_cnt_val);
 }
@@ -1323,9 +1373,9 @@
  *
  * Value should be programmed before enabling the module.
  **/
-void isppreview_update_contrast(u8 *contrast)
+void isppreview_update_contrast(struct isp_prev_device *isp_prev, u8 *contrast)
 {
-	ispprev_obj.contrast = *contrast;
+	isp_prev->contrast = *contrast;
 }
 EXPORT_SYMBOL_GPL(isppreview_update_contrast);
 
@@ -1335,14 +1385,17 @@
  *
  * Value should be programmed before enabling the module.
  **/
-void isppreview_config_contrast(u8 contrast)
+void isppreview_config_contrast(struct isp_prev_device *isp_prev, u8 contrast)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 brt_cnt_val = 0;
 
-	brt_cnt_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
+	brt_cnt_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				    ISPPRV_CNT_BRT);
 	brt_cnt_val &= ~(0xff << ISPPRV_CNT_BRT_CNT_SHIFT);
 	contrast &= 0xff;
-	isp_reg_writel(brt_cnt_val | contrast << ISPPRV_CNT_BRT_CNT_SHIFT,
+	isp_reg_writel(dev,
+		       brt_cnt_val | contrast << ISPPRV_CNT_BRT_CNT_SHIFT,
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
 }
 EXPORT_SYMBOL_GPL(isppreview_config_contrast);
@@ -1364,9 +1417,10 @@
  * @brightness: Pointer to hold the current programmed brightness value.
  *
  **/
-void isppreview_update_brightness(u8 *brightness)
+void isppreview_update_brightness(struct isp_prev_device *isp_prev,
+				  u8 *brightness)
 {
-	ispprev_obj.brightness = *brightness;
+	isp_prev->brightness = *brightness;
 }
 EXPORT_SYMBOL_GPL(isppreview_update_brightness);
 
@@ -1374,15 +1428,19 @@
  * isppreview_config_brightness - Configures the brightness.
  * @contrast: 8bitvalue in U8Q0 format.
  **/
-void isppreview_config_brightness(u8 brightness)
+void isppreview_config_brightness(struct isp_prev_device *isp_prev,
+				  u8 brightness)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 brt_cnt_val = 0;
 
 	DPRINTK_ISPPREV("\tConfiguring brightness in ISP: %d\n", brightness);
-	brt_cnt_val = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
+	brt_cnt_val = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				    ISPPRV_CNT_BRT);
 	brt_cnt_val &= ~(0xff << ISPPRV_CNT_BRT_BRT_SHIFT);
 	brightness &= 0xff;
-	isp_reg_writel(brt_cnt_val | brightness << ISPPRV_CNT_BRT_BRT_SHIFT,
+	isp_reg_writel(dev,
+		       brt_cnt_val | brightness << ISPPRV_CNT_BRT_BRT_SHIFT,
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
 }
 EXPORT_SYMBOL_GPL(isppreview_config_brightness);
@@ -1391,9 +1449,13 @@
  * isppreview_query_brightness - Query the brightness.
  * @brightness: Pointer to hold the current programmed brightness value.
  **/
-void isppreview_query_brightness(u8 *brightness)
+void isppreview_query_brightness(struct isp_prev_device *isp_prev,
+				 u8 *brightness)
 {
-	*brightness = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT);
+	struct device *dev = to_device(isp_prev);
+
+	*brightness = isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				    ISPPRV_CNT_BRT);
 }
 EXPORT_SYMBOL_GPL(isppreview_query_brightness);
 
@@ -1413,10 +1475,10 @@
  * isppreview_set_color - Sets the color effect.
  * @mode: Indicates the required color effect.
  **/
-void isppreview_set_color(u8 *mode)
+void isppreview_set_color(struct isp_prev_device *isp_prev, u8 *mode)
 {
-	ispprev_obj.color = *mode;
-	update_color_matrix = 1;
+	isp_prev->color = *mode;
+	isp_prev->update_color_matrix = 1;
 }
 EXPORT_SYMBOL_GPL(isppreview_set_color);
 
@@ -1424,9 +1486,9 @@
  * isppreview_get_color - Gets the current color effect.
  * @mode: Indicates the current color effect.
  **/
-void isppreview_get_color(u8 *mode)
+void isppreview_get_color(struct isp_prev_device *isp_prev, u8 *mode)
 {
-	*mode = ispprev_obj.color;
+	*mode = isp_prev->color;
 }
 EXPORT_SYMBOL_GPL(isppreview_get_color);
 
@@ -1434,9 +1496,13 @@
  * isppreview_config_yc_range - Configures the max and min Y and C values.
  * @yclimit: Structure containing the range of Y and C values.
  **/
-void isppreview_config_yc_range(struct ispprev_yclimit yclimit)
+void isppreview_config_yc_range(struct isp_prev_device *isp_prev,
+				struct ispprev_yclimit yclimit)
 {
-	isp_reg_writel(yclimit.maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
+	struct device *dev = to_device(isp_prev);
+
+	isp_reg_writel(dev,
+		       yclimit.maxC << ISPPRV_SETUP_YC_MAXC_SHIFT |
 		       yclimit.maxY << ISPPRV_SETUP_YC_MAXY_SHIFT |
 		       yclimit.minC << ISPPRV_SETUP_YC_MINC_SHIFT |
 		       yclimit.minY << ISPPRV_SETUP_YC_MINY_SHIFT,
@@ -1454,18 +1520,19 @@
  * Calculates the number of pixels cropped in the submodules that are enabled,
  * Fills up the output width height variables in the isp_prev structure.
  **/
-int isppreview_try_size(u32 input_w, u32 input_h, u32 *output_w, u32 *output_h)
+int isppreview_try_pipeline(struct isp_prev_device *isp_prev,
+			    struct isp_pipeline *pipe)
 {
-	u32 prevout_w = input_w;
-	u32 prevout_h = input_h;
+	struct device *dev = to_device(isp_prev);
 	u32 div = 0;
 	int max_out;
+	unsigned int wanted_width;
+	unsigned int wanted_height;
+	unsigned int left_boundary;
+	unsigned int right_boundary;
 
-	ispprev_obj.previn_w = input_w;
-	ispprev_obj.previn_h = input_h;
-
-	if (input_w < 32 || input_h < 32) {
-		printk(KERN_ERR "ISP_ERR : preview does not support "
+	if (pipe->ccdc_out_w_img < 32 || pipe->ccdc_out_h < 32) {
+		dev_err(dev, "preview does not support "
 		       "width < 16 or height < 32 \n");
 		return -EINVAL;
 	}
@@ -1474,75 +1541,84 @@
 	else
 		max_out = ISPPRV_MAXOUTPUT_WIDTH_ES2;
 
-	ispprev_obj.fmtavg = 0;
+	wanted_width = pipe->prv_out_w;
+	wanted_height = pipe->prv_out_h;
+	pipe->prv_out_w = pipe->ccdc_out_w;
+	pipe->prv_out_h = pipe->ccdc_out_h;
+	pipe->prv_out_w_img = pipe->ccdc_out_w_img;
+	pipe->prv_out_h_img = pipe->ccdc_out_h;
 
-	if (input_w > max_out) {
-		div = (input_w/max_out);
-		if (div >= 2 && div < 4) {
-			ispprev_obj.fmtavg = 1;
-			prevout_w /= 2;
-		} else if (div >= 4 && div < 8) {
-			ispprev_obj.fmtavg = 2;
-			prevout_w /= 4;
-		} else if (div >= 8) {
-			ispprev_obj.fmtavg = 3;
-			prevout_w /= 8;
-		}
-	}
-
-	if (ispprev_obj.hmed_en)
-		prevout_w -= 4;
-	if (ispprev_obj.nf_en) {
-		prevout_w -= 4;
-		prevout_h -= 4;
-	}
-	if (ispprev_obj.cfa_en) {
-		switch (ispprev_obj.cfafmt) {
-		case CFAFMT_BAYER:
-		case CFAFMT_SONYVGA:
-			prevout_w -= 4;
-			prevout_h -= 4;
-			break;
-		case CFAFMT_RGBFOVEON:
-		case CFAFMT_RRGGBBFOVEON:
-		case CFAFMT_DNSPL:
-		case CFAFMT_HONEYCOMB:
-			prevout_h -= 2;
-			break;
-		};
-	}
-	if (ispprev_obj.yenh_en || ispprev_obj.csup_en)
-		prevout_w -= 2;
+/* 	if (isp_prev->hmed_en) */
+	pipe->prv_out_w_img -= 4;
+/* 	if (isp_prev->nf_en) */
+	pipe->prv_out_w_img -= 4;
+	pipe->prv_out_h_img -= 4;
+/* 	if (isp_prev->cfa_en) */
+	switch (isp_prev->cfafmt) {
+	case CFAFMT_BAYER:
+	case CFAFMT_SONYVGA:
+		pipe->prv_out_w_img -= 4;
+		pipe->prv_out_h_img -= 4;
+		break;
+	case CFAFMT_RGBFOVEON:
+	case CFAFMT_RRGGBBFOVEON:
+	case CFAFMT_DNSPL:
+	case CFAFMT_HONEYCOMB:
+		pipe->prv_out_h_img -= 2;
+		break;
+	};
+/* 	if (isp_prev->yenh_en || isp_prev->csup_en) */
+	pipe->prv_out_w_img -= 2;
 
 	/* Start at the correct row/column by skipping
 	 * a Sensor specific amount.
 	 */
-	prevout_w -= ispprev_obj.sph;
-	prevout_h -= ispprev_obj.slv;
+	pipe->prv_out_w_img -= isp_prev->sph;
+	pipe->prv_out_h_img -= isp_prev->slv;
 
-
-	if (prevout_w % 2)
-		prevout_w -= 1;
-
-	if (ispprev_obj.prev_outfmt == PREVIEW_MEM) {
-		if (((prevout_w * 2) & ISP_32B_BOUNDARY_OFFSET) !=
-		    (prevout_w * 2)) {
-			prevout_w = ((prevout_w * 2) &
-				     ISP_32B_BOUNDARY_OFFSET) / 2;
-		}
+	div = DIV_ROUND_UP(pipe->ccdc_out_w_img, max_out);
+	if (div == 1) {
+		pipe->prv_fmt_avg = 0;
+	} else if (div <= 2) {
+		pipe->prv_fmt_avg = 1;
+		pipe->prv_out_w_img /= 2;
+	} else if (div <= 4) {
+		pipe->prv_fmt_avg = 2;
+		pipe->prv_out_w_img /= 4;
+	} else if (div <= 8) {
+		pipe->prv_fmt_avg = 3;
+		pipe->prv_out_w_img /= 8;
+	} else {
+		return -EINVAL;
 	}
-	*output_w = prevout_w;
-	ispprev_obj.prevout_w = prevout_w;
-	*output_h = prevout_h;
-	ispprev_obj.prevout_h = prevout_h;
+
+	/* output width must be even */
+	pipe->prv_out_w_img &= ~1;
+
+	if (pipe->modules == (OMAP_ISP_CCDC | OMAP_ISP_PREVIEW)) {
+		left_boundary = ALIGN(pipe->prv_out_w_img - 0x20, 0x20);
+		right_boundary = ALIGN(pipe->prv_out_w_img, 0x20);
+		if (wanted_width >= left_boundary &&
+				wanted_width <= right_boundary){
+			pipe->prv_out_w = ALIGN(wanted_width, 0x20);
+			pipe->prv_out_h = wanted_height;
+		} else {
+			pipe->prv_out_w = right_boundary;
+			pipe->prv_out_h = pipe->prv_out_h_img;
+		}
+	} else {
+		/* FIXME: This doesn't apply for prv -> rsz. */
+		pipe->prv_out_w = ALIGN(pipe->prv_out_w, 0x20);
+	}
+
 	return 0;
 }
-EXPORT_SYMBOL_GPL(isppreview_try_size);
+EXPORT_SYMBOL_GPL(isppreview_try_pipeline);
 
 /**
  * isppreview_config_size - Sets the size of ISP preview output.
- * @input_w: input width for the preview in number of pixels per line
- * @input_h: input height for the preview in number of lines
+ * @pipe->ccdc_out_w: input width for the preview in number of pixels per line
+ * @pipe->ccdc_out_h: input height for the preview in number of lines
  * @output_w: output width from the preview in number of pixels per line
  * @output_h: output height for the preview in number of lines
  *
@@ -1550,57 +1626,68 @@
  * HORZ/VERT_INFO. Configures PRV_AVE if needed for downsampling as calculated
  * in trysize.
  **/
-int isppreview_config_size(u32 input_w, u32 input_h, u32 output_w, u32 output_h)
+int isppreview_s_pipeline(struct isp_prev_device *isp_prev,
+			  struct isp_pipeline *pipe)
 {
+	struct device *dev = to_device(isp_prev);
 	u32 prevsdroff;
+	int rval;
 
-	if ((output_w != ispprev_obj.prevout_w) ||
-	    (output_h != ispprev_obj.prevout_h)) {
-		printk(KERN_ERR "ISP_ERR : isppreview_try_size should "
-		       "be called before config size\n");
-		return -EINVAL;
-	}
+	rval = isppreview_config_datapath(isp_prev, pipe);
+	if (rval)
+		return rval;
 
-	isp_reg_writel((ispprev_obj.sph << ISPPRV_HORZ_INFO_SPH_SHIFT) |
-		       (ispprev_obj.previn_w - 1),
+	isp_reg_writel(dev,
+		       (isp_prev->sph << ISPPRV_HORZ_INFO_SPH_SHIFT) |
+		       (pipe->ccdc_out_w - 1),
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
-	isp_reg_writel((ispprev_obj.slv << ISPPRV_VERT_INFO_SLV_SHIFT) |
-		       (ispprev_obj.previn_h - 1),
+	isp_reg_writel(dev,
+		       (isp_prev->slv << ISPPRV_VERT_INFO_SLV_SHIFT) |
+		       (pipe->ccdc_out_h - 1),
 		       OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
 
-	if (ispprev_obj.cfafmt == CFAFMT_BAYER)
-		isp_reg_writel(ISPPRV_AVE_EVENDIST_2 <<
+	if (isp_prev->cfafmt == CFAFMT_BAYER)
+		isp_reg_writel(dev,
+			       ISPPRV_AVE_EVENDIST_2 <<
 			       ISPPRV_AVE_EVENDIST_SHIFT |
 			       ISPPRV_AVE_ODDDIST_2 <<
 			       ISPPRV_AVE_ODDDIST_SHIFT |
-			       ispprev_obj.fmtavg,
+			       pipe->prv_fmt_avg,
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
 
-	if (ispprev_obj.prev_outfmt == PREVIEW_MEM) {
-		prevsdroff = ispprev_obj.prevout_w * 2;
+	if (pipe->prv_out == PREVIEW_MEM) {
+		prevsdroff = pipe->prv_out_w * ISP_BYTES_PER_PIXEL;
 		if ((prevsdroff & ISP_32B_BOUNDARY_OFFSET) != prevsdroff) {
 			DPRINTK_ISPPREV("ISP_WARN: Preview output buffer line"
 					" size is truncated"
 					" to 32byte boundary\n");
 			prevsdroff &= ISP_32B_BOUNDARY_BUF ;
 		}
-		isppreview_config_outlineoffset(prevsdroff);
+		isppreview_config_outlineoffset(isp_prev, prevsdroff);
 	}
+
+	if (pipe->pix.pixelformat == V4L2_PIX_FMT_UYVY)
+		isppreview_config_ycpos(isp_prev, YCPOS_YCrYCb);
+	else
+		isppreview_config_ycpos(isp_prev, YCPOS_CrYCbY);
+
 	return 0;
 }
-EXPORT_SYMBOL_GPL(isppreview_config_size);
+EXPORT_SYMBOL_GPL(isppreview_s_pipeline);
 
 /**
  * isppreview_config_inlineoffset - Configures the Read address line offset.
  * @offset: Line Offset for the input image.
  **/
-int isppreview_config_inlineoffset(u32 offset)
+int isppreview_config_inlineoffset(struct isp_prev_device *isp_prev, u32 offset)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if ((offset & ISP_32B_BOUNDARY_OFFSET) == offset) {
-		isp_reg_writel(offset & 0xffff,
+		isp_reg_writel(dev, offset & 0xffff,
 			       OMAP3_ISP_IOMEM_PREV, ISPPRV_RADR_OFFSET);
 	} else {
-		printk(KERN_ERR "ISP_ERR : Offset should be in 32 byte "
+		dev_err(dev, "preview: Offset should be in 32 byte "
 		       "boundary\n");
 		return -EINVAL;
 	}
@@ -1614,12 +1701,15 @@
  *
  * Configures the memory address from which the input frame is to be read.
  **/
-int isppreview_set_inaddr(u32 addr)
+int isppreview_set_inaddr(struct isp_prev_device *isp_prev, u32 addr)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if ((addr & ISP_32B_BOUNDARY_BUF) == addr)
-		isp_reg_writel(addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
+		isp_reg_writel(dev, addr,
+			       OMAP3_ISP_IOMEM_PREV, ISPPRV_RSDR_ADDR);
 	else {
-		printk(KERN_ERR "ISP_ERR: Address should be in 32 byte "
+		dev_err(dev, "preview: Address should be in 32 byte "
 		       "boundary\n");
 		return -EINVAL;
 	}
@@ -1631,14 +1721,17 @@
  * isppreview_config_outlineoffset - Configures the Write address line offset.
  * @offset: Line Offset for the preview output.
  **/
-int isppreview_config_outlineoffset(u32 offset)
+int isppreview_config_outlineoffset(struct isp_prev_device *isp_prev,
+				    u32 offset)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if ((offset & ISP_32B_BOUNDARY_OFFSET) != offset) {
-		printk(KERN_ERR "ISP_ERR : Offset should be in 32 byte "
+		dev_err(dev, "preview: Offset should be in 32 byte "
 		       "boundary\n");
 		return -EINVAL;
 	}
-	isp_reg_writel(offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+	isp_reg_writel(dev, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
 		       ISPPRV_WADD_OFFSET);
 	return 0;
 }
@@ -1650,14 +1743,17 @@
  *
  * Configures the memory address to which the output frame is written.
  **/
-int isppreview_set_outaddr(u32 addr)
+int isppreview_set_outaddr(struct isp_prev_device *isp_prev, u32 addr)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if ((addr & ISP_32B_BOUNDARY_BUF) != addr) {
-		printk(KERN_ERR "ISP_ERR: Address should be in 32 byte "
+		dev_err(dev, "preview: Address should be in 32 byte "
 		       "boundary\n");
 		return -EINVAL;
 	}
-	isp_reg_writel(addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
+	isp_reg_writel(dev, addr, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_WSDR_ADDR);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_set_outaddr);
@@ -1666,14 +1762,17 @@
  * isppreview_config_darklineoffset - Sets the Dark frame address line offset.
  * @offset: Line Offset for the Darkframe.
  **/
-int isppreview_config_darklineoffset(u32 offset)
+int isppreview_config_darklineoffset(struct isp_prev_device *isp_prev,
+				     u32 offset)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if ((offset & ISP_32B_BOUNDARY_OFFSET) != offset) {
-		printk(KERN_ERR "ISP_ERR : Offset should be in 32 byte "
+		dev_err(dev, "preview: Offset should be in 32 byte "
 		       "boundary\n");
 		return -EINVAL;
 	}
-	isp_reg_writel(offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
+	isp_reg_writel(dev, offset & 0xffff, OMAP3_ISP_IOMEM_PREV,
 		       ISPPRV_DRKF_OFFSET);
 	return 0;
 }
@@ -1683,96 +1782,71 @@
  * isppreview_set_darkaddr - Sets the memory address to store Dark frame.
  * @addr: 32bit memory address aligned on 32 bit boundary.
  **/
-int isppreview_set_darkaddr(u32 addr)
+int isppreview_set_darkaddr(struct isp_prev_device *isp_prev, u32 addr)
 {
+	struct device *dev = to_device(isp_prev);
+
 	if ((addr & ISP_32B_BOUNDARY_BUF) != addr) {
-		printk(KERN_ERR "ISP_ERR : Address should be in 32 byte "
+		dev_err(dev, "preview: Address should be in 32 byte "
 		       "boundary\n");
 		return -EINVAL;
 	}
-	isp_reg_writel(addr, OMAP3_ISP_IOMEM_PREV, ISPPRV_DSDR_ADDR);
+	isp_reg_writel(dev, addr, OMAP3_ISP_IOMEM_PREV,
+		       ISPPRV_DSDR_ADDR);
 	return 0;
 }
 EXPORT_SYMBOL_GPL(isppreview_set_darkaddr);
 
-void __isppreview_enable(int enable)
-{
-	if (enable)
-		isp_reg_or(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ISPPRV_PCR_EN);
-	else
-		isp_reg_and(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR, ~ISPPRV_PCR_EN);
-}
-
 /**
  * isppreview_enable - Enables the Preview module.
  * @enable: 1 - Enables the preview module.
  *
  * Client should configure all the sub modules in Preview before this.
  **/
-void isppreview_enable(int enable)
+void isppreview_enable(struct isp_prev_device *isp_prev, int enable)
 {
-	__isppreview_enable(enable);
-	ispprev_obj.pm_state = enable;
+	struct device *dev = to_device(isp_prev);
+
+	if (enable)
+		isp_reg_or(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			   ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT);
+	else
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR,
+			    ~(ISPPRV_PCR_EN | ISPPRV_PCR_ONESHOT));
 }
 EXPORT_SYMBOL_GPL(isppreview_enable);
 
 /**
- * isppreview_suspend - Suspend Preview module.
- **/
-void isppreview_suspend(void)
-{
-	if (ispprev_obj.pm_state)
-		__isppreview_enable(0);
-}
-EXPORT_SYMBOL_GPL(isppreview_suspend);
-
-/**
- * isppreview_resume - Resume Preview module.
- **/
-void isppreview_resume(void)
-{
-	if (ispprev_obj.pm_state)
-		__isppreview_enable(1);
-}
-EXPORT_SYMBOL_GPL(isppreview_resume);
-
-
-/**
  * isppreview_busy - Gets busy state of preview module.
  **/
-int isppreview_busy(void)
+int isppreview_busy(struct isp_prev_device *isp_prev)
 {
-	return isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR) &
-		ISPPRV_PCR_BUSY;
+	struct device *dev = to_device(isp_prev);
+
+	return isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR)
+		& ISPPRV_PCR_BUSY;
 }
 EXPORT_SYMBOL_GPL(isppreview_busy);
 
 /**
- * isppreview_get_config - Gets parameters of preview module.
- **/
-struct prev_params *isppreview_get_config(void)
-{
-	return prev_config_params;
-}
-EXPORT_SYMBOL_GPL(isppreview_get_config);
-
-/**
  * isppreview_save_context - Saves the values of the preview module registers.
  **/
-void isppreview_save_context(void)
+void isppreview_save_context(struct device *dev)
 {
 	DPRINTK_ISPPREV("Saving context\n");
-	isp_save_context(ispprev_reg_list);
+	isp_save_context(dev, ispprev_reg_list);
+	/* Avoid unwanted enabling when restoring the context. */
+	ispprev_reg_list[0].val &= ~ISPPRV_PCR_EN;
 }
 EXPORT_SYMBOL_GPL(isppreview_save_context);
 
 /**
  * isppreview_restore_context - Restores the values of preview module registers
  **/
-void isppreview_restore_context(void)
+void isppreview_restore_context(struct device *dev)
 {
 	DPRINTK_ISPPREV("Restoring context\n");
-	isp_restore_context(ispprev_reg_list);
+	isp_restore_context(dev, ispprev_reg_list);
 }
 EXPORT_SYMBOL_GPL(isppreview_restore_context);
 
@@ -1781,119 +1855,137 @@
  *
  * Also prints other debug information stored in the preview moduel.
  **/
-void isppreview_print_status(void)
+void isppreview_print_status(struct isp_prev_device *isp_prev,
+			     struct isp_pipeline *pipe)
 {
-	DPRINTK_ISPPREV("Module in use =%d\n", ispprev_obj.prev_inuse);
+#ifdef OMAP_ISPPREV_DEBUG
+	struct device *dev = to_device(isp_prev);
+#endif
+
 	DPRINTK_ISPPREV("Preview Input format =%d, Output Format =%d\n",
-			ispprev_obj.prev_inpfmt,
-			ispprev_obj.prev_outfmt);
-	DPRINTK_ISPPREV("Accepted Preview Input (width = %d,Height = %d)\n",
-			ispprev_obj.previn_w,
-			ispprev_obj.previn_h);
+			pipe->prv_in, pipe->prv_out);
+	DPRINTK_ISPPREV("Accepted CCDC Output (width = %d,Height = %d)\n",
+			pipe->ccdc_out_w,
+			pipe->ccdc_out_h);
 	DPRINTK_ISPPREV("Accepted Preview Output (width = %d,Height = %d)\n",
-			ispprev_obj.prevout_w,
-			ispprev_obj.prevout_h);
+			pipe->prv_out_w,
+			pipe->prv_out_h);
 	DPRINTK_ISPPREV("###ISP_CTRL in preview =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_CTRL));
 	DPRINTK_ISPPREV("###ISP_IRQ0ENABLE in preview =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_IRQ0ENABLE));
 	DPRINTK_ISPPREV("###ISP_IRQ0STATUS in preview =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_MAIN,
+				      ISP_IRQ0STATUS));
 	DPRINTK_ISPPREV("###PRV PCR =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_PCR));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_PCR));
 	DPRINTK_ISPPREV("###PRV HORZ_INFO =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_HORZ_INFO));
 	DPRINTK_ISPPREV("###PRV VERT_INFO =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_VERT_INFO));
 	DPRINTK_ISPPREV("###PRV WSDR_ADDR =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_WSDR_ADDR));
 	DPRINTK_ISPPREV("###PRV WADD_OFFSET =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV,
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
 				      ISPPRV_WADD_OFFSET));
 	DPRINTK_ISPPREV("###PRV AVE =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_AVE));
 	DPRINTK_ISPPREV("###PRV HMED =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_HMED));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_HMED));
 	DPRINTK_ISPPREV("###PRV NF =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_NF));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_NF));
 	DPRINTK_ISPPREV("###PRV WB_DGAIN =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WB_DGAIN));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_WB_DGAIN));
 	DPRINTK_ISPPREV("###PRV WBGAIN =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WBGAIN));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_WBGAIN));
 	DPRINTK_ISPPREV("###PRV WBSEL =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WBSEL));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_WBSEL));
 	DPRINTK_ISPPREV("###PRV CFA =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CFA));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_CFA));
 	DPRINTK_ISPPREV("###PRV BLKADJOFF =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_BLKADJOFF));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_BLKADJOFF));
 	DPRINTK_ISPPREV("###PRV RGB_MAT1 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT1));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_RGB_MAT1));
 	DPRINTK_ISPPREV("###PRV RGB_MAT2 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT2));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_RGB_MAT2));
 	DPRINTK_ISPPREV("###PRV RGB_MAT3 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT3));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_RGB_MAT3));
 	DPRINTK_ISPPREV("###PRV RGB_MAT4 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT4));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_RGB_MAT4));
 	DPRINTK_ISPPREV("###PRV RGB_MAT5 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_MAT5));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_RGB_MAT5));
 	DPRINTK_ISPPREV("###PRV RGB_OFF1 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF1));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_RGB_OFF1));
 	DPRINTK_ISPPREV("###PRV RGB_OFF2 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_RGB_OFF2));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_RGB_OFF2));
 	DPRINTK_ISPPREV("###PRV CSC0 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC0));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_CSC0));
 	DPRINTK_ISPPREV("###PRV CSC1 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC1));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_CSC1));
 	DPRINTK_ISPPREV("###PRV CSC2 =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC2));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_CSC2));
 	DPRINTK_ISPPREV("###PRV CSC_OFFSET =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSC_OFFSET));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_CSC_OFFSET));
 	DPRINTK_ISPPREV("###PRV CNT_BRT =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CNT_BRT));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_CNT_BRT));
 	DPRINTK_ISPPREV("###PRV CSUP =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_CSUP));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_CSUP));
 	DPRINTK_ISPPREV("###PRV SETUP_YC =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_SETUP_YC));
+			isp_reg_readl(dev, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_SETUP_YC));
 }
 EXPORT_SYMBOL_GPL(isppreview_print_status);
 
 /**
  * isp_preview_init - Module Initialization.
  **/
-int __init isp_preview_init(void)
+int __init isp_preview_init(struct device *dev)
 {
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_prev_device *isp_prev = &isp->isp_prev;
+	struct prev_params *params = &isp_prev->params;
 	int i = 0;
 
-	prev_config_params = kmalloc(sizeof(*prev_config_params), GFP_KERNEL);
-	if (!prev_config_params) {
-		printk(KERN_ERR "Can't get memory for isp_preview params!\n");
-		return -ENOMEM;
-	}
-
-	/* Dynamically allocate luma table */
-	prev_config_params->ytable = kmalloc(ISPPRV_YENH_TBL_SIZE*sizeof(u32),
-					GFP_KERNEL);
-	if (!prev_config_params->ytable) {
-		printk(KERN_ERR "Can't get memory for preview luna table!\n");
-		kfree(prev_config_params);
-		return -ENOMEM;
-	}
-
-	params = prev_config_params;
-	ispprev_obj.prev_inuse = 0;
-	mutex_init(&ispprev_obj.ispprev_mutex);
-
 	/* Init values */
-	ispprev_obj.sph = 2;
-	ispprev_obj.slv = 0;
-	ispprev_obj.color = V4L2_COLORFX_NONE;
-	ispprev_obj.contrast = ISPPRV_CONTRAST_DEF;
+	isp_prev->update_color_matrix = 0;
+	isp_prev->update_rgb_blending = 0;
+	isp_prev->update_rgb_to_ycbcr = 0;
+	isp_prev->sph = 2;
+	isp_prev->slv = 0;
+	isp_prev->color = V4L2_COLORFX_NONE;
+	isp_prev->contrast = ISPPRV_CONTRAST_DEF;
 	params->contrast = ISPPRV_CONTRAST_DEF;
-	ispprev_obj.brightness = ISPPRV_BRIGHT_DEF;
+	isp_prev->brightness = ISPPRV_BRIGHT_DEF;
 	params->brightness = ISPPRV_BRIGHT_DEF;
 	params->average = NO_AVE;
 	params->lens_shading_shift = 0;
-	params->pix_fmt = YCPOS_YCrYCb;
 	params->cfa.cfafmt = CFAFMT_BAYER;
 	params->cfa.cfa_table = cfa_coef_table;
 	params->cfa.cfa_gradthrs_horz = FLR_CFA_GRADTHRS_HORZ;
@@ -1901,7 +1993,7 @@
 	params->csup.gain = FLR_CSUP_GAIN;
 	params->csup.thres = FLR_CSUP_THRES;
 	params->csup.hypf_en = 0;
-	isppreview_set_luma_enhancement(luma_enhance_table);
+	params->ytable = luma_enhance_table;
 	params->nf.spread = FLR_NF_STRGTH;
 	memcpy(params->nf.table, noise_filter_table, sizeof(params->nf.table));
 	params->dcor.couplet_mode_en = 1;
@@ -1926,7 +2018,7 @@
 	params->blk_adj.green = FLR_BLKADJ_GREEN;
 	params->blk_adj.blue = FLR_BLKADJ_BLUE;
 	params->rgb2rgb = flr_rgb2rgb;
-	params->rgb2ycbcr = flr_prev_csc[ispprev_obj.color];
+	params->rgb2ycbcr = flr_prev_csc[isp_prev->color];
 
 	params->features = PREV_CFA | PREV_DEFECT_COR | PREV_NOISE_FILTER;
 	params->features &= ~(PREV_AVERAGER | PREV_INVERSE_ALAW |
@@ -1937,14 +2029,8 @@
 			      PREV_DARK_FRAME_CAPTURE |
 			      PREV_CHROMA_SUPPRESS |
 			      PREV_LUMA_ENHANCE);
-	return 0;
-}
 
-/**
- * isp_preview_cleanup - Module Cleanup.
- **/
-void isp_preview_cleanup(void)
-{
-	kfree(prev_config_params->ytable);
-	kfree(prev_config_params);
+	spin_lock_init(&isp_prev->lock);
+
+	return 0;
 }
diff --git a/drivers/media/video/isp/isppreview.h b/drivers/media/video/isp/isppreview.h
index eb7d92a..2ea1aba 100644
--- a/drivers/media/video/isp/isppreview.h
+++ b/drivers/media/video/isp/isppreview.h
@@ -162,7 +162,6 @@
 /**
  * struct prev_params - Structure for all configuration
  * @features: Set of features enabled.
- * @pix_fmt: Output pixel format.
  * @cfa: CFA coefficients.
  * @csup: Chroma suppression coefficients.
  * @ytable: Pointer to Luma enhancement coefficients.
@@ -212,6 +211,8 @@
  * @red_gamma: Pointer to red gamma correction table.
  * @green_gamma: Pointer to green gamma correction table.
  * @blue_gamma: Pointer to blue gamma correction table.
+ * @prev_cfa: Pointer to color filter array configuration.
+ * @prev_wbal: Pointer to colour and digital gain configuration.
  */
 struct isptables_update {
 	u16 update;
@@ -221,136 +222,197 @@
 	u32 *red_gamma;
 	u32 *green_gamma;
 	u32 *blue_gamma;
+	struct ispprev_cfa *prev_cfa;
+	struct ispprev_wbal *prev_wbal;
 };
 
-void isppreview_config_shadow_registers(void);
+/**
+ * struct isp_prev_device - Structure for storing ISP Preview module information
+ * @prevout_w: Preview output width.
+ * @prevout_h: Preview output height.
+ * @previn_w: Preview input width.
+ * @previn_h: Preview input height.
+ * @prev_inpfmt: Preview input format.
+ * @prev_outfmt: Preview output format.
+ * @hmed_en: Horizontal median filter enable.
+ * @nf_en: Noise filter enable.
+ * @dcor_en: Defect correction enable.
+ * @cfa_en: Color Filter Array (CFA) interpolation enable.
+ * @csup_en: Chrominance suppression enable.
+ * @yenh_en: Luma enhancement enable.
+ * @fmtavg: Number of horizontal pixels to average in input formatter. The
+ *          input width should be a multiple of this number.
+ * @brightness: Brightness in preview module.
+ * @contrast: Contrast in preview module.
+ * @color: Color effect in preview module.
+ * @cfafmt: Color Filter Array (CFA) Format.
+ * @wbal_update: Update digital and colour gains in Previewer
+ *
+ * This structure is used to store the OMAP ISP Preview module Information.
+ */
+struct isp_prev_device {
+	int update_color_matrix;
+	u8 update_rgb_blending;
+	u8 update_rgb_to_ycbcr;
+	u8 hmed_en;
+	u8 nf_en;
+	u8 dcor_en;
+	u8 cfa_en;
+	u8 csup_en;
+	u8 yenh_en;
+	u8 rg_update;
+	u8 gg_update;
+	u8 bg_update;
+	u8 cfa_update;
+	u8 nf_enable;
+	u8 nf_update;
+	u8 wbal_update;
+	u8 fmtavg;
+	u8 brightness;
+	u8 contrast;
+	enum v4l2_colorfx color;
+	enum cfa_fmt cfafmt;
+	struct ispprev_nf prev_nf_t;
+	struct prev_params params;
+	int shadow_update;
+	u32 sph;
+	u32 slv;
+	spinlock_t lock;
+};
 
-int isppreview_request(void);
+void isppreview_config_shadow_registers(struct isp_prev_device *isp_prev);
 
-int isppreview_free(void);
+int isppreview_request(struct isp_prev_device *isp_prev);
 
-int isppreview_config_datapath(enum preview_input input,
-			       enum preview_output output);
+void isppreview_free(struct isp_prev_device *isp_prev);
 
-void isppreview_config_ycpos(enum preview_ycpos_mode mode);
+int isppreview_config_datapath(struct isp_prev_device *isp_prev,
+			       struct isp_pipeline *pipe);
 
-void isppreview_config_averager(u8 average);
+void isppreview_config_ycpos(struct isp_prev_device *isp_prev,
+			     enum preview_ycpos_mode mode);
 
-void isppreview_enable_invalaw(u8 enable);
+void isppreview_config_averager(struct isp_prev_device *isp_prev, u8 average);
 
-void isppreview_enable_drkframe(u8 enable);
+void isppreview_enable_invalaw(struct isp_prev_device *isp_prev, u8 enable);
 
-void isppreview_enable_shadcomp(u8 enable);
+void isppreview_enable_drkframe(struct isp_prev_device *isp_prev, u8 enable);
 
-void isppreview_config_drkf_shadcomp(u8 scomp_shtval);
+void isppreview_enable_shadcomp(struct isp_prev_device *isp_prev, u8 enable);
 
-void isppreview_enable_gammabypass(u8 enable);
+void isppreview_config_drkf_shadcomp(struct isp_prev_device *isp_prev,
+				     u8 scomp_shtval);
 
-void isppreview_enable_hmed(u8 enable);
+void isppreview_enable_gammabypass(struct isp_prev_device *isp_prev, u8 enable);
 
-void isppreview_config_hmed(struct ispprev_hmed);
+void isppreview_enable_hmed(struct isp_prev_device *isp_prev, u8 enable);
 
-void isppreview_enable_noisefilter(u8 enable);
+void isppreview_config_hmed(struct isp_prev_device *isp_prev,
+			    struct ispprev_hmed);
 
-void isppreview_config_noisefilter(struct ispprev_nf prev_nf);
+void isppreview_enable_noisefilter(struct isp_prev_device *isp_prev, u8 enable);
 
-void isppreview_enable_dcor(u8 enable);
+void isppreview_config_noisefilter(struct isp_prev_device *isp_prev,
+				   struct ispprev_nf prev_nf);
 
-void isppreview_config_dcor(struct ispprev_dcor prev_dcor);
+void isppreview_enable_dcor(struct isp_prev_device *isp_prev, u8 enable);
+
+void isppreview_config_dcor(struct isp_prev_device *isp_prev,
+			    struct ispprev_dcor prev_dcor);
 
 
-void isppreview_config_cfa(struct ispprev_cfa);
+void isppreview_config_cfa(struct isp_prev_device *isp_prev,
+			   struct ispprev_cfa);
 
-void isppreview_config_gammacorrn(struct ispprev_gtable);
+void isppreview_config_gammacorrn(struct isp_prev_device *isp_prev,
+				  struct ispprev_gtable);
 
-void isppreview_config_chroma_suppression(struct ispprev_csup csup);
+void isppreview_config_chroma_suppression(struct isp_prev_device *isp_prev,
+					  struct ispprev_csup csup);
 
-void isppreview_enable_cfa(u8 enable);
+void isppreview_enable_cfa(struct isp_prev_device *isp_prev, u8 enable);
 
-void isppreview_set_luma_enhancement(u32 *ytable);
+void isppreview_config_luma_enhancement(struct isp_prev_device *isp_prev,
+					u32 *ytable);
 
-void isppreview_config_luma_enhancement(u32 *ytable);
+void isppreview_enable_luma_enhancement(struct isp_prev_device *isp_prev,
+					u8 enable);
 
-void isppreview_enable_luma_enhancement(u8 enable);
+void isppreview_enable_chroma_suppression(struct isp_prev_device *isp_prev,
+					  u8 enable);
 
-void isppreview_enable_chroma_suppression(u8 enable);
+void isppreview_config_whitebalance(struct isp_prev_device *isp_prev,
+				    struct ispprev_wbal);
 
-void isppreview_config_whitebalance(struct ispprev_wbal);
+void isppreview_config_blkadj(struct isp_prev_device *isp_prev,
+			      struct ispprev_blkadj);
 
-void isppreview_config_blkadj(struct ispprev_blkadj);
+void isppreview_config_rgb_blending(struct isp_prev_device *isp_prev,
+				    struct ispprev_rgbtorgb);
 
-void isppreview_config_rgb_blending(struct ispprev_rgbtorgb);
+void isppreview_config_rgb_to_ycbcr(struct isp_prev_device *isp_prev,
+				    struct ispprev_csc);
 
-void isppreview_config_rgb_to_ycbcr(struct ispprev_csc);
+void isppreview_update_contrast(struct isp_prev_device *isp_prev, u8 *contrast);
 
-void isppreview_update_contrast(u8 *contrast);
+void isppreview_query_contrast(struct isp_prev_device *isp_prev, u8 *contrast);
 
-void isppreview_query_contrast(u8 *contrast);
-
-void isppreview_config_contrast(u8 contrast);
+void isppreview_config_contrast(struct isp_prev_device *isp_prev, u8 contrast);
 
 void isppreview_get_contrast_range(u8 *min_contrast, u8 *max_contrast);
 
-void isppreview_update_brightness(u8 *brightness);
+void isppreview_update_brightness(struct isp_prev_device *isp_prev,
+				  u8 *brightness);
 
-void isppreview_config_brightness(u8 brightness);
+void isppreview_config_brightness(struct isp_prev_device *isp_prev,
+				  u8 brightness);
 
 void isppreview_get_brightness_range(u8 *min_brightness, u8 *max_brightness);
 
-void isppreview_set_color(u8 *mode);
+void isppreview_set_color(struct isp_prev_device *isp_prev, u8 *mode);
 
-void isppreview_get_color(u8 *mode);
+void isppreview_get_color(struct isp_prev_device *isp_prev, u8 *mode);
 
-void isppreview_query_brightness(u8 *brightness);
+void isppreview_query_brightness(struct isp_prev_device *isp_prev,
+				 u8 *brightness);
 
-void isppreview_config_yc_range(struct ispprev_yclimit yclimit);
+void isppreview_config_yc_range(struct isp_prev_device *isp_prev,
+				struct ispprev_yclimit yclimit);
 
-int isppreview_try_size(u32 input_w, u32 input_h, u32 *output_w,
-			u32 *output_h);
+int isppreview_try_pipeline(struct isp_prev_device *isp_prev,
+			    struct isp_pipeline *pipe);
 
-int isppreview_config_size(u32 input_w, u32 input_h, u32 output_w,
-			   u32 output_h);
+int isppreview_s_pipeline(struct isp_prev_device *isp_prev,
+			  struct isp_pipeline *pipe);
 
-int isppreview_config_inlineoffset(u32 offset);
+int isppreview_config_inlineoffset(struct isp_prev_device *isp_prev,
+				   u32 offset);
 
-int isppreview_set_inaddr(u32 addr);
+int isppreview_set_inaddr(struct isp_prev_device *isp_prev, u32 addr);
 
-int isppreview_config_outlineoffset(u32 offset);
+int isppreview_config_outlineoffset(struct isp_prev_device *isp_prev,
+				    u32 offset);
 
-int isppreview_set_outaddr(u32 addr);
+int isppreview_set_outaddr(struct isp_prev_device *isp_prev, u32 addr);
 
-int isppreview_config_darklineoffset(u32 offset);
+int isppreview_config_darklineoffset(struct isp_prev_device *isp_prev,
+				     u32 offset);
 
-int isppreview_set_darkaddr(u32 addr);
+int isppreview_set_darkaddr(struct isp_prev_device *isp_prev, u32 addr);
 
-void isppreview_enable(int enable);
+void isppreview_enable(struct isp_prev_device *isp_prev, int enable);
 
-void isppreview_suspend(void);
+int isppreview_busy(struct isp_prev_device *isp_prev);
 
-void isppreview_resume(void);
+void isppreview_print_status(struct isp_prev_device *isp_prev,
+			     struct isp_pipeline *pipe);
 
-int isppreview_busy(void);
+void isppreview_save_context(struct device *dev);
 
-struct prev_params *isppreview_get_config(void);
+void isppreview_restore_context(struct device *dev);
 
-void isppreview_print_status(void);
+int isppreview_config(struct isp_prev_device *isp_prev, void *userspace_add);
 
-#ifndef CONFIG_ARCH_OMAP3410
-void isppreview_save_context(void);
-#else
-static inline void isppreview_save_context(void) {}
-#endif
-
-#ifndef CONFIG_ARCH_OMAP3410
-void isppreview_restore_context(void);
-#else
-static inline void isppreview_restore_context(void) {}
-#endif
-
-int omap34xx_isp_preview_config(void *userspace_add);
-
-int omap34xx_isp_tables_update(struct isptables_update *isptables_struct);
-
-void isppreview_set_skip(u32 h, u32 v);
+void isppreview_set_skip(struct isp_prev_device *isp_prev, u32 h, u32 v);
 
 #endif/* OMAP_ISP_PREVIEW_H */
diff --git a/drivers/media/video/isp/ispreg.h b/drivers/media/video/isp/ispreg.h
index 4f8e1ef..2198a53 100644
--- a/drivers/media/video/isp/ispreg.h
+++ b/drivers/media/video/isp/ispreg.h
@@ -116,7 +116,7 @@
 #define ISP_32B_BOUNDARY_BUF		0xFFFFFFE0
 #define ISP_32B_BOUNDARY_OFFSET		0x0000FFE0
 
-#define CM_CAM_MCLK_HZ			216000000
+#define CM_CAM_MCLK_HZ			172800000	/* Hz */
 
 /* ISP Submodules offset */
 
@@ -209,6 +209,18 @@
 #define ISPCSI1_SYSSTATUS		(0x008)
 #define ISPCSI1_LC01_IRQENABLE		(0x00C)
 #define ISPCSI1_LC01_IRQSTATUS		(0x010)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FS_IRQ	(1 << 11)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_LE_IRQ	(1 << 10)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_LS_IRQ	(1 << 9)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FE_IRQ	(1 << 8)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_COUNT_IRQ	(1 << 7)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FIFO_OVF_IRQ	(1 << 5)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_CRC_IRQ	(1 << 4)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FSP_IRQ	(1 << 3)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FW_IRQ	(1 << 2)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_FSC_IRQ	(1 << 1)
+#define ISPCSI1_LC01_IRQSTATUS_LC0_SSC_IRQ	(1 << 0)
+
 #define ISPCSI1_LC23_IRQENABLE		(0x014)
 #define ISPCSI1_LC23_IRQSTATUS		(0x018)
 #define ISPCSI1_LCM_IRQENABLE		(0x02C)
@@ -305,12 +317,32 @@
 #define ISPCCDC_LSC_TABLE_OFFSET	(0x0A4)
 
 /* SBL */
+#define ISPSBL_PCR			0x4
+#define ISPSBL_PCR_H3A_AEAWB_WBL_OVF	(1 << 16)
+#define ISPSBL_PCR_H3A_AF_WBL_OVF	(1 << 17)
+#define ISPSBL_PCR_RSZ4_WBL_OVF		(1 << 18)
+#define ISPSBL_PCR_RSZ3_WBL_OVF		(1 << 19)
+#define ISPSBL_PCR_RSZ2_WBL_OVF		(1 << 20)
+#define ISPSBL_PCR_RSZ1_WBL_OVF		(1 << 21)
+#define ISPSBL_PCR_PRV_WBL_OVF		(1 << 22)
+#define ISPSBL_PCR_CCDC_WBL_OVF		(1 << 23)
+#define ISPSBL_PCR_CCDCPRV_2_RSZ_OVF	(1 << 24)
+#define ISPSBL_PCR_CSIA_WBL_OVF		(1 << 25)
+#define ISPSBL_PCR_CSIB_WBL_OVF		(1 << 26)
 #define ISPSBL_CCDC_WR_0		(0x028)
 #define ISPSBL_CCDC_WR_0_DATA_READY	(1 << 21)
 #define ISPSBL_CCDC_WR_1		(0x02C)
 #define ISPSBL_CCDC_WR_2		(0x030)
 #define ISPSBL_CCDC_WR_3		(0x034)
 
+#define ISPSBL_SDR_REQ_EXP		0xF8
+#define ISPSBL_SDR_REQ_HIST_EXP_SHIFT	0
+#define ISPSBL_SDR_REQ_HIST_EXP_MASK	(0x3FF)
+#define ISPSBL_SDR_REQ_RSZ_EXP_SHIFT	10
+#define ISPSBL_SDR_REQ_RSZ_EXP_MASK	(0x3FF << ISPSBL_SDR_REQ_RSZ_EXP_SHIFT)
+#define ISPSBL_SDR_REQ_PRV_EXP_SHIFT	20
+#define ISPSBL_SDR_REQ_PRV_EXP_MASK	(0x3FF << ISPSBL_SDR_REQ_PRV_EXP_SHIFT)
+
 /* Histogram registers */
 #define ISPHIST_PID			(0x000)
 #define ISPHIST_PCR			(0x004)
@@ -623,8 +655,9 @@
 
 /* Define bit fields within selected registers */
 #define ISP_REVISION_SHIFT			0
+#define ISP_REVISION_MASK			0xFF
 
-#define ISP_SYSCONFIG_AUTOIDLE			0
+#define ISP_SYSCONFIG_AUTOIDLE			(1 << 0)
 #define ISP_SYSCONFIG_SOFTRESET			(1 << 1)
 #define ISP_SYSCONFIG_MIDLEMODE_SHIFT		12
 #define ISP_SYSCONFIG_MIDLEMODE_FORCESTANDBY	0x0
@@ -905,12 +938,13 @@
 #define ISPCCDC_FMTCFG_VPIN_9_0			(0x6 << 12)
 #define ISPCCDC_FMTCFG_VPEN			(1 << 15)
 
-#define ISPCCDC_FMTCF_VPIF_FRQ_MASK		0xFFF8FFFF
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY2		(0x0 << 16)
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY3		(0x1 << 16)
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY4		(0x2 << 16)
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY5		(0x3 << 16)
-#define ISPCCDC_FMTCF_VPIF_FRQ_BY6		(0x4 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_MASK		0xFFF8FFFF
+#define ISPCCDC_FMTCFG_VPIF_FRQ_SHIFT		16
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY2		(0x0 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY3		(0x1 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY4		(0x2 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY5		(0x3 << 16)
+#define ISPCCDC_FMTCFG_VPIF_FRQ_BY6		(0x4 << 16)
 
 #define ISPCCDC_FMT_HORZ_FMTLNH_SHIFT		0
 #define ISPCCDC_FMT_HORZ_FMTSPH_SHIFT		16
@@ -932,8 +966,9 @@
 #define ISPRSZ_PID_CID_SHIFT			8
 #define ISPRSZ_PID_TID_SHIFT			16
 
-#define ISPRSZ_PCR_ENABLE			0x5
+#define ISPRSZ_PCR_ENABLE			1
 #define ISPRSZ_PCR_BUSY				(1 << 1)
+#define ISPRSZ_PCR_ONESHOT			(1 << 2)
 
 #define ISPRSZ_CNT_HRSZ_SHIFT			0
 #define ISPRSZ_CNT_HRSZ_MASK			0x3FF
@@ -952,9 +987,9 @@
 #define ISPRSZ_CNT_CBILIN			(1 << 29)
 
 #define ISPRSZ_OUT_SIZE_HORZ_SHIFT		0
-#define ISPRSZ_OUT_SIZE_HORZ_MASK		0x7FF
+#define ISPRSZ_OUT_SIZE_HORZ_MASK		0xFFF
 #define ISPRSZ_OUT_SIZE_VERT_SHIFT		16
-#define ISPRSZ_OUT_SIZE_VERT_MASK		0x7FF0000
+#define ISPRSZ_OUT_SIZE_VERT_MASK		0xFFF0000
 
 
 #define ISPRSZ_IN_START_HORZ_ST_SHIFT		0
@@ -1242,6 +1277,7 @@
 
 #define ISPHIST_HV_INFO_MASK			0x3FFF3FFF
 
+#define ISPCCDC_LSC_ENABLE			1
 #define ISPCCDC_LSC_GAIN_MODE_N_MASK		0x700
 #define ISPCCDC_LSC_GAIN_MODE_N_SHIFT		8
 #define ISPCCDC_LSC_GAIN_MODE_M_MASK		0x3800
@@ -1381,6 +1417,9 @@
 #define ISPCSI2_DBG_H				(0x044)
 #define ISPCSI2_GNQ				(0x048)
 #define ISPCSI2_COMPLEXIO_CFG1			(0x050)
+#define ISPCSI2_COMPLEXIO_CFG1_RESET_CTRL_SHIFT		30
+#define ISPCSI2_COMPLEXIO_CFG1_RESET_CTRL_DEASSERTED		\
+	(0x1 << ISPCSI2_COMPLEXIO_CFG1_RESET_CTRL_SHIFT)
 #define ISPCSI2_COMPLEXIO_CFG1_RESET_DONE_SHIFT		29
 #define ISPCSI2_COMPLEXIO_CFG1_RESET_DONE_MASK			\
 	(0x1 << ISPCSI2_COMPLEXIO_CFG1_RESET_DONE_SHIFT)
@@ -1642,6 +1681,9 @@
 #define ISPCSI2PHY_CFG0_THS_SETTLE_RESETVAL		\
 	(0x27 << ISPCSI2PHY_CFG0_THS_SETTLE_SHIFT)
 #define ISPCSI2PHY_CFG1				(0x004)
+#define ISPCSI2PHY_CFG1_RESETDONECTRLCLK_SHIFT		29
+#define ISPCSI2PHY_CFG1_RESETDONECTRLCLK_MASK		\
+	(0x1 << ISPCSI2PHY_CFG1_RESETDONECTRLCLK_SHIFT)
 #define ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT		18
 #define ISPCSI2PHY_CFG1_TCLK_TERM_MASK			\
 	(0x7F << ISPCSI2PHY_CFG1_TCLK_TERM_SHIFT)
diff --git a/drivers/media/video/isp/ispresizer.c b/drivers/media/video/isp/ispresizer.c
index d437b40..78a1a64 100644
--- a/drivers/media/video/isp/ispresizer.c
+++ b/drivers/media/video/isp/ispresizer.c
@@ -20,13 +20,13 @@
  */
 
 #include <linux/module.h>
+#include <linux/device.h>
 
 #include "isp.h"
 #include "ispreg.h"
 #include "ispresizer.h"
 
 /* Default configuration of resizer,filter coefficients,yenh for camera isp */
-static struct isprsz_yenh ispreszdefaultyenh = {0, 0, 0, 0};
 static struct isprsz_coef ispreszdefcoef = {
 	{
 		0x0000, 0x0100, 0x0000, 0x0000,
@@ -68,50 +68,6 @@
 	}
 };
 
-/**
- * struct isp_res - Structure for the resizer module to store its information.
- * @res_inuse: Indicates if resizer module has been reserved. 1 - Reserved,
- *             0 - Freed.
- * @h_startphase: Horizontal starting phase.
- * @v_startphase: Vertical starting phase.
- * @h_resz: Horizontal resizing value.
- * @v_resz: Vertical resizing value.
- * @outputwidth: Output Image Width in pixels.
- * @outputheight: Output Image Height in pixels.
- * @inputwidth: Input Image Width in pixels.
- * @inputheight: Input Image Height in pixels.
- * @algo: Algorithm select. 0 - Disable, 1 - [-1 2 -1]/2 high-pass filter,
- *        2 - [-1 -2 6 -2 -1]/4 high-pass filter.
- * @ipht_crop: Vertical start line for cropping.
- * @ipwd_crop: Horizontal start pixel for cropping.
- * @cropwidth: Crop Width.
- * @cropheight: Crop Height.
- * @resinput: Resizer input.
- * @coeflist: Register configuration for Resizer.
- * @ispres_mutex: Mutex for isp resizer.
- */
-static struct isp_res {
-	int pm_state;
-	u8 res_inuse;
-	u8 h_startphase;
-	u8 v_startphase;
-	u16 h_resz;
-	u16 v_resz;
-	u32 outputwidth;
-	u32 outputheight;
-	u32 inputwidth;
-	u32 inputheight;
-	u8 algo;
-	u32 ipht_crop;
-	u32 ipwd_crop;
-	u32 cropwidth;
-	u32 cropheight;
-	dma_addr_t tmp_buf;
-	enum ispresizer_input resinput;
-	struct isprsz_coef coeflist;
-	struct mutex ispres_mutex; /* For checking/modifying res_inuse */
-} ispres_obj;
-
 /* Structure for saving/restoring resizer module registers */
 static struct isp_reg isprsz_reg_list[] = {
 	{OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, 0x0000},
@@ -159,46 +115,80 @@
 };
 
 /**
- * ispresizer_config_shadow_registers - Configure shadow registers.
- **/
-void ispresizer_config_shadow_registers()
-{
-	return;
-}
-EXPORT_SYMBOL(ispresizer_config_shadow_registers);
-
-/**
- * ispresizer_trycrop - Validate crop dimensions.
- * @left: Left distance to start position of crop.
- * @top: Top distance to start position of crop.
- * @width: Width of input image.
- * @height: Height of input image.
- * @ow: Width of output image.
- * @oh: Height of output image.
- **/
-void ispresizer_trycrop(u32 left, u32 top, u32 width, u32 height, u32 ow,
-			u32 oh)
-{
-	ispres_obj.cropwidth = width + 6;
-	ispres_obj.cropheight = height + 6;
-	ispresizer_try_size(&ispres_obj.cropwidth, &ispres_obj.cropheight, &ow,
-			    &oh);
-	ispres_obj.ipht_crop = top;
-	ispres_obj.ipwd_crop = left;
-}
-EXPORT_SYMBOL(ispresizer_trycrop);
-
-/**
  * ispresizer_applycrop - Apply crop to input image.
  **/
-void ispresizer_applycrop(void)
+void ispresizer_applycrop(struct isp_res_device *isp_res)
 {
-	ispresizer_config_size(ispres_obj.cropwidth, ispres_obj.cropheight,
-			       ispres_obj.outputwidth,
-			       ispres_obj.outputheight);
+	struct isp_device *isp = to_isp_device(isp_res);
+
+	if (!isp_res->applycrop)
+		return;
+
+	ispresizer_s_pipeline(isp_res, &isp->pipeline);
+
+	isp_res->applycrop = 0;
+
 	return;
 }
-EXPORT_SYMBOL(ispresizer_applycrop);
+
+/**
+ * ispresizer_config_shadow_registers - Configure shadow registers.
+ **/
+void ispresizer_config_shadow_registers(struct isp_res_device *isp_res)
+{
+	ispresizer_applycrop(isp_res);
+
+	return;
+}
+
+int ispresizer_config_crop(struct isp_res_device *isp_res,
+			   struct v4l2_crop *a)
+{
+	struct isp_device *isp = to_isp_device(isp_res);
+	struct v4l2_crop *crop = a;
+	int rval;
+
+	if (crop->c.left < 0)
+		crop->c.left = 0;
+	if (crop->c.width < 0)
+		crop->c.width = 0;
+	if (crop->c.top < 0)
+		crop->c.top = 0;
+	if (crop->c.height < 0)
+		crop->c.height = 0;
+
+	if (crop->c.left >= isp->pipeline.prv_out_w_img)
+		crop->c.left = isp->pipeline.prv_out_w_img - 1;
+	if (crop->c.top >= isp->pipeline.rsz_out_h)
+		crop->c.top = isp->pipeline.rsz_out_h - 1;
+
+	/* Make sure the crop rectangle is never smaller than width
+	 * and height divided by 4, since the resizer cannot upscale it
+	 * by more than 4x. */
+
+	if (crop->c.width < (isp->pipeline.rsz_out_w + 3) / 4)
+		crop->c.width = (isp->pipeline.rsz_out_w + 3) / 4;
+	if (crop->c.height < (isp->pipeline.rsz_out_h + 3) / 4)
+		crop->c.height = (isp->pipeline.rsz_out_h + 3) / 4;
+
+	if (crop->c.left + crop->c.width > isp->pipeline.prv_out_w_img)
+		crop->c.width = isp->pipeline.prv_out_w_img - crop->c.left;
+	if (crop->c.top + crop->c.height > isp->pipeline.prv_out_h_img)
+		crop->c.height = isp->pipeline.prv_out_h_img - crop->c.top;
+
+	isp->pipeline.rsz_crop = crop->c;
+
+	rval = ispresizer_try_pipeline(isp_res, &isp->pipeline);
+	if (rval)
+		return rval;
+
+	isp_res->applycrop = 1;
+
+	if (isp->running == ISP_STOPPED)
+		ispresizer_applycrop(isp_res);
+
+	return 0;
+}
 
 /**
  * ispresizer_request - Reserves the Resizer module.
@@ -207,46 +197,50 @@
  *
  * Returns 0 if successful, or -EBUSY if resizer module was already requested.
  **/
-int ispresizer_request()
+int ispresizer_request(struct isp_res_device *isp_res)
 {
-	mutex_lock(&ispres_obj.ispres_mutex);
-	if (!ispres_obj.res_inuse) {
-		ispres_obj.res_inuse = 1;
-		mutex_unlock(&ispres_obj.ispres_mutex);
-		isp_reg_writel(isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL) |
+	struct device *dev = to_device(isp_res);
+
+	mutex_lock(&isp_res->ispres_mutex);
+	if (!isp_res->res_inuse) {
+		isp_res->res_inuse = 1;
+		mutex_unlock(&isp_res->ispres_mutex);
+		isp_reg_writel(dev,
+			       isp_reg_readl(dev,
+					     OMAP3_ISP_IOMEM_MAIN, ISP_CTRL) |
 			       ISPCTRL_SBL_WR0_RAM_EN |
 			       ISPCTRL_RSZ_CLK_EN,
 			       OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 		return 0;
 	} else {
-		mutex_unlock(&ispres_obj.ispres_mutex);
-		printk(KERN_ERR "ISP_ERR : Resizer Module Busy\n");
+		mutex_unlock(&isp_res->ispres_mutex);
+		dev_err(dev, "resizer: Module Busy\n");
 		return -EBUSY;
 	}
 }
-EXPORT_SYMBOL(ispresizer_request);
 
 /**
  * ispresizer_free - Makes Resizer module free.
  *
  * Returns 0 if successful, or -EINVAL if resizer module was already freed.
  **/
-int ispresizer_free()
+int ispresizer_free(struct isp_res_device *isp_res)
 {
-	mutex_lock(&ispres_obj.ispres_mutex);
-	if (ispres_obj.res_inuse) {
-		ispres_obj.res_inuse = 0;
-		mutex_unlock(&ispres_obj.ispres_mutex);
-		isp_reg_and(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
+	struct device *dev = to_device(isp_res);
+
+	mutex_lock(&isp_res->ispres_mutex);
+	if (isp_res->res_inuse) {
+		isp_res->res_inuse = 0;
+		mutex_unlock(&isp_res->ispres_mutex);
+		isp_reg_and(dev, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL,
 			    ~(ISPCTRL_RSZ_CLK_EN | ISPCTRL_SBL_WR0_RAM_EN));
 		return 0;
 	} else {
-		mutex_unlock(&ispres_obj.ispres_mutex);
+		mutex_unlock(&isp_res->ispres_mutex);
 		DPRINTK_ISPRESZ("ISP_ERR : Resizer Module already freed\n");
 		return -EINVAL;
 	}
 }
-EXPORT_SYMBOL(ispresizer_free);
 
 /**
  * ispresizer_config_datapath - Specifies which input to use in resizer module
@@ -256,17 +250,20 @@
  *
  * Returns 0 if successful, or -EINVAL if an unsupported input was requested.
  **/
-int ispresizer_config_datapath(enum ispresizer_input input)
+int ispresizer_config_datapath(struct isp_res_device *isp_res,
+			       struct isp_pipeline *pipe)
 {
+	struct device *dev = to_device(isp_res);
 	u32 cnt = 0;
+
 	DPRINTK_ISPRESZ("ispresizer_config_datapath()+\n");
-	ispres_obj.resinput = input;
-	switch (input) {
+
+	switch (pipe->rsz_in) {
 	case RSZ_OTFLY_YUV:
 		cnt &= ~ISPRSZ_CNT_INPTYP;
 		cnt &= ~ISPRSZ_CNT_INPSRC;
-		ispresizer_set_inaddr(0);
-		ispresizer_config_inlineoffset(0);
+		ispresizer_set_inaddr(isp_res, 0, 0);
+		ispresizer_config_inlineoffset(isp_res, 0);
 		break;
 	case RSZ_MEM_YUV:
 		cnt |= ISPRSZ_CNT_INPSRC;
@@ -277,18 +274,19 @@
 		cnt |= ISPRSZ_CNT_INPTYP;
 		break;
 	default:
-		printk(KERN_ERR "ISP_ERR : Wrong Input\n");
+		dev_err(dev, "resizer: Wrong Input\n");
 		return -EINVAL;
 	}
-	isp_reg_or(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, cnt);
-	ispresizer_config_ycpos(0);
-	ispresizer_config_filter_coef(&ispreszdefcoef);
-	ispresizer_enable_cbilin(0);
-	ispresizer_config_luma_enhance(&ispreszdefaultyenh);
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+		       ~(ISPRSZ_CNT_INPSRC | ISPRSZ_CNT_INPTYP),
+		       cnt);
+	ispresizer_config_ycpos(isp_res, 0);
+	ispresizer_config_filter_coef(isp_res, &ispreszdefcoef);
+	ispresizer_enable_cbilin(isp_res, 0);
+	ispresizer_config_luma_enhance(isp_res, &isp_res->defaultyenh);
 	DPRINTK_ISPRESZ("ispresizer_config_datapath()-\n");
 	return 0;
 }
-EXPORT_SYMBOL(ispresizer_config_datapath);
 
 /**
  * ispresizer_try_size - Validates input and output images size.
@@ -296,7 +294,8 @@
  * @input_h: input height for the resizer in number of lines
  * @output_w: output width from the resizer in number of pixels per line
  *            resizer when writing to memory needs this to be multiple of 16.
- * @output_h: output height for the resizer in number of lines, must be even.
+ * @pipe->rsz_out_h: output height for the resizer in number of lines, must be
+ *		     even.
  *
  * Calculates the horizontal and vertical resize ratio, number of pixels to
  * be cropped in the resizer module and checks the validity of various
@@ -325,34 +324,29 @@
  * Fills up the output/input widht/height, horizontal/vertical resize ratio,
  * horizontal/vertical crop variables in the isp_res structure.
  **/
-int ispresizer_try_size(u32 *input_width, u32 *input_height, u32 *output_w,
-			u32 *output_h)
+int ispresizer_try_pipeline(struct isp_res_device *isp_res,
+			    struct isp_pipeline *pipe)
 {
+	struct device *dev = to_device(isp_res);
 	u32 rsz, rsz_7, rsz_4;
 	u32 sph;
-	u32 input_w, input_h;
 	int max_in_otf, max_out_7tap;
 
-	input_w = *input_width;
-	input_h = *input_height;
-
-	if (input_w < 32 || input_h < 32) {
+	if (pipe->rsz_crop.width < 32 || pipe->rsz_crop.height < 32) {
 		DPRINTK_ISPCCDC("ISP_ERR: RESIZER cannot handle input width"
 				" less than 32 pixels or height less than"
 				" 32\n");
 		return -EINVAL;
 	}
-	input_w -= 6;
-	input_h -= 6;
 
-	if (input_h > MAX_IN_HEIGHT)
+	if (pipe->rsz_crop.height > MAX_IN_HEIGHT)
 		return -EINVAL;
 
-	if (*output_w < 16)
-		*output_w = 16;
+	if (pipe->rsz_out_w < 16)
+		pipe->rsz_out_w = 16;
 
-	if (*output_h < 2)
-		*output_h = 2;
+	if (pipe->rsz_out_h < 2)
+		pipe->rsz_out_h = 2;
 
 	if (omap_rev() == OMAP3430_REV_ES1_0) {
 		max_in_otf = MAX_IN_WIDTH_ONTHEFLY_MODE;
@@ -362,110 +356,118 @@
 		max_out_7tap = MAX_7TAP_VRSZ_OUTWIDTH_ES2;
 	}
 
-	if (ispres_obj.resinput == RSZ_OTFLY_YUV) {
-		if (input_w > max_in_otf)
+	if (pipe->rsz_in == RSZ_OTFLY_YUV) {
+		if (pipe->rsz_crop.width > max_in_otf)
 			return -EINVAL;
 	} else {
-		if (input_w > MAX_IN_WIDTH_MEMORY_MODE)
+		if (pipe->rsz_crop.width > MAX_IN_WIDTH_MEMORY_MODE)
 			return -EINVAL;
 	}
 
-	*output_h &= 0xfffffffe;
+	pipe->rsz_out_h &= 0xfffffffe;
 	sph = DEFAULTSTPHASE;
 
-	rsz_7 = ((input_h - 7) * 256) / (*output_h - 1);
-	rsz_4 = ((input_h - 4) * 256) / (*output_h - 1);
+	rsz_7 = ((pipe->rsz_crop.height - 7) * 256) / (pipe->rsz_out_h - 1);
+	rsz_4 = ((pipe->rsz_crop.height - 4) * 256) / (pipe->rsz_out_h - 1);
 
-	rsz = (input_h * 256) / *output_h;
+	rsz = (pipe->rsz_crop.height * 256) / pipe->rsz_out_h;
 
 	if (rsz <= MID_RESIZE_VALUE) {
 		rsz = rsz_4;
 		if (rsz < MINIMUM_RESIZE_VALUE) {
 			rsz = MINIMUM_RESIZE_VALUE;
-			*output_h = (((input_h - 4) * 256) / rsz) + 1;
-			printk(KERN_INFO "%s: using output_h %d instead\n",
-			       __func__, *output_h);
+			pipe->rsz_out_h =
+				(((pipe->rsz_crop.height - 4) * 256) / rsz) + 1;
+			dev_dbg(dev,
+				"resizer: %s: using height %d instead\n",
+				__func__, pipe->rsz_out_h);
 		}
 	} else {
 		rsz = rsz_7;
-		if (*output_w > max_out_7tap)
-			*output_w = max_out_7tap;
+		if (pipe->rsz_out_w > max_out_7tap)
+			pipe->rsz_out_w = max_out_7tap;
 		if (rsz > MAXIMUM_RESIZE_VALUE) {
 			rsz = MAXIMUM_RESIZE_VALUE;
-			*output_h = (((input_h - 7) * 256) / rsz) + 1;
-			printk(KERN_INFO "%s: using output_h %d instead\n",
-			       __func__, *output_h);
+			pipe->rsz_out_h =
+				(((pipe->rsz_crop.height - 7) * 256) / rsz) + 1;
+			dev_dbg(dev,
+				"resizer: %s: using height %d instead\n",
+				__func__, pipe->rsz_out_h);
 		}
 	}
 
 	if (rsz > MID_RESIZE_VALUE) {
-		input_h =
-			(((64 * sph) + ((*output_h - 1) * rsz) + 32) / 256) + 7;
+		pipe->rsz_crop.height =
+			(((64 * sph) + ((pipe->rsz_out_h - 1) * rsz) + 32)
+			 / 256) + 7;
 	} else {
-		input_h =
-			(((32 * sph) + ((*output_h - 1) * rsz) + 16) / 256) + 4;
+		pipe->rsz_crop.height =
+			(((32 * sph) + ((pipe->rsz_out_h - 1) * rsz) + 16)
+			 / 256) + 4;
 	}
 
-	ispres_obj.outputheight = *output_h;
-	ispres_obj.v_resz = rsz;
-	ispres_obj.inputheight = input_h;
-	ispres_obj.ipht_crop = DEFAULTSTPIXEL;
-	ispres_obj.v_startphase = sph;
+	isp_res->v_resz = rsz;
+	/* FIXME: pipe->rsz_crop.height here is the real input height! */
+	isp_res->v_startphase = sph;
 
-	*output_w &= 0xfffffff0;
+	pipe->rsz_out_w &= 0xfffffff0;
 	sph = DEFAULTSTPHASE;
 
-	rsz_7 = ((input_w - 7) * 256) / (*output_w - 1);
-	rsz_4 = ((input_w - 4) * 256) / (*output_w - 1);
+	rsz_7 = ((pipe->rsz_crop.width - 7) * 256) / (pipe->rsz_out_w - 1);
+	rsz_4 = ((pipe->rsz_crop.width - 4) * 256) / (pipe->rsz_out_w - 1);
 
-	rsz = (input_w * 256) / *output_w;
+	rsz = (pipe->rsz_crop.width * 256) / pipe->rsz_out_w;
 	if (rsz > MID_RESIZE_VALUE) {
 		rsz = rsz_7;
 		if (rsz > MAXIMUM_RESIZE_VALUE) {
 			rsz = MAXIMUM_RESIZE_VALUE;
-			*output_w = (((input_w - 7) * 256) / rsz) + 1;
-			*output_w = (*output_w + 0xf) & 0xfffffff0;
-			printk(KERN_INFO "%s: using output_w %d instead\n",
-			       __func__, *output_w);
+			pipe->rsz_out_w =
+				(((pipe->rsz_crop.width - 7) * 256) / rsz) + 1;
+			pipe->rsz_out_w = (pipe->rsz_out_w + 0xf) & 0xfffffff0;
+			dev_dbg(dev,
+				"resizer: %s: using width %d instead\n",
+				__func__, pipe->rsz_out_w);
 		}
 	} else {
 		rsz = rsz_4;
 		if (rsz < MINIMUM_RESIZE_VALUE) {
 			rsz = MINIMUM_RESIZE_VALUE;
-			*output_w = (((input_w - 4) * 256) / rsz) + 1;
-			*output_w = (*output_w + 0xf) & 0xfffffff0;
-			printk(KERN_INFO "%s: using output_w %d instead\n",
-			       __func__, *output_w);
+			pipe->rsz_out_w =
+				(((pipe->rsz_crop.width - 4) * 256) / rsz) + 1;
+			pipe->rsz_out_w = (pipe->rsz_out_w + 0xf) & 0xfffffff0;
+			dev_dbg(dev,
+				"resizer: %s: using width %d instead\n",
+				__func__, pipe->rsz_out_w);
 		}
 	}
 
 	/* Recalculate input based on TRM equations */
 	if (rsz > MID_RESIZE_VALUE) {
-		input_w =
-			(((64 * sph) + ((*output_w - 1) * rsz) + 32) / 256) + 7;
+		pipe->rsz_crop.width =
+			(((64 * sph) + ((pipe->rsz_out_w - 1) * rsz) + 32)
+			 / 256) + 7;
 	} else {
-		input_w =
-			(((32 * sph) + ((*output_w - 1) * rsz) + 16) / 256) + 7;
+		pipe->rsz_crop.width =
+			(((32 * sph) + ((pipe->rsz_out_w - 1) * rsz) + 16)
+			 / 256) + 7;
 	}
 
-	ispres_obj.outputwidth = *output_w;
-	ispres_obj.h_resz = rsz;
-	ispres_obj.inputwidth = input_w;
-	ispres_obj.ipwd_crop = DEFAULTSTPIXEL;
-	ispres_obj.h_startphase = sph;
+	isp_res->h_resz = rsz;
+	/* FIXME: pipe->rsz_crop.width here is the real input width! */
+	isp_res->h_startphase = sph;
 
-	*input_height = input_h;
-	*input_width = input_w;
+	pipe->rsz_out_w_img = pipe->rsz_out_w;
+
 	return 0;
 }
-EXPORT_SYMBOL(ispresizer_try_size);
 
 /**
  * ispresizer_config_size - Configures input and output image size.
- * @input_w: input width for the resizer in number of pixels per line.
- * @input_h: input height for the resizer in number of lines.
- * @output_w: output width from the resizer in number of pixels per line.
- * @output_h: output height for the resizer in number of lines.
+ * @pipe->rsz_crop.width: input width for the resizer in number of pixels per
+ *			  line.
+ * @pipe->rsz_crop.height: input height for the resizer in number of lines.
+ * @pipe->rsz_out_w: output width from the resizer in number of pixels per line.
+ * @pipe->rsz_out_h: output height for the resizer in number of lines.
  *
  * Configures the appropriate values stored in the isp_res structure in the
  * resizer registers.
@@ -473,93 +475,86 @@
  * Returns 0 if successful, or -EINVAL if passed values haven't been verified
  * with ispresizer_try_size() previously.
  **/
-int ispresizer_config_size(u32 input_w, u32 input_h, u32 output_w,
-			   u32 output_h)
+int ispresizer_s_pipeline(struct isp_res_device *isp_res,
+			  struct isp_pipeline *pipe)
 {
+	struct device *dev = to_device(isp_res);
+	struct isp_device *isp = to_isp_device(isp_res);
 	int i, j;
 	u32 res;
-	DPRINTK_ISPRESZ("ispresizer_config_size()+, input_w = %d,input_h ="
-			" %d, output_w = %d, output_h"
-			" = %d,hresz = %d,vresz = %d,"
-			" hcrop = %d, vcrop = %d,"
-			" hstph = %d, vstph = %d\n",
-			ispres_obj.inputwidth,
-			ispres_obj.inputheight,
-			ispres_obj.outputwidth,
-			ispres_obj.outputheight,
-			ispres_obj.h_resz,
-			ispres_obj.v_resz,
-			ispres_obj.ipwd_crop,
-			ispres_obj.ipht_crop,
-			ispres_obj.h_startphase,
-			ispres_obj.v_startphase);
-	if ((output_w != ispres_obj.outputwidth)
-	    || (output_h != ispres_obj.outputheight)) {
-		printk(KERN_ERR "Output parameters passed do not match the"
-		       " values calculated by the"
-		       " trysize passed w %d, h %d"
-		       " \n", output_w , output_h);
-		return -EINVAL;
-	}
+	int rval;
 
-	/* Set Resizer input address and offset adderss */
-	ispresizer_config_inlineoffset(isp_reg_readl(OMAP3_ISP_IOMEM_PREV,
-						     ISPPRV_WADD_OFFSET));
+	rval = ispresizer_config_datapath(isp_res, pipe);
+	if (rval)
+		return rval;
 
-	res = isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+	res = isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
 		~(ISPRSZ_CNT_HSTPH_MASK | ISPRSZ_CNT_VSTPH_MASK);
-	isp_reg_writel(res |
-		       (ispres_obj.h_startphase << ISPRSZ_CNT_HSTPH_SHIFT) |
-		       (ispres_obj.v_startphase << ISPRSZ_CNT_VSTPH_SHIFT),
+	isp_reg_writel(dev, res |
+		       (isp_res->h_startphase << ISPRSZ_CNT_HSTPH_SHIFT) |
+		       (isp_res->v_startphase << ISPRSZ_CNT_VSTPH_SHIFT),
 		       OMAP3_ISP_IOMEM_RESZ,
 		       ISPRSZ_CNT);
-	/* Set start address for cropping */
-	isp_reg_writel(ispres_obj.tmp_buf + 2 *
-		       (ispres_obj.ipht_crop * ispres_obj.inputwidth +
-			(ispres_obj.ipwd_crop & ~15)),
-		       OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
 
-	isp_reg_writel(
-		((ispres_obj.ipwd_crop & 15) << ISPRSZ_IN_START_HORZ_ST_SHIFT) |
-		(0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT),
-		OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+	/* Set Resizer input address and offset adderss */
+	if (pipe->rsz_in == RSZ_OTFLY_YUV) {
+		/* Set the fractional part of the starting address.*/
+		isp_reg_writel(dev,
+			((pipe->rsz_crop.left * 2)<<
+			ISPRSZ_IN_START_HORZ_ST_SHIFT) |
+			((pipe->rsz_crop.top) <<
+			ISPRSZ_IN_START_VERT_ST_SHIFT),
+			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+	} else {
+		/* Set start address for cropping */
+		ispresizer_set_inaddr(isp_res, isp_res->in_buf_addr,
+			ISP_BYTES_PER_PIXEL *
+			((isp->pipeline.rsz_crop.left & ~0xf) +
+			isp->pipeline.prv_out_w *
+			isp->pipeline.rsz_crop.top));
 
-	isp_reg_writel((0x00 << ISPRSZ_IN_START_HORZ_ST_SHIFT) |
-		       (0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT),
-		       OMAP3_ISP_IOMEM_RESZ,
-		       ISPRSZ_IN_START);
+		/* Set the fractional part of the starting address.*/
+		isp_reg_writel(dev, ((isp->pipeline.rsz_crop.left & 0xf) <<
+			ISPRSZ_IN_START_HORZ_ST_SHIFT) |
+			(0x00 << ISPRSZ_IN_START_VERT_ST_SHIFT),
+			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
+	}
 
-	isp_reg_writel((ispres_obj.inputwidth << ISPRSZ_IN_SIZE_HORZ_SHIFT) |
-		       (ispres_obj.inputheight <<
+	isp_reg_writel(dev,
+		       (pipe->rsz_crop.width << ISPRSZ_IN_SIZE_HORZ_SHIFT) |
+		       (pipe->rsz_crop.height <<
 			ISPRSZ_IN_SIZE_VERT_SHIFT),
 		       OMAP3_ISP_IOMEM_RESZ,
 		       ISPRSZ_IN_SIZE);
-	if (!ispres_obj.algo) {
-		isp_reg_writel((output_w << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
-			       (output_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
+	if (!isp_res->algo) {
+		isp_reg_writel(dev,
+			       (pipe->rsz_out_w << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
+			       (pipe->rsz_out_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
 			       OMAP3_ISP_IOMEM_RESZ,
 			       ISPRSZ_OUT_SIZE);
 	} else {
-		isp_reg_writel(((output_w - 4) << ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
-			       (output_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
+		isp_reg_writel(dev,
+			       ((pipe->rsz_out_w - 4)
+				<< ISPRSZ_OUT_SIZE_HORZ_SHIFT) |
+			       (pipe->rsz_out_h << ISPRSZ_OUT_SIZE_VERT_SHIFT),
 			       OMAP3_ISP_IOMEM_RESZ,
 			       ISPRSZ_OUT_SIZE);
 	}
 
-	res = isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
+	res = isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT) &
 		~(ISPRSZ_CNT_HRSZ_MASK | ISPRSZ_CNT_VRSZ_MASK);
-	isp_reg_writel(res |
-		       ((ispres_obj.h_resz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) |
-		       ((ispres_obj.v_resz - 1) << ISPRSZ_CNT_VRSZ_SHIFT),
+	isp_reg_writel(dev, res |
+		       ((isp_res->h_resz - 1) << ISPRSZ_CNT_HRSZ_SHIFT) |
+		       ((isp_res->v_resz - 1) << ISPRSZ_CNT_VRSZ_SHIFT),
 		       OMAP3_ISP_IOMEM_RESZ,
 		       ISPRSZ_CNT);
-	if (ispres_obj.h_resz <= MID_RESIZE_VALUE) {
+	if (isp_res->h_resz <= MID_RESIZE_VALUE) {
 		j = 0;
 		for (i = 0; i < 16; i++) {
-			isp_reg_writel(
-				(ispres_obj.coeflist.h_filter_coef_4tap[j]
+			isp_reg_writel(dev,
+				(isp_res->coeflist.h_filter_coef_4tap[j]
 				 << ISPRSZ_HFILT10_COEF0_SHIFT) |
-				(ispres_obj.coeflist.h_filter_coef_4tap[j + 1]
+				(isp_res->coeflist.h_filter_coef_4tap[j + 1]
 				 << ISPRSZ_HFILT10_COEF1_SHIFT),
 				OMAP3_ISP_IOMEM_RESZ,
 				ISPRSZ_HFILT10 + (i * 0x04));
@@ -569,17 +564,19 @@
 		j = 0;
 		for (i = 0; i < 16; i++) {
 			if ((i + 1) % 4 == 0) {
-				isp_reg_writel((ispres_obj.coeflist.
+				isp_reg_writel(dev,
+					       (isp_res->coeflist.
 						h_filter_coef_7tap[j] <<
 						ISPRSZ_HFILT10_COEF0_SHIFT),
 					       OMAP3_ISP_IOMEM_RESZ,
 					       ISPRSZ_HFILT10 + (i * 0x04));
 				j += 1;
 			} else {
-				isp_reg_writel((ispres_obj.coeflist.
+				isp_reg_writel(dev,
+					       (isp_res->coeflist.
 						h_filter_coef_7tap[j] <<
 						ISPRSZ_HFILT10_COEF0_SHIFT) |
-					       (ispres_obj.coeflist.
+					       (isp_res->coeflist.
 						h_filter_coef_7tap[j+1] <<
 						ISPRSZ_HFILT10_COEF1_SHIFT),
 					       OMAP3_ISP_IOMEM_RESZ,
@@ -588,13 +585,13 @@
 			}
 		}
 	}
-	if (ispres_obj.v_resz <= MID_RESIZE_VALUE) {
+	if (isp_res->v_resz <= MID_RESIZE_VALUE) {
 		j = 0;
 		for (i = 0; i < 16; i++) {
-			isp_reg_writel((ispres_obj.coeflist.
+			isp_reg_writel(dev, (isp_res->coeflist.
 					v_filter_coef_4tap[j] <<
 					ISPRSZ_VFILT10_COEF0_SHIFT) |
-				       (ispres_obj.coeflist.
+				       (isp_res->coeflist.
 					v_filter_coef_4tap[j + 1] <<
 					ISPRSZ_VFILT10_COEF1_SHIFT),
 				       OMAP3_ISP_IOMEM_RESZ,
@@ -605,17 +602,19 @@
 		j = 0;
 		for (i = 0; i < 16; i++) {
 			if ((i + 1) % 4 == 0) {
-				isp_reg_writel((ispres_obj.coeflist.
+				isp_reg_writel(dev,
+					       (isp_res->coeflist.
 						v_filter_coef_7tap[j] <<
 						ISPRSZ_VFILT10_COEF0_SHIFT),
 					       OMAP3_ISP_IOMEM_RESZ,
 					       ISPRSZ_VFILT10 + (i * 0x04));
 				j += 1;
 			} else {
-				isp_reg_writel((ispres_obj.coeflist.
+				isp_reg_writel(dev,
+					       (isp_res->coeflist.
 						v_filter_coef_7tap[j] <<
 						ISPRSZ_VFILT10_COEF0_SHIFT) |
-					       (ispres_obj.coeflist.
+					       (isp_res->coeflist.
 						v_filter_coef_7tap[j+1] <<
 						ISPRSZ_VFILT10_COEF1_SHIFT),
 					       OMAP3_ISP_IOMEM_RESZ,
@@ -625,26 +624,16 @@
 		}
 	}
 
-	ispresizer_config_outlineoffset(output_w*2);
+	ispresizer_config_outlineoffset(isp_res, pipe->rsz_out_w*2);
+
+	if (pipe->pix.pixelformat == V4L2_PIX_FMT_UYVY)
+		ispresizer_config_ycpos(isp_res, 0);
+	else
+		ispresizer_config_ycpos(isp_res, 1);
+
 	DPRINTK_ISPRESZ("ispresizer_config_size()-\n");
 	return 0;
 }
-EXPORT_SYMBOL(ispresizer_config_size);
-
-void __ispresizer_enable(int enable)
-{
-	int val;
-	DPRINTK_ISPRESZ("+ispresizer_enable()+\n");
-	if (enable) {
-		val = (isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) & 0x2) |
-			ISPRSZ_PCR_ENABLE;
-	} else {
-		val = isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
-			~ISPRSZ_PCR_ENABLE;
-	}
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR);
-	DPRINTK_ISPRESZ("+ispresizer_enable()-\n");
-}
 
 /**
  * ispresizer_enable - Enables the resizer module.
@@ -652,44 +641,37 @@
  *
  * Client should configure all the sub modules in resizer before this.
  **/
-void ispresizer_enable(int enable)
+void ispresizer_enable(struct isp_res_device *isp_res, int enable)
 {
-	__ispresizer_enable(enable);
-	ispres_obj.pm_state = enable;
-}
-EXPORT_SYMBOL(ispresizer_enable);
+	struct device *dev = to_device(isp_res);
+	int val;
 
-/**
- * ispresizer_suspend - Suspend resizer module.
- **/
-void ispresizer_suspend(void)
-{
-	if (ispres_obj.pm_state)
-		__ispresizer_enable(0);
+	DPRINTK_ISPRESZ("+ispresizer_enable()+\n");
+	if (enable) {
+		val = (isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ,
+			ISPRSZ_PCR) & ISPRSZ_PCR_ONESHOT) |
+			ISPRSZ_PCR_ENABLE;
+	} else {
+		val = isp_reg_readl(dev,
+				    OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
+			~ISPRSZ_PCR_ENABLE;
+	}
+	isp_reg_writel(dev, val, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR);
+	DPRINTK_ISPRESZ("+ispresizer_enable()-\n");
 }
-EXPORT_SYMBOL(ispresizer_suspend);
-
-/**
- * ispresizer_resume - Resume resizer module.
- **/
-void ispresizer_resume(void)
-{
-	if (ispres_obj.pm_state)
-		__ispresizer_enable(1);
-}
-EXPORT_SYMBOL(ispresizer_resume);
 
 /**
  * ispresizer_busy - Checks if ISP resizer is busy.
  *
  * Returns busy field from ISPRSZ_PCR register.
  **/
-int ispresizer_busy(void)
+int ispresizer_busy(struct isp_res_device *isp_res)
 {
-	return isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
-		ISPPRV_PCR_BUSY;
+	struct device *dev = to_device(isp_res);
+
+	return isp_reg_readl(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR) &
+		ISPRSZ_PCR_BUSY;
 }
-EXPORT_SYMBOL(ispresizer_busy);
 
 /**
  * ispresizer_config_startphase - Sets the horizontal and vertical start phase.
@@ -699,52 +681,57 @@
  * This API just updates the isp_res struct. Actual register write happens in
  * ispresizer_config_size.
  **/
-void ispresizer_config_startphase(u8 hstartphase, u8 vstartphase)
+void ispresizer_config_startphase(struct isp_res_device *isp_res,
+				  u8 hstartphase, u8 vstartphase)
 {
 	DPRINTK_ISPRESZ("ispresizer_config_startphase()+\n");
-	ispres_obj.h_startphase = hstartphase;
-	ispres_obj.v_startphase = vstartphase;
+	isp_res->h_startphase = hstartphase;
+	isp_res->v_startphase = vstartphase;
 	DPRINTK_ISPRESZ("ispresizer_config_startphase()-\n");
 }
-EXPORT_SYMBOL(ispresizer_config_startphase);
 
 /**
  * ispresizer_config_ycpos - Specifies if output should be in YC or CY format.
  * @yc: 0 - YC format, 1 - CY format
  **/
-void ispresizer_config_ycpos(u8 yc)
+void ispresizer_config_ycpos(struct isp_res_device *isp_res, u8 yc)
 {
+	struct device *dev = to_device(isp_res);
+
 	DPRINTK_ISPRESZ("ispresizer_config_ycpos()+\n");
-	isp_reg_and_or(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_YCPOS,
-		       (yc ? ISPRSZ_CNT_YCPOS : 0));
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+		       ~ISPRSZ_CNT_YCPOS, (yc ? ISPRSZ_CNT_YCPOS : 0));
 	DPRINTK_ISPRESZ("ispresizer_config_ycpos()-\n");
 }
-EXPORT_SYMBOL(ispresizer_config_ycpos);
 
 /**
  * Sets the chrominance algorithm
  * @cbilin: 0 - chrominance uses same processing as luminance,
  *          1 - bilinear interpolation processing
  **/
-void ispresizer_enable_cbilin(u8 enable)
+void ispresizer_enable_cbilin(struct isp_res_device *isp_res, u8 enable)
 {
+	struct device *dev = to_device(isp_res);
+
 	DPRINTK_ISPRESZ("ispresizer_enable_cbilin()+\n");
-	isp_reg_and_or(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT, ~ISPRSZ_CNT_CBILIN,
-		       (enable ? ISPRSZ_CNT_CBILIN : 0));
+	isp_reg_and_or(dev, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
+		       ~ISPRSZ_CNT_CBILIN, (enable ? ISPRSZ_CNT_CBILIN : 0));
 	DPRINTK_ISPRESZ("ispresizer_enable_cbilin()-\n");
 }
-EXPORT_SYMBOL(ispresizer_enable_cbilin);
 
 /**
  * ispresizer_config_luma_enhance - Configures luminance enhancer parameters.
  * @yenh: Pointer to structure containing desired values for core, slope, gain
  *        and algo parameters.
  **/
-void ispresizer_config_luma_enhance(struct isprsz_yenh *yenh)
+void ispresizer_config_luma_enhance(struct isp_res_device *isp_res,
+				    struct isprsz_yenh *yenh)
 {
+	struct device *dev = to_device(isp_res);
+
 	DPRINTK_ISPRESZ("ispresizer_config_luma_enhance()+\n");
-	ispres_obj.algo = yenh->algo;
-	isp_reg_writel((yenh->algo << ISPRSZ_YENH_ALGO_SHIFT) |
+	isp_res->algo = yenh->algo;
+	isp_reg_writel(dev, (yenh->algo << ISPRSZ_YENH_ALGO_SHIFT) |
 		       (yenh->gain << ISPRSZ_YENH_GAIN_SHIFT) |
 		       (yenh->slope << ISPRSZ_YENH_SLOP_SHIFT) |
 		       (yenh->coreoffset << ISPRSZ_YENH_CORE_SHIFT),
@@ -752,7 +739,6 @@
 		       ISPRSZ_YENH);
 	DPRINTK_ISPRESZ("ispresizer_config_luma_enhance()-\n");
 }
-EXPORT_SYMBOL(ispresizer_config_luma_enhance);
 
 /**
  * ispresizer_config_filter_coef - Sets filter coefficients for 4 & 7-tap mode.
@@ -761,25 +747,25 @@
  * @coef: Structure containing horizontal and vertical filter coefficients for
  *        both 4-tap and 7-tap mode.
  **/
-void ispresizer_config_filter_coef(struct isprsz_coef *coef)
+void ispresizer_config_filter_coef(struct isp_res_device *isp_res,
+				   struct isprsz_coef *coef)
 {
 	int i;
 	DPRINTK_ISPRESZ("ispresizer_config_filter_coef()+\n");
 	for (i = 0; i < 32; i++) {
-		ispres_obj.coeflist.h_filter_coef_4tap[i] =
+		isp_res->coeflist.h_filter_coef_4tap[i] =
 			coef->h_filter_coef_4tap[i];
-		ispres_obj.coeflist.v_filter_coef_4tap[i] =
+		isp_res->coeflist.v_filter_coef_4tap[i] =
 			coef->v_filter_coef_4tap[i];
 	}
 	for (i = 0; i < 28; i++) {
-		ispres_obj.coeflist.h_filter_coef_7tap[i] =
+		isp_res->coeflist.h_filter_coef_7tap[i] =
 			coef->h_filter_coef_7tap[i];
-		ispres_obj.coeflist.v_filter_coef_7tap[i] =
+		isp_res->coeflist.v_filter_coef_7tap[i] =
 			coef->v_filter_coef_7tap[i];
 	}
 	DPRINTK_ISPRESZ("ispresizer_config_filter_coef()-\n");
 }
-EXPORT_SYMBOL(ispresizer_config_filter_coef);
 
 /**
  * ispresizer_config_inlineoffset - Configures the read address line offset.
@@ -787,36 +773,44 @@
  *
  * Returns 0 if successful, or -EINVAL if offset is not 32 bits aligned.
  **/
-int ispresizer_config_inlineoffset(u32 offset)
+int ispresizer_config_inlineoffset(struct isp_res_device *isp_res, u32 offset)
 {
+	struct device *dev = to_device(isp_res);
+
 	DPRINTK_ISPRESZ("ispresizer_config_inlineoffset()+\n");
 	if (offset % 32)
 		return -EINVAL;
-	isp_reg_writel(offset << ISPRSZ_SDR_INOFF_OFFSET_SHIFT,
+	isp_reg_writel(dev, offset << ISPRSZ_SDR_INOFF_OFFSET_SHIFT,
 		       OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
 	DPRINTK_ISPRESZ("ispresizer_config_inlineoffset()-\n");
 	return 0;
 }
-EXPORT_SYMBOL(ispresizer_config_inlineoffset);
 
 /**
  * ispresizer_set_inaddr - Sets the memory address of the input frame.
  * @addr: 32bit memory address aligned on 32byte boundary.
+ * @offset: Starting offset.
  *
  * Returns 0 if successful, or -EINVAL if address is not 32 bits aligned.
  **/
-int ispresizer_set_inaddr(u32 addr)
+int ispresizer_set_inaddr(struct isp_res_device *isp_res, u32 addr, u32 offset)
 {
+	struct device *dev = to_device(isp_res);
+
 	DPRINTK_ISPRESZ("ispresizer_set_inaddr()+\n");
-	if (addr % 32)
+
+	if ((addr + offset) % 32)
 		return -EINVAL;
-	isp_reg_writel(addr << ISPRSZ_SDR_INADD_ADDR_SHIFT,
-		       OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
-	ispres_obj.tmp_buf = addr;
+
+	isp_res->in_buf_addr = addr;
+	isp_res->in_buf_addr_off = offset;
+
+	isp_reg_writel(dev, (addr + offset),
+		OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
+
 	DPRINTK_ISPRESZ("ispresizer_set_inaddr()-\n");
 	return 0;
 }
-EXPORT_SYMBOL(ispresizer_set_inaddr);
 
 /**
  * ispresizer_config_outlineoffset - Configures the write address line offset.
@@ -824,105 +818,124 @@
  *
  * Returns 0 if successful, or -EINVAL if address is not 32 bits aligned.
  **/
-int ispresizer_config_outlineoffset(u32 offset)
+int ispresizer_config_outlineoffset(struct isp_res_device *isp_res, u32 offset)
 {
+	struct device *dev = to_device(isp_res);
+
 	DPRINTK_ISPRESZ("ispresizer_config_outlineoffset()+\n");
 	if (offset % 32)
 		return -EINVAL;
-	isp_reg_writel(offset << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT,
+	isp_reg_writel(dev, offset << ISPRSZ_SDR_OUTOFF_OFFSET_SHIFT,
 		       OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
 	DPRINTK_ISPRESZ("ispresizer_config_outlineoffset()-\n");
 	return 0;
 }
-EXPORT_SYMBOL(ispresizer_config_outlineoffset);
 
 /**
  * Configures the memory address to which the output frame is written.
  * @addr: 32bit memory address aligned on 32byte boundary.
  **/
-int ispresizer_set_outaddr(u32 addr)
+int ispresizer_set_outaddr(struct isp_res_device *isp_res, u32 addr)
 {
+	struct device *dev = to_device(isp_res);
+
 	DPRINTK_ISPRESZ("ispresizer_set_outaddr()+\n");
 	if (addr % 32)
 		return -EINVAL;
-	isp_reg_writel(addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
+	isp_reg_writel(dev, addr << ISPRSZ_SDR_OUTADD_ADDR_SHIFT,
 		       OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
 	DPRINTK_ISPRESZ("ispresizer_set_outaddr()-\n");
 	return 0;
 }
-EXPORT_SYMBOL(ispresizer_set_outaddr);
 
 /**
  * ispresizer_save_context - Saves the values of the resizer module registers.
  **/
-void ispresizer_save_context(void)
+void ispresizer_save_context(struct device *dev)
 {
 	DPRINTK_ISPRESZ("Saving context\n");
-	isp_save_context(isprsz_reg_list);
+	isp_save_context(dev, isprsz_reg_list);
 }
-EXPORT_SYMBOL(ispresizer_save_context);
 
 /**
  * ispresizer_restore_context - Restores resizer module register values.
  **/
-void ispresizer_restore_context(void)
+void ispresizer_restore_context(struct device *dev)
 {
 	DPRINTK_ISPRESZ("Restoring context\n");
-	isp_restore_context(isprsz_reg_list);
+	isp_restore_context(dev, isprsz_reg_list);
 }
-EXPORT_SYMBOL(ispresizer_restore_context);
 
 /**
  * ispresizer_print_status - Prints the values of the resizer module registers.
  **/
-void ispresizer_print_status()
+void ispresizer_print_status(struct isp_res_device *isp_res)
 {
+#ifdef OMAP_ISPRESZ_DEBUG
+	struct device *dev = to_device(isp_res);
+#endif
+
 	if (!is_ispresz_debug_enabled())
 		return;
 	DPRINTK_ISPRESZ("###ISP_CTRL inresizer =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_MAIN, ISP_CTRL));
 	DPRINTK_ISPRESZ("###ISP_IRQ0ENABLE in resizer =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE));
 	DPRINTK_ISPRESZ("###ISP_IRQ0STATUS in resizer =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0STATUS));
 	DPRINTK_ISPRESZ("###RSZ PCR =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_PCR));
 	DPRINTK_ISPRESZ("###RSZ CNT =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT));
 	DPRINTK_ISPRESZ("###RSZ OUT SIZE =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE));
 	DPRINTK_ISPRESZ("###RSZ IN START =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START));
 	DPRINTK_ISPRESZ("###RSZ IN SIZE =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE));
 	DPRINTK_ISPRESZ("###RSZ SDR INADD =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD));
 	DPRINTK_ISPRESZ("###RSZ SDR INOFF =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF));
 	DPRINTK_ISPRESZ("###RSZ SDR OUTADD =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD));
 	DPRINTK_ISPRESZ("###RSZ SDR OTOFF =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF));
 	DPRINTK_ISPRESZ("###RSZ YENH =0x%x\n",
-			isp_reg_readl(OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH));
+			isp_reg_readl(dev,
+				      OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH));
 }
-EXPORT_SYMBOL(ispresizer_print_status);
 
 /**
  * isp_resizer_init - Module Initialisation.
  *
  * Always returns 0.
  **/
-int __init isp_resizer_init(void)
+int __init isp_resizer_init(struct device *dev)
 {
-	mutex_init(&ispres_obj.ispres_mutex);
-	ispres_obj.pm_state = 0;
+	struct isp_device *isp = dev_get_drvdata(dev);
+	struct isp_res_device *isp_res = &isp->isp_res;
+
+	mutex_init(&isp_res->ispres_mutex);
+
 	return 0;
 }
 
 /**
  * isp_resizer_cleanup - Module Cleanup.
  **/
-void isp_resizer_cleanup(void)
+void isp_resizer_cleanup(struct device *dev)
 {
 }
diff --git a/drivers/media/video/isp/ispresizer.h b/drivers/media/video/isp/ispresizer.h
index 4e92225..47100e4 100644
--- a/drivers/media/video/isp/ispresizer.h
+++ b/drivers/media/video/isp/ispresizer.h
@@ -66,7 +66,7 @@
  * 	- free()
  */
 
-enum ispresizer_input {
+enum resizer_input {
 	RSZ_OTFLY_YUV,
 	RSZ_MEM_YUV,
 	RSZ_MEM_COL8
@@ -104,55 +104,87 @@
 	u8 coreoffset;
 };
 
-void ispresizer_config_shadow_registers(void);
+/**
+ * struct isp_res_device - Structure for the resizer module to store its
+ * 			   information.
+ * @res_inuse: Indicates if resizer module has been reserved. 1 - Reserved,
+ *             0 - Freed.
+ * @h_startphase: Horizontal starting phase.
+ * @v_startphase: Vertical starting phase.
+ * @h_resz: Horizontal resizing value.
+ * @v_resz: Vertical resizing value.
+ * @outputwidth: Output Image Width in pixels.
+ * @outputheight: Output Image Height in pixels.
+ * @inputwidth: Input Image Width in pixels.
+ * @inputheight: Input Image Height in pixels.
+ * @algo: Algorithm select. 0 - Disable, 1 - [-1 2 -1]/2 high-pass filter,
+ *        2 - [-1 -2 6 -2 -1]/4 high-pass filter.
+ * @ipht_crop: Vertical start line for cropping.
+ * @ipwd_crop: Horizontal start pixel for cropping.
+ * @cropwidth: Crop Width.
+ * @cropheight: Crop Height.
+ * @resinput: Resizer input.
+ * @coeflist: Register configuration for Resizer.
+ * @ispres_mutex: Mutex for isp resizer.
+ */
+struct isp_res_device {
+	u8 res_inuse;
+	u8 h_startphase;
+	u8 v_startphase;
+	u16 h_resz;
+	u16 v_resz;
+	u8 algo;
+	dma_addr_t in_buf_addr;
+	dma_addr_t in_buf_addr_off;
+	struct isprsz_coef coeflist;
+	struct mutex ispres_mutex; /* For checking/modifying res_inuse */
+	struct isprsz_yenh defaultyenh;
+	int applycrop;
+};
 
-int ispresizer_request(void);
+int ispresizer_config_crop(struct isp_res_device *isp_res,
+			   struct v4l2_crop *a);
+void ispresizer_config_shadow_registers(struct isp_res_device *isp_res);
 
-int ispresizer_free(void);
+int ispresizer_request(struct isp_res_device *isp_res);
 
-int ispresizer_config_datapath(enum ispresizer_input input);
+int ispresizer_free(struct isp_res_device *isp_res);
 
-void ispresizer_enable_cbilin(u8 enable);
+void ispresizer_enable_cbilin(struct isp_res_device *isp_res, u8 enable);
 
-void ispresizer_config_ycpos(u8 yc);
+void ispresizer_config_ycpos(struct isp_res_device *isp_res, u8 yc);
 
-void ispresizer_config_startphase(u8 hstartphase, u8 vstartphase);
+void ispresizer_config_startphase(struct isp_res_device *isp_res,
+				  u8 hstartphase, u8 vstartphase);
 
-void ispresizer_config_filter_coef(struct isprsz_coef *coef);
+void ispresizer_config_filter_coef(struct isp_res_device *isp_res,
+				   struct isprsz_coef *coef);
 
-void ispresizer_config_luma_enhance(struct isprsz_yenh *yenh);
+void ispresizer_config_luma_enhance(struct isp_res_device *isp_res,
+				    struct isprsz_yenh *yenh);
 
-int ispresizer_try_size(u32 *input_w, u32 *input_h, u32 *output_w,
-			u32 *output_h);
+int ispresizer_try_pipeline(struct isp_res_device *isp_res,
+			    struct isp_pipeline *pipe);
 
-void ispresizer_applycrop(void);
+int ispresizer_s_pipeline(struct isp_res_device *isp_res,
+			  struct isp_pipeline *pipe);
 
-void ispresizer_trycrop(u32 left, u32 top, u32 width, u32 height, u32 ow,
-			u32 oh);
+int ispresizer_config_inlineoffset(struct isp_res_device *isp_res, u32 offset);
 
-int ispresizer_config_size(u32 input_w, u32 input_h, u32 output_w,
-			   u32 output_h);
+int ispresizer_set_inaddr(struct isp_res_device *isp_res, u32 addr, u32 offset);
 
-int ispresizer_config_inlineoffset(u32 offset);
+int ispresizer_config_outlineoffset(struct isp_res_device *isp_res, u32 offset);
 
-int ispresizer_set_inaddr(u32 addr);
+int ispresizer_set_outaddr(struct isp_res_device *isp_res, u32 addr);
 
-int ispresizer_config_outlineoffset(u32 offset);
+void ispresizer_enable(struct isp_res_device *isp_res, int enable);
 
-int ispresizer_set_outaddr(u32 addr);
+int ispresizer_busy(struct isp_res_device *isp_res);
 
-void ispresizer_enable(int enable);
+void ispresizer_save_context(struct device *dev);
 
-void ispresizer_suspend(void);
+void ispresizer_restore_context(struct device *dev);
 
-void ispresizer_resume(void);
-
-int ispresizer_busy(void);
-
-void ispresizer_save_context(void);
-
-void ispresizer_restore_context(void);
-
-void ispresizer_print_status(void);
+void ispresizer_print_status(struct isp_res_device *isp_res);
 
 #endif		/* OMAP_ISP_RESIZER_H */
diff --git a/drivers/media/video/isp/ispstat.c b/drivers/media/video/isp/ispstat.c
new file mode 100644
index 0000000..ca2d337
--- /dev/null
+++ b/drivers/media/video/isp/ispstat.c
@@ -0,0 +1,342 @@
+/*
+ * ispstat.c
+ *
+ * STAT module for TI's OMAP3 Camera ISP
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ *
+ * Contributors:
+ *	Sergio Aguirre <saaguirre@ti.com>
+ *	Troy Laramy
+ *
+ * This package 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 PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/uaccess.h>
+
+#include "isp.h"
+
+inline int greater_overflow(int a, int b, int limit)
+{
+	int limit2 = limit / 2;
+
+	if (b - a > limit2)
+		return 1;
+	else if (a - b > limit2)
+		return 0;
+	else
+		return a > b;
+}
+
+int ispstat_buf_queue(struct ispstat *stat)
+{
+	unsigned long flags;
+
+	if (!stat->active_buf)
+		return -1;
+
+	do_gettimeofday(&stat->active_buf->ts);
+
+	spin_lock_irqsave(&stat->lock, flags);
+
+	stat->active_buf->config_counter = stat->config_counter;
+	stat->active_buf->frame_number = stat->frame_number;
+
+	stat->frame_number++;
+	if (stat->frame_number == stat->max_frame)
+		stat->frame_number = 0;
+
+	stat->active_buf = NULL;
+
+	spin_unlock_irqrestore(&stat->lock, flags);
+
+	return 0;
+}
+
+/* Get next free buffer to write the statistics to and mark it active. */
+struct ispstat_buffer *ispstat_buf_next(struct ispstat *stat)
+{
+	unsigned long flags;
+	struct ispstat_buffer *found = NULL;
+	int i;
+
+	spin_lock_irqsave(&stat->lock, flags);
+
+	if (stat->active_buf)
+		dev_dbg(stat->dev, "%s: new buffer requested without queuing "
+				   "active one.\n", stat->tag);
+
+	for (i = 0; i < stat->nbufs; i++) {
+		struct ispstat_buffer *curr = &stat->buf[i];
+
+		/*
+		 * Don't select the buffer which is being copied to
+		 * userspace.
+		 */
+		if (curr == stat->locked_buf)
+			continue;
+
+		/* Uninitialised buffer -- pick that one over anything else. */
+		if (curr->frame_number == stat->max_frame) {
+			found = curr;
+			break;
+		}
+
+		if (!found ||
+		    !greater_overflow(curr->frame_number, found->frame_number,
+				      stat->max_frame))
+			found = curr;
+	}
+
+	stat->active_buf = found;
+
+	spin_unlock_irqrestore(&stat->lock, flags);
+
+	return found;
+}
+
+/* Get buffer to userspace. */
+static struct ispstat_buffer *ispstat_buf_find(
+	struct ispstat *stat, u32 frame_number)
+{
+	int i;
+
+	for (i = 0; i < stat->nbufs; i++) {
+		struct ispstat_buffer *curr = &stat->buf[i];
+
+		/* We cannot deal with the active buffer. */
+		if (curr == stat->active_buf)
+			continue;
+
+		/* Don't take uninitialised buffers. */
+		if (curr->frame_number == stat->max_frame)
+			continue;
+
+		/* Found correct number. */
+		if (curr->frame_number == frame_number)
+			return curr;
+	}
+
+	return NULL;
+}
+
+/**
+ * ispstat_stats_available - Check for stats available of specified frame.
+ * @aewbdata: Pointer to return AE AWB statistics data
+ *
+ * Returns 0 if successful, or -1 if statistics are unavailable.
+ **/
+struct ispstat_buffer *ispstat_buf_get(struct ispstat *stat,
+				       void __user *ptr,
+				       unsigned int frame_number)
+{
+	int rval = 0;
+	unsigned long flags;
+	struct ispstat_buffer *buf;
+
+	spin_lock_irqsave(&stat->lock, flags);
+
+	buf = ispstat_buf_find(stat, frame_number);
+	if (!buf) {
+		spin_unlock_irqrestore(&stat->lock, flags);
+		dev_dbg(stat->dev, "%s: cannot find requested buffer. "
+				"frame_number = %d\n", stat->tag, frame_number);
+		return ERR_PTR(-EBUSY);
+	}
+
+	stat->locked_buf = buf;
+
+	spin_unlock_irqrestore(&stat->lock, flags);
+
+	rval = copy_to_user((void *)ptr,
+			    buf->virt_addr,
+			    stat->buf_size);
+
+	if (rval) {
+		dev_info(stat->dev,
+			 "%s: failed copying %d bytes of stat data\n",
+			 stat->tag, rval);
+		buf = ERR_PTR(-EFAULT);
+		ispstat_buf_release(stat);
+	}
+
+	return buf;
+}
+
+void ispstat_buf_release(struct ispstat *stat)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&stat->lock, flags);
+	stat->locked_buf = NULL;
+	spin_unlock_irqrestore(&stat->lock, flags);
+}
+
+void ispstat_bufs_free(struct ispstat *stat)
+{
+	struct isp_device *isp = dev_get_drvdata(stat->dev);
+	int i;
+
+	for (i = 0; i < stat->nbufs; i++) {
+		struct ispstat_buffer *buf = &stat->buf[i];
+
+		if (!stat->dma_buf) {
+			if (!buf->iommu_addr)
+				continue;
+
+			iommu_vfree(isp->iommu, buf->iommu_addr);
+		} else {
+			if (!buf->virt_addr)
+				continue;
+
+			dma_free_coherent(stat->dev, stat->buf_alloc_size,
+					  buf->virt_addr, buf->dma_addr);
+		}
+		buf->iommu_addr = 0;
+		buf->dma_addr = 0;
+		buf->virt_addr = NULL;
+	}
+
+	stat->buf_alloc_size = 0;
+}
+
+static int ispstat_bufs_alloc_iommu(struct ispstat *stat, unsigned int size)
+{
+	struct isp_device *isp = dev_get_drvdata(stat->dev);
+	int i;
+
+	stat->buf_alloc_size = size;
+
+	for (i = 0; i < stat->nbufs; i++) {
+		struct ispstat_buffer *buf = &stat->buf[i];
+
+		WARN_ON(buf->dma_addr);
+		buf->iommu_addr = iommu_vmalloc(isp->iommu, 0, size,
+						IOMMU_FLAG);
+		if (buf->iommu_addr == 0) {
+			dev_err(stat->dev,
+				 "%s stat: Can't acquire memory for "
+				 "buffer %d\n", stat->tag, i);
+			ispstat_bufs_free(stat);
+			return -ENOMEM;
+		}
+		buf->virt_addr = da_to_va(isp->iommu, (u32)buf->iommu_addr);
+		buf->frame_number = stat->max_frame;
+	}
+	stat->dma_buf = 0;
+
+	return 0;
+}
+
+static int ispstat_bufs_alloc_dma(struct ispstat *stat, unsigned int size)
+{
+	int i;
+
+	/* dma_alloc_coherent() size is PAGE_ALIGNED */
+	size = PAGE_ALIGN(size);
+	stat->buf_alloc_size = size;
+
+	for (i = 0; i < stat->nbufs; i++) {
+		struct ispstat_buffer *buf = &stat->buf[i];
+
+		WARN_ON(buf->iommu_addr);
+		buf->virt_addr = dma_alloc_coherent(stat->dev, size,
+					&buf->dma_addr, GFP_KERNEL | GFP_DMA);
+
+		if (!buf->virt_addr || !buf->dma_addr) {
+			dev_info(stat->dev,
+				 "%s stat: Can't acquire memory for "
+				 "DMA buffer %d\n", stat->tag, i);
+			ispstat_bufs_free(stat);
+			return -ENOMEM;
+		}
+		buf->frame_number = stat->max_frame;
+	}
+	stat->dma_buf = 1;
+
+	return 0;
+}
+
+int ispstat_bufs_alloc(struct ispstat *stat,
+		       unsigned int size, int dma_buf)
+{
+	struct isp_device *isp = dev_get_drvdata(stat->dev);
+	unsigned long flags;
+	int ret = 0;
+	int i;
+
+	spin_lock_irqsave(&stat->lock, flags);
+
+	BUG_ON(stat->locked_buf != NULL);
+
+	dma_buf = dma_buf ? 1 : 0;
+
+	/* Are the old buffers big enough? */
+	if ((stat->buf_alloc_size >= size) && (stat->dma_buf == dma_buf)) {
+		for (i = 0; i < stat->nbufs; i++)
+			stat->buf[i].frame_number = stat->max_frame;
+		spin_unlock_irqrestore(&stat->lock, flags);
+		goto out;
+	}
+
+	if (isp->running != ISP_STOPPED) {
+		dev_info(stat->dev,
+			 "%s stat: trying to configure when busy\n",
+			 stat->tag);
+		spin_unlock_irqrestore(&stat->lock, flags);
+		return -EBUSY;
+	}
+
+	spin_unlock_irqrestore(&stat->lock, flags);
+
+	ispstat_bufs_free(stat);
+
+	if (dma_buf)
+		ret = ispstat_bufs_alloc_dma(stat, size);
+	else
+		ret = ispstat_bufs_alloc_iommu(stat, size);
+	if (ret)
+		size = 0;
+
+out:
+	stat->buf_size = size;
+	stat->active_buf = NULL;
+
+	return ret;
+}
+
+int ispstat_init(struct device *dev, char *tag, struct ispstat *stat,
+		 unsigned int nbufs, unsigned int max_frame)
+{
+	BUG_ON(nbufs < 2);
+	BUG_ON(max_frame < 2);
+	BUG_ON(nbufs >= max_frame);
+
+	memset(stat, 0, sizeof(*stat));
+
+	stat->buf = kcalloc(nbufs, sizeof(*stat->buf), GFP_KERNEL);
+	if (!stat->buf)
+		return -ENOMEM;
+
+	spin_lock_init(&stat->lock);
+	stat->nbufs = nbufs;
+	stat->dev = dev;
+	stat->tag = tag;
+	stat->max_frame = max_frame;
+	stat->frame_number = 1;
+
+	return 0;
+}
+
+void ispstat_free(struct ispstat *stat)
+{
+	ispstat_bufs_free(stat);
+	kfree(stat->buf);
+}
diff --git a/drivers/media/video/isp/ispstat.h b/drivers/media/video/isp/ispstat.h
new file mode 100644
index 0000000..984a76b
--- /dev/null
+++ b/drivers/media/video/isp/ispstat.h
@@ -0,0 +1,69 @@
+/*
+ * ispstat.h
+ *
+ * Copyright (C) 2009 Nokia Corporation
+ *
+ * Contact: Sakari Ailus <sakari.ailus@nokia.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ *
+ */
+
+#ifndef ISPSTAT_H
+#define ISPSTAT_H
+
+#include "isp.h"
+
+struct ispstat_buffer {
+	unsigned long iommu_addr;
+	void *virt_addr;
+	dma_addr_t dma_addr;
+	struct timeval ts;
+	u32 config_counter;
+	u32 frame_number;
+};
+
+struct ispstat {
+	spinlock_t lock;		/* Lock for this struct */
+
+	u8 dma_buf;
+	unsigned int nbufs;
+	struct ispstat_buffer *buf;
+	unsigned int buf_size;
+	unsigned int buf_alloc_size;
+	struct ispstat_buffer *active_buf;
+	struct ispstat_buffer *locked_buf;
+	unsigned int frame_number;
+	unsigned int max_frame;
+	unsigned int config_counter;
+
+	struct device *dev;
+	char *tag;		/* ispstat instantiation tag */
+};
+
+int ispstat_buf_queue(struct ispstat *stat);
+struct ispstat_buffer *ispstat_buf_next(struct ispstat *stat);
+struct ispstat_buffer *ispstat_buf_get(struct ispstat *stat,
+				       void __user *ptr,
+				       unsigned int frame_number);
+void ispstat_buf_release(struct ispstat *stat);
+void ispstat_bufs_free(struct ispstat *stat);
+int ispstat_bufs_alloc(struct ispstat *stat,
+		       unsigned int size, int dma_buf);
+int ispstat_init(struct device *dev, char *tag, struct ispstat *stat,
+		 unsigned int nbufs, unsigned int max_frame);
+void ispstat_free(struct ispstat *stat);
+
+#endif /* ISPSTAT_H */
diff --git a/drivers/media/video/isp/omap_previewer.c b/drivers/media/video/isp/omap_previewer.c
index 6405ea5..22bcab3 100644
--- a/drivers/media/video/isp/omap_previewer.c
+++ b/drivers/media/video/isp/omap_previewer.c
@@ -32,8 +32,6 @@
 #include <asm/cacheflush.h>
 
 #include "isp.h"
-#include "ispmmu.h"
-#include "ispreg.h"
 #include "omap_previewer.h"
 
 #define OMAP_PREV_NAME		"omap-previewer"
@@ -44,22 +42,20 @@
 			| (val << shift);	\
 	} while (0)
 
-/*
-#define OMAP_ISP_PREVIEWER_DEBUG
-*/
-#undef OMAP_ISP_PREVIEWER_DEBUG
-
-#ifdef OMAP_ISP_PREVIEWER_DEBUG
-#define DPRINTK_PREVIEWER(format, ...) \
-	printk(KERN_DEBUG "PREV: " format, ## __VA_ARGS__)
-#else
-#define DPRINTK_PREVIEWER(format, ...)
-#endif
-
 #define ISP_CTRL_SBL_SHARED_RPORTB	(1 << 28)
-#define ISP_CTRL_SBL_SHARED_RPORTA 	(1 << 27)
+#define ISP_CTRL_SBL_SHARED_RPORTA	(1 << 27)
 #define SBL_RD_RAM_EN				18
 
+static struct isp_interface_config prevwrap_config = {
+	.ccdc_par_ser = ISP_NONE,
+	.dataline_shift = 0,
+	.hsvs_syncdetect = ISPCTRL_SYNC_DETECT_VSRISE,
+	.strobe = 0,
+	.prestrobe = 0,
+	.shutter = 0,
+	.wait_hs_vs = 0,
+};
+
 static u32 isp_ctrl;
 static u32 prv_wsdr_addr;
 static int prev_major = -1;
@@ -67,10 +63,9 @@
 static struct class *prev_class;
 static struct prev_device *prevdevice;
 static struct platform_driver omap_previewer_driver;
-
 static u32 prev_bufsize;
 static u32 lsc_bufsize;
-static u32 ytable[ISPPRV_YENH_TBL_SIZE];
+static struct prev_params isppreview_tmp;
 
 /**
  * prev_calculate_crop - Calculate crop size according to device parameters
@@ -83,22 +78,20 @@
 static int prev_calculate_crop(struct prev_device *device,
 						struct prev_cropsize *crop)
 {
-	int ret;
-
-	dev_dbg(prev_dev, "prev_calculate_crop E\n");
+	int ret = 0;
 
 	if (!device || !crop) {
-		dev_err(prev_dev, "\nErron in argument");
+		dev_err(prev_dev, "%s: invalid argument\n", __func__);
 		return -EINVAL;
 	}
 
-	ret = isppreview_try_size(device->params->size_params.hsize,
-					device->params->size_params.vsize,
-						&crop->hcrop, &crop->vcrop);
+	crop->hcrop = device->out_hsize;
+	crop->vcrop = device->out_vsize;
 
-	crop->hcrop &= PREV_16PIX_ALIGN_MASK;
-
-	dev_dbg(prev_dev, "prev_calculate_crop L\n");
+	dev_dbg(prev_dev, "%s: Exit (%dx%d -> %dx%d)\n", __func__,
+		device->params->size_params.hsize,
+		device->params->size_params.vsize,
+		crop->hcrop, crop->vcrop);
 
 	return ret;
 }
@@ -113,11 +106,13 @@
  **/
 static int prev_get_status(struct prev_status *status)
 {
+	struct isp_device *isp = dev_get_drvdata(prevdevice->isp);
+
 	if (!status) {
-		dev_err(prev_dev, "get_status: invalid parameter\n");
+		dev_err(prev_dev, "%s: invalid argument\n", __func__);
 		return -EINVAL;
 	}
-	status->hw_busy = (char)isppreview_busy();
+	status->hw_busy = (char)isppreview_busy(&isp->isp_prev);
 	return 0;
 }
 
@@ -132,45 +127,47 @@
  **/
 static int prev_hw_setup(struct prev_params *config)
 {
-	dev_dbg(prev_dev, "prev_hw_setup E\n");
+	struct isp_device *isp = dev_get_drvdata(prevdevice->isp);
+
+	dev_dbg(prev_dev, "%s: Enter\n", __func__);
 
 	if (config->features & PREV_AVERAGER)
-		isppreview_config_averager(config->average);
+		isppreview_config_averager(&isp->isp_prev, config->average);
 	else
-		isppreview_config_averager(0);
+		isppreview_config_averager(&isp->isp_prev, 0);
 
 	if (config->features & PREV_INVERSE_ALAW)
-		isppreview_enable_invalaw(1);
+		isppreview_enable_invalaw(&isp->isp_prev, 1);
 	else
-		isppreview_enable_invalaw(0);
+		isppreview_enable_invalaw(&isp->isp_prev, 0);
 
 	if (config->features & PREV_HORZ_MEDIAN_FILTER) {
-		isppreview_config_hmed(config->hmf_params);
-		isppreview_enable_hmed(1);
+		isppreview_config_hmed(&isp->isp_prev, config->hmf_params);
+		isppreview_enable_hmed(&isp->isp_prev, 1);
 	} else
-		isppreview_enable_hmed(0);
+		isppreview_enable_hmed(&isp->isp_prev, 0);
 
 	if (config->features & PREV_DARK_FRAME_SUBTRACT) {
-		DPRINTK_PREVIEWER("[%s] darkaddr %08x, darklineoffset %d\n",
-						__func__,
-						config->drkf_params.addr,
-						config->drkf_params.offset);
-		isppreview_set_darkaddr(config->drkf_params.addr);
-		isppreview_config_darklineoffset(config->drkf_params.offset);
-		isppreview_enable_drkframe(1);
+		dev_dbg(prev_dev, "%s: darkaddr %08x, darklineoffset %d\n",
+			__func__,
+			config->drkf_params.addr,
+			config->drkf_params.offset);
+		isppreview_set_darkaddr(&isp->isp_prev,
+					config->drkf_params.addr);
+		isppreview_config_darklineoffset(&isp->isp_prev,
+						 config->drkf_params.offset);
+		isppreview_enable_drkframe(&isp->isp_prev, 1);
 	} else
-		isppreview_enable_drkframe(0);
+		isppreview_enable_drkframe(&isp->isp_prev, 0);
 
 	if (config->features & PREV_LENS_SHADING) {
-		isppreview_config_drkf_shadcomp(config->lens_shading_shift);
-		isppreview_enable_shadcomp(1);
+		isppreview_config_drkf_shadcomp(&isp->isp_prev,
+						config->lens_shading_shift);
+		isppreview_enable_shadcomp(&isp->isp_prev, 1);
 	} else
-		isppreview_enable_shadcomp(0);
+		isppreview_enable_shadcomp(&isp->isp_prev, 0);
 
-	if (config->ytable)
-		isppreview_set_luma_enhancement(config->ytable);
-
-	dev_dbg(prev_dev, "prev_hw_setup L\n");
+	dev_dbg(prev_dev, "%s: Exit\n", __func__);
 	return 0;
 }
 
@@ -185,26 +182,25 @@
 static int prev_validate_params(struct prev_params *params)
 {
 	if (!params) {
-		dev_err(prev_dev, "validate_params: error in argument");
+		dev_err(prev_dev, "%s: invalid argument\n", __func__);
 		goto err_einval;
 	}
 
 	if ((params->features & PREV_AVERAGER) == PREV_AVERAGER) {
 		if ((params->average != NO_AVE)
-					&& (params->average != AVE_2_PIX)
-					&& (params->average != AVE_4_PIX)
-					&& (params->average != AVE_8_PIX)) {
-			dev_err(prev_dev, "validate_params: wrong pix "
-								"average\n");
+				&& (params->average != AVE_2_PIX)
+				&& (params->average != AVE_4_PIX)
+				&& (params->average != AVE_8_PIX)) {
+			dev_err(prev_dev, "%s: wrong pix average\n", __func__);
 			goto err_einval;
 		} else if (((params->average == AVE_2_PIX)
-					&& (params->size_params.hsize % 2))
-					|| ((params->average == AVE_4_PIX)
-					&& (params->size_params.hsize % 4))
-					|| ((params->average == AVE_8_PIX)
-					&& (params->size_params.hsize % 8))) {
-			dev_err(prev_dev, "validate_params: "
-					"wrong pix average for input size\n");
+				&& (params->size_params.hsize % 2))
+				|| ((params->average == AVE_4_PIX)
+				&& (params->size_params.hsize % 4))
+				|| ((params->average == AVE_8_PIX)
+				&& (params->size_params.hsize % 8))) {
+			dev_err(prev_dev, "%s: wrong pix average for input"
+				" size\n", __func__);
 			goto err_einval;
 		}
 	}
@@ -212,45 +208,47 @@
 	if ((params->size_params.pixsize != PREV_INWIDTH_8BIT)
 					&& (params->size_params.pixsize
 					!= PREV_INWIDTH_10BIT)) {
-		dev_err(prev_dev, "validate_params: wrong pixsize\n");
+		dev_err(prev_dev, "%s: wrong pixsize\n", __func__);
 		goto err_einval;
 	}
 
 	if (params->size_params.hsize > MAX_IMAGE_WIDTH
 					|| params->size_params.hsize < 0) {
-		dev_err(prev_dev, "validate_params: wrong hsize\n");
+		dev_err(prev_dev, "%s: wrong hsize\n", __func__);
 		goto err_einval;
 	}
 
 	if (params->size_params.hsize % 32) {
-		dev_err(prev_dev, "validate_params: width must be multiple of"
-			" 64 bytes\n");
+		dev_err(prev_dev, "%s: width must be multiple of"
+			" 64 bytes\n", __func__);
 		goto err_einval;
 	}
 
 	if ((params->pix_fmt != YCPOS_YCrYCb)
-					&& (YCPOS_YCbYCr != params->pix_fmt)
-					&& (YCPOS_CbYCrY != params->pix_fmt)
-					&& (YCPOS_CrYCbY != params->pix_fmt)) {
-		dev_err(prev_dev, "validate_params: wrong pix_fmt");
+			&& (YCPOS_YCbYCr != params->pix_fmt)
+			&& (YCPOS_CbYCrY != params->pix_fmt)
+			&& (YCPOS_CrYCbY != params->pix_fmt)) {
+		dev_err(prev_dev, "%s: wrong pix_fmt\n", __func__);
 		goto err_einval;
 	}
 
 	if ((params->features & PREV_DARK_FRAME_SUBTRACT)
-						&& (params->features
-						& PREV_DARK_FRAME_CAPTURE)) {
-		dev_err(prev_dev, "validate_params: DARK FRAME CAPTURE and "
-						"SUBSTRACT cannot be enabled "
-						"at same time\n");
+			&& (params->features & PREV_DARK_FRAME_CAPTURE)) {
+		dev_err(prev_dev, "%s: DARK FRAME CAPTURE and SUBSTRACT "
+			"cannot be enabled at same time\n", __func__);
 		goto err_einval;
 	}
 
 	if ((params->size_params.in_pitch <= 0)
-				|| (params->size_params.in_pitch % 32)) {
-		params->size_params.in_pitch =
-				(params->size_params.hsize * 2) & 0xFFE0;
-		dev_err(prev_dev, "Error in in_pitch; new value = %d\n",
-						params->size_params.in_pitch);
+			|| (params->size_params.in_pitch % 32)) {
+		dev_err(prev_dev, "%s: invalid input pitch\n", __func__);
+		goto err_einval;
+	}
+
+	if ((params->size_params.out_pitch <= 0)
+			|| (params->size_params.out_pitch % 32)) {
+		dev_err(prev_dev, "%s: invalid output pitch\n", __func__);
+		goto err_einval;
 	}
 
 	return 0;
@@ -283,7 +281,7 @@
 {
 	u32 val;
 
-	val = isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+	val = isp_reg_readl(prevdevice->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 
 	isp_ctrl = val;
 
@@ -297,9 +295,10 @@
 	BIT_SET(val, SBL_RD_RAM_EN, 0x1, 0x1);
 
 	/* write ISP CTRL register */
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+	isp_reg_writel(prevdevice->isp, val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 
-	prv_wsdr_addr = isp_reg_readl(OMAP3_ISP_IOMEM_PREV, ISPPRV_WSDR_ADDR);
+	prv_wsdr_addr = isp_reg_readl(prevdevice->isp, OMAP3_ISP_IOMEM_PREV,
+				      ISPPRV_WSDR_ADDR);
 }
 
 /*
@@ -307,9 +306,10 @@
  */
 static void prev_unset_isp_ctrl(void)
 {
+	struct isp_device *isp = dev_get_drvdata(prevdevice->isp);
 	u32 val;
 
-	val = isp_reg_readl(OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+	val = isp_reg_readl(prevdevice->isp, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 
 	if (isp_ctrl & ISP_CTRL_SBL_SHARED_RPORTB)
 		val |= ISP_CTRL_SBL_SHARED_RPORTB;
@@ -321,14 +321,86 @@
 		val &= ~(1 << SBL_RD_RAM_EN);
 
 	/* write ISP CTRL register */
-	isp_reg_writel(val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
+	isp_reg_writel(prevdevice->isp, val, OMAP3_ISP_IOMEM_MAIN, ISP_CTRL);
 
 	/* disable dark frame and shading compensation */
-	isppreview_enable_drkframe(0);
-	isppreview_enable_shadcomp(0);
+	isppreview_enable_drkframe(&isp->isp_prev, 0);
+	isppreview_enable_shadcomp(&isp->isp_prev, 0);
 
 	/* Set output and input adresses to 0 */
-	isppreview_set_outaddr(prv_wsdr_addr);
+	isppreview_set_outaddr(&isp->isp_prev, prv_wsdr_addr);
+}
+
+/**
+ * prev_config_size - Set input width and height in previewer registers
+ * @input_w: input width
+ * @inout_h: input height
+ *
+ * Returns 0 if successful, or -EINVAL if the sent parameters are invalid.
+ **/
+static void prev_config_size(u32 input_w, u32 input_h)
+{
+	isp_reg_writel(prevdevice->isp,
+		       (0 << ISPPRV_HORZ_INFO_SPH_SHIFT) | (input_w - 1),
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_HORZ_INFO);
+
+	isp_reg_writel(prevdevice->isp,
+		       (0 << ISPPRV_VERT_INFO_SLV_SHIFT) | (input_h - 1),
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_VERT_INFO);
+
+	isp_reg_writel(prevdevice->isp,
+		       (ISPPRV_AVE_EVENDIST_2 << ISPPRV_AVE_EVENDIST_SHIFT) |
+		       (ISPPRV_AVE_ODDDIST_2 << ISPPRV_AVE_ODDDIST_SHIFT),
+		       OMAP3_ISP_IOMEM_PREV, ISPPRV_AVE);
+}
+
+/**
+ * prev_negotiate_output_size - Calculate previewer engine output size
+ * @device: Structure containing ISP preview wrapper global information
+ * @out_hsize: Return horizontal size
+ * @out_vsize: Return vertical size
+ *
+ * Returns 0 if successful, or -EINVAL if the sent parameters are invalid.
+ **/
+static int prev_negotiate_output_size(struct prev_device *prvdev,
+				u32 *out_hsize, u32 *out_vsize)
+{
+	struct isp_device *isp = dev_get_drvdata(prvdev->isp);
+	int bpp, ret;
+	struct isp_pipeline pipe;
+
+	if (prvdev->params->size_params.pixsize == PREV_INWIDTH_8BIT)
+		bpp = 1;
+	else
+		bpp = 2;
+
+	pipe.prv_in = PRV_RAW_MEM;
+	pipe.prv_out = PREVIEW_MEM;
+	pipe.ccdc_out_w = prvdev->params->size_params.hsize;
+	pipe.ccdc_out_w_img = prvdev->params->size_params.hsize;
+	pipe.ccdc_out_h = prvdev->params->size_params.vsize;
+
+	ret = isppreview_config_datapath(&isp->isp_prev, &pipe);
+	if (ret) {
+		dev_err(prev_dev, "%s: ERROR while configure isp "
+			"preview datapath!\n", __func__);
+		return ret;
+	}
+
+	ret = isppreview_try_pipeline(&isp->isp_prev, &pipe);
+	if (ret) {
+		dev_err(prev_dev, "%s: ERROR while try isp preview size!\n",
+			__func__);
+		return ret;
+	}
+
+	dev_dbg(prev_dev, "%s: try size %dx%d -> %dx%d\n", __func__,
+		pipe.ccdc_out_w_img, pipe.ccdc_out_h,
+		pipe.prv_out_w, pipe.prv_out_h);
+
+	*out_hsize = pipe.prv_out_w_img;
+	*out_vsize = pipe.prv_out_h_img;
+	return 0;
 }
 
 /**
@@ -339,111 +411,86 @@
  **/
 static int prev_do_preview(struct prev_device *device)
 {
-	int bpp, size;
-	int ret = 0;
-	u32 out_hsize, out_vsize, out_line_offset;
+	struct isp_device *isp = dev_get_drvdata(device->isp);
+	u32 out_hsize, out_vsize, out_line_offset, in_line_offset;
+	int ret = 0, bpp;
 
-	dev_dbg(prev_dev, "prev_do_preview E\n");
+	dev_dbg(prev_dev, "%s: Enter\n", __func__);
 
 	if (!device) {
-		dev_err(prev_dev, "preview: invalid parameters\n");
+		dev_err(prev_dev, "%s: invalid argument\n", __func__);
 		return -EINVAL;
 	}
 
 	prev_set_isp_ctrl(device->params->features);
-	isppreview_set_skip(2, 0);
 
 	if (device->params->size_params.pixsize == PREV_INWIDTH_8BIT)
 		bpp = 1;
 	else
 		bpp = 2;
 
-	size = device->params->size_params.hsize *
-		   device->params->size_params.vsize * bpp;
+	out_hsize = device->out_hsize;
+	out_vsize = device->out_vsize;
 
-	isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM);
+	in_line_offset = device->params->size_params.hsize * bpp;
 
-	ret = isppreview_try_size(device->params->size_params.hsize,
-					device->params->size_params.vsize,
-						&out_hsize, &out_vsize);
-
-	if (ret) {
-		dev_err(prev_dev, "ERROR while try size!\n");
-		goto out;
-	}
-
-	ret = isppreview_config_inlineoffset(device->params->size_params.hsize
-						* bpp);
+	ret = isppreview_config_inlineoffset(&isp->isp_prev, in_line_offset);
 	if (ret)
 		goto out;
 
+	dev_dbg(prev_dev, "%s: out_pitch %d, output width %d, out_hsize %d, "
+						"out_vsize %d\n", __func__,
+		device->params->size_params.out_pitch,
+		device->params->size_params.out_pitch / bpp,
+		out_hsize, out_vsize);
+
 	out_line_offset = (out_hsize * bpp) & PREV_32BYTES_ALIGN_MASK;
 
-	ret = isppreview_config_outlineoffset(out_line_offset);
+	ret = isppreview_config_outlineoffset(&isp->isp_prev, out_line_offset);
 	if (ret)
 		goto out;
 
-	ret = isppreview_config_size(device->params->size_params.hsize,
-					device->params->size_params.vsize,
-					out_hsize, out_vsize);
-	if (ret)
-		goto out;
+	prev_config_size(device->params->size_params.hsize,
+					device->params->size_params.vsize);
 
 	device->params->drkf_params.addr = device->isp_addr_lsc;
 
 	prev_hw_setup(device->params);
 
-	ret = isppreview_set_inaddr(device->isp_addr_read);
+	ret = isppreview_set_inaddr(&isp->isp_prev, device->isp_addr_read);
 	if (ret)
 		goto out;
 
-	ret = isppreview_set_outaddr(device->isp_addr_read);
+	ret = isppreview_set_outaddr(&isp->isp_prev, device->isp_addr_read);
 	if (ret)
 		goto out;
 
-	isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM);
-
-	isppreview_try_size(device->params->size_params.hsize,
-					device->params->size_params.vsize,
-					    &out_hsize,
-					    &out_vsize);
-
-	ret = isppreview_config_inlineoffset(device->params->size_params.hsize
-						* bpp);
-	if (ret)
-		goto out;
-
-	out_line_offset = (out_hsize * bpp) & PREV_32BYTES_ALIGN_MASK;
-
-	ret = isppreview_config_outlineoffset(out_line_offset);
-	if (ret)
-		goto out;
-
-	ret = isppreview_config_size(device->params->size_params.hsize,
-					device->params->size_params.vsize,
-							out_hsize, out_vsize);
-
-	ret = isp_set_callback(CBK_PREV_DONE, prev_isr, (void *) device,
-								(void *) NULL);
+	ret = isp_set_callback(device->isp, CBK_PREV_DONE, prev_isr,
+			       (void *) device, (void *) NULL);
 	if (ret) {
-		dev_err(prev_dev, "ERROR while setting Previewer callback!\n");
+		dev_err(prev_dev,
+			"%s: setting previewer callback failed\n", __func__);
 		goto out;
 	}
 
 	/* Make sure we don't wait for any HS_VS interrupts */
-	isp_set_hs_vs(0);
+	isp_set_hs_vs(device->isp, 0);
 
-	isppreview_enable(1);
+	isp_configure_interface(device->isp, &prevwrap_config);
+
+	isp_start(device->isp);
+
+	isppreview_enable(&isp->isp_prev, 1);
 
 	wait_for_completion_interruptible(&device->wfc);
 
-	isppreview_enable(0);
+	isppreview_enable(&isp->isp_prev, 0);
 
-	ret = isp_unset_callback(CBK_PREV_DONE);
+	ret = isp_unset_callback(device->isp, CBK_PREV_DONE);
 
 	prev_unset_isp_ctrl();
 
-	dev_dbg(prev_dev, "prev_do_preview L\n");
+	dev_dbg(prev_dev, "%s: Exit\n", __func__);
 out:
 	return ret;
 }
@@ -459,14 +506,16 @@
 	struct prev_fh *fh = q->priv_data;
 	struct prev_device *device = fh->device;
 
+	dev_dbg(prev_dev, "%s: Enter\n", __func__);
+
 	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		ispmmu_vunmap(device->isp_addr_read);
+		ispmmu_vunmap(device->isp, device->isp_addr_read);
 		device->isp_addr_read = 0;
 		spin_lock(&device->inout_vbq_lock);
 		vb->state = VIDEOBUF_NEEDS_INIT;
 		spin_unlock(&device->inout_vbq_lock);
 	} else if (q->type == V4L2_BUF_TYPE_PRIVATE) {
-		ispmmu_vunmap(device->isp_addr_lsc);
+		ispmmu_vunmap(device->isp, device->isp_addr_lsc);
 		device->isp_addr_lsc = 0;
 		spin_lock(&device->lsc_vbq_lock);
 		vb->state = VIDEOBUF_NEEDS_INIT;
@@ -478,7 +527,7 @@
 		videobuf_dma_free(videobuf_to_dma(vb));
 	}
 
-	dev_dbg(prev_dev, "previewer_vbq_release\n");
+	dev_dbg(prev_dev, "%s: Exit\n", __func__);
 }
 
 /**
@@ -497,6 +546,8 @@
 	struct prev_device *device = fh->device;
 	u32 bpp = 1;
 
+	dev_dbg(prev_dev, "%s: Enter\n", __func__);
+
 	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		spin_lock(&device->inout_vbq_lock);
 
@@ -508,13 +559,15 @@
 
 		if (!device->params->size_params.hsize ||
 			!device->params->size_params.vsize) {
-			dev_err(prev_dev, "Can't setup inout buffer size\n");
+			dev_err(prev_dev, "%s: Can't setup input/output "
+				"buffer sizes\n", __func__);
 			spin_unlock(&device->inout_vbq_lock);
 			return -EINVAL;
 		}
 
 		if (device->params->size_params.pixsize == PREV_INWIDTH_10BIT)
 			bpp = 2;
+
 		*size = prev_bufsize = bpp * device->params->size_params.hsize *
 					device->params->size_params.vsize;
 		spin_unlock(&device->inout_vbq_lock);
@@ -528,7 +581,8 @@
 
 		if (!device->params->size_params.hsize ||
 			!device->params->size_params.vsize) {
-			dev_err(prev_dev, "Can't setup lsc buffer size\n");
+			dev_err(prev_dev, "%s: Can't setup lsc buffer size\n",
+				 __func__);
 			spin_unlock(&device->lsc_vbq_lock);
 			return -EINVAL;
 		}
@@ -543,7 +597,7 @@
 		return -EINVAL;
 	}
 
-	dev_dbg(prev_dev, "previewer_vbq_setup\n");
+	dev_dbg(prev_dev, "%s: Exit\n", __func__);
 	return 0;
 }
 
@@ -566,7 +620,7 @@
 	unsigned int isp_addr;
 	struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
 
-	dev_dbg(prev_dev, "previewer_vbq_prepare E\n");
+	dev_dbg(prev_dev, "%s: Enter\n", __func__);
 
 	if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
 		spin_lock(&device->inout_vbq_lock);
@@ -574,11 +628,12 @@
 		if (vb->baddr) {
 			vb->size = prev_bufsize;
 			vb->bsize = prev_bufsize;
-			DPRINTK_PREVIEWER("[%s] bsize = %d\n", __func__,
-								vb->bsize);
+			dev_dbg(prev_dev, "%s: bsize = %d\n",
+				__func__, vb->bsize);
 		} else {
 			spin_unlock(&device->inout_vbq_lock);
-			dev_err(prev_dev, "No user buffer allocated\n");
+			dev_err(prev_dev, "%s: No user buffer allocated\n",
+				__func__);
 			goto out;
 		}
 
@@ -588,19 +643,21 @@
 		spin_unlock(&device->inout_vbq_lock);
 
 		if (vb->state == VIDEOBUF_NEEDS_INIT) {
-			DPRINTK_PREVIEWER("[%s] baddr = %08x\n", __func__,
-								(int)vb->baddr);
+			dev_dbg(prev_dev, "%s: baddr = %08x\n",
+				__func__, (int)vb->baddr);
 			err = videobuf_iolock(q, vb, NULL);
 			if (!err) {
-				isp_addr = ispmmu_vmap(dma->sglist,
-						dma->sglen);
+				isp_addr = ispmmu_vmap(device->isp,
+						       dma->sglist,
+						       dma->sglen);
 
 				if (!isp_addr) {
 					err = -EIO;
 				} else {
 					device->isp_addr_read = isp_addr;
-					DPRINTK_PREVIEWER("[%s] isp_addr_read ="
-						" %08x\n", __func__, isp_addr);
+					dev_dbg(prev_dev, "%s: isp_addr_read "
+						"= %08x\n",
+						__func__, isp_addr);
 				}
 			}
 		}
@@ -620,11 +677,12 @@
 		if (vb->baddr) {
 			vb->size = lsc_bufsize;
 			vb->bsize = lsc_bufsize;
-			DPRINTK_PREVIEWER("[%s] bsize = %d\n", __func__,
-								vb->bsize);
+			dev_dbg(prev_dev, "%s: bsize = %d\n",
+				__func__, vb->bsize);
 		} else {
 			spin_unlock(&device->lsc_vbq_lock);
-			dev_err(prev_dev, "No user buffer allocated\n");
+			dev_err(prev_dev, "%s: No user buffer allocated\n",
+				__func__);
 			goto out;
 		}
 
@@ -634,18 +692,20 @@
 		spin_unlock(&device->lsc_vbq_lock);
 
 		if (vb->state == VIDEOBUF_NEEDS_INIT) {
-			DPRINTK_PREVIEWER("[%s] baddr = %08x\n", __func__,
-								(int)vb->baddr);
+			dev_dbg(prev_dev, "%s: baddr = %08x\n",
+				__func__, (int)vb->baddr);
 			err = videobuf_iolock(q, vb, NULL);
 			if (!err) {
-				isp_addr = ispmmu_vmap(dma->sglist,
-								dma->sglen);
+				isp_addr = ispmmu_vmap(device->isp,
+						       dma->sglist,
+						       dma->sglen);
 				if (!isp_addr) {
 					err = -EIO;
 				} else {
 					device->isp_addr_lsc = isp_addr;
-					DPRINTK_PREVIEWER("[%s] isp_addr_lsc ="
-						" %08x\n", __func__, isp_addr);
+					dev_dbg(prev_dev, "%s: isp_addr_lsc"
+						"= %08x\n",
+						__func__, isp_addr);
 				}
 			}
 		}
@@ -662,7 +722,7 @@
 		return -EINVAL;
 	}
 
-	dev_dbg(prev_dev, "previewer_vbq_prepare L\n");
+	dev_dbg(prev_dev, "%s: Exit\n", __func__);
 out:
 	return err;
 }
@@ -684,46 +744,44 @@
  **/
 static int previewer_open(struct inode *inode, struct file *filp)
 {
-	int ret = 0;
 	struct prev_device *device = prevdevice;
-	struct prev_params *config = isppreview_get_config();
 	struct prev_fh *fh;
+	int ret = 0;
+	struct device *isp;
+	struct isp_device *isp_dev;
 
-	if (config == NULL) {
-		dev_err(prev_dev, "Unable to initialize default config "
-			"from isppreviewer\n\n");
-		return -EACCES;
-	}
+	if (mutex_lock_interruptible(&device->prevwrap_mutex))
+		return -EINTR;
 
 	if (device->opened || (filp->f_flags & O_NONBLOCK)) {
-		dev_err(prev_dev, "previewer_open: device is already "
-								"opened\n");
-		return -EBUSY;
+		dev_err(prev_dev, "%s: Device is already opened\n", __func__);
+		ret = -EBUSY;
+		goto err_open_fh;
 	}
 
 	fh = kzalloc(sizeof(struct prev_fh), GFP_KERNEL);
-	if (NULL == fh)
-		return -ENOMEM;
+	if (NULL == fh) {
+		ret = -ENOMEM;
+		goto err_open_fh;
+	}
 
-	ret = isp_get();
+	isp = isp_get();
+	if (!isp) {
+		dev_err(prev_dev, "%s: Can't acquire isp core\n", __func__);
+		ret = -EACCES;
+		goto err_isp;
+	}
+	device->isp = isp;
+	isp_dev = dev_get_drvdata(isp);
+	device->params = &isp_dev->isp_prev.params;
 
+	ret = isppreview_request(&isp_dev->isp_prev);
 	if (ret < 0) {
-		kfree(fh);
-		printk(KERN_ERR "Can't enable ISP clocks (ret %d)\n", ret);
-		return -EACCES;
+		dev_err(prev_dev, "%s: Can't acquire isp preview\n", __func__);
+		goto err_prev;
 	}
 
-	ret = isppreview_request();
-
-	if (ret) {
-		kfree(fh);
-		isp_put();
-		dev_err(prev_dev, "Can't acquire isppreview\n");
-		return ret;
-	}
-
-	device->params = config;
-	device->opened = 1;
+	device->opened = true;
 
 	filp->private_data = fh;
 	fh->inout_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
@@ -731,20 +789,27 @@
 	fh->device = device;
 
 	videobuf_queue_sg_init(&fh->inout_vbq, &device->vbq_ops, NULL,
-					&device->inout_vbq_lock, fh->inout_type,
-					V4L2_FIELD_NONE,
-					sizeof(struct videobuf_buffer), fh);
+			&device->inout_vbq_lock, fh->inout_type,
+			V4L2_FIELD_NONE,
+			sizeof(struct videobuf_buffer), fh);
 
 	videobuf_queue_sg_init(&fh->lsc_vbq, &device->vbq_ops, NULL,
-					&device->lsc_vbq_lock, fh->lsc_type,
-					V4L2_FIELD_NONE,
-					sizeof(struct videobuf_buffer), fh);
+			&device->lsc_vbq_lock, fh->lsc_type,
+			V4L2_FIELD_NONE,
+			sizeof(struct videobuf_buffer), fh);
 
 	init_completion(&device->wfc);
-	device->wfc.done = 0;
-	mutex_init(&device->prevwrap_mutex);
-
+	device->configured = false;
+	mutex_unlock(&device->prevwrap_mutex);
 	return 0;
+
+err_prev:
+	isp_put();
+err_isp:
+	kfree(fh);
+err_open_fh:
+	mutex_unlock(&device->prevwrap_mutex);
+	return ret;
 }
 
 /**
@@ -758,23 +823,25 @@
 {
 	struct prev_fh *fh = filp->private_data;
 	struct prev_device *device = fh->device;
+	struct isp_device *isp = dev_get_drvdata(device->isp);
 	struct videobuf_queue *q1 = &fh->inout_vbq;
 	struct videobuf_queue *q2 = &fh->lsc_vbq;
 
-	device->opened = 0;
-	device->params = NULL;
+	if (mutex_lock_interruptible(&device->prevwrap_mutex))
+		return -EINTR;
+	device->opened = false;
 	videobuf_mmap_free(q1);
 	videobuf_mmap_free(q2);
 	videobuf_queue_cancel(q1);
 	videobuf_queue_cancel(q2);
-	isppreview_free();
+	isppreview_free(&isp->isp_prev);
 	isp_put();
 	prev_bufsize = 0;
 	lsc_bufsize = 0;
 	filp->private_data = NULL;
+	mutex_unlock(&device->prevwrap_mutex);
 	kfree(fh);
-
-	dev_dbg(prev_dev, "previewer_release\n");
+	dev_dbg(prev_dev, "%s: Exit\n", __func__);
 	return 0;
 }
 
@@ -792,6 +859,141 @@
 }
 
 /**
+ * prev_copy_params - Copy usermode params to kernel.
+ * @usr_params: Pointer to usermode structure
+ * @isp_params: Pointer to kernel structure
+ *
+ * Returns 0 if successful, or negative on fail
+ **/
+static int prev_copy_params(struct prev_params *usr_params,
+				struct prev_params *isp_params)
+{
+	isp_params->features = usr_params->features;
+	isp_params->pix_fmt = usr_params->pix_fmt;
+	isp_params->cfa.cfafmt = usr_params->cfa.cfafmt;
+	isp_params->cfa.cfa_gradthrs_vert = usr_params->cfa.cfa_gradthrs_vert;
+	isp_params->cfa.cfa_gradthrs_horz = usr_params->cfa.cfa_gradthrs_horz;
+
+	if (usr_params->cfa.cfa_table && isp_params->cfa.cfa_table) {
+		if (copy_from_user(isp_params->cfa.cfa_table,
+				usr_params->cfa.cfa_table,
+				ISPPRV_CFA_TBL_SIZE * 4))
+			return -EFAULT;
+	} else {
+		dev_warn(prev_dev,
+			"%s: invalid cfa table pointer (usr: %08x,"
+			" krn: %08x)\n", __func__,
+			(int)usr_params->cfa.cfa_table,
+			(int)isp_params->cfa.cfa_table);
+	}
+
+	isp_params->csup = usr_params->csup;
+
+	if (usr_params->ytable && isp_params->ytable) {
+		if (copy_from_user(isp_params->ytable,
+				usr_params->ytable, ISPPRV_YENH_TBL_SIZE * 4))
+			return -EFAULT;
+	} else {
+		dev_warn(prev_dev,
+			"%s: invalid ytable pointer (usr: %08x, krn: %08x)\n",
+			__func__,
+			(int)usr_params->ytable, (int)isp_params->ytable);
+	}
+
+	isp_params->nf = usr_params->nf;
+	isp_params->dcor = usr_params->dcor;
+
+	if (usr_params->gtable.redtable && isp_params->gtable.redtable) {
+		if (copy_from_user(isp_params->gtable.redtable,
+				usr_params->gtable.redtable,
+				ISPPRV_GAMMA_TBL_SIZE * 4))
+			return -EFAULT;
+	} else {
+		dev_warn(prev_dev,
+			"%s: invalid gtable red pointer (usr: %08x, "
+			"krn: %08x)\n", __func__,
+			(int)usr_params->gtable.redtable,
+			(int)isp_params->gtable.redtable);
+	}
+
+	if (usr_params->gtable.greentable && isp_params->gtable.greentable) {
+		if (copy_from_user(isp_params->gtable.greentable,
+				usr_params->gtable.greentable,
+				ISPPRV_GAMMA_TBL_SIZE * 4))
+			return -EFAULT;
+	} else {
+		dev_warn(prev_dev,
+			"%s: invalid gtable green pointer (usr: %08x,"
+			"krn: %08x)\n", __func__,
+			(int)usr_params->gtable.greentable,
+			(int)isp_params->gtable.greentable);
+	}
+
+	if (usr_params->gtable.bluetable && isp_params->gtable.bluetable) {
+		if (copy_from_user(isp_params->gtable.bluetable,
+				usr_params->gtable.bluetable,
+				ISPPRV_GAMMA_TBL_SIZE * 4))
+			return -EFAULT;
+	} else {
+		dev_warn(prev_dev,
+			"%s: invalid gtable blue pointer (usr: %08x,"
+			" krn: %08x)\n", __func__,
+			(int)usr_params->gtable.bluetable,
+			(int)isp_params->gtable.bluetable);
+	}
+
+	isp_params->wbal = usr_params->wbal;
+	isp_params->blk_adj = usr_params->blk_adj;
+	isp_params->rgb2rgb = usr_params->rgb2rgb;
+	isp_params->rgb2ycbcr = usr_params->rgb2ycbcr;
+	isp_params->hmf_params = usr_params->hmf_params;
+	isp_params->size_params = usr_params->size_params;
+	isp_params->drkf_params = usr_params->drkf_params;
+	isp_params->lens_shading_shift = usr_params->lens_shading_shift;
+	isp_params->average = usr_params->average;
+	isp_params->contrast = usr_params->contrast;
+	isp_params->brightness = usr_params->brightness;
+
+	return 0;
+}
+
+static int prev_get_params(struct prev_params __user *usr_params,
+			   struct prev_device *device)
+{
+	struct prev_params usr_params_new;
+	u32 *cfa_table; /* params.cfa.cfa_table */
+	u32 *ytable; /* params.ytable */
+	u32 *redtable; /* params.gtable.redtable */
+	u32 *greentable; /* params.gtable.greentable */
+	u32 *bluetable; /* params.gtable.bluetable */
+
+	if (copy_from_user(&usr_params_new, usr_params,
+			   sizeof(struct prev_params)))
+		return -EFAULT;
+
+	/* Backup user pointers */
+	cfa_table = usr_params_new.cfa.cfa_table;
+	ytable = usr_params_new.ytable;
+	redtable = usr_params_new.gtable.redtable;
+	greentable = usr_params_new.gtable.greentable;
+	bluetable = usr_params_new.gtable.bluetable;
+
+	memcpy(&usr_params_new, device->params, sizeof(struct prev_params));
+
+	/* Restore user pointers */
+	usr_params_new.cfa.cfa_table = cfa_table;
+	usr_params_new.ytable = ytable;
+	usr_params_new.gtable.redtable = redtable;
+	usr_params_new.gtable.greentable = greentable;
+	usr_params_new.gtable.bluetable = bluetable;
+
+	if (copy_to_user(usr_params, &usr_params_new,
+			 sizeof(struct prev_params)))
+		return -EFAULT;
+	return 0;
+}
+
+/**
  * previewer_ioctl - I/O control function for Preview Wrapper
  * @inode: Inode structure associated with the Preview Wrapper.
  * @file: File structure associated with the Preview Wrapper.
@@ -812,11 +1014,11 @@
 	struct v4l2_buffer b;
 	struct v4l2_requestbuffers req;
 
-	dev_dbg(prev_dev, "Entering previewer_ioctl()\n");
+	dev_dbg(prev_dev, "%s: Enter\n", __func__);
 
 	if ((_IOC_TYPE(cmd) != PREV_IOC_BASE)
 					|| (_IOC_NR(cmd) > PREV_IOC_MAXNR)) {
-		dev_err(prev_dev, "Bad command Value \n");
+		dev_err(prev_dev, "%s: bad command value\n", __func__);
 		goto err_minusone;
 	}
 
@@ -825,7 +1027,7 @@
 	else if (_IOC_DIR(cmd) & _IOC_WRITE)
 		ret = !access_ok(VERIFY_READ, (void *)arg, _IOC_SIZE(cmd));
 	if (ret) {
-		dev_err(prev_dev, "access denied\n");
+		dev_err(prev_dev, "%s: access denied\n", __func__);
 		goto err_minusone;
 	}
 
@@ -902,44 +1104,46 @@
 			return -EFAULT;
 		}
 
-		if (params.ytable && copy_from_user(ytable, params.ytable,
-				ISPPRV_YENH_TBL_SIZE*sizeof(u32))) {
-			mutex_unlock(&device->prevwrap_mutex);
-			return -EFAULT;
+		memcpy(&isppreview_tmp, device->params,
+			sizeof(isppreview_tmp));
+
+		ret = prev_copy_params(&params, device->params);
+		if (ret) {
+			memcpy(device->params, &isppreview_tmp,
+				sizeof(isppreview_tmp));
+			dev_err(prev_dev, "%s: copy parameters fail\n",
+				__func__);
+			goto out;
 		}
 
-		ret = prev_validate_params(&params);
+		ret = prev_validate_params(device->params);
 		if (ret < 0) {
-			dev_err(prev_dev, "Error validating parameters!\n");
+			memcpy(device->params, &isppreview_tmp,
+				sizeof(isppreview_tmp));
+			dev_err(prev_dev, "%s: validating parameters fail!\n",
+				 __func__);
 			mutex_unlock(&device->prevwrap_mutex);
 			goto out;
 		}
 
-		if (device->params) {
-			memcpy(device->params, &params,
-						sizeof(struct prev_params));
+		device->configured = true;
 
-			if (params.ytable)
-				device->params->ytable = ytable;
-		} else {
-			mutex_unlock(&device->prevwrap_mutex);
-			return -EINVAL;
+		ret = prev_negotiate_output_size(device, &device->out_hsize,
+					&device->out_vsize);
+		if (ret) {
+			dev_err(prev_dev, "%s: negotiate output size fail\n",
+				 __func__);
+			ret = -EINVAL;
+			goto out;
 		}
-
-		/* Update the values in Preview module now b/c otherwise when
-		 * isppreview_try_size() is next called it won't update the
-		 * output size correctly.
-		 */
-		ret = prev_hw_setup(device->params);
-		isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM);
+		dev_dbg(prev_dev, "%s: out_hsize %d, out_vsize %d\n", __func__,
+			device->out_hsize, device->out_vsize);
 
 		mutex_unlock(&device->prevwrap_mutex);
 		break;
 
 	case PREV_GET_PARAM:
-		if (copy_to_user((struct prev_params *)arg, device->params,
-						sizeof(struct prev_params)))
-			ret = -EFAULT;
+		prev_get_params((struct prev_params *)arg, device);
 		break;
 
 	case PREV_GET_STATUS:
@@ -967,18 +1171,25 @@
 	{
 		struct prev_cropsize outputsize;
 
+		if (device->configured == false) {
+			ret = -EPERM;
+			dev_err(prev_dev, "%s: not configured yet\n",
+				__func__);
+			break;
+		}
+
 		ret = prev_calculate_crop(device, &outputsize);
 		if (ret)
 			break;
 
 		if (copy_to_user((struct prev_cropsize *)arg, &outputsize,
-						sizeof(struct prev_cropsize)))
+					sizeof(struct prev_cropsize)))
 			ret = -EFAULT;
 		break;
 	}
 
 	default:
-		dev_err(prev_dev, "previewer_ioctl: Invalid Command Value\n");
+		dev_err(prev_dev, "%s: invalid command value\n", __func__);
 		ret = -EINVAL;
 	}
 out:
@@ -997,7 +1208,7 @@
  **/
 static void previewer_platform_release(struct device *device)
 {
-	dev_dbg(prev_dev, "previewer_platform_release()\n");
+	dev_dbg(prev_dev, "%s: Enter\n", __func__);
 }
 
 static const struct file_operations prev_fops = {
@@ -1068,10 +1279,10 @@
 	prev_major = register_chrdev(0, OMAP_PREV_NAME, &prev_fops);
 
 	if (prev_major < 0) {
-		dev_err(prev_dev, OMAP_PREV_NAME ": initialization "
-				"failed. could not register character "
-				"device\n");
-		return -ENODEV;
+		dev_err(prev_dev, OMAP_PREV_NAME ": Initialization "
+			"failed. Could not register character device\n");
+		ret = -ENODEV;
+		goto fail1;
 	}
 
 	ret = platform_driver_register(&omap_previewer_driver);
@@ -1094,13 +1305,14 @@
 	prev_dev = device_create(prev_class, prev_dev,
 					MKDEV(prev_major, 0), NULL,
 					OMAP_PREV_NAME);
-	dev_dbg(prev_dev, OMAP_PREV_NAME ": Registered Previewer Wrapper\n");
-	device->opened = 0;
+	dev_info(prev_dev, OMAP_PREV_NAME ": Registered preview wrapper\n");
+	device->opened = false;
 
 	device->vbq_ops.buf_setup = previewer_vbq_setup;
 	device->vbq_ops.buf_prepare = previewer_vbq_prepare;
 	device->vbq_ops.buf_release = previewer_vbq_release;
 	device->vbq_ops.buf_queue = previewer_vbq_queue;
+	mutex_init(&device->prevwrap_mutex);
 	spin_lock_init(&device->inout_vbq_lock);
 	spin_lock_init(&device->lsc_vbq_lock);
 	prevdevice = device;
@@ -1112,7 +1324,8 @@
 	platform_driver_unregister(&omap_previewer_driver);
 fail2:
 	unregister_chrdev(prev_major, OMAP_PREV_NAME);
-
+fail1:
+	kfree(device);
 	return ret;
 }
 
diff --git a/drivers/media/video/isp/omap_previewer.h b/drivers/media/video/isp/omap_previewer.h
index 805cd9c..00dcc07 100644
--- a/drivers/media/video/isp/omap_previewer.h
+++ b/drivers/media/video/isp/omap_previewer.h
@@ -143,6 +143,7 @@
 struct prev_device {
 	struct prev_params *params;
 	unsigned char opened;
+	unsigned char configured;
 	struct completion wfc;
 	struct mutex prevwrap_mutex;
 	spinlock_t inout_vbq_lock; /* Spinlock for in/out videobuf queues. */
@@ -150,6 +151,9 @@
 	struct videobuf_queue_ops vbq_ops;
 	dma_addr_t isp_addr_read;
 	dma_addr_t isp_addr_lsc;
+	u32 out_hsize;
+	u32 out_vsize;
+	struct device *isp;
 };
 
 /**
diff --git a/drivers/media/video/isp/omap_resizer.c b/drivers/media/video/isp/omap_resizer.c
index 128f6da..2bc5755 100644
--- a/drivers/media/video/isp/omap_resizer.c
+++ b/drivers/media/video/isp/omap_resizer.c
@@ -30,9 +30,9 @@
 #include <linux/uaccess.h>
 #include <media/v4l2-dev.h>
 #include <asm/cacheflush.h>
+#include <mach/iovmm.h>
 
 #include "isp.h"
-#include "ispmmu.h"
 #include "ispreg.h"
 #include "ispresizer.h"
 #include <linux/omap_resizer.h>
@@ -41,13 +41,15 @@
 
 /* Defines and Constants*/
 #define MAX_CHANNELS		16
-#define MAX_IMAGE_WIDTH		2047
-#define MAX_IMAGE_WIDTH_HIGH	2047
 #define ALIGNMENT		16
 #define CHANNEL_BUSY		1
 #define CHANNEL_FREE		0
 #define PIXEL_EVEN		2
 #define RATIO_MULTIPLIER	256
+#define MAX_4TAP_OUTWIDTH_3430	3300
+#define MAX_7TAP_OUTWIDTH_3430	1650
+#define MAX_4TAP_OUTWIDTH_3630	4096
+#define MAX_7TAP_OUTWIDTH_3630	2048
 /* Bit position Macro */
 /* macro for bit set and clear */
 #define BITSET(variable, bit)	((variable) | (1 << bit))
@@ -77,16 +79,16 @@
 #define COEFF_ADDRESS_OFFSET	0x04
 
 static DECLARE_MUTEX(resz_wrapper_mutex);
+static int multipass_active;
 
-/* Global structure which contains information about number of channels
-   and protection variables */
-struct device_params {
-
-	unsigned char opened;			/* state of the device */
-	struct completion compl_isr;		/* Completion for interrupt */
-	struct mutex reszwrap_mutex;		/* Semaphore for array */
-
-	struct videobuf_queue_ops vbq_ops;	/* videobuf queue operations */
+static struct isp_interface_config reszwrap_config = {
+	.ccdc_par_ser = ISP_NONE,
+	.dataline_shift = 0,
+	.hsvs_syncdetect = ISPCTRL_SYNC_DETECT_VSRISE,
+	.strobe = 0,
+	.prestrobe = 0,
+	.shutter = 0,
+	.wait_hs_vs = 0,
 };
 
 /* Register mapped structure which contains the every register
@@ -184,7 +186,31 @@
 	enum config_done config_state;
 	u8 input_buf_index;
 	u8 output_buf_index;
-
+};
+/* Global structure which contains information about number of channels
+   and protection variables */
+struct device_params {
+	struct rsz_params *params;
+	struct channel_config *config;		/* Pointer to channel */
+	struct rsz_mult *multipass;		/* Multipass to support */
+	unsigned char opened;			/* state of the device */
+	struct completion compl_isr;		/* Completion for interrupt */
+	struct mutex reszwrap_mutex;		/* Semaphore for array */
+	struct videobuf_queue_ops vbq_ops;	/* videobuf queue operations */
+	rsz_callback 	callback;		/* callback function which gets
+						 * called when Resizer
+						 * finishes resizing
+						 */
+	void *callback_arg;
+	u32 in_buf_virt_addr[32];
+	u32 *out_buf_phy_addr[32];
+	u32 out_buf_virt_addr[32];
+	u32 num_video_buffers;
+	dma_addr_t tmp_buf;
+	size_t tmp_buf_size;
+	struct rsz_mult original_multipass;
+	struct resizer_config original_rsz_conf_chan;
+	struct device *isp;
 };
 
 /* per-filehandle data structure */
@@ -201,7 +227,6 @@
 	enum v4l2_buf_type type;
 	struct videobuf_queue vbq;
 	struct device_params *device;
-
 	dma_addr_t isp_addr_read;		/* Input/Output address */
 	dma_addr_t isp_addr_write;		/* Input/Output address */
 	u32 rsz_bufsize;			/* channel specific buffersize
@@ -211,8 +236,10 @@
 static struct device_params *device_config;
 static struct device *rsz_device;
 static int rsz_major = -1;
+
 /* functions declaration */
-static void rsz_hardware_setup(struct channel_config *rsz_conf_chan);
+static void rsz_hardware_setup(struct device_params *device,
+			       struct channel_config *rsz_conf_chan);
 static int rsz_set_params(struct rsz_mult *multipass, struct rsz_params *,
 						struct channel_config *);
 static int rsz_get_params(struct rsz_params *, struct channel_config *);
@@ -222,54 +249,65 @@
 						void *arg2);
 static void rsz_calculate_crop(struct channel_config *rsz_conf_chan,
 					struct rsz_cropsize *cropsize);
-static int rsz_set_multipass(struct rsz_mult *multipass,
-					struct channel_config *rsz_conf_chan);
+static int rsz_set_multipass(struct device_params *device,
+			     struct rsz_mult *multipass,
+			     struct channel_config *rsz_conf_chan);
 static int rsz_set_ratio(struct rsz_mult *multipass,
 					struct channel_config *rsz_conf_chan);
 static void rsz_config_ratio(struct rsz_mult *multipass,
 					struct channel_config *rsz_conf_chan);
 
+static void rsz_tmp_buf_free(void);
+static u32 rsz_tmp_buf_alloc(size_t size);
+static void rsz_save_multipass_context(void);
+static void rsz_restore_multipass_context(void);
+
+static void isp_enable_interrupts(struct device *dev, int is_raw)
+{
+	isp_reg_writel(dev, IRQ0ENABLE_RSZ_DONE_IRQ,
+		       OMAP3_ISP_IOMEM_MAIN, ISP_IRQ0ENABLE);
+}
+
 /**
  * rsz_hardware_setup - Sets hardware configuration registers
  * @rsz_conf_chan: Structure containing channel configuration
  *
  * Set hardware configuration registers
  **/
-static void rsz_hardware_setup(struct channel_config *rsz_conf_chan)
+static void rsz_hardware_setup(struct device_params *device,
+			       struct channel_config *rsz_conf_chan)
 {
 	int coeffcounter;
 	int coeffoffset = 0;
 
 	down(&resz_wrapper_mutex);
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_cnt,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_cnt,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT);
-
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_in_start,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_in_start,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_START);
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_in_size,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_in_size,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_IN_SIZE);
-
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_out_size,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_out_size,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_OUT_SIZE);
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_sdr_inadd,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_sdr_inadd,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_sdr_inoff,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_sdr_inoff,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INOFF);
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_sdr_outadd,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_sdr_outadd,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_sdr_outoff,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_sdr_outoff,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
-	isp_reg_writel(rsz_conf_chan->register_config.rsz_yehn,
+	isp_reg_writel(device->isp, rsz_conf_chan->register_config.rsz_yehn,
 			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_YENH);
 
 	for (coeffcounter = 0; coeffcounter < MAX_COEF_COUNTER;
 							coeffcounter++) {
-		isp_reg_writel(rsz_conf_chan->register_config.
+		isp_reg_writel(device->isp, rsz_conf_chan->register_config.
 						rsz_coeff_horz[coeffcounter],
 						OMAP3_ISP_IOMEM_RESZ,
 						ISPRSZ_HFILT10 + coeffoffset);
 
-		isp_reg_writel(rsz_conf_chan->register_config.
+		isp_reg_writel(device->isp, rsz_conf_chan->register_config.
 						rsz_coeff_vert[coeffcounter],
 						OMAP3_ISP_IOMEM_RESZ,
 						ISPRSZ_VFILT10 + coeffoffset);
@@ -278,6 +316,47 @@
 	up(&resz_wrapper_mutex);
 }
 
+static void rsz_save_multipass_context()
+{
+	struct channel_config *rsz_conf_chan = device_config->config;
+	struct rsz_mult *multipass = device_config->multipass;
+
+	struct resizer_config  *original_rsz_conf_chan
+		= &device_config->original_rsz_conf_chan;
+	struct rsz_mult *original_multipass
+		= &device_config->original_multipass;
+
+	memset(original_rsz_conf_chan,
+		0, sizeof(struct  resizer_config));
+	memcpy(original_rsz_conf_chan,
+		(struct resizer_config *) &rsz_conf_chan->register_config,
+		sizeof(struct  resizer_config));
+	memset(original_multipass,
+		0, sizeof(struct rsz_mult));
+	memcpy(original_multipass,
+		multipass, sizeof(struct rsz_mult));
+
+	return;
+}
+
+static void rsz_restore_multipass_context()
+{
+	struct channel_config *rsz_conf_chan = device_config->config;
+	struct rsz_mult *multipass = device_config->multipass;
+
+	struct resizer_config  *original_rsz_conf_chan
+		= &device_config->original_rsz_conf_chan;
+	struct rsz_mult *original_multipass
+		= &device_config->original_multipass;
+
+	memcpy((struct resizer_config *) &rsz_conf_chan->register_config,
+		original_rsz_conf_chan, sizeof(struct  resizer_config));
+
+	memcpy(multipass, original_multipass, sizeof(struct rsz_mult));
+
+	return;
+}
+
 /**
  * rsz_start - Enables Resizer Wrapper
  * @device: Structure containing ISP resizer wrapper global information
@@ -294,6 +373,8 @@
 int rsz_start(struct rsz_fh *fh)
 {
 	struct channel_config *rsz_conf_chan = fh->config;
+	struct device_params *device = fh->device;
+	struct isp_device *isp = dev_get_drvdata(device->isp);
 	struct rsz_mult *multipass = fh->multipass;
 	struct videobuf_queue *q = &fh->vbq;
 	int ret;
@@ -305,20 +386,24 @@
 
 	rsz_conf_chan->status = CHANNEL_BUSY;
 
-	rsz_hardware_setup(rsz_conf_chan);
+	rsz_hardware_setup(device, rsz_conf_chan);
 
-	if (isp_set_callback(CBK_RESZ_DONE, rsz_isr, (void *) NULL,
-							(void *)NULL)) {
+	if (isp_set_callback(device->isp, CBK_RESZ_DONE, rsz_isr,
+			     (void *)NULL, (void *)NULL)) {
 		dev_err(rsz_device, "No callback for RSZR\n");
 		goto err_einval;
 	}
 
-	/* Make sure we don't wait for any HS_VS interrupts */
-	isp_set_hs_vs(0);
+	isp_configure_interface(device->isp, &reszwrap_config);
+
+	isp_start(device->isp);
+
+	isp_enable_interrupts(device->isp, 0);
+
 mult:
 	device_config->compl_isr.done = 0;
 
-	ispresizer_enable(1);
+	ispresizer_enable(&isp->isp_res, 1);
 
 	ret = wait_for_completion_interruptible(&device_config->compl_isr);
 	if (ret != 0) {
@@ -328,16 +413,16 @@
 	}
 
 	if (multipass->active) {
-		rsz_set_multipass(multipass, rsz_conf_chan);
+		rsz_set_multipass(device, multipass, rsz_conf_chan);
 		goto mult;
 	}
 
 	if (fh->isp_addr_read) {
-		ispmmu_vunmap(fh->isp_addr_read);
+		ispmmu_vunmap(device->isp, fh->isp_addr_read);
 		fh->isp_addr_read = 0;
 	}
 	if (fh->isp_addr_write) {
-		ispmmu_vunmap(fh->isp_addr_write);
+		ispmmu_vunmap(device->isp, fh->isp_addr_write);
 		fh->isp_addr_write = 0;
 	}
 
@@ -357,7 +442,7 @@
 	videobuf_dma_free(videobuf_to_dma(
 				q->bufs[rsz_conf_chan->output_buf_index]));
 
-	isp_unset_callback(CBK_RESZ_DONE);
+	isp_unset_callback(device->isp, CBK_RESZ_DONE);
 
 	return 0;
 err_einval:
@@ -370,8 +455,9 @@
  *
  * Returns always 0
  **/
-static int rsz_set_multipass(struct rsz_mult *multipass,
-			struct channel_config *rsz_conf_chan)
+static int rsz_set_multipass(struct device_params *device,
+			     struct rsz_mult *multipass,
+			     struct channel_config *rsz_conf_chan)
 {
 	multipass->in_hsize = multipass->out_hsize;
 	multipass->in_vsize = multipass->out_vsize;
@@ -383,9 +469,11 @@
 	multipass->in_pitch = (multipass->inptyp ? multipass->in_hsize
 						: (multipass->in_hsize * 2));
 
+	rsz_conf_chan->register_config.rsz_sdr_inadd =
+		rsz_conf_chan->register_config.rsz_sdr_outadd;
 	rsz_set_ratio(multipass, rsz_conf_chan);
 	rsz_config_ratio(multipass, rsz_conf_chan);
-	rsz_hardware_setup(rsz_conf_chan);
+	rsz_hardware_setup(device, rsz_conf_chan);
 	return 0;
 }
 
@@ -549,15 +637,11 @@
 static int rsz_set_ratio(struct rsz_mult *multipass,
 				struct channel_config *rsz_conf_chan)
 {
+	struct isp_device *isp = dev_get_drvdata(device_config->isp);
 	int alignment = 0;
 
 	rsz_conf_chan->register_config.rsz_cnt = 0;
 
-	if ((multipass->out_hsize > MAX_IMAGE_WIDTH) ||
-			(multipass->out_vsize > MAX_IMAGE_WIDTH)) {
-		dev_err(rsz_device, "Invalid output size!");
-		goto err_einval;
-	}
 	if (multipass->cbilin) {
 		rsz_conf_chan->register_config.rsz_cnt =
 				BITSET(rsz_conf_chan->register_config.rsz_cnt,
@@ -588,20 +672,18 @@
 		}
 
 	}
-	multipass->vrsz =
-		(multipass->in_vsize * RATIO_MULTIPLIER) / multipass->out_vsize;
-	multipass->hrsz =
-		(multipass->in_hsize * RATIO_MULTIPLIER) / multipass->out_hsize;
-	if (UP_RSZ_RATIO > multipass->vrsz || UP_RSZ_RATIO > multipass->hrsz) {
-		dev_err(rsz_device, "Upscaling ratio not supported!");
-		goto err_einval;
-	}
+
 	multipass->vrsz = (multipass->in_vsize - NUM_D2TAPS) * RATIO_MULTIPLIER
 						/ (multipass->out_vsize - 1);
 	multipass->hrsz = ((multipass->in_hsize - NUM_D2TAPS)
 						* RATIO_MULTIPLIER) /
 						(multipass->out_hsize - 1);
 
+	if (UP_RSZ_RATIO > multipass->vrsz || UP_RSZ_RATIO > multipass->hrsz) {
+		dev_err(rsz_device, "Upscaling ratio not supported!");
+		goto err_einval;
+	}
+
 	if (multipass->hrsz <= 512) {
 		multipass->hrsz = (multipass->in_hsize - NUM_TAPS)
 						* RATIO_MULTIPLIER
@@ -663,17 +745,9 @@
 		}
 	}
 	if (multipass->hrsz >= 64 && multipass->hrsz <= 1024) {
-		if (multipass->out_hsize > MAX_IMAGE_WIDTH) {
-			dev_err(rsz_device, "wrong width\n");
-			goto err_einval;
-		}
 		multipass->active = 0;
 
 	} else if (multipass->hrsz > 1024) {
-		if (multipass->out_hsize > MAX_IMAGE_WIDTH) {
-			dev_err(rsz_device, "wrong width\n");
-			goto err_einval;
-		}
 		if (multipass->hstph > NUM_D2PH)
 			goto err_einval;
 		multipass->num_htap = 0;
@@ -692,12 +766,37 @@
 
 	}
 
-	if (multipass->vrsz > 1024) {
-		if (multipass->out_vsize > MAX_IMAGE_WIDTH_HIGH) {
+	/* 4Tap: Check max Output width */
+	if (multipass->vrsz <= 512) {
+		if (isp->revision <= ISP_REVISION_2_0 &&
+		    multipass->out_vsize > MAX_4TAP_OUTWIDTH_3430) {
 			dev_err(rsz_device, "wrong width\n");
 			goto err_einval;
 		}
 
+		if (isp->revision > ISP_REVISION_2_0 &&
+		    multipass->out_vsize > MAX_4TAP_OUTWIDTH_3630) {
+			dev_err(rsz_device, "wrong width\n");
+			goto err_einval;
+		}
+	}
+
+	/* 7Tap: Check max Output width */
+	if (multipass->vrsz > 512) {
+		if (isp->revision <= ISP_REVISION_2_0 &&
+		    multipass->out_vsize > MAX_7TAP_OUTWIDTH_3430) {
+			dev_err(rsz_device, "wrong width\n");
+			goto err_einval;
+		}
+
+		if (isp->revision > ISP_REVISION_2_0 &&
+		    multipass->out_vsize > MAX_7TAP_OUTWIDTH_3630) {
+			dev_err(rsz_device, "wrong width\n");
+			goto err_einval;
+		}
+	}
+
+	if (multipass->vrsz > 1024) {
 		multipass->out_vsize = multipass->in_vsize * 256 / 1024;
 		multipass->vrsz = ((multipass->in_vsize - NUM_D2TAPS)
 						* RATIO_MULTIPLIER)
@@ -999,6 +1098,7 @@
 {
 	int i;
 	struct rsz_fh *fh = q->priv_data;
+	struct device_params *device = fh->device;
 
 	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
 		struct videobuf_dmabuf *dma = NULL;
@@ -1011,8 +1111,8 @@
 		videobuf_dma_free(dma);
 	}
 
-	ispmmu_vunmap(fh->isp_addr_read);
-	ispmmu_vunmap(fh->isp_addr_write);
+	ispmmu_vunmap(device->isp, fh->isp_addr_read);
+	ispmmu_vunmap(device->isp, fh->isp_addr_write);
 	fh->isp_addr_read = 0;
 	fh->isp_addr_write = 0;
 	spin_lock(&fh->vbq_lock);
@@ -1085,6 +1185,7 @@
 						enum v4l2_field field)
 {
 	struct rsz_fh *fh = q->priv_data;
+	struct device_params *device = fh->device;
 	struct channel_config *rsz_conf_chan = fh->config;
 	struct rsz_mult *multipass = fh->multipass;
 	int err = 0;
@@ -1114,7 +1215,8 @@
 	if (vb->state == VIDEOBUF_NEEDS_INIT) {
 		err = videobuf_iolock(q, vb, NULL);
 		if (!err) {
-			isp_addr = ispmmu_vmap(dma->sglist, dma->sglen);
+			isp_addr = ispmmu_vmap(device->isp, dma->sglist,
+					       dma->sglen);
 			if (!isp_addr)
 				err = -EIO;
 			else {
@@ -1184,6 +1286,7 @@
 	struct device_params *device = device_config;
 	struct rsz_params *params;
 	struct rsz_mult *multipass;
+	struct device *isp;
 
 	if ((filp->f_flags & O_NONBLOCK) == O_NONBLOCK) {
 		printk(KERN_DEBUG "omap-resizer: Device is opened in "
@@ -1192,11 +1295,18 @@
 		printk(KERN_DEBUG "omap-resizer: Device is opened in blocking "
 					"mode\n");
 	}
+
 	fh = kzalloc(sizeof(struct rsz_fh), GFP_KERNEL);
 	if (NULL == fh)
 		return -ENOMEM;
 
-	isp_get();
+	isp = isp_get();
+	if (!isp) {
+		printk(KERN_ERR "Can't enable ISP clocks (ret %d)\n", ret);
+		ret = -EACCES;
+		goto err_resz;
+	}
+	device->isp = isp;
 
 	rsz_conf_chan = kzalloc(sizeof(struct channel_config), GFP_KERNEL);
 	if (rsz_conf_chan == NULL) {
@@ -1249,6 +1359,8 @@
 err_enomem1:
 	kfree(rsz_conf_chan);
 err_enomem0:
+	isp_put();
+err_resz:
 	kfree(fh);
 	return ret;
 }
@@ -1330,6 +1442,7 @@
 	int ret = 0;
 	struct rsz_fh *fh = file->private_data;
 	struct device_params *device = fh->device;
+	struct isp_device *isp = dev_get_drvdata(device->isp);
 	struct channel_config *rsz_conf_chan = fh->config;
 
 	if ((_IOC_TYPE(cmd) != RSZ_IOC_BASE)
@@ -1426,7 +1539,7 @@
 		struct rsz_status status;
 
 		status.chan_busy = rsz_conf_chan->status;
-		status.hw_busy = ispresizer_busy();
+		status.hw_busy = ispresizer_busy(&isp->isp_res);
 		status.src = INPUT_RAM;
 
 		if (copy_to_user((struct rsz_status *)arg, &status,
@@ -1437,7 +1550,7 @@
 
 	case RSZ_RESIZE:
 		if (file->f_flags & O_NONBLOCK) {
-			if (ispresizer_busy())
+			if (ispresizer_busy(&isp->isp_res))
 				return -EBUSY;
 			else {
 				if (!mutex_trylock(&device->reszwrap_mutex))
@@ -1490,7 +1603,347 @@
 };
 
 /**
- * rsz_isr - Interrupt Service Routine for Resizer wrapper
+ * rsz_get_resource - get the Resizer module from the kernel space.
+ * This function will make sure that Resizer module is not used by any other
+ * application. It is equivalent of open() call from user space.
+ * It returns busy if the device is already opened by other application
+ * or ENOMEM if it fails to allocate memory for structures
+ * or 0 if the call is successful.
+ **/
+
+int rsz_get_resource(void)
+{
+	int ret = 0;
+	struct channel_config *rsz_conf_chan;
+	struct device_params *device = device_config;
+	struct rsz_params *params;
+	struct rsz_mult *multipass;
+	struct device *isp;
+
+	if (device->opened) {
+		dev_err(rsz_device, "rsz_get_resource: device is "
+						"already opened\n");
+		return -EBUSY;
+	}
+
+	isp = isp_get();
+	if (!isp) {
+		printk(KERN_ERR "Can't enable ISP clocks (ret %d)\n", ret);
+		return -EACCES;
+	}
+	device->isp = isp;
+
+	rsz_conf_chan = kzalloc(sizeof(struct channel_config), GFP_KERNEL);
+	if (rsz_conf_chan == NULL) {
+		dev_err(rsz_device, "\n Can not allocate memory to config");
+		ret = -ENOMEM;
+		goto err_enomem0;
+	}
+	params = kzalloc(sizeof(struct rsz_params), GFP_KERNEL);
+	if (params == NULL) {
+		dev_warn(rsz_device, "\n Can not allocate memory to params");
+		ret = -ENOMEM;
+		goto err_enomem1;
+	}
+	multipass = kzalloc(sizeof(struct rsz_mult), GFP_KERNEL);
+	if (multipass == NULL) {
+		dev_err(rsz_device, "\n cannot allocate memory to multipass");
+		ret = -ENOMEM;
+		goto err_enomem2;
+	}
+
+	device->params = params;
+	device->config = rsz_conf_chan;
+	device->multipass = multipass;
+	device->opened = 1;
+
+	rsz_conf_chan->config_state = STATE_NOT_CONFIGURED;
+
+	init_completion(&device->compl_isr);
+	mutex_init(&device->reszwrap_mutex);
+
+	return 0;
+err_enomem2:
+	kfree(params);
+err_enomem1:
+	kfree(rsz_conf_chan);
+err_enomem0:
+	isp_put();
+
+	return ret;
+}
+EXPORT_SYMBOL(rsz_get_resource);
+
+/**
+ * rsz_put_resource - release all the resource which were acquired during
+ * rsz_get_resource() call.
+ **/
+void rsz_put_resource(void)
+{
+	struct device_params *device = device_config;
+	struct channel_config *rsz_conf_chan = device->config;
+	struct rsz_params *params = device->params;
+	struct rsz_mult *multipass = device->multipass;
+	struct isp_device *isp = dev_get_drvdata(device->isp);
+	int i = 0;
+
+	if (device->opened != 1)
+		return;
+
+	/* unmap output buffers if allocated */
+	for (i = 0; i < device->num_video_buffers; ++i) {
+		if (device->out_buf_virt_addr[i]) {
+			iommu_kunmap(isp->iommu, device->out_buf_virt_addr[i]);
+			device_config->out_buf_virt_addr[i] = 0;
+		}
+		if (device->in_buf_virt_addr[i]) {
+			iommu_kunmap(isp->iommu, device->in_buf_virt_addr[i]);
+			device_config->in_buf_virt_addr[i] = 0;
+		}
+	}
+
+	if (multipass_active) {
+		rsz_tmp_buf_free();
+		multipass_active = 0;
+	}
+	/* free all memory which was allocate during get() */
+	kfree(rsz_conf_chan);
+	kfree(params);
+	kfree(multipass);
+
+	/* make device available */
+	device->opened = 0;
+	device->params = NULL;
+	device->config = NULL;
+	device->multipass = NULL;
+
+	/* release isp resource*/
+	isp_put();
+
+	return ;
+}
+EXPORT_SYMBOL(rsz_put_resource);
+
+/**
+  * rsz_configure - configure the Resizer parameters
+  * @params: Structure containing the Resizer Wrapper parameters
+  * @callback: callback function to call after resizing is over
+  * @arg1: argument to callback function
+  *
+  * This function can be called from DSS to set the parameter of resizer
+  * in case there is need to downsize the input image through resizer
+  * before calling this function calling driver must already have called
+  * rsz_get_resource() function so that necessory initialization is over.
+  * Returns 0 if successful,
+  **/
+int rsz_configure(struct rsz_params *params, rsz_callback callback,
+		  u32 num_video_buffers, void *arg1)
+{
+	int retval;
+	struct channel_config *rsz_conf_chan = device_config->config;
+	struct rsz_mult *multipass = device_config->multipass;
+	size_t tmp_size;
+
+	multipass_active = 0;
+	retval = rsz_set_params(multipass, params, rsz_conf_chan);
+	if (retval != 0)
+		return retval;
+
+	if (device_config->multipass->active) {
+		multipass_active = 1;
+		tmp_size = PAGE_ALIGN(multipass->out_hsize
+				     * multipass->out_vsize
+				     * (multipass->inptyp ? 1 : 2));
+		rsz_tmp_buf_alloc(tmp_size);
+		rsz_conf_chan->register_config.rsz_sdr_outadd =
+			(u32)device_config->tmp_buf;
+		rsz_save_multipass_context();
+	}
+
+	rsz_hardware_setup(device_config, rsz_conf_chan);
+	device_config->callback = callback;
+	device_config->callback_arg = arg1;
+	device_config->num_video_buffers = num_video_buffers;
+
+	return 0;
+}
+EXPORT_SYMBOL(rsz_configure);
+
+static void rsz_tmp_buf_free(void)
+{
+	struct isp_device *isp = dev_get_drvdata(device_config->isp);
+
+	if (device_config->tmp_buf) {
+		iommu_vfree(isp->iommu, device_config->tmp_buf);
+		device_config->tmp_buf = 0;
+		device_config->tmp_buf_size = 0;
+	}
+}
+static u32 rsz_tmp_buf_alloc(size_t size)
+{
+	struct isp_device *isp = dev_get_drvdata(device_config->isp);
+
+	rsz_tmp_buf_free();
+	printk(KERN_INFO "%s: allocating %d bytes\n", __func__, size);
+
+	device_config->tmp_buf =
+		iommu_vmalloc(isp->iommu, 0, size, IOMMU_FLAG);
+	if (IS_ERR((void *)device_config->tmp_buf)) {
+		printk(KERN_ERR "ispmmu_vmap mapping failed ");
+		return -ENOMEM;
+	}
+	device_config->tmp_buf_size = size;
+
+	return 0;
+}
+
+/** rsz_begin - Function to be called by DSS when resizing of the input image/
+  * buffer is needed
+  * @slot: buffer index where the input image is stored
+  * @output_buffer_index: output buffer index where output of resizer will
+  * be stored
+  * @out_off: The line size in bytes for output buffer. as most probably
+  * this will be VRFB with YUV422 data, it should come 0x2000 as input
+  * @out_phy_add: physical address of the start of output memory area for this
+  * @in_phy_add: physical address of the start of input memory area for this
+  * @in_off:: The line size in bytes for output buffer.
+  * rsz_begin()  takes the input buffer index and output buffer index
+  * to start the process of resizing. after resizing is complete,
+  * the callback function will be called with the argument.
+  * Indexes of the input and output buffers are used so that it is faster
+  * and easier to configure the input and output address for the ISP resizer.
+  * As per the current implementation, DSS uses six VRFB contexts for rotation.
+  * for both input and output buffers index and physical address has been taken
+  * as argument. if this buffer is not already mapped to ISP address space we
+  * use physical address to map it, otherwise only the index is used.
+  **/
+int rsz_begin(u32 input_buffer_index, int output_buffer_index,
+		u32 out_off, u32 out_phy_add, u32 in_phy_add, u32 in_off)
+{
+	unsigned int output_size;
+	struct channel_config *rsz_conf_chan = device_config->config;
+	struct isp_device *isp = dev_get_drvdata(device_config->isp);
+
+	if (output_buffer_index >= device_config->num_video_buffers) {
+		dev_err(rsz_device,
+		"ouput buffer index is out of range %d", output_buffer_index);
+		return -EINVAL;
+	}
+
+	if (multipass_active) {
+		rsz_restore_multipass_context();
+		rsz_hardware_setup(device_config, rsz_conf_chan);
+	}
+
+	/* If this output buffer has not been mapped till now then map it */
+	if (!device_config->out_buf_virt_addr[output_buffer_index]) {
+		output_size =
+			(rsz_conf_chan->register_config.rsz_out_size >>
+			ISPRSZ_OUT_SIZE_VERT_SHIFT) * out_off;
+		device_config->out_buf_virt_addr[output_buffer_index] = iommu_kmap(
+						isp->iommu,
+						0,
+						out_phy_add,
+						output_size,
+						IOMMU_FLAG);
+		if (IS_ERR_VALUE(
+			device_config->out_buf_virt_addr[output_buffer_index])) {
+			dev_err(rsz_device, "Mapping of output buffer failed"
+						"for index \n");
+			return -ENOMEM;
+		}
+	}
+
+	if (!device_config->in_buf_virt_addr[input_buffer_index]) {
+		device_config->in_buf_virt_addr[input_buffer_index] =
+				iommu_kmap(isp->iommu,
+						0,
+						in_phy_add,
+						in_off,
+						IOMMU_FLAG);
+		if (IS_ERR_VALUE(
+			device_config->in_buf_virt_addr[input_buffer_index])) {
+			dev_err(rsz_device, "Mapping of output buffer failed"
+						"for index \n");
+			return -ENOMEM;
+		}
+	}
+	down(&resz_wrapper_mutex);
+	rsz_conf_chan->register_config.rsz_sdr_inadd =
+		device_config->in_buf_virt_addr[input_buffer_index];
+
+	/* Configure the input and output address with output line size
+	in resizer hardware */
+	isp_reg_writel(device_config->isp,
+		rsz_conf_chan->register_config.rsz_sdr_inadd,
+		OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_INADD);
+
+	if (!multipass_active) {
+		rsz_conf_chan->register_config.rsz_sdr_outoff = out_off;
+		isp_reg_writel(device_config->isp,
+			rsz_conf_chan->register_config.rsz_sdr_outoff,
+			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
+		rsz_conf_chan->register_config.rsz_sdr_outadd =
+			(u32)device_config->\
+			out_buf_virt_addr[output_buffer_index];
+		isp_reg_writel(device_config->isp,
+			rsz_conf_chan->register_config.rsz_sdr_outadd,
+			OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
+	}
+
+	up(&resz_wrapper_mutex);
+
+	/* Set ISP callback for the resizing complete even */
+	if (isp_set_callback(device_config->isp,
+			     CBK_RESZ_DONE, rsz_isr,
+			     (void *) NULL, (void *)NULL)) {
+		dev_err(rsz_device, "No callback for RSZR\n");
+		return -1;
+	}
+
+	/* All settings are done.Enable the resizer */
+
+mult:
+	device_config->compl_isr.done = 0;
+
+	ispresizer_enable(&isp->isp_res, 1);
+	/* Wait for resizing complete event */
+	wait_for_completion_interruptible(&device_config->compl_isr);
+
+	if (device_config->multipass->active) {
+		multipass_active = 1;
+		rsz_set_multipass(device_config,
+				  device_config->multipass, rsz_conf_chan);
+		down(&resz_wrapper_mutex);
+		if (!device_config->multipass->active) {
+			rsz_conf_chan->register_config.rsz_sdr_outoff = out_off;
+			isp_reg_writel(device_config->isp,
+				rsz_conf_chan->register_config.rsz_sdr_outoff,
+				OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTOFF);
+
+			rsz_conf_chan->register_config.rsz_sdr_outadd =
+				(u32)device_config->\
+				out_buf_virt_addr[output_buffer_index];
+
+			isp_reg_writel(device_config->isp,
+				rsz_conf_chan->register_config.rsz_sdr_outadd,
+				OMAP3_ISP_IOMEM_RESZ, ISPRSZ_SDR_OUTADD);
+		}
+		up(&resz_wrapper_mutex);
+		goto mult;
+	}
+	/* Unset the ISP callback function */
+	isp_unset_callback(device_config->isp, CBK_RESZ_DONE);
+
+	/* Callback function for DSS driver */
+	if (device_config->callback)
+		device_config->callback(device_config->callback_arg);
+
+	return 0;
+}
+EXPORT_SYMBOL(rsz_begin);
+
+ /* rsz_isr - Interrupt Service Routine for Resizer wrapper
  * @status: ISP IRQ0STATUS register value
  * @arg1: Currently not used
  * @arg2: Currently not used
@@ -1569,18 +2022,19 @@
 {
 	int ret = 0;
 	struct device_params *device;
+
 	device = kzalloc(sizeof(struct device_params), GFP_KERNEL);
 	if (!device) {
-		dev_err(rsz_device, OMAP_REZR_NAME ": could not allocate "
-								"memory\n");
+		printk(KERN_ERR  "%s : could not allocate "
+					"memory\n", OMAP_REZR_NAME);
 		return -ENOMEM;
 	}
 
 	ret = alloc_chrdev_region(&dev, 0, 1, OMAP_REZR_NAME);
 	if (ret < 0) {
-		dev_err(rsz_device, OMAP_REZR_NAME ": intialization failed. "
+		printk(KERN_ERR "%s : intialization failed. "
 			"Could not allocate region "
-			"for character device\n");
+			"for character device\n" , OMAP_REZR_NAME);
 		kfree(device);
 		return -ENODEV;
 	}
@@ -1594,8 +2048,8 @@
 	/* Addding character device */
 	ret = cdev_add(&c_dev, dev, 1);
 	if (ret) {
-		dev_err(rsz_device, OMAP_REZR_NAME ": Error adding "
-			"device - %d\n", ret);
+		printk(KERN_ERR  "%s : Error adding "
+			"device - %d\n", OMAP_REZR_NAME, ret);
 		goto fail2;
 	}
 	rsz_major = MAJOR(dev);
@@ -1603,23 +2057,23 @@
 	/* register driver as a platform driver */
 	ret = platform_driver_register(&omap_resizer_driver);
 	if (ret) {
-		dev_err(rsz_device, OMAP_REZR_NAME
-		       ": Failed to register platform driver!\n");
+		printk(KERN_ERR "%s : Failed to "
+			"register platform driver!\n", OMAP_REZR_NAME);
 		goto fail3;
 	}
 
 	/* Register the drive as a platform device */
 	ret = platform_device_register(&omap_resizer_device);
 	if (ret) {
-		dev_err(rsz_device, OMAP_REZR_NAME
-		       ": Failed to register platform device!\n");
+		printk(KERN_ERR "%s : Failed to register "
+			"platform device!\n", OMAP_REZR_NAME);
 		goto fail4;
 	}
 
 	rsz_class = class_create(THIS_MODULE, OMAP_REZR_NAME);
 	if (!rsz_class) {
-		dev_err(rsz_device, OMAP_REZR_NAME
-			": Failed to create class!\n");
+		printk(KERN_ERR "%s : Failed to "
+			"create class!\n", OMAP_REZR_NAME);
 		goto fail5;
 	}
 
@@ -1627,7 +2081,16 @@
 	rsz_device = device_create(rsz_class, rsz_device,
 					MKDEV(rsz_major, 0), NULL,
 					OMAP_REZR_NAME);
-	dev_dbg(rsz_device, OMAP_REZR_NAME ": Registered Resizer Wrapper\n");
+	if (rsz_device)
+		dev_dbg(rsz_device, OMAP_REZR_NAME ":"
+			"Registered Resizer Wrapper\n");
+	else {
+		printk(KERN_ERR "%s : Registered Resizer Wrapper",
+					OMAP_REZR_NAME);
+		ret = -ENODEV;
+		goto fail6;
+	}
+
 	device->opened = 0;
 
 	device->vbq_ops.buf_setup = rsz_vbq_setup;
@@ -1640,6 +2103,8 @@
 	device_config = device;
 	return 0;
 
+fail6:
+	class_destroy(rsz_class);
 fail5:
 	platform_device_unregister(&omap_resizer_device);
 fail4:
diff --git a/drivers/media/video/lv8093.c b/drivers/media/video/lv8093.c
index ea3320d..dcd179a 100644
--- a/drivers/media/video/lv8093.c
+++ b/drivers/media/video/lv8093.c
@@ -427,6 +427,54 @@
 	return lens->pdata->priv_data_set(p);
 }
 
+static int lv8093_power_on(struct lv8093_device *lens)
+{
+	struct i2c_client *c = lens->i2c_client;
+	int rval = -EINVAL;
+
+	if (lens->pdata->power_set)
+		rval = lens->pdata->power_set(V4L2_POWER_ON);
+
+	if (rval < 0) {
+		v4l_err(c, "Unable to set the power state ON\n");
+		return rval;
+	}
+
+	return 0;
+}
+
+static int lv8093_power_off(struct lv8093_device *lens)
+{
+	struct i2c_client *c = lens->i2c_client;
+	int rval = -EINVAL;
+
+	if (lens->pdata->power_set)
+		rval = lens->pdata->power_set(V4L2_POWER_OFF);
+
+	if (rval < 0) {
+		v4l_err(c, "Unable to set the power state OFF\n");
+		return rval;
+	}
+
+	return 0;
+}
+
+static int lv8093_power_standby(struct lv8093_device *lens)
+{
+	struct i2c_client *c = lens->i2c_client;
+	int rval = -EINVAL;
+
+	if (lens->pdata->power_set)
+		rval = lens->pdata->power_set(V4L2_POWER_STANDBY);
+
+	if (rval < 0) {
+		v4l_err(c, "Unable to set the power state STANDBY\n");
+		return rval;
+	}
+
+	return 0;
+}
+
 /**
  * ioctl_s_power - V4L2 sensor interface handler for vidioc_int_s_power_num
  * @s: pointer to standard V4L2 device structure
@@ -438,49 +486,84 @@
 {
 	struct lv8093_device *lens = s->priv;
 	struct i2c_client *c = lens->i2c_client;
-	int rval;
+	int rval = 0;
 
-	if (lens->pdata->power_set)
-		rval = lens->pdata->power_set(on);
+	switch (on) {
+	case V4L2_POWER_ON:
+		rval = lv8093_power_on(lens);
+		if (rval)
+			goto error;
+
+		if (lens->power_state == V4L2_POWER_STANDBY) {
+			rval = lv8093_reginit(c);
+			if (rval < 0) {
+				v4l_err(c, "Unable to initialize " LV8093_NAME
+					" lens HW\n");
+				lens->state = LENS_NOT_DETECTED;
+				return rval;
+			}
+		}
+		break;
+	case V4L2_POWER_OFF:
+		rval = lv8093_power_off(lens);
+		break;
+	case V4L2_POWER_STANDBY:
+		rval = lv8093_power_standby(lens);
+		break;
+	}
 
 	lens->power_state = on;
+error:
+	return rval;
+}
 
-	if ((on == V4L2_POWER_ON) && (lens->state == LENS_NOT_DETECTED)) {
-		rval = lv8093_detect(c);
-		if (rval < 0) {
-			v4l_err(c, "Unable to detect " LV8093_NAME
-				" lens HW\n");
-			lens->state = LENS_NOT_DETECTED;
-			return rval;
-		}
-		lens->state = LENS_DETECTED;
-		pr_info(LV8093_NAME " Lens HW detected\n");
+/**
+ * ioctl_dev_init - V4L2 sensor interface handler for vidioc_int_dev_init_num
+ * @s: pointer to standard V4L2 device structure
+ *
+ * Initialise the device when slave attaches to the master.  Returns 0 if
+ * lv8093 device could be found, otherwise returns appropriate error.
+ */
+static int ioctl_dev_init(struct v4l2_int_device *s)
+{
+	struct lv8093_device *lens = s->priv;
+	struct i2c_client *c = lens->i2c_client;
+	int err;
 
-		rval = lv8093_reginit(c);
-		if (rval < 0) {
-			v4l_err(c, "Unable to initialize " LV8093_NAME
-				" lens HW\n");
-			lens->state = LENS_NOT_DETECTED;
-			return rval;
-		}
+	err = lv8093_power_on(lens);
+	if (err)
+		return -ENODEV;
+
+	err = lv8093_detect(c);
+	if (err < 0) {
+		v4l_err(c, "Unable to detect " LV8093_NAME
+			" lens HW\n");
+		lens->state = LENS_NOT_DETECTED;
+		return err;
+	}
+	lens->state = LENS_DETECTED;
+	pr_info(LV8093_NAME " Lens HW detected\n");
+
+	err = lv8093_reginit(c);
+	if (err < 0) {
+		v4l_err(c, "Unable to initialize " LV8093_NAME
+			" lens HW\n");
+		lens->state = LENS_NOT_DETECTED;
+		return err;
 	}
 
-	if ((lens->power_state == V4L2_POWER_STANDBY) && (on == V4L2_POWER_ON)
-	    && (lens->state == LENS_DETECTED)) {
-		rval = lv8093_reginit(c);
-		if (rval < 0) {
-			v4l_err(c, "Unable to initialize " LV8093_NAME
-				" lens HW\n");
-			lens->state = LENS_NOT_DETECTED;
-			return rval;
-		}
-	}
+	err = lv8093_power_off(lens);
+	if (err)
+		return -ENODEV;
+
 	return 0;
 }
 
 static struct v4l2_int_ioctl_desc lv8093_ioctl_desc[] = {
 	{.num = vidioc_int_s_power_num,
 	 .func = (v4l2_int_ioctl_func *) ioctl_s_power},
+	{ .num = vidioc_int_dev_init_num,
+	  .func = (v4l2_int_ioctl_func *)ioctl_dev_init},
 	{.num = vidioc_int_g_priv_num,
 	 .func = (v4l2_int_ioctl_func *) ioctl_g_priv},
 	{.num = vidioc_int_queryctrl_num,
diff --git a/drivers/media/video/omap-vout/Kconfig b/drivers/media/video/omap-vout/Kconfig
deleted file mode 100644
index 6a8334e..0000000
--- a/drivers/media/video/omap-vout/Kconfig
+++ /dev/null
@@ -1,8 +0,0 @@
-config VIDEO_OMAP_VIDEOOUT
-	tristate "Video out driver"
-	depends on VIDEO_DEV && VIDEO_V4L2 && OMAP2_DSS
-
-config VIDEO_OMAP_VIDEOOUT_BUFPOOL
-	tristate "Video out driver buffer pool"
-	depends on VIDEO_OMAP_VIDEOOUT
-
diff --git a/drivers/media/video/omap-vout/Makefile b/drivers/media/video/omap-vout/Makefile
deleted file mode 100644
index a8e420e..0000000
--- a/drivers/media/video/omap-vout/Makefile
+++ /dev/null
@@ -1,7 +0,0 @@
-
-vout-objs := omapvout.o omapvout-dss.o omapvout-mem.o omapvout-vbq.o
-
-obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL) += omapvout-bp.o
-
-obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT) += vout.o
-
diff --git a/drivers/media/video/omap-vout/omapvout-bp.c b/drivers/media/video/omap-vout/omapvout-bp.c
deleted file mode 100644
index c56f9ed..0000000
--- a/drivers/media/video/omap-vout/omapvout-bp.c
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-bp.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/mm.h>
-
-#include "omapvout.h"
-#include "omapvout-mem.h"
-#include "omapvout-bp.h"
-
-#define OMAPVOUT_BP_MAX_BUFFERS (20)
-
-struct omapvout_bp *omapvout_bp_create(u8 num_bufs, u32 buf_size)
-{
-	struct omapvout_bp *bp;
-	int num = num_bufs;
-	int size;
-	int i;
-	unsigned long paddr;
-	void *vaddr;
-	u32 bsize;
-
-	if (num > OMAPVOUT_BP_MAX_BUFFERS)
-		num = OMAPVOUT_BP_MAX_BUFFERS;
-
-	size = sizeof(struct omapvout_bp) +
-			(num * sizeof(struct omapvout_bp_entry));
-	bp = kzalloc(size, GFP_KERNEL);
-	if (!bp)
-		return NULL;
-
-	mutex_init(&bp->lock);
-	mutex_lock(&bp->lock);
-
-	bsize = PAGE_ALIGN(buf_size);
-	bp->num_entries = num;
-	for (i = 0; i < num; i++) {
-		if (omapvout_mem_alloc(bsize, &paddr, &vaddr) == 0) {
-			bp->buf[i].size = bsize;
-			bp->buf[i].phy_addr = paddr;
-			bp->buf[i].virt_addr = vaddr;
-		}
-	}
-
-	mutex_unlock(&bp->lock);
-
-	return bp;
-}
-
-void omapvout_bp_init(struct omapvout_device *vout)
-{
-	struct omapvout_bp *bp = vout->bp;
-
-	mutex_lock(&bp->lock);
-
-	bp->ref_cnt++;
-
-	mutex_unlock(&bp->lock);
-}
-
-void omapvout_bp_destroy(struct omapvout_device *vout)
-{
-	struct omapvout_bp *bp = vout->bp;
-	int i;
-
-	if (bp == NULL)
-		return;
-
-	vout->bp = NULL;
-
-	mutex_lock(&bp->lock);
-
-	if (bp->ref_cnt > 0)
-		bp->ref_cnt--;
-
-	if (bp->ref_cnt > 0) {
-		/* Release any buffers still alloc'd to this user */
-		for (i = 0; i < bp->num_entries; i++) {
-			if (bp->buf[i].size == 0)
-				continue;
-
-			if (bp->buf[i].in_use && bp->buf[i].user == vout->id)
-				bp->buf[i].in_use = 0;
-		}
-		mutex_unlock(&bp->lock);
-	} else {
-		/* Destroy everything */
-		for (i = 0; i < bp->num_entries; i++) {
-			if (bp->buf[i].size == 0)
-				continue;
-
-			if (bp->buf[i].in_use)
-				DBG("Destroying an in-use buffer\n");
-
-			omapvout_mem_free(bp->buf[i].phy_addr,
-					bp->buf[i].virt_addr,
-					bp->buf[i].size);
-		}
-		mutex_unlock(&bp->lock);
-
-		mutex_destroy(&bp->lock);
-		kfree(bp);
-	}
-}
-
-bool omapvout_is_bp_buffer(struct omapvout_device *vout,
-			unsigned long phy_addr)
-{
-	struct omapvout_bp *bp = vout->bp;
-	int i;
-
-	if (!bp)
-		return false;
-
-	for (i = 0; i < bp->num_entries; i++) {
-		if (phy_addr == bp->buf[i].phy_addr)
-			return true;
-	}
-
-	return false;
-}
-
-int omapvout_bp_alloc(struct omapvout_device *vout, u32 req_size,
-			unsigned long *phy_addr, void **virt_addr, u32 *size)
-{
-	struct omapvout_bp *bp = vout->bp;
-	int i;
-	int rc = -ENOMEM;
-
-	if (!bp)
-		return -ENOMEM;
-
-	mutex_lock(&bp->lock);
-
-	for (i = 0; i < bp->num_entries; i++) {
-		if (bp->buf[i].in_use == 0 && bp->buf[i].size >= req_size) {
-			bp->buf[i].in_use = 1;
-			bp->buf[i].user = vout->id;
-			*phy_addr = bp->buf[i].phy_addr;
-			*virt_addr = bp->buf[i].virt_addr;
-			*size = bp->buf[i].size;
-			rc = 0;
-			break;
-		}
-	}
-
-	mutex_unlock(&bp->lock);
-
-	return rc;
-}
-
-int omapvout_bp_release(struct omapvout_device *vout, unsigned long phy_addr)
-{
-	struct omapvout_bp *bp = vout->bp;
-	int i;
-	int rc = -EINVAL;
-
-	mutex_lock(&bp->lock);
-
-	for (i = 0; i < bp->num_entries; i++) {
-		if (bp->buf[i].phy_addr == phy_addr) {
-			if (bp->buf[i].in_use)
-				bp->buf[i].in_use = 0;
-			else
-				DBG("Releasing an unused buffer\n");
-
-			/* Found the buffer, so say so */
-			rc = 0;
-
-			break;
-		}
-	}
-
-	mutex_unlock(&bp->lock);
-
-	return rc;
-}
-
diff --git a/drivers/media/video/omap-vout/omapvout-bp.h b/drivers/media/video/omap-vout/omapvout-bp.h
deleted file mode 100644
index 01bfa93..0000000
--- a/drivers/media/video/omap-vout/omapvout-bp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-bp.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef __OMAPVOUT_BP_H__
-#define __OMAPVOUT_BP_H__
-
-struct omapvout_bp_entry {
-	u32 in_use;
-	u32 user;
-	u32 size;
-	unsigned long phy_addr;
-	void *virt_addr;
-};
-
-struct omapvout_bp {
-	struct mutex lock; /* Lock for all buffer pool accesses */
-	int ref_cnt;
-	int num_entries;
-	struct omapvout_bp_entry buf[0];
-};
-
-extern struct omapvout_bp *omapvout_bp_create(u8 num_buffers, u32 buf_size);
-extern void omapvout_bp_init(struct omapvout_device *vout);
-extern void omapvout_bp_destroy(struct omapvout_device *vout);
-extern bool omapvout_is_bp_buffer(struct omapvout_device *vout,
-			unsigned long phy_addr);
-extern int omapvout_bp_alloc(struct omapvout_device *vout, u32 req_size,
-			unsigned long *phy_addr, void **virt_addr, u32 *size);
-extern int omapvout_bp_release(struct omapvout_device *vout,
-			unsigned long phy_addr);
-
-#endif /* __OMAPVOUT_BP_H__ */
-
diff --git a/drivers/media/video/omap-vout/omapvout-dss.c b/drivers/media/video/omap-vout/omapvout-dss.c
deleted file mode 100644
index 2f4e016..0000000
--- a/drivers/media/video/omap-vout/omapvout-dss.c
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-dss.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/mm.h>
-#include <mach/display.h>
-#include <mach/dma.h>
-#include <mach/vrfb.h>
-
-#include "omapvout.h"
-#include "omapvout-dss.h"
-#include "omapvout-mem.h"
-#include "omapvout-vbq.h"
-
-#define DMA_CHAN_ALLOTED	1
-#define DMA_CHAN_NOT_ALLOTED	0
-
-#define VRFB_TX_TIMEOUT		1000
-
-/*=== Local Functions ==================================================*/
-
-static int omapvout_dss_format_bytespp(u32 pixelformat)
-{
-	int bpp = 2;
-
-	switch (pixelformat) {
-	case V4L2_PIX_FMT_RGB32:
-		bpp = 4;
-		break;
-	case V4L2_PIX_FMT_RGB565:
-	case V4L2_PIX_FMT_YUYV:
-	case V4L2_PIX_FMT_UYVY:
-		bpp = 2;
-		break;
-	}
-
-	return bpp;
-}
-
-static enum omap_color_mode omapvout_dss_color_mode(u32 pixelformat)
-{
-	enum omap_color_mode mode = OMAP_DSS_COLOR_RGB16;
-
-	switch (pixelformat) {
-	case V4L2_PIX_FMT_RGB32:
-		mode = OMAP_DSS_COLOR_RGB24U;
-		break;
-	case V4L2_PIX_FMT_RGB565:
-		mode = OMAP_DSS_COLOR_RGB16;
-		break;
-	case V4L2_PIX_FMT_YUYV:
-		mode = OMAP_DSS_COLOR_YUV2;
-		break;
-	case V4L2_PIX_FMT_UYVY:
-		mode = OMAP_DSS_COLOR_UYVY;
-		break;
-	}
-
-	return mode;
-}
-
-static int omapvout_dss_calc_offset(struct omapvout_device *vout)
-{
-	struct omapvout_dss *dss;
-	int rc = 0;
-	u32 fmt;
-	int bpp;
-	int bpp_mult = 1;
-	u16 ow, oh;
-	int iw, ih;
-	int cx, cy, cw, ch;
-
-	/* It is assumed that the caller has locked the vout mutex */
-
-	fmt = vout->pix.pixelformat;
-	bpp = omapvout_dss_format_bytespp(fmt);
-	if (fmt == V4L2_PIX_FMT_YUYV || fmt == V4L2_PIX_FMT_UYVY)
-		bpp_mult = 2;
-
-	iw = vout->pix.width;
-	ih = vout->pix.height;
-	cx = vout->crop.left;
-	cy = vout->crop.top;
-	cw = vout->crop.width;
-	ch = vout->crop.height;
-
-	ow = iw;
-	oh = ih;
-	omap_vrfb_adjust_size(&ow, &oh, bpp);
-	ow = ow - iw;
-	oh = oh - ih;
-
-	dss = vout->dss;
-
-	switch (vout->rotation)	{
-	case 3: /* 270 degrees */
-		dss->foffset = (cx * OMAP_VRFB_LINE_LEN * bpp * bpp_mult)
-				+ ((oh + (ih - cy - ch)) * bpp * bpp_mult);
-		break;
-	case 2: /* 180 degrees */
-		dss->foffset = ((oh + (ih - cy - ch)) * OMAP_VRFB_LINE_LEN
-							* bpp * bpp_mult)
-				+ ((ow + (iw - cx - cw)) * bpp * bpp_mult);
-		break;
-	case 1: /* 90 degrees */
-		dss->foffset = ((ow + (iw - cx - cw)) * OMAP_VRFB_LINE_LEN
-							* bpp * bpp_mult)
-				+ (cy * bpp * bpp_mult);
-		break;
-	default:
-	case 0: /* 0 degrees */
-		dss->foffset = ((cy * iw) + (cx)) * bpp;
-		break;
-	}
-
-	return rc;
-}
-
-static int omapvout_dss_get_overlays(struct omap_overlay **gfx,
-			struct omap_overlay **vid1, struct omap_overlay **vid2)
-{
-	struct omap_overlay *t;
-	int num_ovlys;
-	int i;
-
-	*gfx = NULL;
-	*vid1 = NULL;
-	*vid2 = NULL;
-	num_ovlys = omap_dss_get_num_overlays();
-	for (i = 0; i < num_ovlys; i++) {
-		t = omap_dss_get_overlay(i);
-
-		switch (t->id) {
-		case OMAP_DSS_GFX:
-			*gfx = t;
-			break;
-		case OMAP_DSS_VIDEO1:
-			*vid1 = t;
-			break;
-		case OMAP_DSS_VIDEO2:
-			*vid2 = t;
-			break;
-		}
-	}
-
-	if (*gfx && *vid1 && *vid2)
-		return 0;
-
-	return -EINVAL;
-}
-
-/* The algorithm below was cooked up to provide a reasonable global alpha
- * configuration based on the typical use case, which is a single video plane
- * blended with the graphics plane.  This algorithm will handle multiple
- * video planes as well, but the thought is that typically the user is not
- * going to want to be forced to set the global alpha value via the graphics
- * plane (the frame buffer), but instead via the video plane.
- *
- * Algorithm:
- * 1) For video1, if video2 is enabled, place the global alpha value set to
- *    video2, else set to the graphics plane.
- * 2) For video2, always place the global alpha value set to the graphics
- *   plane, but need to be careful to move the video1 alpha value if its
- *   already enabled.
- */
-static void omapvout_dss_set_global_alpha(struct omapvout_device *vout)
-{
-	struct omap_overlay *gfx, *vid1, *vid2;
-	struct omap_overlay_info info;
-	u8 alpha;
-	u8 t;
-
-	/* Invert the requested alpha value since this alpha value is how
-	 * transparent the video plane is supposed to be, but it is being
-	 * applied to the plane above.
-	 */
-	alpha = 255 - vout->win.global_alpha;
-
-	if (omapvout_dss_get_overlays(&gfx, &vid1, &vid2)) {
-		DBG("Not all planes available\n");
-		return;
-	}
-
-	if (vout->dss->overlay->id == OMAP_DSS_VIDEO1) {
-		vid2->get_overlay_info(vid2, &info);
-		if (info.enabled) {
-			info.global_alpha = alpha;
-			vid2->set_overlay_info(vid2, &info);
-		} else {
-			gfx->get_overlay_info(gfx, &info);
-			info.global_alpha = alpha;
-			gfx->set_overlay_info(gfx, &info);
-		}
-	} else if (vout->dss->overlay->id == OMAP_DSS_VIDEO2) {
-		vid1->get_overlay_info(vid1, &info);
-		if (info.enabled) {
-			gfx->get_overlay_info(gfx, &info);
-			t = info.global_alpha;
-			info.global_alpha = alpha;
-			gfx->set_overlay_info(gfx, &info);
-			vid2->get_overlay_info(vid2, &info);
-			info.global_alpha = t;
-			vid2->set_overlay_info(vid2, &info);
-		} else {
-			gfx->get_overlay_info(gfx, &info);
-			info.global_alpha = alpha;
-			gfx->set_overlay_info(gfx, &info);
-			vid2->get_overlay_info(vid2, &info);
-			info.global_alpha = 255;
-			vid2->set_overlay_info(vid2, &info);
-		}
-	}
-
-#ifdef DEBUG
-	gfx->get_overlay_info(gfx, &info);
-	DBG("GFX Alpha = %d\n", info.global_alpha);
-	vid2->get_overlay_info(vid2, &info);
-	DBG("VID2 Alpha = %d\n", info.global_alpha);
-	vid1->get_overlay_info(vid1, &info);
-	DBG("VID1 Alpha = %d\n", info.global_alpha);
-#endif
-}
-
-/* This algorithm reverses the changes made in the "_set_" function and
- * returns a flag denoting if alpha should still be enabled.
- *
- * The non-trivial part is to handle the case where both video planes are
- * enabled.
- */
-static bool omapvout_dss_clr_global_alpha(struct omapvout_device *vout)
-{
-	struct omap_overlay *gfx, *vid1, *vid2;
-	struct omap_overlay_info info;
-	bool alpha_en = false;
-	u8 t;
-
-	if (omapvout_dss_get_overlays(&gfx, &vid1, &vid2)) {
-		DBG("Not all planes available\n");
-		return false;
-	}
-
-	if (vout->dss->overlay->id == OMAP_DSS_VIDEO1) {
-		vid2->get_overlay_info(vid2, &info);
-		if (info.enabled)
-			alpha_en = true;
-	} else if (vout->dss->overlay->id == OMAP_DSS_VIDEO2) {
-		vid1->get_overlay_info(vid1, &info);
-		if (info.enabled) {
-			alpha_en = true;
-
-			/* Set gfx alpha to vid1's alpha */
-			vid2->get_overlay_info(vid2, &info);
-			t = info.global_alpha;
-			gfx->get_overlay_info(gfx, &info);
-			info.global_alpha = t;
-			gfx->set_overlay_info(gfx, &info);
-		}
-	}
-
-	return alpha_en;
-}
-
-static int omapvout_dss_enable_transparency(struct omapvout_device *vout)
-{
-	struct omap_overlay_manager *mgr;
-	struct omap_overlay_manager_info m_info;
-
-	mgr = vout->dss->overlay->manager;
-	if (mgr == NULL)
-		return -EINVAL;
-
-	if (mgr->set_manager_info == NULL || mgr->get_manager_info == NULL)
-		return -EINVAL;
-
-	mgr->get_manager_info(mgr, &m_info);
-
-	m_info.default_color = vout->bg_color;
-
-	if (vout->fbuf.flags & V4L2_FBUF_FLAG_CHROMAKEY) {
-		m_info.trans_key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
-		m_info.trans_key = vout->win.chromakey;
-		m_info.trans_enabled = true;
-	} else if (vout->fbuf.flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) {
-		m_info.trans_key_type = OMAP_DSS_COLOR_KEY_VID_SRC;
-		m_info.trans_key = vout->win.chromakey;
-		m_info.trans_enabled = true;
-	} else {
-		m_info.trans_enabled = false;
-	}
-
-	if (vout->fbuf.flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
-		m_info.alpha_enabled = true;
-	} else if (vout->fbuf.flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) {
-		omapvout_dss_set_global_alpha(vout);
-		m_info.alpha_enabled = true;
-	} else {
-		m_info.alpha_enabled = false;
-	}
-
-	DBG("Trans Enable = %d\n", m_info.trans_enabled);
-	DBG("Trans Mode = %d\n", m_info.trans_key_type);
-	DBG("Alpha Enable = %d\n", m_info.alpha_enabled);
-
-	mgr->set_manager_info(mgr, &m_info);
-
-	return 0;
-}
-
-static int omapvout_dss_disable_transparency(struct omapvout_device *vout)
-{
-	struct omap_overlay_manager *mgr;
-	struct omap_overlay_manager_info m_info;
-
-	mgr = vout->dss->overlay->manager;
-	if (mgr == NULL)
-		return -EINVAL;
-
-	if (mgr->set_manager_info == NULL || mgr->get_manager_info == NULL)
-		return -EINVAL;
-
-	mgr->get_manager_info(mgr, &m_info);
-
-	m_info.alpha_enabled = omapvout_dss_clr_global_alpha(vout);
-	m_info.trans_enabled = false;
-
-	mgr->set_manager_info(mgr, &m_info);
-
-	return 0;
-}
-
-/* This functions wakes up the application once the DMA transfer to
- * VRFB space is completed.
- */
-static void omapvout_dss_vrfb_dma_cb(int lch, u16 ch_status, void *data)
-{
-	struct omapvout_dss_vrfb *vrfb;
-
-	vrfb = (struct omapvout_dss_vrfb *) data;
-
-	vrfb->dma_complete = true;
-	wake_up_interruptible(&vrfb->wait);
-}
-
-static int omapvout_dss_acquire_vrfb(struct omapvout_device *vout)
-{
-	int rc = 0;
-	int size;
-	int w, h;
-	int max_pixels;
-	struct omapvout_dss_vrfb *vrfb;
-
-	/* It is assumed that the caller has locked the vout mutex */
-
-	vrfb = &vout->dss->vrfb;
-	vrfb->dma_id = OMAP_DMA_NO_DEVICE;
-	vrfb->dma_ch = -1;
-	vrfb->req_status = DMA_CHAN_NOT_ALLOTED;
-	vrfb->next = 0;
-
-	rc = omap_vrfb_request_ctx(&vrfb->ctx[0]);
-	if (rc != 0) {
-		DBG("VRFB context allocation 0 failed %d\n", rc);
-		goto failed_ctx0;
-	}
-
-	rc = omap_vrfb_request_ctx(&vrfb->ctx[1]);
-	if (rc != 0) {
-		DBG("VRFB context allocation 1 failed %d\n", rc);
-		goto failed_ctx1;
-	}
-
-	/* Determine the VFRB buffer size by oversizing for the VRFB */
-	w = vout->max_video_width;
-	h = vout->max_video_height;
-	max_pixels = w * h;
-	w += 32; /* Oversize as typical for VRFB */
-	h += 32;
-	size = PAGE_ALIGN(w * h * (vout->max_video_buffer_size / max_pixels));
-	vrfb->size = size;
-
-	rc = omapvout_mem_alloc(size, &vrfb->phy_addr[0], &vrfb->virt_addr[0]);
-	if (rc != 0) {
-		DBG("VRFB buffer alloc 0 failed %d\n", rc);
-		goto failed_mem0;
-	}
-
-	rc = omapvout_mem_alloc(size, &vrfb->phy_addr[1], &vrfb->virt_addr[1]);
-	if (rc != 0) {
-		DBG("VRFB buffer alloc 1 failed %d\n", rc);
-		goto failed_mem1;
-	}
-
-	rc = omap_request_dma(vrfb->dma_id, "VRFB DMA",
-				omapvout_dss_vrfb_dma_cb,
-				(void *)vrfb,
-				&vrfb->dma_ch);
-	if (rc != 0) {
-		printk(KERN_INFO "No VRFB DMA channel for %d\n", vout->id);
-		goto failed_dma;
-	}
-
-	vrfb->req_status = DMA_CHAN_ALLOTED;
-	init_waitqueue_head(&vrfb->wait);
-
-	return rc;
-
-failed_dma:
-	omapvout_mem_free(vrfb->phy_addr[1], vrfb->virt_addr[1], size);
-failed_mem1:
-	omapvout_mem_free(vrfb->phy_addr[0], vrfb->virt_addr[0], size);
-failed_mem0:
-	omap_vrfb_release_ctx(&vrfb->ctx[1]);
-failed_ctx1:
-	omap_vrfb_release_ctx(&vrfb->ctx[0]);
-failed_ctx0:
-	return rc;
-}
-
-static int omapvout_dss_release_vrfb(struct omapvout_device *vout)
-{
-	int rc = 0;
-	int size;
-	struct omapvout_dss_vrfb *vrfb;
-
-	/* It is assumed that the caller has locked the vout mutex */
-
-	vrfb = &vout->dss->vrfb;
-	if (vrfb->req_status == DMA_CHAN_ALLOTED) {
-		vrfb->req_status = DMA_CHAN_NOT_ALLOTED;
-		omap_free_dma(vrfb->dma_ch);
-		/* FIXME: de-init the wait queue? */
-
-		size = vrfb->size;
-		omapvout_mem_free(vrfb->phy_addr[0], vrfb->virt_addr[0], size);
-		omapvout_mem_free(vrfb->phy_addr[1], vrfb->virt_addr[1], size);
-
-		omap_vrfb_release_ctx(&vrfb->ctx[0]);
-		omap_vrfb_release_ctx(&vrfb->ctx[1]);
-	}
-
-	return rc;
-}
-
-static int omapvout_dss_perform_vrfb_dma(struct omapvout_device *vout,
-					int buf_idx, bool vrfb_cfg)
-{
-	int rc = 0;
-	int rot = 0;
-	struct omapvout_dss_vrfb *vrfb;
-	u32 src_paddr;
-	u32 dst_paddr;
-
-	/* It is assumed that the caller has locked the vout mutex */
-
-	if (vout->dss->vrfb.req_status != DMA_CHAN_ALLOTED)
-		return -EINVAL;
-
-	vrfb = &vout->dss->vrfb;
-
-	if (vrfb_cfg) {
-		enum omap_color_mode dss_fmt;
-		int bytespp;
-		int w, h;
-		u32 fmt = vout->pix.pixelformat;
-
-		w = vout->crop.width;
-		h = vout->crop.height;
-
-		dss_fmt = omapvout_dss_color_mode(vout->pix.pixelformat);
-		omap_vrfb_setup(&vrfb->ctx[0], vrfb->phy_addr[0],
-				w, h, dss_fmt, vout->rotation);
-		omap_vrfb_setup(&vrfb->ctx[1], vrfb->phy_addr[1],
-				w, h, dss_fmt, vout->rotation);
-
-		bytespp = omapvout_dss_format_bytespp(vout->pix.pixelformat);
-		vrfb->en = (w * bytespp) / 4; /* 32 bit ES */
-		vrfb->fn = h;
-		vrfb->dst_ei = 1;
-		if (fmt == V4L2_PIX_FMT_YUYV || fmt == V4L2_PIX_FMT_UYVY) {
-			vrfb->dst_fi = (OMAP_VRFB_LINE_LEN * bytespp * 2)
-							- (vrfb->en * 4) + 1;
-		} else {
-			vrfb->dst_fi = (OMAP_VRFB_LINE_LEN * bytespp)
-							- (vrfb->en * 4) + 1;
-		}
-	}
-
-	switch (vout->rotation) {
-	case 1:
-		rot = 3;
-		break;
-	case 3:
-		rot = 1;
-		break;
-	default:
-		rot = vout->rotation;
-		break;
-	}
-
-	src_paddr = vout->queue.bufs[buf_idx]->baddr;
-	dst_paddr = vrfb->ctx[vrfb->next].paddr[rot];
-
-	omap_set_dma_transfer_params(vrfb->dma_ch, OMAP_DMA_DATA_TYPE_S32,
-				vrfb->en, vrfb->fn, OMAP_DMA_SYNC_ELEMENT,
-				vrfb->dma_id, 0x0);
-	omap_set_dma_src_params(vrfb->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
-				src_paddr, 0, 0);
-	omap_set_dma_src_burst_mode(vrfb->dma_ch, OMAP_DMA_DATA_BURST_16);
-	omap_set_dma_dest_params(vrfb->dma_ch, 0, OMAP_DMA_AMODE_DOUBLE_IDX,
-				dst_paddr, vrfb->dst_ei, vrfb->dst_fi);
-	omap_set_dma_dest_burst_mode(vrfb->dma_ch, OMAP_DMA_DATA_BURST_16);
-	omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
-
-	vrfb->dma_complete = false;
-	omap_start_dma(vrfb->dma_ch);
-	wait_event_interruptible_timeout(vrfb->wait, vrfb->dma_complete,
-							VRFB_TX_TIMEOUT);
-
-	if (!vrfb->dma_complete) {
-		DBG("VRFB DMA timeout\n");
-		omap_stop_dma(vrfb->dma_ch);
-		return -EINVAL;
-	}
-
-	return rc;
-}
-
-static int omapvout_dss_update_overlay(struct omapvout_device *vout,
-							int buf_idx)
-{
-	struct omap_overlay_info o_info;
-	struct omap_overlay *ovly;
-	struct omapvout_dss_vrfb *vrfb;
-	int rc = 0;
-	int rot = vout->rotation;
-
-	/* It is assumed that the caller has locked the vout mutex */
-
-	/* Populate the overlay info struct and set it */
-	ovly = vout->dss->overlay;
-	ovly->get_overlay_info(ovly, &o_info);
-	o_info.enabled = true;
-	vrfb = &vout->dss->vrfb;
-	o_info.paddr = vrfb->ctx[vrfb->next].paddr[0];
-	o_info.paddr += vout->dss->foffset;
-	o_info.vaddr = NULL;
-	o_info.screen_width = OMAP_VRFB_LINE_LEN;
-	vrfb->next = (vrfb->next) ? 0 : 1;
-
-	if (rot == 1 || rot == 3) { /* 90 or 270 degree rotation */
-		o_info.width = vout->crop.height;
-		o_info.height = vout->crop.width;
-	} else {
-		o_info.width = vout->crop.width;
-		o_info.height = vout->crop.height;
-	}
-
-	o_info.pos_x = vout->win.w.left & ~1;
-	o_info.pos_y = vout->win.w.top & ~1;
-	o_info.out_width = vout->win.w.width;
-	o_info.out_height = vout->win.w.height;
-	o_info.color_mode = omapvout_dss_color_mode(vout->pix.pixelformat);
-	o_info.rotation_type = OMAP_DSS_ROT_VRFB;
-	o_info.rotation = rot;
-	o_info.mirror = false;
-
-	rc = ovly->set_overlay_info(ovly, &o_info);
-	if (rc) {
-		DBG("Failed setting the overlay info %d\n", rc);
-		return rc;
-	}
-
-	rc = ovly->manager->apply(ovly->manager);
-	if (rc) {
-		DBG("Failed apply to overlay manager %d\n", rc);
-		return rc;
-	}
-
-	rc = ovly->manager->device->update(ovly->manager->device,
-					o_info.pos_x, o_info.pos_y,
-					o_info.out_width, o_info.out_height);
-	if (rc)
-		DBG("Overlay update failed %d\n", rc);
-
-	return rc;
-}
-
-static void omapvout_dss_mark_buf_done(struct omapvout_device *vout, int idx)
-{
-	/* FIXME: Should set the state to VIDEOBUF_DONE here, but since we
-	 * don't properly DQ yet, this has been hacked to allow no DQ.
-	 */
-	vout->queue.bufs[idx]->state = VIDEOBUF_IDLE;
-	wake_up_interruptible(&vout->queue.bufs[idx]->done);
-}
-
-static void omapvout_dss_perform_update(struct work_struct *work)
-{
-	struct omapvout_device *vout;
-	struct omapvout_dss *dss;
-	struct omap_dss_device *dev;
-	struct videobuf_buffer *buf;
-	int rc;
-	int idx = 0;
-
-	dss = container_of(work, struct omapvout_dss, work);
-	vout = dss->vout;
-
-	if (!dss->enabled)
-		return;
-
-	mutex_lock(&vout->mtx);
-
-	dss->working = true;
-
-	while (!list_empty(&vout->q_list)) {
-
-		buf = list_entry(vout->q_list.next,
-				struct videobuf_buffer, queue);
-		list_del(&buf->queue);
-		buf->state = VIDEOBUF_ACTIVE;
-		idx = buf->i;
-
-		/*DBG("Processing frame %d\n", idx);*/
-
-		if (dss->need_cfg) {
-			rc = omapvout_dss_calc_offset(vout);
-			if (rc != 0) {
-				DBG("Offset calculation failed %d\n", rc);
-				goto failed_need_done;
-			}
-
-			rc = omapvout_dss_enable_transparency(vout);
-			if (rc != 0) {
-				DBG("Alpha config failed %d\n", rc);
-				goto failed_need_done;
-			}
-		}
-
-		rc = omapvout_dss_perform_vrfb_dma(vout, idx, dss->need_cfg);
-		if (rc != 0) {
-			DBG("VRFB rotation failed %d\n", rc);
-			goto failed_need_done;
-		}
-
-                omapvout_dss_mark_buf_done(vout, idx);
-
-		rc = omapvout_dss_update_overlay(vout, idx);
-		if (rc != 0) {
-			DBG("DSS update failed %d\n", rc);
-			goto failed;
-		}
-
-		dss->need_cfg = false;
-
-		mutex_unlock(&vout->mtx);
-
-		/* Wait until the new frame is being used.  There is no problem
-		 * doing this here since we are in a worker thread.  The mutex
-		 * is unlocked since the sync may take some time.
-		 */
-		dev = dss->overlay->manager->device;
-		if (dev->sync)
-			dev->sync(dev);
-
-		/* Since the mutex was unlocked, it is possible that the DSS
-		 * may be disabled when we return, so check for this and exit
-		 * if so.
-		 */
-		if (!dss->enabled) {
-			/* Since the DSS is disabled, this isn't a problem */
-			dss->working = false;
-
-			/* Clean up the states of the final buffer */
-			omapvout_dss_mark_buf_done(vout, idx);
-			return;
-		}
-
-		mutex_lock(&vout->mtx);
-	}
-
-	dss->working = false;
-	mutex_unlock(&vout->mtx);
-
-	return;
-
-failed_need_done:
-	/* Set the done flag on failures to be sure the buffer can be DQ'd */
-	omapvout_dss_mark_buf_done(vout, idx);
-failed:
-	dss->working = false;
-	mutex_unlock(&vout->mtx);
-}
-
-/*=== Public Functions =================================================*/
-
-int  omapvout_dss_init(struct omapvout_device *vout, enum omap_plane plane)
-{
-	struct omap_overlay *ovly;
-	int rc = 0;
-	int i;
-	int cnt;
-
-	if (vout->dss) {
-		rc = -EINVAL;
-		goto failed;
-	}
-
-	vout->dss = kzalloc(sizeof(struct omapvout_dss), GFP_KERNEL);
-	if (vout->dss == NULL) {
-		rc = -ENOMEM;
-		goto failed;
-	}
-
-	/* Retrieve the desired DSS overlay object */
-	vout->dss->overlay = NULL;
-	cnt = omap_dss_get_num_overlays();
-	for (i = 0; i < cnt; i++) {
-		ovly = omap_dss_get_overlay(i);
-		if (ovly->id == plane) {
-			vout->dss->overlay = ovly;
-			break;
-		}
-	}
-
-	if (vout->dss->overlay == NULL) {
-		DBG("No overlay %d found\n", plane);
-		rc = -ENODEV;
-		goto failed_mem;
-	}
-
-	rc = omapvout_dss_acquire_vrfb(vout);
-	if (rc != 0) {
-		DBG("VRFB allocation failed\n");
-		goto failed_mem;
-	}
-
-	vout->dss->vout = vout;
-
-	return rc;
-
-failed_mem:
-	kfree(vout->dss);
-failed:
-	return rc;
-}
-
-void omapvout_dss_remove(struct omapvout_device *vout)
-{
-	if (vout->dss != NULL) {
-		omapvout_dss_release_vrfb(vout);
-		kfree(vout->dss);
-	}
-}
-
-int omapvout_dss_open(struct omapvout_device *vout, u16 *disp_w, u16 *disp_h)
-{
-	struct omap_dss_device *dev;
-	int rc = 0;
-
-	/* It is assumed that the caller has locked the vout mutex */
-
-	if (vout->dss->overlay->manager == NULL) {
-		DBG("No manager found\n");
-		rc = -ENODEV;
-		goto failed;
-	}
-
-	if (vout->dss->overlay->manager->device == NULL) {
-		DBG("No device found\n");
-		rc = -ENODEV;
-		goto failed;
-	}
-
-	dev = vout->dss->overlay->manager->device;
-
-	/* TODO: Do we need to deal with rotation? */
-	dev->get_resolution(dev, disp_w, disp_h);
-
-	vout->dss->workqueue = create_singlethread_workqueue("OMAPVOUT-DSS");
-	if (vout->dss->workqueue == NULL) {
-		rc = -ENOMEM;
-		goto failed;
-	}
-
-	INIT_WORK(&vout->dss->work, omapvout_dss_perform_update);
-
-	vout->dss->enabled = false;
-
-failed:
-	return rc;
-}
-
-void omapvout_dss_release(struct omapvout_device *vout)
-{
-	/* It is assumed that the caller has locked the vout mutex */
-
-	if (vout->dss->enabled)
-		omapvout_dss_disable(vout);
-
-	flush_workqueue(vout->dss->workqueue);
-	destroy_workqueue(vout->dss->workqueue);
-}
-
-bool omapvout_dss_is_rotation_supported(struct omapvout_device *vout)
-{
-	return vout->dss->vrfb.req_status == DMA_CHAN_ALLOTED;
-}
-
-int omapvout_dss_enable(struct omapvout_device *vout)
-{
-	/* It is assumed that the caller has locked the vout mutex */
-
-	/* Reset the current frame idx */
-	vout->dss->cur_q_idx = -1;
-
-	/* Force a reconfiguration */
-	vout->dss->need_cfg = true;
-
-	vout->dss->enabled = true;
-
-	return 0;
-}
-
-void omapvout_dss_disable(struct omapvout_device *vout)
-{
-	int rc = 0;
-	struct omap_overlay_info o_info;
-	struct omap_overlay *ovly;
-	struct omap_dss_device *dev;
-
-	/* It is assumed that the caller has locked the vout mutex */
-
-	memset(&o_info, 0, sizeof(o_info));
-	o_info.enabled = false;
-
-	vout->dss->enabled = false;
-
-	dev = vout->dss->overlay->manager->device;
-	if (vout->dss->working && dev->sync) {
-		/* Allow the current frame to finish */
-		mutex_unlock(&vout->mtx);
-		dev->sync(dev);
-		mutex_lock(&vout->mtx);
-	}
-
-	rc = omapvout_dss_disable_transparency(vout);
-	if (rc)
-		DBG("Disabling transparency failed %d\n", rc);
-
-	ovly = vout->dss->overlay;
-	rc = ovly->set_overlay_info(ovly, &o_info);
-	if (rc)
-		DBG("Setting overlay info failed %d\n", rc);
-
-	rc = ovly->manager->apply(ovly->manager);
-	if (rc)
-		DBG("Overlay manager apply failed %d\n", rc);
-
-	rc = ovly->manager->device->update(ovly->manager->device,
-				0, 0, vout->disp_width, vout->disp_height);
-	if (rc)
-		DBG("Display update failed %d\n", rc);
-}
-
-int omapvout_dss_update(struct omapvout_device *vout)
-{
-	/* It is assumed that the caller has locked the vout mutex */
-
-	if (!vout->dss->enabled) {
-		DBG("DSS overlay is not enabled\n");
-		return -EINVAL;
-	}
-
-	if (vout->dss->working) {
-		/* Exit quitely, since still working on previous frame */
-		/*DBG("DSS busy, handle shortly\n");*/
-		return 0;
-	}
-
-	if (queue_work(vout->dss->workqueue, &vout->dss->work) == 0) {
-		DBG("Queuing DSS work failed\n");
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
diff --git a/drivers/media/video/omap-vout/omapvout-dss.h b/drivers/media/video/omap-vout/omapvout-dss.h
deleted file mode 100644
index 3249133..0000000
--- a/drivers/media/video/omap-vout/omapvout-dss.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-dss.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef __OMAPVOUT_DSS_H__
-#define __OMAPVOUT_DSS_H__
-
-struct omapvout_dss_vrfb {
-	/* Ping-pong buffers and VRFB contexts */
-	struct vrfb ctx[2];
-	unsigned long phy_addr[2];
-	void *virt_addr[2];
-	int size;
-	int next;
-
-	/* VRFB dma config data */
-	u32 en;
-	u32 fn;
-	u32 dst_ei;
-	u32 dst_fi;
-
-	/* VRFB dma channel data */
-	int dma_id;
-	int dma_ch;
-	int req_status;
-	bool dma_complete;
-	wait_queue_head_t wait;
-};
-
-struct omapvout_dss {
-	struct omap_overlay *overlay;
-
-	/* FIXME: This is a minor hack to allow the work callback to
-	 * gain access to the vout pointer.
-	 */
-	struct omapvout_device *vout;
-
-	bool enabled;
-	bool need_cfg;
-
-	struct omapvout_dss_vrfb vrfb;
-	int foffset; /* per frame address offset */
-
-	struct work_struct work;
-	struct workqueue_struct *workqueue;
-	bool working;
-
-	int cur_q_idx; /* The current Q frame used by DSS */
-};
-
-/* Driver init/remove time calls */
-extern int  omapvout_dss_init(struct omapvout_device *vout,
-						enum omap_plane plane);
-extern void omapvout_dss_remove(struct omapvout_device *vout);
-
-/* Driver open/release time calls */
-extern int  omapvout_dss_open(struct omapvout_device *vout,
-						u16 *disp_w, u16 *disp_h);
-extern void omapvout_dss_release(struct omapvout_device *vout);
-
-/* Driver operation calls */
-extern bool omapvout_dss_is_rotation_supported(struct omapvout_device *vout);
-extern int  omapvout_dss_enable(struct omapvout_device *vout);
-extern void omapvout_dss_disable(struct omapvout_device *vout);
-extern int  omapvout_dss_update(struct omapvout_device *vout);
-
-#endif /* __OMAPVOUT_DSS_H__ */
-
diff --git a/drivers/media/video/omap-vout/omapvout-mem.c b/drivers/media/video/omap-vout/omapvout-mem.c
deleted file mode 100644
index f63a848..0000000
--- a/drivers/media/video/omap-vout/omapvout-mem.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-mem.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/gfp.h>
-
-#include <asm/processor.h>
-#include <asm/cacheflush.h>
-#include <asm/page.h>
-
-#include "omapvout.h"
-#include "omapvout-mem.h"
-
-int omapvout_mem_alloc(u32 size, unsigned long *phy_addr, void **virt_addr)
-{
-	void *page_addr;
-
-	size = PAGE_ALIGN(size);
-
-	page_addr = alloc_pages_exact(size, GFP_KERNEL);
-	if (!page_addr) {
-		printk(KERN_ERR "Failed to allocate pages!\n");
-		return -ENOMEM;
-	}
-
-	*phy_addr = virt_to_phys(page_addr);
-	*virt_addr = ioremap_cached(*phy_addr, size);
-
-	DBG("mem_alloc: page/%08x; phy/%08lx; virt/%08x; size/%x\n",
-		(unsigned int) page_addr, *phy_addr,
-		(unsigned int) *virt_addr, size);
-
-	return 0;
-}
-
-void omapvout_mem_free(unsigned long phy_addr, void *virt_addr, u32 size)
-{
-	void *page_addr;
-
-	size = PAGE_ALIGN(size);
-	page_addr = __va((void *)phy_addr);
-
-	free_pages_exact(page_addr, size);
-
-	iounmap(virt_addr);
-}
-
-int omapvout_mem_map(struct vm_area_struct *vma, unsigned long phy_addr)
-{
-	struct page *cpage;
-	void *pos;
-	u32 start;
-	u32 size;
-
-	vma->vm_flags |= VM_RESERVED;
-	vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
-	pos = (void *) phy_addr;
-	start = vma->vm_start;
-	size = (vma->vm_end - vma->vm_start);
-
-	while (size > 0) {
-		cpage = pfn_to_page(((unsigned int)pos) >> PAGE_SHIFT);
-		if (vm_insert_page(vma, start, cpage)) {
-			printk(KERN_ERR "Failed to insert page to VMA \n");
-			return -EAGAIN;
-		}
-		start += PAGE_SIZE;
-		pos += PAGE_SIZE;
-		size -= PAGE_SIZE;
-	}
-
-	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
-
-	return 0;
-}
-
-
diff --git a/drivers/media/video/omap-vout/omapvout-mem.h b/drivers/media/video/omap-vout/omapvout-mem.h
deleted file mode 100644
index 6665a15..0000000
--- a/drivers/media/video/omap-vout/omapvout-mem.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-mem.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef __OMAPVOUT_MEM_H__
-#define __OMAPVOUT_MEM_H__
-
-extern int  omapvout_mem_alloc(u32 size, unsigned long *phy_addr,
-						void **virt_addr);
-extern void omapvout_mem_free(unsigned long phy_addr, void *virt_addr,
-						u32 size);
-extern int  omapvout_mem_map(struct vm_area_struct *vma,
-						unsigned long phy_addr);
-
-#endif /* __OMAPVOUT_MEM_H__ */
-
diff --git a/drivers/media/video/omap-vout/omapvout-vbq.c b/drivers/media/video/omap-vout/omapvout-vbq.c
deleted file mode 100644
index d6da499..0000000
--- a/drivers/media/video/omap-vout/omapvout-vbq.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-vbq.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- * This file contains the code necessary to interface with the
- * vbq (video buffer queue).
- */
-
-#include <media/videobuf-core.h>
-#include <linux/mm.h>
-
-#include "omapvout.h"
-#include "omapvout-vbq.h"
-#include "omapvout-bp.h"
-#include "omapvout-dss.h"
-#include "omapvout-mem.h"
-
-/*=== Local Functions ==================================================*/
-
-static void omapvout_vbq_vm_open(struct vm_area_struct *vma)
-{
-	struct omapvout_device *vout = vma->vm_private_data;
-	DBG("vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
-	vout->mmap_cnt++;
-}
-
-static void omapvout_vbq_vm_close(struct vm_area_struct *vma)
-{
-	struct omapvout_device *vout = vma->vm_private_data;
-	DBG("vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
-	vout->mmap_cnt--;
-}
-
-static struct vm_operations_struct vm_ops = {
-	.open = omapvout_vbq_vm_open,
-	.close = omapvout_vbq_vm_close
-};
-
-static void omapvout_acquire_frames(struct omapvout_device *vout,
-							int cnt, int size)
-{
-	struct omapvout_vbq *vbq;
-	int i;
-	int fcnt;
-	unsigned long paddr;
-	void *vaddr;
-	u32 fsize;
-
-	/* It is assumed that the vout->mtx is locked for this call */
-
-	vbq = vout->vbq;
-
-	vbq->min_size = 0x7FFFFFF; /* Some large value */
-	fcnt = 0;
-	for (i = 0; i < cnt; i++) {
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
-		if (vout->bp &&	omapvout_bp_alloc(vout, size,
-					&paddr, &vaddr, &fsize) == 0) {
-			DBG("Alloc'd from the pool\n");
-		} else {
-#else
-		{
-#endif
-			if (omapvout_mem_alloc(size, &paddr, &vaddr)) {
-				DBG("Alloc failed %d\n", i);
-				break;
-			}
-			fsize = size;
-		}
-
-		memset(vaddr, 0, fsize);
-
-		vbq->buf[fcnt].size = fsize;
-		vbq->buf[fcnt].phy_addr = paddr;
-		vbq->buf[fcnt].virt_addr = vaddr;
-		vbq->buf[fcnt].released = false;
-
-		fcnt++;
-
-		if (fsize < vbq->min_size)
-			vbq->min_size = fsize;
-	}
-
-	vbq->cnt = fcnt;
-}
-
-static void omapvout_release_frames(struct omapvout_device *vout)
-{
-	struct omapvout_vbq *vbq;
-	int i;
-	unsigned long paddr;
-	void *vaddr;
-	u32 size;
-
-	/* It is assumed that the vout->mtx is locked for this call */
-
-	vbq = vout->vbq;
-
-	for (i = 0; i < vbq->cnt; i++) {
-		paddr = vbq->buf[i].phy_addr;
-		vaddr = vbq->buf[i].virt_addr;
-		size  = vbq->buf[i].size;
-
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
-		if (omapvout_is_bp_buffer(vout, paddr)) {
-			if (omapvout_bp_release(vout, paddr))
-				DBG("Error releasing to the pool\n");
-		} else {
-#else
-		{
-#endif
-			omapvout_mem_free(paddr, vaddr, size);
-		}
-	}
-
-	vbq->cnt = 0;
-	vbq->min_size = 0;
-	memset(vbq->buf, 0, sizeof(vbq->buf));
-}
-
-static int omapvout_vbq_buf_setup(struct videobuf_queue *q,
-			unsigned int *count, unsigned int *size)
-{
-	struct omapvout_device *vout;
-	struct omapvout_vbq *vbq;
-	int cnt = *count;
-	int sz;
-
-	vout = q->priv_data;
-	if (!vout)
-		return -EINVAL;
-
-	vbq = vout->vbq;
-
-	/* It is assumed that the video out format is correctly configured */
-	if (vout->pix.sizeimage == 0)
-		return -EINVAL;
-
-	sz = vout->pix.sizeimage;
-
-	/* Use the existing frames if possible */
-	if (cnt <= vbq->cnt && sz <= vbq->min_size)
-		goto success;
-
-	if (cnt > VIDEO_MAX_FRAME)
-		cnt = VIDEO_MAX_FRAME;
-
-	omapvout_release_frames(vout);
-	omapvout_acquire_frames(vout, cnt, sz);
-
-	if (vbq->cnt <= 0) {
-		DBG("Buffer allocation failed\n");
-		return -ENOMEM;
-	}
-	cnt = vbq->cnt;
-
-success:
-	*count = cnt;
-	*size = sz;
-
-	return 0;
-}
-
-static int omapvout_vbq_buf_prepare(struct videobuf_queue *q,
-			struct videobuf_buffer *vb, enum v4l2_field field)
-{
-	struct omapvout_device *vout;
-
-	vout = q->priv_data;
-	if (!vout)
-		return -EINVAL;
-
-	if (vb->state == VIDEOBUF_NEEDS_INIT) {
-		vb->width = vout->pix.width;
-		vb->height = vout->pix.height;
-		vb->size = vout->pix.sizeimage;
-		vb->field = field;
-		vb->privsize = 0;  /* Reusing for buf seq number */
-	}
-
-	vb->state = VIDEOBUF_PREPARED;
-
-	return 0;
-}
-
-static void omapvout_vbq_buf_queue(struct videobuf_queue *q,
-			struct videobuf_buffer *vb)
-{
-	struct omapvout_device *vout;
-
-	vout = q->priv_data;
-	if (!vout)
-		return;
-
-	/* Add it to the incoming queue */
-	list_add_tail(&vb->queue, &vout->q_list);
-
-	vb->state = VIDEOBUF_QUEUED;
-
-	omapvout_dss_update(vout);
-}
-
-static void omapvout_vbq_buf_release(struct videobuf_queue *q,
-			struct videobuf_buffer *vb)
-{
-	struct omapvout_device *vout;
-	int i;
-
-	vout = q->priv_data;
-	if (!vout)
-		return;
-
-	if (vout->vbq->cnt <= 0)
-		return;
-
-	vout->vbq->buf[vb->i].released = true;
-
-	for (i = 0; i < vout->vbq->cnt; i++) {
-		if (!vout->vbq->buf[i].released)
-			break;
-	}
-	if (i > vout->vbq->cnt) /* All buffers have been released */
-		omapvout_release_frames(vout);
-
-	vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static struct videobuf_queue_ops vbq_buf_ops = {
-	.buf_setup = omapvout_vbq_buf_setup,
-	.buf_prepare = omapvout_vbq_buf_prepare,
-	.buf_queue = omapvout_vbq_buf_queue,
-	.buf_release = omapvout_vbq_buf_release
-};
-
-static void *omapvout_vbq_alloc(size_t size)
-{
-	return kzalloc(size, GFP_KERNEL);
-}
-
-static void *omapvout_vbq_vmalloc(struct videobuf_buffer *buf)
-{
-	/* Do nothing */
-	return NULL;
-}
-
-static int omapvout_vbq_iolock(struct videobuf_queue *q,
-		struct videobuf_buffer *vb, struct v4l2_framebuffer *fbuf)
-{
-	/* Do nothing */
-	return 0;
-}
-
-static int omapvout_vbq_mmap_op(struct videobuf_queue *q, unsigned int *count,
-				unsigned int *size, enum v4l2_memory memory)
-{
-	/* Do nothing */
-	return 0;
-}
-
-static int omapvout_vbq_sync(struct videobuf_queue *q,
-				struct videobuf_buffer *buf)
-{
-	/* Do nothing */
-	return 0;
-}
-
-static int omapvout_vbq_copy_user(struct videobuf_queue *q, char __user *data,
-						size_t count, int nonblocking)
-{
-	/* Do nothing */
-	return 0;
-}
-
-static int omapvout_vbq_copy_strm(struct videobuf_queue *q, char __user *data,
-			size_t count, size_t pos, int vbihack, int nonblocking)
-{
-	/* Do nothing */
-	return 0;
-}
-
-static int omapvout_vbq_mmap_free(struct videobuf_queue *q)
-{
-	/* Do nothing */
-	return 0;
-}
-
-static int omapvout_vbq_mmap_mapper(struct videobuf_queue *q,
-					struct vm_area_struct *vma)
-{
-	struct omapvout_device *vout;
-	int rc;
-	int idx;
-	int cnt;
-	u32 offset;
-
-	vout = q->priv_data;
-	if (!vout)
-		return -EINVAL;
-
-	cnt = vout->vbq->cnt;
-
-	/* look for the buffer to map */
-	offset = (vma->vm_pgoff << PAGE_SHIFT);
-	for (idx = 0; idx < cnt; idx++) {
-		if (q->bufs[idx]->boff == offset)
-			break;
-	}
-
-	if (idx >= cnt) {
-		DBG("Invalid offset 0x%lx\n", (unsigned long) offset);
-		return -EINVAL;
-	}
-
-	DBG("omapvout_vbq_mmap %d\n", idx);
-
-	vma->vm_ops = &vm_ops;
-	vma->vm_private_data = (void *) vout;
-
-	rc = omapvout_mem_map(vma, vout->vbq->buf[idx].phy_addr);
-	if (rc != 0) {
-		DBG("Failed mem_map %d\n", rc);
-		return rc;
-	}
-
-	q->bufs[idx]->baddr = vout->vbq->buf[idx].phy_addr;
-
-	return 0;
-}
-
-static struct videobuf_qtype_ops vbq_ops = {
-	.magic = MAGIC_QTYPE_OPS,
-	.alloc = omapvout_vbq_alloc,
-	.vmalloc = omapvout_vbq_vmalloc,
-	.iolock = omapvout_vbq_iolock,
-	.mmap = omapvout_vbq_mmap_op,
-	.sync = omapvout_vbq_sync,
-	.video_copy_to_user = omapvout_vbq_copy_user,
-	.copy_stream = omapvout_vbq_copy_strm,
-	.mmap_free = omapvout_vbq_mmap_free,
-	.mmap_mapper = omapvout_vbq_mmap_mapper
-};
-
-/*=== Public Interface Functions =========================================*/
-
-int omapvout_vbq_init(struct omapvout_device *vout)
-{
-	struct omapvout_vbq *vbq;
-	int rc;
-
-	/* It is assumed that the caller has locked the vout mutex */
-
-	if (vout->vbq) {
-		rc = -EINVAL;
-		goto failed;
-	}
-
-	vout->vbq = kzalloc(sizeof(struct omapvout_vbq), GFP_KERNEL);
-	if (vout->vbq == NULL) {
-		rc = -ENOMEM;
-		goto failed;
-	}
-
-	vbq = vout->vbq;
-
-	vbq->cnt = 0;
-	vbq->min_size = 0;
-
-	spin_lock_init(&vbq->lock);
-	videobuf_queue_core_init(&vout->queue, &vbq_buf_ops, NULL,
-			&vbq->lock, V4L2_BUF_TYPE_VIDEO_OUTPUT,
-			V4L2_FIELD_NONE, sizeof(struct videobuf_buffer),
-			vout, &vbq_ops);
-
-	return 0;
-
-failed:
-	return rc;
-}
-
-void omapvout_vbq_destroy(struct omapvout_device *vout)
-{
-	/* It is assumed that the caller has locked the vout mutex */
-
-	if (vout->vbq) {
-		omapvout_release_frames(vout);
-		kfree(vout->vbq);
-		vout->vbq = NULL;
-	}
-}
-
-int omapvout_vbq_buf_cnt(struct omapvout_device *vout)
-{
-	return vout->vbq->cnt;
-}
-
diff --git a/drivers/media/video/omap-vout/omapvout-vbq.h b/drivers/media/video/omap-vout/omapvout-vbq.h
deleted file mode 100644
index 64fd522..0000000
--- a/drivers/media/video/omap-vout/omapvout-vbq.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout-vbq.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- * This file contains the code necessary to interface with the
- * vbq (video buffer queue).
- */
-
-#ifndef __OMAPVOUT_VBQ_H__
-#define __OMAPVOUT_VBQ_H__
-
-#include <linux/videodev2.h>
-
-#include "omapvout.h"
-
-struct omapvout_buf {
-	u32 size;
-	unsigned long phy_addr;
-	void *virt_addr;
-	bool released;
-};
-
-struct omapvout_vbq {
-	spinlock_t lock;
-	int cnt; /* number of frames in the queue */
-	int min_size; /* smallest frame in the queue */
-	struct omapvout_buf buf[VIDEO_MAX_FRAME];
-};
-
-extern int  omapvout_vbq_init(struct omapvout_device *vout);
-extern void omapvout_vbq_destroy(struct omapvout_device *vout);
-extern int  omapvout_vbq_buf_cnt(struct omapvout_device *vout);
-
-#endif /* __OMAPVOUT_VBQ_H__ */
-
diff --git a/drivers/media/video/omap-vout/omapvout.c b/drivers/media/video/omap-vout/omapvout.c
deleted file mode 100644
index 9b1c38f..0000000
--- a/drivers/media/video/omap-vout/omapvout.c
+++ /dev/null
@@ -1,1232 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout.c
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/mutex.h>
-#include <linux/platform_device.h>
-#include <linux/videodev2.h>
-#include <linux/vmalloc.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-common.h>
-#include <mach/io.h>
-#include <mach/board.h>
-
-#include "omapvout.h"
-#include "omapvout-dss.h"
-#include "omapvout-mem.h"
-#include "omapvout-vbq.h"
-#include "omapvout-bp.h"
-
-#define MODULE_NAME "omapvout"
-
-/* list of image formats supported by OMAP2 video pipelines */
-const static struct v4l2_fmtdesc omap2_formats[] = {
-{
-	/* Note:  V4L2 defines RGB565 as:
-	 *      Byte 0                    Byte 1
-	 *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
-	 *
-	 * We interpret RGB565 as:
-	 *      Byte 0                    Byte 1
-	 *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
-	 */
-	.description = "RGB565, le",
-	.pixelformat = V4L2_PIX_FMT_RGB565,
-},
-{
-	/* Note:  V4L2 defines RGB32 as: RGB-8-8-8-8  we use
-	 *        this for RGB24 unpack mode, the last 8 bits are ignored
-	 */
-	.description = "RGB32, le",
-	.pixelformat = V4L2_PIX_FMT_RGB32,
-},
-{
-	.description = "YUYV (YUV 4:2:2), packed",
-	.pixelformat = V4L2_PIX_FMT_YUYV,
-},
-{
-	.description = "UYVY (YUV 4:2:2), packed",
-	.pixelformat = V4L2_PIX_FMT_UYVY,
-},
-};
-
-#define NUM_OUTPUT_FORMATS (sizeof(omap2_formats)/sizeof(omap2_formats[0]))
-
-/*=== Local Functions ==================================================*/
-
-static int omapvout_crop_to_size(struct v4l2_rect *rect, int w, int h)
-{
-	struct v4l2_rect try;
-	int t;
-
-	try = *rect;
-
-	if (try.left < 0)
-		try.left = 0;
-	if (try.top < 0)
-		try.top = 0;
-	if (try.width > w)
-		try.width = w;
-	if (try.height > h)
-		try.height = h;
-	t = ((try.left + try.width) - w);
-	if (t > 0)
-		try.width = w - t;
-	t = ((try.top + try.height) - h);
-	if (t > 0)
-		try.height = h - t;
-	try.width &= ~1;
-	try.height &= ~1;
-
-	if (try.width <= 0 || try.height <= 0)
-		return -EINVAL;
-
-	*rect = try;
-
-	return 0;
-}
-
-static int omapvout_try_pixel_format(struct omapvout_device *vout,
-				struct v4l2_pix_format *pix)
-{
-	int ifmt;
-	int bpp = 0;
-
-	if (pix->width > vout->max_video_width)
-		pix->width = vout->max_video_width;
-
-	if (pix->height > vout->max_video_height)
-		pix->height = vout->max_video_height;
-
-	for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
-		if (pix->pixelformat == omap2_formats[ifmt].pixelformat)
-			break;
-	}
-
-	if (ifmt >= NUM_OUTPUT_FORMATS)
-		ifmt = 0;
-
-	pix->pixelformat = omap2_formats[ifmt].pixelformat;
-	pix->field = V4L2_FIELD_NONE;
-	pix->priv = 0;
-
-	switch (pix->pixelformat) {
-	case V4L2_PIX_FMT_RGB565:
-		pix->colorspace = V4L2_COLORSPACE_SRGB;
-		bpp = 2;
-		break;
-	case V4L2_PIX_FMT_RGB32:
-		pix->colorspace = V4L2_COLORSPACE_SRGB;
-		bpp = 4;
-		break;
-	case V4L2_PIX_FMT_YUYV:
-	case V4L2_PIX_FMT_UYVY:
-	default:
-		pix->colorspace = V4L2_COLORSPACE_JPEG;
-		bpp = 2;
-		break;
-	}
-
-	pix->bytesperline = pix->width * bpp;
-	pix->sizeimage = pix->bytesperline * pix->height;
-
-	return 0;
-}
-
-static int omapvout_try_window(struct omapvout_device *vout,
-					struct v4l2_window *win)
-{
-	int rc = 0;
-
-	rc = omapvout_crop_to_size(&win->w, vout->disp_width,
-							vout->disp_height);
-	if (rc == 0)
-		win->field = V4L2_FIELD_NONE;
-
-	return rc;
-}
-
-static int omapvout_try_crop(struct omapvout_device *vout,
-					struct v4l2_rect *crop)
-{
-	return omapvout_crop_to_size(crop, vout->pix.width, vout->pix.height);
-}
-
-/* Make sure the input size, window rectangle, crop rectangle, and rotation
- * parameters together make up a valid configuration for the hardware
- */
-static int omapvout_validate_cfg(struct omapvout_device *vout)
-{
-	int rc = 0;
-	int win_w, win_h;
-	int crp_w, crp_h;
-
-	/* Is it assumed:
-	 * - The rotation value denotes 0, 90, 180, or 270
-	 * - The input size is valid based on the platform limits
-	 * - The output rectangle is within the display area
-	 * - The crop rectangle is within the input frame
-	 */
-
-	/* Validate scaling */
-	win_w = vout->win.w.width;
-	win_h = vout->win.w.height;
-	crp_w = vout->crop.width;
-	crp_h = vout->crop.height;
-
-	if ( vout->rotation == 0 || vout->rotation == 2 ) {
-		win_w = vout->win.w.width;
-		win_h = vout->win.w.height;
-	} else {
-		win_w = vout->win.w.height;
-		win_h = vout->win.w.width;
-	}
-
-	/* Down-scaling */
-	if (((win_w < crp_w) && ((win_w * 4) < crp_w)) ||
-	    ((win_h < crp_w) && ((win_h * 4) < crp_h)))
-		rc = -EINVAL;
-
-	/* Up-scaling */
-	if (((win_w > crp_w) && ((crp_w * 8) < win_w)) ||
-	    ((win_h > crp_h) && ((crp_h * 8) < win_h)))
-		rc = -EINVAL;
-
-	return rc;
-}
-
-static void omapvout_free_resources(struct omapvout_device *vout)
-{
-	if (vout == NULL)
-		return;
-
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
-	if (vout->bp != NULL)
-		omapvout_bp_destroy(vout);
-#endif
-
-	video_set_drvdata(&vout->vdev, NULL);
-	kfree(vout);
-}
-
-/*=== V4L2 Interface Functions =========================================*/
-
-static int omapvout_open(struct file *file)
-{
-	struct omapvout_device *vout;
-	u16 w, h;
-	int rc;
-
-	DBG("omapvout_open\n");
-
-	vout = video_drvdata(file);
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	/* We only support single open */
-	if (vout->opened) {
-		DBG("Device already opened\n");
-		rc = -EBUSY;
-		goto failed;
-	}
-
-	rc = omapvout_dss_open(vout, &w, &h);
-	if (rc != 0)
-		goto failed;
-
-	DBG("Overlay Display %dx%d\n", w, h);
-
-	if (w == 0 || h == 0) {
-		DBG("Invalid display resolution\n");
-		rc = -EINVAL;
-		goto failed;
-	}
-
-	rc = omapvout_vbq_init(vout);
-	if (rc != 0)
-		goto failed;
-
-	vout->disp_width = w;
-	vout->disp_height = h;
-	vout->opened = 1;
-
-	memset(&vout->pix, 0, sizeof(vout->pix));
-	vout->pix.width = w;
-	vout->pix.height = h;
-	vout->pix.field = V4L2_FIELD_NONE;
-	vout->pix.pixelformat = V4L2_PIX_FMT_RGB565; /* Arbitrary */
-	vout->pix.colorspace = V4L2_COLORSPACE_SRGB; /* Arbitrary */
-	vout->pix.bytesperline = w * 2;
-	vout->pix.sizeimage = w * h * 2;
-
-	memset(&vout->win, 0, sizeof(vout->win));
-	vout->win.w.width = w;
-	vout->win.w.height = h;
-	vout->win.field = V4L2_FIELD_NONE;
-
-	memset(&vout->crop, 0, sizeof(vout->crop));
-	vout->crop.width = w;
-	vout->crop.height = h;
-
-	memset(&vout->fbuf, 0, sizeof(vout->fbuf));
-
-	vout->rotation = 0;
-	vout->bg_color = 0;
-
-	vout->mmap_cnt = 0;
-
-	mutex_unlock(&vout->mtx);
-
-	file->private_data = vout;
-
-	return 0;
-
-failed:
-	mutex_unlock(&vout->mtx);
-	return rc;
-}
-
-static int omapvout_release(struct file *file)
-{
-	struct omapvout_device *vout;
-
-	DBG("omapvout_release\n");
-
-	vout = video_drvdata(file);
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	if (vout->queue.streaming) {
-		omapvout_dss_disable(vout);
-		videobuf_streamoff(&vout->queue);
-	}
-
-	if (vout->mmap_cnt) {
-		vout->mmap_cnt = 0;
-		DBG("Releasing with non-zero mmap_cnt\n");
-	}
-
-	omapvout_dss_release(vout);
-
-	omapvout_vbq_destroy(vout);
-
-	vout->opened = 0;
-
-	mutex_unlock(&vout->mtx);
-
-	file->private_data = NULL;
-
-	return 0;
-}
-
-static int omapvout_mmap(struct file *file, struct vm_area_struct *vma)
-{
-	struct omapvout_device *vout;
-	int rc;
-
-	vout = video_drvdata(file);
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	rc = videobuf_mmap_mapper(&vout->queue, vma);
-	if (rc != 0)
-		goto failed;
-
-	vout->mmap_cnt++;
-
-	mutex_unlock(&vout->mtx);
-
-	return 0;
-
-failed:
-	mutex_unlock(&vout->mtx);
-	return rc;
-}
-
-static int omapvout_vidioc_querycap(struct file *file, void *priv,
-				struct v4l2_capability *cap)
-{
-	struct omapvout_device *vout = priv;
-
-	memset(cap, 0, sizeof(*cap));
-	strncpy(cap->driver, MODULE_NAME, sizeof(cap->driver));
-	strncpy(cap->card, vout->vdev.name, sizeof(cap->card));
-	cap->bus_info[0] = '\0';
-	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
-
-	return 0;
-}
-
-static int omapvout_vidioc_enum_output(struct file *file, void *priv,
-				struct v4l2_output *output)
-{
-	int index = output->index;
-
-	if (index > 0)
-		return -EINVAL;
-
-	memset(output, 0, sizeof(*output));
-	output->index = index;
-
-	strncpy(output->name, "video out", sizeof(output->name));
-	output->type = V4L2_OUTPUT_TYPE_MODULATOR;
-
-	return 0;
-}
-
-static int omapvout_vidioc_g_output(struct file *file, void *priv,
-				unsigned int *i)
-{
-	*i = 0;
-
-	return 0;
-}
-
-static int omapvout_vidioc_s_output(struct file *file, void *priv,
-				unsigned int i)
-{
-	if (i > 0)
-		return -EINVAL;
-
-	return 0;
-}
-
-static int omapvout_vidioc_enum_fmt_vid_overlay(struct file *file, void *priv,
-				struct v4l2_fmtdesc *f)
-{
-	int index = f->index;
-	enum v4l2_buf_type type = f->type;
-
-	if (index >= NUM_OUTPUT_FORMATS)
-		return -EINVAL;
-
-	memset(f, 0, sizeof(*f));
-	f->index = index;
-	f->type = type;
-	f->flags = omap2_formats[index].flags;
-	strncpy(f->description, omap2_formats[index].description,
-					sizeof(f->description));
-	f->pixelformat = omap2_formats[index].pixelformat;
-
-	return 0;
-}
-
-static int omapvout_vidioc_enum_fmt_vid_out(struct file *file, void *priv,
-				struct v4l2_fmtdesc *f)
-{
-	/* Same formats as the overlay */
-	return omapvout_vidioc_enum_fmt_vid_overlay(file, priv, f);
-}
-
-static int omapvout_vidioc_g_fmt_vid_overlay(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct omapvout_device *vout = priv;
-	struct v4l2_window *win = &f->fmt.win;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	/*
-	 * The API has a bit of a problem here. We're returning a v4l2_window
-	 * structure, but that structure contains pointers to variable-sized
-	 * objects for clipping rectangles and clipping bitmaps.  We will just
-	 * return NULLs for those pointers.
-	 */
-
-	mutex_lock(&vout->mtx);
-
-	memset(win, 0, sizeof(*win));
-	win->w = vout->win.w;
-	win->field = vout->win.field;
-	win->chromakey = vout->win.chromakey;
-	win->global_alpha = vout->win.global_alpha;
-
-	mutex_unlock(&vout->mtx);
-
-	return 0;
-}
-
-static int omapvout_vidioc_g_fmt_vid_out(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct omapvout_device *vout = priv;
-	struct v4l2_pix_format *pix = &f->fmt.pix;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	memset(pix, 0, sizeof(*pix));
-	*pix = vout->pix;
-
-	mutex_unlock(&vout->mtx);
-
-	return 0;
-}
-
-static int omapvout_vidioc_try_fmt_vid_overlay(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct omapvout_device *vout = priv;
-	struct v4l2_window *win = &f->fmt.win;
-	int rc;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	rc = omapvout_try_window(vout, win);
-
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_try_fmt_vid_out(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct omapvout_device *vout = priv;
-	struct v4l2_pix_format *pix = &f->fmt.pix;
-	int rc;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	rc = omapvout_try_pixel_format(vout, pix);
-
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_s_fmt_vid_overlay(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct omapvout_device *vout = priv;
-	struct v4l2_window *win = &f->fmt.win;
-	int rc = 0;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	if (vout->queue.streaming) {
-		rc = -EBUSY;
-		goto failed;
-	}
-
-	rc = omapvout_try_window(vout, win);
-	if (rc != 0)
-		goto failed;
-
-	vout->win.w = win->w;
-	vout->win.field = win->field;
-	vout->win.chromakey = win->chromakey;
-	vout->win.global_alpha = win->global_alpha;
-
-	/* Streaming has to be disabled, so config the hardware
-	 * later when streaming is enabled
-	 */
-
-failed:
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_s_fmt_vid_out(struct file *file, void *priv,
-				struct v4l2_format *f)
-{
-	struct omapvout_device *vout = priv;
-	struct v4l2_pix_format *pix = &f->fmt.pix;
-	int rc = 0;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	if (vout->queue.streaming) {
-		rc = -EBUSY;
-		goto failed;
-	}
-
-	rc = omapvout_try_pixel_format(vout, pix);
-	if (rc != 0)
-		goto failed;
-
-	memcpy(&vout->pix, pix, sizeof(*pix));
-
-	/* Default the cropping rectangle to the input frame size */
-	vout->crop.left = 0;
-	vout->crop.top = 0;
-	vout->crop.width = vout->pix.width;
-	vout->crop.height = vout->pix.height;
-
-	/* Streaming has to be disabled, so config the hardware
-	 * later when streaming is enabled
-	 */
-
-failed:
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_cropcap(struct file *file, void *priv,
-				struct v4l2_cropcap *ccap)
-{
-	struct omapvout_device *vout = priv;
-	enum v4l2_buf_type type = ccap->type;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-		return -EINVAL;
-
-	mutex_lock(&vout->mtx);
-
-	memset(ccap, 0, sizeof(*ccap));
-	ccap->type = type;
-	ccap->bounds.width = vout->pix.width & ~1;
-	ccap->bounds.height = vout->pix.height & ~1;
-	ccap->defrect.left = 0;
-	ccap->defrect.top = 0;
-	ccap->defrect.width = ccap->bounds.width;
-	ccap->defrect.left = ccap->bounds.height;
-	ccap->pixelaspect.numerator = 1;
-	ccap->pixelaspect.denominator = 1;
-
-	mutex_unlock(&vout->mtx);
-
-	return 0;
-}
-
-static int omapvout_vidioc_g_crop(struct file *file, void *priv,
-				struct v4l2_crop *crop)
-{
-	struct omapvout_device *vout = priv;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-		return -EINVAL;
-
-	mutex_lock(&vout->mtx);
-
-	crop->c = vout->crop;
-
-	mutex_unlock(&vout->mtx);
-
-	return 0;
-}
-
-static int omapvout_vidioc_s_crop(struct file *file, void *priv,
-				struct v4l2_crop *crop)
-{
-	struct omapvout_device *vout = priv;
-	struct v4l2_rect rect = crop->c;
-	int rc = 0;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
-		return -EINVAL;
-
-	mutex_lock(&vout->mtx);
-
-	if (vout->queue.streaming) {
-		rc = -EBUSY;
-		goto failed;
-	}
-
-	rc = omapvout_try_crop(vout, &rect);
-	if (rc != 0)
-		goto failed;
-
-	vout->crop = rect;
-
-	/* Streaming has to be disabled, so config the hardware
-	 * later when streaming is enabled
-	 */
-
-failed:
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_reqbufs(struct file *file, void *priv,
-				struct v4l2_requestbuffers *req)
-{
-	struct omapvout_device *vout = priv;
-	int rc = 0;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	/* A limitation of this implementation */
-	if (req->memory != V4L2_MEMORY_MMAP)
-		return -EINVAL;
-
-	if (req->count == 0) {
-		videobuf_queue_cancel(&vout->queue);
-		return 0;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	/* Don't allow new buffers when some are still mapped */
-	if (vout->mmap_cnt) {
-		DBG("Buffers are still mapped\n");
-		rc = -EBUSY;
-		goto failed;
-	}
-
-	INIT_LIST_HEAD(&vout->q_list);
-
-	videobuf_reqbufs(&vout->queue, req);
-
-	mutex_unlock(&vout->mtx);
-
-	return 0;
-
-failed:
-	mutex_unlock(&vout->mtx);
-	return rc;
-}
-
-static int omapvout_vidioc_querybuf(struct file *file, void *priv,
-				struct v4l2_buffer *b)
-{
-	struct omapvout_device *vout = priv;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	return videobuf_querybuf(&vout->queue, b);
-}
-
-static int omapvout_vidioc_qbuf(struct file *file, void *priv,
-				struct v4l2_buffer *b)
-{
-	struct omapvout_device *vout = priv;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	DBG("Q'ing Frame %d\n", b->index);
-
-	return videobuf_qbuf(&vout->queue, b);
-}
-
-static int omapvout_vidioc_dqbuf(struct file *file, void *priv,
-				struct v4l2_buffer *b)
-{
-	struct omapvout_device *vout = priv;
-	int block = 0;
-	int rc;
-
-	if (file->f_flags & O_NONBLOCK)
-		block = 1;
-
-	rc = videobuf_dqbuf(&vout->queue, b, block);
-
-	DBG("DQ'ing Frame %d\n", b->index);
-
-	return rc;
-}
-
-static int omapvout_vidioc_streamon(struct file *file, void *priv,
-				enum v4l2_buf_type type)
-{
-	struct omapvout_device *vout = priv;
-	int rc;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	/* Not sure how else to do this.  We can't truly validate the
-	 * configuration until all of the pieces have been provided, like
-	 * input, output, crop sizes and rotation.  This is the only point
-	 * where we can be sure the client has provided all the data, thus
-	 * the only place to make sure we don't cause a DSS failure.
-	 */
-	rc = omapvout_validate_cfg(vout);
-	if (rc) {
-		DBG("Configuration Validation Failed\n");
-		goto failed;
-	}
-
-	rc = omapvout_dss_enable(vout);
-	if (rc) {
-		DBG("DSS Enable Failed\n");
-		goto failed;
-	}
-
-	rc = videobuf_streamon(&vout->queue);
-	if (rc)
-		omapvout_dss_disable(vout);
-
-failed:
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_streamoff(struct file *file, void *priv,
-				enum v4l2_buf_type type)
-{
-	struct omapvout_device *vout = priv;
-	int rc = 0;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	omapvout_dss_disable(vout);
-
-	rc = videobuf_streamoff(&vout->queue);
-
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_queryctrl(struct file *file, void *priv,
-				struct v4l2_queryctrl *qctrl)
-{
-	switch (qctrl->id) {
-	case V4L2_CID_ROTATE:
-		v4l2_ctrl_query_fill(qctrl, 0, 270, 90, 0);
-		break;
-	case V4L2_CID_BG_COLOR:
-		v4l2_ctrl_query_fill(qctrl, 0, 0xFFFFFF, 1, 0);
-		break;
-	default:
-		qctrl->name[0] = '\0';
-		return -EINVAL;
-	}
-
-	return 0;
-}
-
-static int omapvout_vidioc_g_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct omapvout_device *vout = priv;
-	int rc = 0;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	switch (ctrl->id) {
-	case V4L2_CID_ROTATE:
-		ctrl->value = vout->rotation * 90;
-		break;
-	case V4L2_CID_BG_COLOR:
-		ctrl->value = vout->bg_color;
-		break;
-	default:
-		rc = -EINVAL;
-		break;
-	}
-
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct omapvout_device *vout = priv;
-	int v = ctrl->value;
-	int rc = 0;
-
-	if (vout == NULL) {
-		DBG("Invalid device\n");
-		return -ENODEV;
-	}
-
-	mutex_lock(&vout->mtx);
-
-	if (vout->queue.streaming) {
-		rc = -EBUSY;
-		goto failed;
-	}
-
-	switch (ctrl->id) {
-	case V4L2_CID_ROTATE:
-		if (!omapvout_dss_is_rotation_supported(vout) && v != 0) {
-			rc = -EINVAL;
-		} else if (v == 0 || v == 90 || v == 180 || v == 270) {
-			vout->rotation = v / 90;
-		} else {
-			DBG("Invalid rotation %d\n", v);
-			rc = -ERANGE;
-		}
-		break;
-	case V4L2_CID_BG_COLOR:
-		if (v < 0 || v > 0xFFFFFF) {
-			DBG("Invalid BG color 0x%08lx\n", (unsigned long) v);
-			rc = -ERANGE;
-		} else {
-			vout->bg_color = v;
-		}
-		break;
-	default:
-		rc = -EINVAL;
-		break;
-	}
-
-	/* Streaming has to be disabled, so config the hardware
-	 * later when streaming is enabled
-	 */
-
-failed:
-	mutex_unlock(&vout->mtx);
-
-	return rc;
-}
-
-static int omapvout_vidioc_g_fbuf(struct file *file, void *priv,
-				struct v4l2_framebuffer *a)
-{
-	struct omapvout_device *vout = priv;
-
-	mutex_lock(&vout->mtx);
-
-	if (vout->dss->overlay->id == OMAP_DSS_VIDEO1) {
-		a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
-				V4L2_FBUF_CAP_GLOBAL_ALPHA |
-				V4L2_FBUF_CAP_CHROMAKEY	|
-				V4L2_FBUF_CAP_SRC_CHROMAKEY;
-	} else {
-		a->capability = V4L2_FBUF_CAP_EXTERNOVERLAY |
-				V4L2_FBUF_CAP_LOCAL_ALPHA |
-				V4L2_FBUF_CAP_GLOBAL_ALPHA |
-				V4L2_FBUF_CAP_CHROMAKEY	|
-				V4L2_FBUF_CAP_SRC_CHROMAKEY;
-	}
-	a->flags = vout->fbuf.flags;
-	memset(&a->fmt, 0, sizeof(a->fmt));
-
-	mutex_unlock(&vout->mtx);
-
-	return 0;
-}
-
-static int omapvout_vidioc_s_fbuf(struct file *file, void *priv,
-				struct v4l2_framebuffer *a)
-{
-	struct omapvout_device *vout = priv;
-	int rc = 0;
-
-	/* OMAP DSS doesn't support SRC & DST colorkey together */
-	if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
-			(a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY))
-		return -EINVAL;
-
-	/* OMAP DSS doesn't support DST colorkey and alpha blending together */
-	if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY) &&
-			(a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
-		return -EINVAL;
-
-	mutex_lock(&vout->mtx);
-
-	/* OMAP DSS doesn't support local alpha for video 1 */
-	if ((vout->dss->overlay->id == OMAP_DSS_VIDEO1) &&
-			(a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)) {
-		rc = -EINVAL;
-		goto failed;
-	}
-
-	vout->fbuf.flags = a->flags;
-
-failed:
-	mutex_unlock(&vout->mtx);
-
-	return 0;
-}
-
-/*=== Driver Functions =================================================*/
-
-static struct v4l2_file_operations omapvout_fops = {
-	.owner = THIS_MODULE,
-	.open = omapvout_open,
-	.release = omapvout_release,
-	.mmap = omapvout_mmap,
-	.ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops omapvout_ioctl_ops = {
-	.vidioc_querycap = omapvout_vidioc_querycap,
-	.vidioc_enum_output = omapvout_vidioc_enum_output,
-	.vidioc_g_output = omapvout_vidioc_g_output,
-	.vidioc_s_output = omapvout_vidioc_s_output,
-	.vidioc_enum_fmt_vid_overlay = omapvout_vidioc_enum_fmt_vid_overlay,
-	.vidioc_enum_fmt_vid_out = omapvout_vidioc_enum_fmt_vid_out,
-	.vidioc_g_fmt_vid_overlay = omapvout_vidioc_g_fmt_vid_overlay,
-	.vidioc_g_fmt_vid_out = omapvout_vidioc_g_fmt_vid_out,
-	.vidioc_try_fmt_vid_overlay = omapvout_vidioc_try_fmt_vid_overlay,
-	.vidioc_try_fmt_vid_out = omapvout_vidioc_try_fmt_vid_out,
-	.vidioc_s_fmt_vid_overlay = omapvout_vidioc_s_fmt_vid_overlay,
-	.vidioc_s_fmt_vid_out = omapvout_vidioc_s_fmt_vid_out,
-	.vidioc_cropcap = omapvout_vidioc_cropcap,
-	.vidioc_g_crop = omapvout_vidioc_g_crop,
-	.vidioc_s_crop = omapvout_vidioc_s_crop,
-	.vidioc_reqbufs = omapvout_vidioc_reqbufs,
-	.vidioc_querybuf = omapvout_vidioc_querybuf,
-	.vidioc_qbuf = omapvout_vidioc_qbuf,
-	.vidioc_dqbuf = omapvout_vidioc_dqbuf,
-	.vidioc_streamon = omapvout_vidioc_streamon,
-	.vidioc_streamoff = omapvout_vidioc_streamoff,
-	.vidioc_queryctrl = omapvout_vidioc_queryctrl,
-	.vidioc_g_ctrl = omapvout_vidioc_g_ctrl,
-	.vidioc_s_ctrl = omapvout_vidioc_s_ctrl,
-	.vidioc_g_fbuf = omapvout_vidioc_g_fbuf,
-	.vidioc_s_fbuf = omapvout_vidioc_s_fbuf,
-};
-
-static struct video_device omapvout_devdata = {
-	.name = MODULE_NAME,
-	.fops = &omapvout_fops,
-	.ioctl_ops = &omapvout_ioctl_ops,
-	.vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY,
-	.release = video_device_release,
-	.minor = -1,
-};
-
-static int __init omapvout_probe_device(struct omap_vout_config *cfg,
-					struct omapvout_bp *bp,
-					enum omap_plane plane, int vid)
-{
-	struct omapvout_device *vout = NULL;
-	int rc = 0;
-
-	DBG("omapvout_probe_device %d %d\n", plane, vid);
-
-	vout = kzalloc(sizeof(struct omapvout_device), GFP_KERNEL);
-	if (vout == NULL) {
-		rc = -ENOMEM;
-		goto err0;
-	}
-
-	mutex_init(&vout->mtx);
-
-	vout->max_video_width = cfg->max_width;
-	vout->max_video_height = cfg->max_height;
-	vout->max_video_buffer_size = cfg->max_buffer_size;
-
-	rc = omapvout_dss_init(vout, plane);
-	if (rc != 0) {
-		printk(KERN_INFO "DSS init failed\n");
-		kfree(vout);
-		goto err0;
-	}
-
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
-	vout->bp = bp;
-	omapvout_bp_init(vout);
-#endif
-
-	/* register the V4L2 interface */
-	vout->vdev = omapvout_devdata;
-	video_set_drvdata(&vout->vdev, vout);
-	if (video_register_device(&vout->vdev, VFL_TYPE_GRABBER, vid) < 0) {
-		printk(KERN_ERR MODULE_NAME": could not register with V4L2\n");
-		rc = -EINVAL;
-		goto cleanup;
-	}
-
-	vout->id = plane;
-
-	return 0;
-
-cleanup:
-	omapvout_free_resources(vout);
-err0:
-	return rc;
-}
-
-/* Some reasonable defaults if the platform does not supply a config */
-static struct omap_vout_config default_cfg = {
-	.max_width = 864,
-	.max_height = 648,
-	.max_buffer_size = 0x112000, /* (w * h * 2) page aligned */
-	.num_buffers = 6,
-	.num_devices = 2,
-	.device_ids = {1, 2},
-};
-
-static int __init omapvout_probe(struct platform_device *pdev)
-{
-	struct omapvout_bp *bp = NULL;
-	struct omap_vout_config *cfg;
-	int i;
-	int rc = 0;
-	static const enum omap_plane planes[] = {
-		OMAP_DSS_VIDEO1,
-		OMAP_DSS_VIDEO2,
-	};
-
-	if (pdev->dev.platform_data) {
-		cfg = pdev->dev.platform_data;
-	} else {
-		DBG("omapvout_probe - using default configuration\n");
-		cfg = &default_cfg;
-	}
-
-	if (cfg->max_width > 2048) /* Hardware limitation */
-		cfg->max_width = 2048;
-	if (cfg->max_height > 2048) /* Hardware limitation */
-		cfg->max_height = 2048;
-	if (cfg->num_buffers > 16) /* Arbitrary limitation */
-		cfg->num_buffers = 16;
-	if (cfg->num_devices > 2) /* Hardware limitation */
-		cfg->num_devices = 2;
-	for (i = 0; i < cfg->num_devices; i++)
-		if (cfg->device_ids[i] > 64)
-			cfg->device_ids[i] = -1;
-
-#ifdef CONFIG_VIDEO_OMAP_VIDEOOUT_BUFPOOL
-	bp = omapvout_bp_create(cfg->num_buffers, cfg->max_buffer_size);
-#endif
-
-	for (i = 0; i < cfg->num_devices; i++) {
-		rc = omapvout_probe_device(cfg, bp, planes[i],
-						cfg->device_ids[i]);
-		if (rc) {
-			DBG("omapvout_probe %d failed\n", (i + 1));
-			return rc;
-		}
-	}
-
-	return 0;
-}
-
-static int omapvout_remove(struct platform_device *pdev)
-{
-	struct omapvout_device *vout = platform_get_drvdata(pdev);
-
-	DBG("omapvout_remove\n");
-
-	omapvout_dss_remove(vout);
-	omapvout_free_resources(vout);
-
-	return 0;
-}
-
-static struct platform_driver omapvout_driver = {
-	.remove         = omapvout_remove,
-	.driver         = {
-		.name   = MODULE_NAME,
-	},
-};
-
-static int __init omapvout_init(void)
-{
-	int rc;
-
-	DBG("omapvout_init\n");
-
-	rc = platform_driver_probe(&omapvout_driver, omapvout_probe);
-	if (rc != 0) {
-		printk(KERN_ERR "failed omapvout register/probe %d\n", rc);
-		return -ENODEV;
-	}
-
-	return 0;
-}
-
-static void __exit omapvout_exit(void)
-{
-	DBG("omapvout_exit\n");
-	platform_driver_unregister(&omapvout_driver);
-}
-
-module_init(omapvout_init);
-module_exit(omapvout_exit);
-
-MODULE_AUTHOR("Motorola");
-MODULE_DESCRIPTION("OMAP2/3 Video Out for V4L2");
-MODULE_LICENSE("GPL");
-
diff --git a/drivers/media/video/omap-vout/omapvout.h b/drivers/media/video/omap-vout/omapvout.h
deleted file mode 100644
index d8a376a..0000000
--- a/drivers/media/video/omap-vout/omapvout.h
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * drivers/media/video/omap/omapvout.h
- *
- * Copyright (C) 2009 Motorola Inc.
- *
- * Based on drivers/media/video/omap24xx/omap24xxvout.c&h
- *
- * Copyright (C) 2005-2006 Texas Instruments.
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- */
-
-#ifndef __OMAPVOUT_H__
-#define __OMAPVOUT_H__
-
-#include <linux/mutex.h>
-#include <linux/videodev2.h>
-#include <linux/wait.h>
-#include <mach/display.h>
-#include <mach/vrfb.h>
-#include <media/v4l2-dev.h>
-#include <media/videobuf-core.h>
-
-/*#define DEBUG*/
-#ifdef DEBUG
-#define DBG(format, ...) \
-	printk(KERN_DEBUG "OMAPVOUT: " format, ## __VA_ARGS__)
-#else
-#define DBG(format, ...)
-#endif
-
-/* The device structure */
-
-struct omapvout_device {
-	struct video_device vdev;
-	struct mutex  mtx; /* Lock for all device accesses */
-	struct video_device *vfd;
-
-	int opened;
-	int id;
-
-	int disp_width;
-	int disp_height;
-
-	int max_video_width;
-	int max_video_height;
-	int max_video_buffer_size;
-
-	/* Buffer pool */
-	struct omapvout_bp *bp;
-
-	/* DSS data */
-	struct omapvout_dss *dss;
-
-	/* V4L2 data */
-	int rotation;
-	int bg_color;
-	struct v4l2_pix_format pix;
-	struct v4l2_window win;
-	struct v4l2_rect crop;
-	struct v4l2_framebuffer fbuf;
-
-	/* Frame Q */
-	struct videobuf_queue queue;
-	struct omapvout_vbq *vbq;
-	struct list_head q_list;
-
-	/* Don't allow new buffers when some are still mapped */
-	int mmap_cnt;
-};
-
-#define vdev_to_omapvout(d) container_of(d, struct omapvout_device, vdev)
-
-#endif /* __OMAPVOUT_H__ */
diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig
new file mode 100644
index 0000000..7687ee9
--- /dev/null
+++ b/drivers/media/video/omap/Kconfig
@@ -0,0 +1,27 @@
+config VIDEO_OMAP_VIDEOLIB
+	tristate "OMAP Video out library"
+	depends on VIDEO_OMAP3_V4L2
+	default VIDEO_OMAP3_V4L2
+
+config VIDEO_OMAP_VIDEOOUT
+	tristate "OMAP Video out driver"
+	select VIDEOBUF_DMA_SG
+	select VIDEOBUF_GEN
+	depends on VIDEO_OMAP3_V4L2
+	default VIDEO_OMAP3_V4L2
+
+choice
+        prompt "TV Mode"
+        default NTSC_M
+
+config NTSC_M
+        bool "Use NTSC_M mode"
+        help
+          Select this option if you want NTSC_M mode on TV
+
+config PAL_BDGHI
+        bool "Use PAL_BDGHI mode"
+        help
+          Select this option if you want PAL_BDGHI mode on TV
+
+endchoice
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
new file mode 100644
index 0000000..75e01d3
--- /dev/null
+++ b/drivers/media/video/omap/Makefile
@@ -0,0 +1,3 @@
+obj-$(CONFIG_VIDEO_OMAP_VIDEOLIB) += omap_voutlib.o
+obj-$(CONFIG_VIDEO_OMAP_VIDEOOUT) += omap_vout.o
+
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
new file mode 100644
index 0000000..156a6e4
--- /dev/null
+++ b/drivers/media/video/omap/omap_vout.c
@@ -0,0 +1,2922 @@
+/*
+ * drivers/media/video/omap/omap_vout.c
+ *
+ * Copyright (C) 2005-2009 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Leveraged code from the OMAP2 camera driver
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * History:
+ * 20-APR-2006	Khasim		Modified VRFB based Rotation,
+ *				The image data is always read from 0 degree
+ *				view and written
+ *				to the virtual space of desired rotation angle
+ * 4-DEC-2006 Jian		Changed to support better memory management
+ *
+ * 17-Nov-2008 Hardik		Changed to used the new DSS paches by Tomi
+ *				Changed driver to use video_ioctl2
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/interrupt.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/videodev2.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <media/videobuf-dma-sg.h>
+#include <linux/input.h>
+#include <linux/dma-mapping.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-ioctl.h>
+#include <mach/display.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/semaphore.h>
+#include <linux/omap_resizer.h>
+#include <asm/processor.h>
+#include <asm/cacheflush.h>
+#include <mach/dma.h>
+#include <mach/vrfb.h>
+#include <media/v4l2-common.h>
+#include <mach/display.h>
+#include "omap_voutlib.h"
+#include "omap_voutdef.h"
+
+#define OMAP_VIDEO1 0
+#define OMAP_VIDEO2 1
+
+/* configuration macros */
+#define VOUT_NAME		"omap_vout"
+
+#define QQVGA_WIDTH		160
+#define QQVGA_HEIGHT		120
+
+#define NUM_OF_VIDEO_CHANNELS	2
+
+#define VID_MAX_WIDTH		1280	/* Largest width */
+#define VID_MAX_HEIGHT		864	/* Largest height */
+#define VID_720P_HEIGHT		720	/* 720p height */
+
+/* Mimimum requirement is 2x2 for DSS */
+#define VID_MIN_WIDTH		2
+#define VID_MIN_HEIGHT		2
+
+/* 2048 x 2048 is max res supported by OMAP display controller */
+#define DMA_CHAN_ALLOTED        1
+#define DMA_CHAN_NOT_ALLOTED    0
+#define MAX_PIXELS_PER_LINE     2048
+#define VRFB_TX_TIMEOUT         1000
+
+#define VDD1_OPP3_FREQ         500000000
+#define VDD1_OPP1_FREQ         125000000
+
+#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_720P_HEIGHT*2)
+
+/* IRQ Bits mask of DSS */
+#define OMAP_VOUT_IRQ_MASK (DISPC_IRQ_VSYNC | DISPC_IRQ_EVSYNC_EVEN | \
+			    DISPC_IRQ_EVSYNC_ODD | DISPC_IRQ_FRAMEDONE)
+
+int cacheable_buffers;
+int flushable_buffers;
+
+/* ISP resizer related code*/
+enum {
+	VIDEO_720_ENABLE = 1,
+	VIDEO_720_RESIZER_N_STREAMING,
+	VIDEO_720_DISABLE,
+};
+
+static int flg_720  = VIDEO_720_DISABLE;
+
+struct rsz_params isp_rsz_params;
+int rsz_configured;
+
+static u16 omap_vout_rsz_filter_4_tap_high_quality[] = {
+	0x0000, 0x0100, 0x0000, 0x0000,
+	0x03FA, 0x00F6, 0x0010, 0x0000,
+	0x03F9, 0x00DB, 0x002C, 0x0000,
+	0x03FB, 0x00B3, 0x0053, 0x03FF,
+	0x03FD, 0x0082, 0x0084, 0x03FD,
+	0x03FF, 0x0053, 0x00B3, 0x03FB,
+	0x0000, 0x002C, 0x00DB, 0x03F9,
+	0x0000, 0x0010, 0x00F6, 0x03FA
+};
+
+static u16 omap_vout_rsz_filter_7_tap_high_quality[] = {
+	0x0004, 0x0023, 0x005A, 0x0058,
+	0x0023, 0x0004, 0x0000, 0x0000,
+	0x0002, 0x0018, 0x004d, 0x0060,
+	0x0031, 0x0008, 0x0000, 0x0000,
+	0x0001, 0x000f, 0x003f, 0x0062,
+	0x003f, 0x000f, 0x0001, 0x0000,
+	0x0000, 0x0008, 0x0031, 0x0060,
+	0x004d, 0x0018, 0x0002, 0x0000
+};
+
+/* End ISP resizer*/
+
+static struct videobuf_queue_ops video_vbq_ops;
+
+static u32 video1_numbuffers = OMAP_VOUT_MAX_BUFFERS;
+static u32 video2_numbuffers = OMAP_VOUT_MAX_BUFFERS;
+static u32 video1_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
+static u32 video2_bufsize = OMAP_VOUT_MAX_BUF_SIZE;
+static u32 vid1_static_vrfb_alloc;
+static u32 vid2_static_vrfb_alloc;
+static int debug;
+struct vout_platform_data *pdata;
+
+/* Module parameters */
+module_param(video1_numbuffers, uint, S_IRUGO);
+MODULE_PARM_DESC(video1_numbuffers, "Number of buffers to be allocated at \
+		init time for Video1 device.");
+
+module_param(video2_numbuffers, uint, S_IRUGO);
+MODULE_PARM_DESC(video2_numbuffers, "Number of buffers to be allocated at \
+		init time for Video2 device.");
+
+module_param(video1_bufsize, uint, S_IRUGO);
+MODULE_PARM_DESC(video1_bufsize, "Size of the buffer to be allocated for \
+		video1 device");
+
+module_param(video2_bufsize, uint, S_IRUGO);
+MODULE_PARM_DESC(video2_bufsize, "Size of the buffer to be allocated for \
+		video2 device");
+
+module_param(vid1_static_vrfb_alloc, bool, S_IRUGO);
+MODULE_PARM_DESC(vid1_static_vrfb_alloc, "Static allocation of the VRFB \
+		buffer for video1 device");
+
+module_param(vid2_static_vrfb_alloc, bool, S_IRUGO);
+MODULE_PARM_DESC(vid2_static_vrfb_alloc, "Static allocation of the VRFB \
+		buffer for video2 device");
+
+module_param(debug, bool, S_IRUGO);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/* Local Helper functions */
+static int omap_vout_create_video_devices(struct platform_device *pdev);
+static int omapvid_apply_changes(struct omap_vout_device *vout);
+static int omapvid_init(struct omap_vout_device *vout, u32 addr);
+static int omapvid_setup_overlay(struct omap_vout_device *vout,
+		struct omap_overlay *ovl, int posx, int posy,
+		int outw, int outh, u32 addr);
+static enum omap_color_mode video_mode_to_dss_mode(struct omap_vout_device
+		*vout);
+static void omap_vout_isr(void *arg, unsigned int irqstatus);
+static void omap_vout_cleanup_device(struct omap_vout_device *vout);
+
+/*
+ * Maximum amount of memory to use for rendering buffers.
+ * Default is enough to four (RGB24) DVI 720P buffers.
+ */
+#define MAX_ALLOWED_VIDBUFFERS            6
+
+/* list of image formats supported by OMAP2 video pipelines */
+const static struct v4l2_fmtdesc omap_formats[] = {
+	{
+	 /* Note:  V4L2 defines RGB565 as:
+	  *
+	  *      Byte 0                    Byte 1
+	  *      g2 g1 g0 r4 r3 r2 r1 r0   b4 b3 b2 b1 b0 g5 g4 g3
+	  *
+	  * We interpret RGB565 as:
+	  *
+	  *      Byte 0                    Byte 1
+	  *      g2 g1 g0 b4 b3 b2 b1 b0   r4 r3 r2 r1 r0 g5 g4 g3
+	  */
+	 .description = "RGB565, le",
+	 .pixelformat = V4L2_PIX_FMT_RGB565,
+	 },
+	{
+	 /* Note:  V4L2 defines RGB32 as: RGB-8-8-8-8  we use
+	  *  this for RGB24 unpack mode, the last 8 bits are ignored
+	  * */
+	 .description = "RGB32, le",
+	 .pixelformat = V4L2_PIX_FMT_RGB32,
+	 },
+	{
+	 /* Note:  V4L2 defines RGB24 as: RGB-8-8-8  we use
+	  *        this for RGB24 packed mode
+	  *
+	  */
+	 .description = "RGB24, le",
+	 .pixelformat = V4L2_PIX_FMT_RGB24,
+	 },
+	{
+	 .description = "YUYV (YUV 4:2:2), packed",
+	 .pixelformat = V4L2_PIX_FMT_YUYV,
+	 },
+	{
+	 .description = "UYVY, packed",
+	 .pixelformat = V4L2_PIX_FMT_UYVY,
+	 },
+};
+
+#define NUM_OUTPUT_FORMATS (sizeof(omap_formats)/sizeof(omap_formats[0]))
+
+/* Allocate buffers */
+static unsigned long omap_vout_alloc_buffer(u32 buf_size, u32 *phys_addr)
+{
+	unsigned long virt_addr, addr;
+	u32 size;
+
+	size = PAGE_ALIGN(buf_size);
+	virt_addr = (u32) alloc_pages_exact(size, GFP_KERNEL | GFP_DMA);
+	addr = virt_addr;
+	if (virt_addr) {
+		while (size > 0) {
+			SetPageReserved(virt_to_page(addr));
+			addr += PAGE_SIZE;
+			size -= PAGE_SIZE;
+		}
+	}
+	*phys_addr = (u32) virt_to_phys((void *) virt_addr);
+	return virt_addr;
+}
+
+/* Free buffers */
+static void omap_vout_free_buffer(unsigned long virtaddr, u32 phys_addr,
+			 u32 buf_size)
+{
+	unsigned long addr = virtaddr;
+	u32 size;
+
+	size = PAGE_ALIGN(buf_size);
+	while (size > 0) {
+		ClearPageReserved(virt_to_page(addr));
+		addr += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	free_pages_exact((void *) virtaddr, size);
+}
+
+/* Function for allocating video buffers */
+static int omap_vout_allocate_vrfb_buffers(struct omap_vout_device *vout,
+		int count)
+{
+	int i, j;
+
+	for (i = 0; i < count; i++) {
+		if (!vout->smsshado_virt_addr[i]) {
+			vout->smsshado_virt_addr[i] =
+				omap_vout_alloc_buffer(vout->smsshado_size,
+						&vout->smsshado_phy_addr[i]);
+		}
+		if (!vout->smsshado_virt_addr[i]) {
+			for (j = 0; j < i; j++) {
+				omap_vout_free_buffer(
+						vout->smsshado_virt_addr[j],
+						vout->smsshado_phy_addr[j],
+						vout->smsshado_size);
+				vout->smsshado_virt_addr[j] = 0;
+				vout->smsshado_phy_addr[j] = 0;
+			}
+			count = 0;
+			return -ENOMEM;
+		}
+		memset((void *) vout->smsshado_virt_addr[i], 0,
+				vout->smsshado_size);
+	}
+	return 0;
+}
+
+/* Try format */
+static int omap_vout_try_format(struct v4l2_pix_format *pix,
+				struct v4l2_pix_format *def_pix)
+{
+	int ifmt, bpp = 0;
+
+	if (pix->width > VID_MAX_WIDTH)
+		pix->width = VID_MAX_WIDTH;
+	if (pix->height > VID_MAX_HEIGHT)
+		pix->height = VID_MAX_HEIGHT;
+
+	if (pix->width <= VID_MIN_WIDTH)
+		pix->width = def_pix->width;
+	if (pix->height <= VID_MIN_HEIGHT)
+		pix->height = def_pix->height;
+
+	for (ifmt = 0; ifmt < NUM_OUTPUT_FORMATS; ifmt++) {
+		if (pix->pixelformat == omap_formats[ifmt].pixelformat)
+			break;
+	}
+
+	if (ifmt == NUM_OUTPUT_FORMATS)
+		ifmt = 0;
+
+	pix->pixelformat = omap_formats[ifmt].pixelformat;
+	pix->field = V4L2_FIELD_ANY;
+	pix->priv = 0;
+
+	switch (pix->pixelformat) {
+	case V4L2_PIX_FMT_YUYV:
+	case V4L2_PIX_FMT_UYVY:
+	default:
+		pix->colorspace = V4L2_COLORSPACE_JPEG;
+		bpp = YUYV_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB565:
+	case V4L2_PIX_FMT_RGB565X:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB565_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB24:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB24_BPP;
+		break;
+	case V4L2_PIX_FMT_RGB32:
+	case V4L2_PIX_FMT_BGR32:
+		pix->colorspace = V4L2_COLORSPACE_SRGB;
+		bpp = RGB32_BPP;
+		break;
+	}
+	pix->bytesperline = pix->width * bpp;
+	pix->sizeimage = pix->bytesperline * pix->height;
+	return bpp;
+}
+
+/*
+ * omap_vout_uservirt_to_phys: This inline function is used to convert user
+ * space virtual address to physical address.
+ */
+static inline u32 omap_vout_uservirt_to_phys(u32 virtp)
+{
+	unsigned long physp = 0;
+	struct mm_struct *mm = current->mm;
+	struct vm_area_struct *vma;
+
+	vma = find_vma(mm, virtp);
+	/* For kernel direct-mapped memory, take the easy way */
+	if (virtp >= PAGE_OFFSET) {
+		physp = virt_to_phys((void *) virtp);
+	} else if ((vma) && (vma->vm_flags & VM_IO)
+			&& (vma->vm_pgoff)) {
+		/* this will catch, kernel-allocated,
+		   mmaped-to-usermode addresses */
+		physp = (vma->vm_pgoff << PAGE_SHIFT) + (virtp - vma->vm_start);
+	} else {
+		/* otherwise, use get_user_pages() for general userland pages */
+		int res, nr_pages = 1;
+		struct page *pages;
+		down_read(&current->mm->mmap_sem);
+
+		res = get_user_pages(current, current->mm, virtp, nr_pages,
+				1, 0, &pages, NULL);
+		up_read(&current->mm->mmap_sem);
+
+		if (res == nr_pages) {
+			physp =  __pa(page_address(&pages[0]) +
+					(virtp & ~PAGE_MASK));
+		} else {
+			printk(KERN_WARNING VOUT_NAME
+				"omap_vout_uservirt_to_phys:\
+					get_user_pages failed\n");
+			return 0;
+		}
+	}
+
+	return physp;
+}
+
+/* This function wakes up the application once
+ * the DMA transfer to VRFB space is completed by the
+ * ISP resizer block
+ */
+void omap_vout_isp_rsz_dma_tx_callback(void *arg)
+{
+	struct omap_vout_device *vout;
+	vout = (struct omap_vout_device *) arg;
+
+	vout->vrfb_dma_tx.tx_status = 1;
+	wake_up_interruptible(&vout->vrfb_dma_tx.wait);
+}
+
+/* This functions wakes up the application once
+ * the DMA transfer to VRFB space is completed. */
+static void omap_vout_vrfb_dma_tx_callback(int lch, u16 ch_status, void *data)
+{
+	struct vid_vrfb_dma *t = (struct vid_vrfb_dma *) data;
+
+	t->tx_status = 1;
+	wake_up_interruptible(&t->wait);
+}
+
+/* Release the VRFB context once the module exits */
+static void omap_vout_release_vrfb(struct omap_vout_device *vout)
+{
+	int i;
+
+	for (i = 0; i < OMAP_VOUT_MAX_VBUF_CTXT; i++)
+		omap_vrfb_release_ctx(&vout->vrfb_context[i]);
+
+	if (vout->vrfb_dma_tx.req_status == DMA_CHAN_ALLOTED) {
+		vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+		omap_free_dma(vout->vrfb_dma_tx.dma_ch);
+	}
+
+}
+
+/* Return true if rotation is 90 or 270 */
+static inline int rotate_90_or_270(int rotation)
+{
+	return rotation == 1 || rotation == 3;
+}
+
+/* Return true if rotation is enabled */
+static inline int rotation_enabled(int rotation)
+{
+	return rotation != -1;
+}
+
+/* Reverse the rotation degree if mirroring is enabled */
+static inline int rotation_with_mirror(int rotation)
+{
+	return (rotation == 1) ? 3 :
+		(rotation == 3) ? 1 :
+		(rotation == 2) ? 0 : 2;
+}
+
+/* Free the V4L2 buffers */
+static void omap_vout_free_buffers(struct omap_vout_device *vout)
+{
+	int i, numbuffers;
+
+	/* Allocate memory for the buffes */
+	numbuffers = (vout->vid) ?  video2_numbuffers : video1_numbuffers;
+	vout->buffer_size = (vout->vid) ? video2_bufsize : video1_bufsize;
+
+	for (i = 0; i < numbuffers; i++) {
+		omap_vout_free_buffer(vout->buf_virt_addr[i],
+			 vout->buf_phy_addr[i], vout->buffer_size);
+		vout->buf_phy_addr[i] = 0;
+		vout->buf_virt_addr[i] = 0;
+	}
+}
+
+/* Free VRFB buffers */
+static void omap_vout_free_vrfb_buffers(struct omap_vout_device *vout)
+{
+	int j;
+
+	for (j = 0; j < OMAP_VOUT_MAX_BUFFERS; j++) {
+		omap_vout_free_buffer(vout->smsshado_virt_addr[j],
+				vout->smsshado_phy_addr[j],
+				vout->smsshado_size);
+		vout->smsshado_virt_addr[j] = 0;
+		vout->smsshado_phy_addr[j] = 0;
+	}
+}
+
+/* Allocate the buffers for the VRFB space.  Data is copied from V4L2
+ * buffers to the VRFB buffers using the DMA engine.*/
+static int omap_vout_vrfb_buffer_setup(struct omap_vout_device *vout,
+			  unsigned int *count, unsigned int startindex)
+{
+	int i, j;
+	int buffer_set;
+	u32 width, height;
+
+	/* Allocate the VRFB buffers only if the buffers are not
+	 * allocated during init time.
+	 */
+	if ((rotation_enabled(vout->rotation)) &&
+			!vout->vrfb_static_allocation) {
+		for (i = 0; i < *count; i++) {
+			buffer_set = vout->smsshado_virt_addr[i];
+			if (!buffer_set) {
+				vout->smsshado_virt_addr[i] =
+					omap_vout_alloc_buffer(
+						vout->smsshado_size,
+						&vout->smsshado_phy_addr[i]);
+			}
+			if (!vout->smsshado_virt_addr[i]) {
+				if (V4L2_MEMORY_MMAP == vout->memory
+						&& i >= startindex)
+					break;
+				for (j = 0; j < i; j++) {
+					omap_vout_free_buffer(
+						vout->smsshado_virt_addr[j],
+						vout->smsshado_phy_addr[j],
+						vout->smsshado_size);
+					vout->smsshado_virt_addr[j] = 0;
+					vout->smsshado_phy_addr[j] = 0;
+				}
+				*count = 0;
+				return -ENOMEM;
+			}
+			if (!buffer_set) {
+				memset((void *) vout->smsshado_virt_addr[i], 0,
+					vout->smsshado_size);
+			}
+		}
+	}
+	for (i = 0; i < *count; i++) {
+		if (flg_720 == VIDEO_720_ENABLE) {
+			width = vout->win.w.width;
+			height = vout->win.w.height;
+		} else {
+			width = vout->pix.width;
+			height = vout->pix.height;
+		}
+			omap_vrfb_setup(&vout->vrfb_context[i],
+				vout->smsshado_phy_addr[i],
+				width, height,
+				vout->dss_mode,
+				vout->rotation);
+	}
+	return 0;
+}
+
+/* Convert V4L2 rotation to DSS rotation
+ * V4L2 understand 0, 90, 180, 270.
+ * convert to 0, 1, 2 and 3 repsectively for DSS */
+static int v4l2_rot_to_dss_rot(int v4l2_rotation, int *dss_rotation,
+		int mirror)
+{
+	switch (v4l2_rotation) {
+	case 90:
+		*dss_rotation = 3;
+		return 0;
+	case 180:
+		*dss_rotation = 2;
+		return 0;
+	case 270:
+		*dss_rotation = 1;
+		return 0;
+	case 0:
+		*dss_rotation = 0;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+
+}
+
+/* Calculate the buffer offsets from which the streaming should
+ * start.  This offset calculation is mainly required because of
+ * the VRFB 32 pixels alignment with rotation
+ */
+static int omap_vout_calculate_offset(struct omap_vout_device *vout)
+{
+	struct v4l2_pix_format *pix = &(vout->pix);
+	struct v4l2_rect *crop = &(vout->crop);
+	struct v4l2_window *win = &(vout->win);
+	int rotation;
+	int mirroring = vout->mirror;
+	int vr_ps = 1, ps = 2, temp_ps = 2;
+	int offset = 0, ctop = 0, cleft = 0, line_length = 0;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_dss_device *cur_display;
+	int *cropped_offset = &(vout->cropped_offset);
+
+	if (flg_720 == VIDEO_720_ENABLE) {
+		pix->height = win->w.height;
+		pix->width = win->w.width;
+		crop->height = win->w.height;
+		crop->width = win->w.width;
+	}
+
+	ovid = &(vout->vid_info);
+	ovl = ovid->overlays[0];
+	/* get the display device attached to the overlay */
+	if (!ovl->manager || !ovl->manager->device)
+		return -1;
+	cur_display = ovl->manager->device;
+
+	if ((cur_display->type == OMAP_DISPLAY_TYPE_VENC) &&
+	    ((win->w.width == crop->width)
+	     && (win->w.height == crop->height)))
+		vout->flicker_filter = 1;
+	else
+		vout->flicker_filter = 0;
+
+	if (1 == vout->mirror)
+		rotation = rotation_with_mirror(vout->rotation);
+	else
+		rotation = vout->rotation;
+
+	if (V4L2_PIX_FMT_YUYV == pix->pixelformat ||
+	    V4L2_PIX_FMT_UYVY == pix->pixelformat) {
+		if (rotation_enabled(vout->rotation)) {
+			/*
+			 * ps    - Actual pixel size for YUYV/UYVY for
+			 *              VRFB/Mirroring is 4 bytes
+			 * vr_ps - Virtually pixel size for YUYV/UYVY is
+			 *              2 bytes
+			 */
+			ps = 4;
+			vr_ps = 2;
+		} else {
+			ps = 2;	/* otherwise the pixel size is 2 byte */
+		}
+	} else if (V4L2_PIX_FMT_RGB32 == pix->pixelformat) {
+		ps = 4;
+	} else if (V4L2_PIX_FMT_RGB24 == pix->pixelformat) {
+		ps = 3;
+	}
+	vout->ps = ps;
+	vout->vr_ps = vr_ps;
+	if (rotation_enabled(vout->rotation)) {
+		line_length = MAX_PIXELS_PER_LINE;
+		ctop = (pix->height - crop->height) - crop->top;
+		cleft = (pix->width - crop->width) - crop->left;
+	} else {
+		line_length = pix->width;
+	}
+	vout->line_length = line_length;
+	switch (rotation) {
+	case 1:
+		offset = MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
+			vout->vrfb_context[0].bytespp;
+		temp_ps = ps / vr_ps;
+		if (mirroring == 0) {
+			*cropped_offset = offset + line_length *
+				temp_ps * cleft + crop->top * temp_ps;
+		} else {
+			*cropped_offset = offset + line_length * temp_ps *
+				cleft + crop->top * temp_ps + (line_length *
+				((crop->width / (vr_ps)) - 1) * ps);
+		}
+		break;
+	case 2:
+		offset = ((MAX_PIXELS_PER_LINE * vout->vrfb_context[0].yoffset *
+			vout->vrfb_context[0].bytespp) +
+			(vout->vrfb_context[0].xoffset *
+			vout->vrfb_context[0].bytespp));
+		if (mirroring == 0) {
+			*cropped_offset = offset + (line_length * ps * ctop) +
+				(cleft / vr_ps) * ps;
+
+		} else {
+			*cropped_offset = offset + (line_length * ps * ctop) +
+				(cleft / vr_ps) * ps + (line_length *
+				(crop->height - 1) * ps);
+		}
+		break;
+	case 3:
+		offset = vout->vrfb_context[0].xoffset *
+			vout->vrfb_context[0].bytespp;
+		temp_ps = ps / vr_ps;
+		if (mirroring == 0) {
+			*cropped_offset = offset + line_length *
+			    temp_ps * crop->left + ctop * ps;
+		} else {
+			*cropped_offset = offset + line_length *
+				temp_ps * crop->left + ctop * ps +
+				(line_length * ((crop->width / vr_ps) - 1) *
+				 ps);
+		}
+		break;
+	case 0:
+		if (mirroring == 0) {
+			*cropped_offset = (line_length * ps) *
+				crop->top + (crop->left / vr_ps) * ps;
+		} else {
+			*cropped_offset = (line_length * ps) *
+				crop->top + (crop->left / vr_ps) * ps +
+				(line_length * (crop->height - 1) * ps);
+		}
+		break;
+	default:
+		if (mirroring == 0) {
+			*cropped_offset =
+			    line_length * ps * crop->top + crop->left * ps;
+		} else {
+			*cropped_offset = (line_length * ps * crop->top) /
+				vr_ps + (crop->left * ps) / vr_ps +
+				((crop->width / vr_ps) - 1) * ps;
+		}
+		break;
+	}
+	v4l2_dbg(1, debug, vout->dev->driver,
+	"%s Offset:%x\n", __func__, *cropped_offset);
+	return 0;
+}
+
+/* Initialize the overlay structure */
+int omapvid_init(struct omap_vout_device *vout, u32 addr)
+{
+	int r = 0;
+	struct omapvideo_info *ovid = &(vout->vid_info);
+	struct omap_overlay *ovl;
+	int posx, posy;
+	int outw, outh, temp, rotation;
+	int i;
+	struct v4l2_window *win;
+	struct omap_video_timings *timing;
+
+	win = &vout->win;
+	rotation = vout->rotation;
+	for (i = 0; i < ovid->num_overlays; i++) {
+		ovl = ovid->overlays[i];
+		if (!ovl->manager || !ovl->manager->device)
+			return -EINVAL;
+
+		timing = &ovl->manager->device->panel.timings;
+
+		outw = win->w.width;
+		outh = win->w.height;
+		switch (rotation) {
+
+		case 1:
+			/* Invert the height and widht for 90
+			 * and 270 degree rotation
+			 */
+			temp = outw;
+			outw = outh;
+			outh = temp;
+			posy = (timing->y_res - win->w.width)-
+				win->w.left;
+			posx = win->w.top;
+			break;
+
+		case 2:
+			posx = (timing->x_res - win->w.width) -
+				win->w.left;
+			posy = (timing->y_res - win->w.height) -
+				win->w.top;
+			break;
+
+		case 3:
+			temp = outw;
+			outw = outh;
+			outh = temp;
+			posy = win->w.left;
+			posx = (timing->x_res - win->w.height)
+				- win->w.top;
+			break;
+
+		default:
+			posx = win->w.left;
+			posy = win->w.top;
+			break;
+		}
+
+		r = omapvid_setup_overlay(vout, ovl, posx, posy, outw,
+				outh, addr);
+		if (r)
+			goto err;
+	}
+	return 0;
+err:
+	printk(KERN_WARNING VOUT_NAME "apply_changes failed\n");
+	return r;
+}
+
+/*  Apply the changes set the go bit of DSS */
+int omapvid_apply_changes(struct omap_vout_device *vout)
+{
+	struct omapvideo_info *ovid = &(vout->vid_info);
+	struct omap_overlay *ovl;
+	struct omap_dss_device *device;
+	int i;
+
+	for (i = 0; i < ovid->num_overlays; i++) {
+		ovl = ovid->overlays[i];
+		if (!ovl->manager || !ovl->manager->device)
+			return -EINVAL;
+		ovl->manager->apply(ovl->manager);
+		if (ovl->manager->device->update) {
+			device = ovl->manager->device;
+			device->update(device, 0, 0,
+				       device->panel.timings.x_res,
+				       device->panel.timings.y_res);
+		}
+	}
+	return 0;
+
+}
+
+/* Setup the overlay */
+int omapvid_setup_overlay(struct omap_vout_device *vout,
+		struct omap_overlay *ovl, int posx, int posy, int outw,
+		int outh, u32 addr)
+{
+	int r = 0;
+	enum omap_color_mode mode = 0;
+	int rotation, mirror;
+	int cropheight, cropwidth, pixheight, pixwidth;
+	u32 new_crop_width, new_crop_height, new_pix_width, new_pix_height;
+	struct omap_overlay_info info;
+
+	if ((ovl->caps & OMAP_DSS_OVL_CAP_SCALE) == 0 &&
+			(outw != vout->pix.width || outh != vout->pix.height)) {
+		r = -EINVAL;
+		goto err;
+	}
+
+	vout->dss_mode = video_mode_to_dss_mode(vout);
+
+	if (mode == -EINVAL) {
+		r = -EINVAL;
+		goto err;
+	}
+
+	rotation = vout->rotation;
+	mirror = vout->mirror;
+
+	/* For 720p set the width and height for ISP resizer downscaling*/
+	if (flg_720 == VIDEO_720_ENABLE) {
+		new_crop_width = vout->win.w.width;
+		new_crop_height = vout->win.w.height;
+		new_pix_width = vout->win.w.width;
+		new_pix_height = vout->win.w.height;
+
+	} else {
+		new_crop_width = vout->crop.width;
+		new_crop_height = vout->crop.height;
+		new_pix_width = vout->pix.width;
+		new_pix_height = vout->pix.height;
+	}
+
+	/* Setup the input plane parameters according to
+	 * rotation value selected.
+	 */
+	if (rotate_90_or_270(vout->rotation)) {
+		cropheight = new_crop_width;
+		cropwidth = new_crop_height;
+		pixheight = new_pix_width;
+		pixwidth = new_pix_height;
+	} else {
+		cropheight = new_crop_height;
+		cropwidth = new_crop_width;
+		pixheight = new_pix_height;
+		pixwidth = new_pix_width;
+	}
+
+	ovl->get_overlay_info(ovl, &info);
+	info.paddr = addr;
+	info.vaddr = NULL;
+	info.width = cropwidth;
+	info.height = cropheight;
+	info.color_mode = vout->dss_mode;
+	info.mirror = mirror;
+	info.pos_x = posx;
+	info.pos_y = posy;
+	info.out_width = outw;
+	info.out_height = outh;
+	if (!rotation_enabled(vout->rotation)) {
+		info.rotation = 0;
+		info.rotation_type = OMAP_DSS_ROT_DMA;
+		info.screen_width = pixwidth;
+	} else {
+		info.rotation = vout->rotation;
+		info.rotation_type = OMAP_DSS_ROT_VRFB;
+		info.screen_width = 2048;
+	}
+
+	v4l2_dbg(1, debug, vout->dev->driver,
+	"%s info.enable=%d info.addr=%x info.width=%d\n info.height=%d \
+	info.color_mode=%d info.rotation=%d info.mirror=%d\n \
+	info.posx=%d info.posy=%d info.out_width = %d info.out_height=%d\n \
+	info.rotation_type=%d info.screen_width=%d\n", __func__, info.enabled,
+	info.paddr, info.width, info.height, info.color_mode, info.rotation,
+	info.mirror, info.pos_x, info.pos_y, info.out_width, info.out_height,
+	info.rotation_type, info.screen_width);
+
+	r = ovl->set_overlay_info(ovl, &info);
+	if (r)
+		goto err;
+
+	return 0;
+err:
+	printk(KERN_WARNING VOUT_NAME "setup_overlay failed\n");
+	return r;
+}
+
+/* convert V4L2 pixel format to DSS pixel format */
+static enum omap_color_mode video_mode_to_dss_mode(struct omap_vout_device
+			*vout)
+{
+	struct v4l2_pix_format *pix = &vout->pix;
+
+	switch (pix->pixelformat) {
+	case 0:
+		break;
+	case V4L2_PIX_FMT_YUYV:
+		return OMAP_DSS_COLOR_YUV2;
+
+	case V4L2_PIX_FMT_UYVY:
+		return OMAP_DSS_COLOR_UYVY;
+
+	case V4L2_PIX_FMT_RGB565:
+		return OMAP_DSS_COLOR_RGB16;
+
+	case V4L2_PIX_FMT_RGB24:
+		return OMAP_DSS_COLOR_RGB24P;
+
+	case V4L2_PIX_FMT_RGB32:
+		return (vout->vid == OMAP_VIDEO1) ?
+			OMAP_DSS_COLOR_RGB24U : OMAP_DSS_COLOR_ARGB32;
+	case V4L2_PIX_FMT_BGR32:
+		return OMAP_DSS_COLOR_RGBX32;
+
+	default:
+		return -EINVAL;
+	}
+	return -EINVAL;
+}
+
+/* Video buffer call backs */
+
+/* Buffer setup function is called by videobuf layer when REQBUF ioctl is
+ * called. This is used to setup buffers and return size and count of
+ * buffers allocated. After the call to this buffer, videobuf layer will
+ * setup buffer queue depending on the size and count of buffers
+ */
+static int omap_vout_buffer_setup(struct videobuf_queue *q, unsigned int *count,
+			  unsigned int *size)
+{
+	struct omap_vout_device *vout = q->priv_data;
+	int startindex = 0, i, j;
+	u32 phy_addr = 0, virt_addr = 0;
+
+	if (!vout)
+		return -EINVAL;
+
+	if (V4L2_BUF_TYPE_VIDEO_OUTPUT != q->type)
+		return -EINVAL;
+
+	startindex = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+
+	if ((rotation_enabled(vout->rotation)) &&
+				*count > OMAP_VOUT_MAX_BUFFERS)
+		*count = OMAP_VOUT_MAX_BUFFERS;
+
+	/* If rotation is enabled, allocate memory for VRFB space also */
+	if (rotation_enabled(vout->rotation)) {
+		if (omap_vout_vrfb_buffer_setup(vout, count, startindex))
+			return -ENOMEM;
+	}
+
+	if (V4L2_MEMORY_MMAP != vout->memory)
+		return 0;
+
+	/* Now allocated the V4L2 buffers */
+	*size = vout->pix.width * vout->pix.height * vout->bpp;
+	*size = PAGE_ALIGN(*size);
+	startindex = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+	for (i = startindex; i < *count; i++) {
+		vout->buffer_size = *size;
+
+		virt_addr = omap_vout_alloc_buffer(vout->buffer_size,
+				&phy_addr);
+		if (!virt_addr) {
+			if (!rotation_enabled(vout->rotation))
+				break;
+			/* Free the VRFB buffers if no space for V4L2 buffers */
+			for (j = i; j < *count; j++) {
+				omap_vout_free_buffer(
+					vout->smsshado_virt_addr[j],
+					vout->smsshado_phy_addr[j],
+					vout->smsshado_size);
+				vout->smsshado_virt_addr[j] = 0;
+				vout->smsshado_phy_addr[j] = 0;
+			}
+		}
+		vout->buf_virt_addr[i] = virt_addr;
+		vout->buf_phy_addr[i] = phy_addr;
+	}
+	if (startindex < *count)
+		*count = vout->buffer_allocated = i;
+	else
+		*count = vout->buffer_allocated = *count;
+
+	return 0;
+}
+
+/* Free the V4L2 buffers additionally allocated than default
+ * number of buffers and free all the VRFB buffers */
+static void omap_vout_free_allbuffers(struct omap_vout_device *vout)
+{
+	int num_buffers = 0, i;
+
+	num_buffers = (vout->vid == OMAP_VIDEO1) ?
+		video1_numbuffers : video2_numbuffers;
+	for (i = num_buffers; i < vout->buffer_allocated; i++) {
+		if (vout->buf_virt_addr[i]) {
+			omap_vout_free_buffer(vout->buf_virt_addr[i],
+				vout->buf_phy_addr[i], vout->buffer_size);
+		}
+		vout->buf_virt_addr[i] = 0;
+		vout->buf_phy_addr[i] = 0;
+	}
+	/* Free the VRFB buffers only if they are allocated
+	 * during reqbufs.  Don't free if init time allocated
+	 */
+	if (!vout->vrfb_static_allocation) {
+		for (i = 0; i < OMAP_VOUT_MAX_BUFFERS; i++) {
+			if (vout->smsshado_virt_addr[i]) {
+				omap_vout_free_buffer(
+						vout->smsshado_virt_addr[i],
+						vout->smsshado_phy_addr[i],
+						vout->smsshado_size);
+				vout->smsshado_virt_addr[i] = 0;
+				vout->smsshado_phy_addr[i] = 0;
+			}
+		}
+	}
+	vout->buffer_allocated = num_buffers;
+}
+
+/* This function will be called when VIDIOC_QBUF ioctl is called.
+ * It prepare buffers before give out for the display. This function
+ * user space virtual address into physical address if userptr memory
+ * exchange mechanism is used. If rotation is enabled, it copies entire
+ * buffer into VRFB memory space before giving it to the DSS.
+ */
+static int omap_vout_buffer_prepare(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb,
+			    enum v4l2_field field)
+{
+	struct omap_vout_device *vout = q->priv_data;
+	u32 dest_frame_index = 0, src_element_index = 0;
+	u32 dest_element_index = 0, src_frame_index = 0;
+	u32 elem_count = 0, frame_count = 0, pixsize = 2;
+	struct videobuf_dmabuf *dmabuf = NULL;
+	int rotation;
+	int ret = 0;
+
+	rotation = (vout->mirror) ?
+		rotation_with_mirror(vout->rotation) :
+		vout->rotation;
+
+	if (VIDEOBUF_NEEDS_INIT == vb->state) {
+		vb->width = vout->pix.width;
+		vb->height = vout->pix.height;
+		vb->size = vb->width * vb->height * vout->bpp;
+		vb->field = field;
+	}
+	vb->state = VIDEOBUF_PREPARED;
+	/* if user pointer memory mechanism is used, get the physical
+	 * address of the buffer
+	 */
+	if (V4L2_MEMORY_USERPTR == vb->memory) {
+		if (0 == vb->baddr)
+			return -EINVAL;
+		/* Virtual address */
+		/* priv points to struct videobuf_pci_sg_memory. But we went
+		 * pointer to videobuf_dmabuf, which is member of
+		 * videobuf_pci_sg_memory */
+		dmabuf = videobuf_to_dma(q->bufs[vb->i]);
+		dmabuf->vmalloc = (void *) vb->baddr;
+
+		/* Physical address */
+		dmabuf->bus_addr =
+			(dma_addr_t) omap_vout_uservirt_to_phys(vb->baddr);
+	}
+
+	dmabuf = videobuf_to_dma(q->bufs[vb->i]);
+	/* Flush only cacheable memory region */
+	if (cacheable_buffers == 1 && flushable_buffers == 1) {
+		dmac_clean_range(dmabuf->vmalloc,
+				 dmabuf->vmalloc + vout->buffer_size);
+		outer_clean_range(dmabuf->bus_addr,
+				  dmabuf->bus_addr + vout->buffer_size);
+	}
+
+	if (!rotation_enabled(vout->rotation)) {
+
+		vout->queued_buf_addr[vb->i] = (u8 *) dmabuf->bus_addr;
+		return 0;
+	}
+
+	if (flg_720 == VIDEO_720_ENABLE) {
+		flg_720  = VIDEO_720_RESIZER_N_STREAMING;
+
+		/*Start resizing*/
+		ret = rsz_begin(vb->i, vb->i, 8192,
+			(u32)vout->vrfb_context[vb->i].paddr[rotation],
+			vout->buf_phy_addr[vb->i], vout->buffer_size);
+
+		if (ret) {
+			printk(KERN_ERR "<%s> Failed to resize the 720p buffer"
+					" = %d\n", __func__, ret);
+			return ret;
+		}
+
+		flg_720 = VIDEO_720_ENABLE;
+	} else {
+		/* If rotation is enabled, copy input buffer into VRFB
+		 * memory space using DMA. We are copying input buffer
+		 * into VRFB memory space of desired angle and DSS will
+		 * read image VRFB memory for 0 degree angle
+		 */
+		pixsize = vout->bpp * vout->vrfb_bpp;
+		/*
+		 * DMA transfer in double index mode
+		 */
+
+		/* Frame index */
+		dest_frame_index = ((MAX_PIXELS_PER_LINE * pixsize) -
+				(vout->pix.width * vout->bpp)) + 1;
+
+		/* Source and destination parameters */
+		src_element_index = 0;
+		src_frame_index = 0;
+		dest_element_index = 1;
+		/* Number of elements per frame */
+		elem_count = vout->pix.width * vout->bpp;
+		frame_count = vout->pix.height;
+		vout->vrfb_dma_tx.tx_status = 0;
+		omap_set_dma_transfer_params(vout->vrfb_dma_tx.dma_ch,
+					     OMAP_DMA_DATA_TYPE_S32,
+					     (elem_count / 4), frame_count,
+					     OMAP_DMA_SYNC_ELEMENT,
+					     vout->vrfb_dma_tx.dev_id, 0x0);
+		/* src_port required only for OMAP1 */
+		omap_set_dma_src_params(vout->vrfb_dma_tx.dma_ch, 0,
+				OMAP_DMA_AMODE_POST_INC, dmabuf->bus_addr,
+				src_element_index, src_frame_index);
+		/*set dma source burst mode for VRFB */
+		omap_set_dma_src_burst_mode(vout->vrfb_dma_tx.dma_ch,
+				OMAP_DMA_DATA_BURST_16);
+
+		/* dest_port required only for OMAP1 */
+		omap_set_dma_dest_params(vout->vrfb_dma_tx.dma_ch, 0,
+				OMAP_DMA_AMODE_DOUBLE_IDX,
+				vout->vrfb_context[vb->i].paddr[rotation],
+				dest_element_index, dest_frame_index);
+		/*set dma dest burst mode for VRFB */
+		omap_set_dma_dest_burst_mode(vout->vrfb_dma_tx.dma_ch,
+				OMAP_DMA_DATA_BURST_16);
+		omap_dma_set_global_params(DMA_DEFAULT_ARB_RATE, 0x20, 0);
+
+		omap_start_dma(vout->vrfb_dma_tx.dma_ch);
+		interruptible_sleep_on_timeout(&vout->vrfb_dma_tx.wait,
+				VRFB_TX_TIMEOUT);
+
+		if (vout->vrfb_dma_tx.tx_status == 0) {
+			omap_stop_dma(vout->vrfb_dma_tx.dma_ch);
+			return -EINVAL;
+		}
+	}
+	/* Store buffers physical address into an array. Addresses
+	 * from this array will be used to configure DSS */
+	vout->queued_buf_addr[vb->i] = (u8 *)
+		vout->vrfb_context[vb->i].paddr[0];
+	return 0;
+}
+
+/* Buffer queue funtion will be called from the videobuf layer when _QBUF
+ * ioctl is called. It is used to enqueue buffer, which is ready to be
+ * displayed. */
+static void omap_vout_buffer_queue(struct videobuf_queue *q,
+			  struct videobuf_buffer *vb)
+{
+	struct omap_vout_device *vout = q->priv_data;
+
+	/* Driver is also maintainig a queue. So enqueue buffer in the driver
+	 * queue */
+	list_add_tail(&vb->queue, &vout->dma_queue);
+
+	vb->state = VIDEOBUF_PREPARED;
+}
+
+/* Buffer release function is called from videobuf layer to release buffer
+ * which are already allocated */
+static void omap_vout_buffer_release(struct videobuf_queue *q,
+			    struct videobuf_buffer *vb)
+{
+	struct omap_vout_device *vout = q->priv_data;
+
+	vb->state = VIDEOBUF_NEEDS_INIT;
+
+	if (V4L2_MEMORY_MMAP != vout->memory)
+		return;
+}
+
+/*
+ *  File operations
+ */
+static void omap_vout_vm_open(struct vm_area_struct *vma)
+{
+	struct omap_vout_device *vout = vma->vm_private_data;
+
+	v4l2_dbg(1, debug, vout->dev->driver,
+	"vm_open [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+	vout->mmap_count++;
+}
+
+static void omap_vout_vm_close(struct vm_area_struct *vma)
+{
+	struct omap_vout_device *vout = vma->vm_private_data;
+
+	v4l2_dbg(1, debug, vout->dev->driver,
+	"vm_close [vma=%08lx-%08lx]\n", vma->vm_start, vma->vm_end);
+	vout->mmap_count--;
+}
+
+static struct vm_operations_struct omap_vout_vm_ops = {
+	.open = omap_vout_vm_open,
+	.close = omap_vout_vm_close,
+};
+
+static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
+{
+	struct omap_vout_device *vout = file->private_data;
+	struct videobuf_queue *q = &vout->vbq;
+	unsigned long size = (vma->vm_end - vma->vm_start);
+	unsigned long start = vma->vm_start;
+	struct page *cpage;
+	int i;
+	void *pos;
+	struct videobuf_dmabuf *dmabuf = NULL;
+
+	v4l2_dbg(1, debug, vout->dev->driver,
+		" %s pgoff=0x%lx, start=0x%lx, end=0x%lx\n", __func__,
+		vma->vm_pgoff, vma->vm_start, vma->vm_end);
+
+	/* look for the buffer to map */
+	for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+		if (NULL == q->bufs[i])
+			continue;
+		if (V4L2_MEMORY_MMAP != q->bufs[i]->memory)
+			continue;
+		if (q->bufs[i]->boff == (vma->vm_pgoff << PAGE_SHIFT))
+			break;
+	}
+
+	if (VIDEO_MAX_FRAME == i) {
+		v4l2_dbg(1, debug, vout->dev->driver,
+		"offset invalid [offset=0x%lx]\n",
+			(vma->vm_pgoff << PAGE_SHIFT));
+		return -EINVAL;
+	}
+	q->bufs[i]->baddr = vma->vm_start;
+
+	vma->vm_flags |= VM_RESERVED;
+	if (cacheable_buffers == 0) {
+		vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
+		printk(KERN_DEBUG "Requested uncached buffers\n");
+	}
+	vma->vm_ops = &omap_vout_vm_ops;
+	vma->vm_private_data = (void *) vout;
+	dmabuf = videobuf_to_dma(q->bufs[i]);
+
+	pos = (void *)(dmabuf->bus_addr);
+
+	while (size > 0) {
+		cpage = pfn_to_page(((unsigned int) pos) >> PAGE_SHIFT);
+		if (vm_insert_page(vma, start, cpage)) {
+			printk(KERN_ERR "vout_mmap: Failed to insert bus_addr"
+							"page to VMA \n");
+			return -EAGAIN;
+			}
+		start += PAGE_SIZE;
+		pos += PAGE_SIZE;
+		size -= PAGE_SIZE;
+	}
+	vma->vm_flags &= ~VM_IO; /* using shared anonymous pages */
+	vout->mmap_count++;
+	v4l2_dbg(1, debug, vout->dev->driver, "Exiting %s\n", __func__);
+	return 0;
+}
+
+static int omap_vout_release(struct file *file)
+{
+
+	struct omap_vout_device *vout = file->private_data;
+	struct videobuf_queue *q;
+	unsigned int t;
+	struct omapvideo_info *ovid;
+	unsigned int r;
+
+	v4l2_dbg(1, debug, vout->dev->driver, "Entering %s\n", __func__);
+	ovid = &(vout->vid_info);
+
+	if (!vout)
+		return 0;
+	q = &vout->vbq;
+
+	/* Disable all the overlay managers connected with this interface */
+	for (t = 0; t < ovid->num_overlays; t++) {
+			struct omap_overlay *ovl = ovid->overlays[t];
+			if (ovl->manager && ovl->manager->device) {
+				struct omap_overlay_info info;
+				ovl->get_overlay_info(ovl, &info);
+				info.enabled = 0;
+				ovl->set_overlay_info(ovl, &info);
+			}
+
+		}
+	/* Turn off the pipeline */
+	r = omapvid_apply_changes(vout);
+	if (r)
+		printk(KERN_WARNING VOUT_NAME "Unable to apply changes\n");
+
+	/* Release the ISP resizer resource if not already done so*/
+	if ((flg_720 == VIDEO_720_ENABLE) ||
+	    (flg_720 == VIDEO_720_RESIZER_N_STREAMING)) {
+		rsz_put_resource();
+		flg_720 = VIDEO_720_DISABLE;
+	}
+
+	/* Free all buffers */
+	omap_vout_free_allbuffers(vout);
+	videobuf_mmap_free(q);
+
+	/* Even if apply changes fails we should continue
+	   freeing allocated memeory */
+	if (vout->streaming) {
+		omap_dispc_unregister_isr(omap_vout_isr, vout,
+					  OMAP_VOUT_IRQ_MASK);
+		vout->streaming = 0;
+
+		videobuf_streamoff(q);
+		videobuf_queue_cancel(q);
+
+	}
+
+	if (vout->mmap_count != 0)
+		vout->mmap_count = 0;
+
+	vout->opened -= 1;
+	file->private_data = NULL;
+
+	if (vout->buffer_allocated)
+		videobuf_mmap_free(q);
+	v4l2_dbg(1, debug, vout->dev->driver, "Exiting %s\n", __func__);
+	return r;
+}
+
+static int omap_vout_open(struct file *file)
+{
+	struct omap_vout_device *vout = NULL;
+	struct videobuf_queue *q;
+
+	vout = video_drvdata(file);
+	v4l2_dbg(1, debug, vout->dev->driver, "Entering %s\n", __func__);
+
+	if (vout == NULL)
+		return -ENODEV;
+
+	/* for now, we only support single open */
+	if (vout->opened)
+		return -EBUSY;
+
+	vout->opened += 1;
+
+	file->private_data = vout;
+	vout->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+	q = &vout->vbq;
+	video_vbq_ops.buf_setup = omap_vout_buffer_setup;
+	video_vbq_ops.buf_prepare = omap_vout_buffer_prepare;
+	video_vbq_ops.buf_release = omap_vout_buffer_release;
+	video_vbq_ops.buf_queue = omap_vout_buffer_queue;
+	spin_lock_init(&vout->vbq_lock);
+
+	videobuf_queue_sg_init(q, &video_vbq_ops, NULL, &vout->vbq_lock,
+			       vout->type, V4L2_FIELD_NONE, sizeof
+			       (struct videobuf_buffer), vout);
+	v4l2_dbg(1, debug, vout->dev->driver, "Exiting %s\n", __func__);
+	return 0;
+}
+
+/* V4L2 ioctls */
+static int vidioc_querycap(struct file *file, void *fh,
+		struct v4l2_capability *cap)
+{
+	struct omap_vout_device *vout = fh;
+
+	strlcpy(cap->driver, VOUT_NAME,
+		sizeof(cap->driver));
+	strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
+	cap->bus_info[0] = '\0';
+	cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT;
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_fmtdesc *fmt)
+{
+	int index = fmt->index;
+	enum v4l2_buf_type type = fmt->type;
+
+	fmt->index = index;
+	fmt->type = type;
+	if (index >= NUM_OUTPUT_FORMATS)
+		return -EINVAL;
+
+	fmt->flags = omap_formats[index].flags;
+	strlcpy(fmt->description, omap_formats[index].description,
+			sizeof(fmt->description));
+	fmt->pixelformat = omap_formats[index].pixelformat;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_vout_device *vout = fh;
+
+	struct v4l2_pix_format *pix = &f->fmt.pix;
+	*pix = vout->pix;
+	return 0;
+
+}
+
+static int vidioc_try_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_vout_device *vout = fh;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_video_timings *timing;
+
+	if (vout->streaming)
+		return -EBUSY;
+
+	ovid = &(vout->vid_info);
+	ovl = ovid->overlays[0];
+
+	if (!ovl->manager || !ovl->manager->device)
+		return -EINVAL;
+	/* get the display device attached to the overlay */
+	timing = &ovl->manager->device->panel.timings;
+
+	vout->fbuf.fmt.height = timing->y_res;
+	vout->fbuf.fmt.width = timing->x_res;
+
+	omap_vout_try_format(&f->fmt.pix, &vout->fbuf.fmt);
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_out(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_vout_device *vout = fh;
+	int bpp;
+	int r;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_video_timings *timing;
+
+	if (vout->streaming)
+		return -EBUSY;
+
+	mutex_lock(&vout->lock);
+
+	/*check for 720p format*/
+	if (vout->pix.height * vout->pix.width == VID_MAX_WIDTH * 720)
+		flg_720 = VIDEO_720_ENABLE;
+	else
+		flg_720 = VIDEO_720_DISABLE;
+
+	ovid = &(vout->vid_info);
+	ovl = ovid->overlays[0];
+
+	/* get the display device attached to the overlay */
+	if (!ovl->manager || !ovl->manager->device) {
+		mutex_unlock(&vout->lock);
+		return -EINVAL;
+	}
+	timing = &ovl->manager->device->panel.timings;
+
+	/* We dont support RGB24-packed mode if vrfb rotation
+	 * is enabled*/
+	if ((rotation_enabled(vout->rotation)) &&
+			f->fmt.pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+		mutex_unlock(&vout->lock);
+		return -EINVAL;
+	}
+
+	/* get the framebuffer parameters */
+
+	if (rotate_90_or_270(vout->rotation)) {
+		vout->fbuf.fmt.height = timing->x_res;
+		vout->fbuf.fmt.width = timing->y_res;
+	} else {
+		vout->fbuf.fmt.height = timing->y_res;
+		vout->fbuf.fmt.width = timing->x_res;
+	}
+
+	/* change to samller size is OK */
+
+	bpp = omap_vout_try_format(&f->fmt.pix, &vout->fbuf.fmt);
+	f->fmt.pix.sizeimage = f->fmt.pix.width * f->fmt.pix.height * bpp;
+
+	/* try & set the new output format */
+	vout->bpp = bpp;
+	vout->pix = f->fmt.pix;
+	vout->vrfb_bpp = 1;
+
+	/* If YUYV then vrfb bpp is 2, for  others its 1 */
+	if (V4L2_PIX_FMT_YUYV == vout->pix.pixelformat ||
+		V4L2_PIX_FMT_UYVY == vout->pix.pixelformat)
+		vout->vrfb_bpp = 2;
+
+	/* set default crop and win */
+	omap_vout_new_format(&vout->pix, &vout->fbuf, &vout->crop, &vout->win);
+
+	/* Save the changes in the overlay strcuture */
+	r = omapvid_init(vout, 0);
+	if (r) {
+		printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+		mutex_unlock(&vout->lock);
+		return -EINVAL;
+	}
+	mutex_unlock(&vout->lock);
+	return 0;
+}
+
+static int vidioc_try_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	int err = -EINVAL;
+	struct omap_vout_device *vout = fh;
+	struct v4l2_window *win = &f->fmt.win;
+
+	err = omap_vout_try_window(&vout->fbuf, win);
+
+	if (err)
+		return err;
+
+	if (vout->vid == OMAP_VIDEO1)
+		win->global_alpha = 255;
+	return 0;
+}
+
+static int vidioc_s_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_vout_device *vout = fh;
+	int err = -EINVAL;
+	struct v4l2_window *win = &f->fmt.win;
+
+	mutex_lock(&vout->lock);
+	if (flg_720 == VIDEO_720_ENABLE) {
+		/* align the output width to 16 bytes
+		 * ISP resizer requires the output width to be
+		 * aligned to 16 bytes.
+		 */
+		win->w.width = ((win->w.width + 0x0f) & ~0x0f);
+	}
+	err = omap_vout_new_window(&vout->crop, &vout->win, &vout->fbuf, win);
+	if (err) {
+		mutex_unlock(&vout->lock);
+		return err;
+	}
+	if (vout->vid == OMAP_VIDEO1)
+		vout->win.global_alpha = 255;
+	else
+		vout->win.global_alpha = f->fmt.win.global_alpha;
+
+	vout->win.chromakey = f->fmt.win.chromakey;
+	mutex_unlock(&vout->lock);
+	return 0;
+}
+
+static int vidioc_enum_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_fmtdesc *fmt)
+{
+	int index = fmt->index;
+	enum v4l2_buf_type type = fmt->type;
+
+	fmt->index = index;
+	fmt->type = type;
+	if (index >= NUM_OUTPUT_FORMATS)
+		return -EINVAL;
+
+	fmt->flags = omap_formats[index].flags;
+	strlcpy(fmt->description, omap_formats[index].description,
+		sizeof(fmt->description));
+	fmt->pixelformat = omap_formats[index].pixelformat;
+	return 0;
+}
+
+static int vidioc_g_fmt_vid_overlay(struct file *file, void *fh,
+			struct v4l2_format *f)
+{
+	struct omap_vout_device *vout = fh;
+	struct omap_overlay *ovl;
+	struct omapvideo_info *ovid;
+	struct v4l2_window *win = &f->fmt.win;
+	struct omap_overlay_manager_info info;
+
+	ovid = &(vout->vid_info);
+	ovl = ovid->overlays[0];
+
+	win->w = vout->win.w;
+	win->field = vout->win.field;
+	win->global_alpha = vout->win.global_alpha;
+
+	if (!ovl->manager || !ovl->manager->get_manager_info)
+		return -EINVAL;
+
+	ovl->manager->get_manager_info(ovl->manager, &info);
+	win->chromakey = info.trans_key;
+
+	return 0;
+}
+
+static int vidioc_cropcap(struct file *file, void *fh,
+			struct v4l2_cropcap *cropcap)
+{
+	struct omap_vout_device *vout = fh;
+	enum v4l2_buf_type type = cropcap->type;
+	struct v4l2_pix_format *pix = &vout->pix;
+
+	cropcap->type = type;
+	if (type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+
+	/* Width and height are always even */
+	cropcap->bounds.width = pix->width & ~1;
+	cropcap->bounds.height = pix->height & ~1;
+
+	omap_vout_default_crop(&vout->pix, &vout->fbuf, &cropcap->defrect);
+	cropcap->pixelaspect.numerator = 1;
+	cropcap->pixelaspect.denominator = 1;
+	return 0;
+}
+
+static int vidioc_g_crop(struct file *file, void *fh,
+	struct v4l2_crop *crop)
+{
+	struct omap_vout_device *vout = fh;
+
+	if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+		return -EINVAL;
+	crop->c = vout->crop;
+	return 0;
+}
+
+static int vidioc_s_crop(struct file *file, void *fh,
+			struct v4l2_crop *crop)
+{
+	struct omap_vout_device *vout = fh;
+	int err = -EINVAL;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_video_timings *timing;
+
+	if (vout->streaming)
+		return -EBUSY;
+
+	mutex_lock(&vout->lock);
+	ovid = &(vout->vid_info);
+	ovl = ovid->overlays[0];
+
+	if (!ovl->manager || !ovl->manager->device) {
+		mutex_unlock(&vout->lock);
+		return -EINVAL;
+	}
+	/* get the display device attached to the overlay */
+	timing = &ovl->manager->device->panel.timings;
+
+	if (rotate_90_or_270(vout->rotation)) {
+		vout->fbuf.fmt.height = timing->x_res;
+		vout->fbuf.fmt.width = timing->y_res;
+	} else {
+		vout->fbuf.fmt.height = timing->y_res;
+		vout->fbuf.fmt.width = timing->x_res;
+	}
+
+	if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+		err = omap_vout_new_crop(&vout->pix, &vout->crop, &vout->win,
+			&vout->fbuf, &crop->c);
+		mutex_unlock(&vout->lock);
+		return err;
+	} else {
+		mutex_unlock(&vout->lock);
+		return -EINVAL;
+	}
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+		struct v4l2_queryctrl *ctrl)
+{
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+		v4l2_ctrl_query_fill(ctrl, 0, 270, 90, 0);
+		break;
+	case V4L2_CID_BG_COLOR:
+		v4l2_ctrl_query_fill(ctrl, 0, 0xFFFFFF, 1, 0);
+		break;
+	case V4L2_CID_VFLIP:
+		v4l2_ctrl_query_fill(ctrl, 0, 1, 1, 0);
+	default:
+		ctrl->name[0] = '\0';
+		return -EINVAL;
+
+	}
+	return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *ctrl)
+{
+	struct omap_vout_device *vout = fh;
+
+	switch (ctrl->id) {
+	case V4L2_CID_ROTATE:
+		ctrl->value = vout->control[0].value;
+		return 0;
+	case V4L2_CID_BG_COLOR:
+	{
+		struct omapvideo_info *ovid;
+		struct omap_overlay *ovl;
+		struct omap_overlay_manager_info info;
+
+		ovid = &(vout->vid_info);
+		ovl = ovid->overlays[0];
+
+		if (!ovl->manager || !ovl->manager->get_manager_info)
+			return -EINVAL;
+
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		ctrl->value = info.default_color;
+		return 0;
+	}
+
+	case V4L2_CID_VFLIP:
+		ctrl->value = vout->control[2].value;
+		return 0;
+	default:
+		return -EINVAL;
+	}
+}
+
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *a)
+{
+	struct omap_vout_device *vout = fh;
+
+	switch (a->id) {
+	case V4L2_CID_ROTATE:
+	{
+		int rotation = a->value;
+
+		mutex_lock(&vout->lock);
+		if ((v4l2_rot_to_dss_rot(rotation, &vout->rotation,
+				vout->mirror))) {
+			mutex_unlock(&vout->lock);
+			return -EINVAL;
+		}
+		if (vout->pix.pixelformat == V4L2_PIX_FMT_RGB24 &&
+				rotation_enabled(vout->rotation)) {
+			mutex_unlock(&vout->lock);
+			return -EINVAL;
+		}
+		vout->control[0].value = rotation;
+		mutex_unlock(&vout->lock);
+		return 0;
+	}
+	case V4L2_CID_BG_COLOR:
+	{
+		unsigned int  color = a->value;
+		struct omapvideo_info *ovid;
+		struct omap_overlay *ovl;
+		struct omap_overlay_manager_info info;
+		ovid = &(vout->vid_info);
+		ovl = ovid->overlays[0];
+
+		mutex_lock(&vout->lock);
+		if (!ovl->manager || !ovl->manager->get_manager_info) {
+			mutex_unlock(&vout->lock);
+			return -EINVAL;
+		}
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		info.default_color = color;
+		ovl->manager->set_manager_info(ovl->manager, &info);
+
+		vout->control[1].value = color;
+		mutex_unlock(&vout->lock);
+		return 0;
+	}
+	case V4L2_CID_VFLIP:
+	{
+		unsigned int  mirror = a->value;
+		struct omapvideo_info *ovid;
+		struct omap_overlay *ovl;
+		ovid = &(vout->vid_info);
+		ovl = ovid->overlays[0];
+
+		mutex_lock(&vout->lock);
+
+		if (mirror  && vout->pix.pixelformat == V4L2_PIX_FMT_RGB24) {
+			mutex_unlock(&vout->lock);
+			return -EINVAL;
+		}
+		/* Use VRFB if mirroring is enabled */
+		if (mirror && !rotation_enabled(vout->rotation))
+			vout->rotation = 0;
+		/* Disabled VRFB if mirroring is disabled */
+		if (!mirror && vout->rotation == 0)
+			vout->rotation = -1;
+
+		vout->mirror = mirror;
+		vout->control[2].value = mirror;
+		mutex_unlock(&vout->lock);
+		return 0;
+	}
+
+	default:
+		return -EINVAL;
+	}
+
+}
+
+static int vidioc_reqbufs(struct file *file, void *fh,
+			struct v4l2_requestbuffers *req)
+{
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &(vout->vbq);
+	unsigned int i, num_buffers = 0;
+	int ret = 0;
+	struct videobuf_dmabuf *dmabuf = NULL;
+
+	if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
+		return -EINVAL;
+	/* if memory is not mmp or userptr
+	   return error */
+	if ((V4L2_MEMORY_MMAP != req->memory) &&
+		(V4L2_MEMORY_USERPTR != req->memory))
+		return -EINVAL;
+
+	mutex_lock(&vout->lock);
+	/* Cannot be requested when streaming is on */
+	if (vout->streaming) {
+		mutex_unlock(&vout->lock);
+		return -EBUSY;
+	}
+
+	/*
+	* struct v4l2_requestbuffers reserved field used to define
+	* cacheable/non-cacheable and flushable/non-flushable buffers
+	* from user space
+	*/
+	cacheable_buffers = (req->reserved[0] == 1) ? 1 : 0;
+	flushable_buffers = (req->reserved[1] == 1) ? 1 : 0;
+
+	/*check for 720p format*/
+	if (vout->pix.height * vout->pix.width ==
+			VID_MAX_WIDTH * 720)
+		flg_720 = VIDEO_720_ENABLE;
+	else
+		flg_720 = VIDEO_720_DISABLE;
+
+	/* If buffers are already allocated free them */
+	if (q->bufs[0] && (V4L2_MEMORY_MMAP == q->bufs[0]->memory)) {
+		if (vout->mmap_count) {
+			mutex_unlock(&vout->lock);
+			return -EBUSY;
+		}
+		num_buffers = (vout->vid == OMAP_VIDEO1) ?
+			video1_numbuffers : video2_numbuffers;
+		for (i = num_buffers; i < vout->buffer_allocated; i++) {
+			dmabuf = videobuf_to_dma(q->bufs[i]);
+			omap_vout_free_buffer((u32)dmabuf->vmalloc,
+				dmabuf->bus_addr, vout->buffer_size);
+			vout->buf_virt_addr[i] = 0;
+			vout->buf_phy_addr[i] = 0;
+		}
+		vout->buffer_allocated = num_buffers;
+		videobuf_mmap_free(q);
+	} else if (q->bufs[0] && (V4L2_MEMORY_USERPTR == q->bufs[0]->memory)) {
+		if (vout->buffer_allocated) {
+			videobuf_mmap_free(q);
+			for (i = 0; i < vout->buffer_allocated; i++) {
+				kfree(q->bufs[i]);
+				q->bufs[i] = NULL;
+			}
+			vout->buffer_allocated = 0;
+		}
+	}
+
+	/*store the memory type in data structure */
+	vout->memory = req->memory;
+
+	INIT_LIST_HEAD(&vout->dma_queue);
+
+	/* call videobuf_reqbufs api */
+	ret = videobuf_reqbufs(q, req);
+	if (ret < 0) {
+		mutex_unlock(&vout->lock);
+		return ret;
+	}
+
+	vout->buffer_allocated = req->count;
+	for (i = 0; i < req->count; i++) {
+		dmabuf = videobuf_to_dma(q->bufs[i]);
+		dmabuf->vmalloc = (void *) vout->buf_virt_addr[i];
+		dmabuf->bus_addr = (dma_addr_t) vout->buf_phy_addr[i];
+		dmabuf->sglen = 1;
+	}
+	mutex_unlock(&vout->lock);
+	return 0;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh,
+			struct v4l2_buffer *b)
+{
+	struct omap_vout_device *vout = fh;
+
+	return videobuf_querybuf(&(vout->vbq), b);
+}
+
+static int vidioc_qbuf(struct file *file, void *fh,
+			struct v4l2_buffer *buffer)
+{
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+	int ret, k, num_video_buffers;
+
+	if ((V4L2_BUF_TYPE_VIDEO_OUTPUT != buffer->type) ||
+			(buffer->index >= vout->buffer_allocated) ||
+			(q->bufs[buffer->index]->memory != buffer->memory)) {
+		return -EINVAL;
+	}
+	if (V4L2_MEMORY_USERPTR == buffer->memory) {
+		if ((buffer->length < vout->pix.sizeimage) ||
+			(0 == buffer->m.userptr)) {
+			return -EINVAL;
+		}
+	}
+
+	if ((rotation_enabled(vout->rotation)) &&
+			vout->vrfb_dma_tx.req_status == DMA_CHAN_NOT_ALLOTED) {
+		printk(KERN_WARNING VOUT_NAME
+				"DMA Channel not allocated for Rotation\n");
+		return -EINVAL;
+	}
+
+	/* get the ISP resizer resource and configure it*/
+	if (flg_720 == VIDEO_720_ENABLE) {
+		if (rsz_configured == 0) {
+			rsz_get_resource();
+
+			isp_rsz_params.in_hsize = vout->pix.width;
+			isp_rsz_params.in_vsize = vout->pix.height;
+			isp_rsz_params.out_hsize = vout->win.w.width;
+			isp_rsz_params.out_vsize = vout->win.w.height;
+
+			isp_rsz_params.in_pitch = isp_rsz_params.in_hsize * 2;
+			isp_rsz_params.inptyp = RSZ_INTYPE_YCBCR422_16BIT;
+			isp_rsz_params.vert_starting_pixel = 0;
+			isp_rsz_params.horz_starting_pixel = 0;
+
+			/* We are going to do downsampling, 0.75x*/
+			isp_rsz_params.cbilin = 0;
+			isp_rsz_params.out_pitch = isp_rsz_params.out_hsize * 2;
+			isp_rsz_params.hstph = 0;
+			isp_rsz_params.vstph = 0;
+			isp_rsz_params.yenh_params.type = 0;
+			isp_rsz_params.yenh_params.gain = 0;
+			isp_rsz_params.yenh_params.slop = 0;
+			isp_rsz_params.yenh_params.core = 0;
+
+			if (vout->pix.pixelformat == V4L2_PIX_FMT_YUYV)
+				isp_rsz_params.pix_fmt = RSZ_PIX_FMT_YUYV;
+			if (vout->pix.pixelformat == V4L2_PIX_FMT_UYVY)
+				isp_rsz_params.pix_fmt = RSZ_PIX_FMT_UYVY;
+
+			/* As we are downsizing, we put */
+			for (k = 0; k < 32; k++)
+				isp_rsz_params.tap4filt_coeffs[k] =
+				omap_vout_rsz_filter_4_tap_high_quality[k];
+			for (k = 0; k < 32; k++)
+				isp_rsz_params.tap7filt_coeffs[k] =
+				omap_vout_rsz_filter_7_tap_high_quality[k];
+
+			num_video_buffers = (vout->vid == OMAP_VIDEO1) ?
+			video1_numbuffers : video2_numbuffers;
+
+			ret = rsz_configure(&isp_rsz_params,
+					  omap_vout_isp_rsz_dma_tx_callback,
+					  num_video_buffers,
+					  (void *)vout);
+			printk(KERN_ERR "<%s>: rsz_configure = %d\n",
+			       __func__, ret);
+			if (ret) {
+				printk(KERN_ERR "<%s> failed to configure "
+						"ISP_resizer = %d\n",
+				       __func__, ret);
+				return ret;
+			}
+			rsz_configured = 1;
+		}
+	}
+
+	ret = videobuf_qbuf(q, buffer);
+	return ret;
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh,
+			struct v4l2_buffer *b)
+{
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+	int ret = 0;
+
+	if (!vout->streaming)
+		return -EINVAL;
+
+	if (file->f_flags & O_NONBLOCK)
+		/* Call videobuf_dqbuf for non blocking mode */
+		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 1);
+	else
+		/* Call videobuf_dqbuf for  blocking mode */
+		ret = videobuf_dqbuf(q, (struct v4l2_buffer *)b, 0);
+	return ret;
+}
+
+static int vidioc_streamon(struct file *file, void *fh,
+			enum v4l2_buf_type i)
+{
+	struct omap_vout_device *vout = fh;
+	struct videobuf_queue *q = &vout->vbq;
+	struct vout_platform_data *pdata = (vout->dev)->platform_data;
+	unsigned int count ;
+	u32 addr = 0;
+	int r = 0;
+	int t;
+	struct omapvideo_info *ovid = &(vout->vid_info);
+
+	mutex_lock(&vout->lock);
+
+	if (vout->streaming) {
+		mutex_unlock(&vout->lock);
+		return -EBUSY;
+	}
+
+	r = videobuf_streamon(q);
+	if (r < 0) {
+		mutex_unlock(&vout->lock);
+		return r;
+	}
+
+	if (list_empty(&vout->dma_queue)) {
+		mutex_unlock(&vout->lock);
+		return -EIO;
+	}
+	/* Get the next frame from the buffer queue */
+	vout->next_frm = vout->cur_frm = list_entry(vout->dma_queue.next,
+				struct videobuf_buffer, queue);
+	/* Remove buffer from the buffer queue */
+	list_del(&vout->cur_frm->queue);
+	/* Mark state of the current frame to active */
+	vout->cur_frm->state = VIDEOBUF_ACTIVE;
+	/* Initialize field_id and started member */
+	vout->field_id = 0;
+
+	/* set flag here. Next QBUF will start DMA */
+	vout->streaming = 1;
+
+	vout->first_int = 1;
+
+	/*check for 720p format*/
+	if (vout->pix.height * vout->pix.width == VID_MAX_WIDTH * 720)
+		flg_720 = VIDEO_720_ENABLE;
+	else
+		flg_720 = VIDEO_720_DISABLE;
+
+	if (omap_vout_calculate_offset(vout)) {
+		mutex_unlock(&vout->lock);
+		return -EINVAL;
+	}
+	addr = (unsigned long) vout->queued_buf_addr[vout->cur_frm->i]
+	+ vout->cropped_offset;
+
+	count = vout->buffer_allocated;
+	omap_vout_vrfb_buffer_setup(vout, &count, 0);
+
+#ifdef CONFIG_PM
+	if (pdata->set_min_bus_tput) {
+		if (cpu_is_omap3630()) {
+			pdata->set_min_bus_tput(vout->dev , OCP_INITIATOR_AGENT,
+								200 * 1000 * 4);
+		} else {
+			pdata->set_min_bus_tput(vout->dev , OCP_INITIATOR_AGENT,
+								166 * 1000 * 4);
+		}
+	}
+
+	/*
+	* Setting VDD1 at OPP3 Frequency to get better performance
+	* on streamon.
+	*/
+
+	if (pdata->set_vdd1_opp)
+		pdata->set_vdd1_opp(vout->dev, VDD1_OPP3_FREQ);
+#endif
+	omap_dispc_register_isr(omap_vout_isr, vout, OMAP_VOUT_IRQ_MASK);
+
+	for (t = 0; t < ovid->num_overlays; t++) {
+		struct omap_overlay *ovl = ovid->overlays[t];
+		if (ovl->manager && ovl->manager->device) {
+			struct omap_overlay_info info;
+			ovl->get_overlay_info(ovl, &info);
+			info.enabled = 1;
+			info.paddr = addr;
+			if (ovl->set_overlay_info(ovl, &info)) {
+				mutex_unlock(&vout->lock);
+				return -EINVAL;
+			}
+		}
+	}
+
+	/* First save the configuration in ovelray structure */
+	r = omapvid_init(vout, addr);
+	if (r)
+		printk(KERN_ERR VOUT_NAME "failed to set overlay info\n");
+	/* Enable the pipeline and set the Go bit */
+	r = omapvid_apply_changes(vout);
+	if (r)
+		printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+
+	mutex_unlock(&vout->lock);
+	return r;
+}
+
+static int vidioc_streamoff(struct file *file, void *fh,
+			enum v4l2_buf_type i)
+{
+	struct omap_vout_device *vout = fh;
+	int t, r = 0;
+	struct omapvideo_info *ovid = &(vout->vid_info);
+	struct vout_platform_data *pdata = (vout->dev)->platform_data;
+
+	if (!vout->streaming)
+		return -EINVAL;
+	if (vout->streaming) {
+		vout->streaming = 0;
+
+		omap_dispc_unregister_isr(omap_vout_isr, vout,
+					  OMAP_VOUT_IRQ_MASK);
+
+#ifdef CONFIG_PM
+		if (pdata->set_min_bus_tput)
+			pdata->set_min_bus_tput(vout->dev, OCP_INITIATOR_AGENT,
+								0);
+		/*
+		* Setting VDD1 at OPP1 when streamoff is called.
+		*/
+		if (pdata->set_vdd1_opp)
+			pdata->set_vdd1_opp(vout->dev, VDD1_OPP1_FREQ);
+#endif
+		for (t = 0; t < ovid->num_overlays; t++) {
+			struct omap_overlay *ovl = ovid->overlays[t];
+			if (ovl->manager && ovl->manager->device) {
+				struct omap_overlay_info info;
+
+				ovl->get_overlay_info(ovl, &info);
+				info.enabled = 0;
+				r = ovl->set_overlay_info(ovl, &info);
+				if (r) {
+					printk(KERN_ERR VOUT_NAME "failed to \
+						update overlay info\n");
+					return r;
+				}
+			}
+		}
+
+		/* Turn of the pipeline */
+		r = omapvid_apply_changes(vout);
+		if (r) {
+			printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+			return r;
+		}
+
+		/*release resizer now */
+		if (flg_720 == VIDEO_720_ENABLE) {
+			printk(KERN_ERR "<%s> rsz_put_resource\n", __func__);
+			flg_720 = VIDEO_720_DISABLE;
+			rsz_configured  = 0;
+			rsz_put_resource();
+		}
+
+		videobuf_streamoff(&vout->vbq);
+		videobuf_queue_cancel(&vout->vbq);
+	}
+	return 0;
+}
+
+static int vidioc_s_fbuf(struct file *file, void *fh,
+		struct v4l2_framebuffer *a)
+{
+	struct omap_vout_device *vout = fh;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_overlay_manager_info info;
+	enum omap_dss_trans_key_type key_type = OMAP_DSS_COLOR_KEY_GFX_DST;
+	int enable = 0;
+
+	ovid = &(vout->vid_info);
+	ovl = ovid->overlays[0];
+
+	/* OMAP DSS doesn't support Source and Destination color
+	   key together */
+	if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY) &&
+			(a->flags & V4L2_FBUF_FLAG_CHROMAKEY))
+		return -EINVAL;
+	/* OMAP DSS Doesn't support the Destination color key
+	   and alpha blending together */
+	if (a->flags & V4L2_FBUF_FLAG_CHROMAKEY &&
+			(a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA))
+		return -EINVAL;
+
+	if ((a->flags & V4L2_FBUF_FLAG_SRC_CHROMAKEY)) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+		key_type =  OMAP_DSS_COLOR_KEY_VID_SRC;
+	} else
+		vout->fbuf.flags &= ~V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+
+	if ((a->flags & V4L2_FBUF_FLAG_CHROMAKEY)) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+		key_type =  OMAP_DSS_COLOR_KEY_GFX_DST;
+	} else
+		vout->fbuf.flags &=  ~V4L2_FBUF_FLAG_CHROMAKEY;
+
+	if (a->flags & (V4L2_FBUF_FLAG_CHROMAKEY |
+				V4L2_FBUF_FLAG_SRC_CHROMAKEY))
+		enable = 1;
+	else
+		enable = 0;
+
+	if (ovl->manager && ovl->manager->get_manager_info &&
+	    ovl->manager->set_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		info.trans_enabled = enable;
+		info.trans_key = vout->win.chromakey;
+		ovl->manager->set_manager_info(ovl->manager, &info);
+	}
+
+	if (a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA) {
+		vout->fbuf.flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+		enable = 1;
+	} else if (!(a->flags & V4L2_FBUF_FLAG_LOCAL_ALPHA)) {
+		vout->fbuf.flags &= ~V4L2_FBUF_FLAG_LOCAL_ALPHA;
+		enable = 0;
+	}
+	if (ovl->manager && ovl->manager->get_manager_info &&
+	    ovl->manager->set_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		info.alpha_enabled = enable;
+		ovl->manager->set_manager_info(ovl->manager, &info);
+	}
+
+	return 0;
+}
+
+static int vidioc_g_fbuf(struct file *file, void *fh,
+		struct v4l2_framebuffer *a)
+{
+	struct omap_vout_device *vout = fh;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_overlay_manager_info info;
+
+	ovid = &(vout->vid_info);
+	ovl = ovid->overlays[0];
+
+	a->flags = 0x0;
+
+	a->capability = V4L2_FBUF_CAP_LOCAL_ALPHA | V4L2_FBUF_CAP_CHROMAKEY
+		| V4L2_FBUF_CAP_SRC_CHROMAKEY;
+
+	if (ovl->manager && ovl->manager->get_manager_info) {
+		ovl->manager->get_manager_info(ovl->manager, &info);
+		if (info.trans_enabled) {
+			if (info.trans_key_type == OMAP_DSS_COLOR_KEY_VID_SRC)
+				a->flags |= V4L2_FBUF_FLAG_SRC_CHROMAKEY;
+			if (info.trans_key_type == OMAP_DSS_COLOR_KEY_GFX_DST)
+				a->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
+
+		}
+		if (info.alpha_enabled)
+			a->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
+	}
+
+	return 0;
+}
+
+static const struct v4l2_ioctl_ops vout_ioctl_ops = {
+	.vidioc_querycap      			= vidioc_querycap,
+	.vidioc_enum_fmt_vid_out 		= vidioc_enum_fmt_vid_out,
+	.vidioc_g_fmt_vid_out			= vidioc_g_fmt_vid_out,
+	.vidioc_try_fmt_vid_out			= vidioc_try_fmt_vid_out,
+	.vidioc_s_fmt_vid_out			= vidioc_s_fmt_vid_out,
+	.vidioc_queryctrl    			= vidioc_queryctrl,
+	.vidioc_g_ctrl       			= vidioc_g_ctrl,
+	.vidioc_s_fbuf				= vidioc_s_fbuf,
+	.vidioc_g_fbuf				= vidioc_g_fbuf,
+	.vidioc_s_ctrl       			= vidioc_s_ctrl,
+	.vidioc_try_fmt_vid_overlay 		= vidioc_try_fmt_vid_overlay,
+	.vidioc_s_fmt_vid_overlay		= vidioc_s_fmt_vid_overlay,
+	.vidioc_enum_fmt_vid_overlay		= vidioc_enum_fmt_vid_overlay,
+	.vidioc_g_fmt_vid_overlay		= vidioc_g_fmt_vid_overlay,
+	.vidioc_cropcap				= vidioc_cropcap,
+	.vidioc_g_crop				= vidioc_g_crop,
+	.vidioc_s_crop				= vidioc_s_crop,
+	.vidioc_reqbufs				= vidioc_reqbufs,
+	.vidioc_querybuf			= vidioc_querybuf,
+	.vidioc_qbuf				= vidioc_qbuf,
+	.vidioc_dqbuf				= vidioc_dqbuf,
+	.vidioc_streamon			= vidioc_streamon,
+	.vidioc_streamoff			= vidioc_streamoff,
+};
+
+static const struct v4l2_file_operations omap_vout_fops = {
+	.owner 		= THIS_MODULE,
+	.ioctl 		= video_ioctl2,
+	.mmap 		= omap_vout_mmap,
+	.open 		= omap_vout_open,
+	.release 	= omap_vout_release,
+};
+
+/* Init functions used during driver intitalization */
+/* Initial setup of video_data */
+static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
+{
+	struct v4l2_pix_format *pix;
+	struct video_device *vfd;
+	struct v4l2_control *control;
+	struct omap_dss_device *display =
+		vout->vid_info.overlays[0]->manager->device;
+
+	/* set the default pix */
+	pix = &vout->pix;
+
+	/* Set the default picture of QVGA  */
+	pix->width = QQVGA_WIDTH;
+	pix->height = QQVGA_HEIGHT;
+
+	/* Default pixel format is RGB 5-6-5 */
+	pix->pixelformat = V4L2_PIX_FMT_RGB565;
+	pix->field = V4L2_FIELD_ANY;
+	pix->bytesperline = pix->width * 2;
+	pix->sizeimage = pix->bytesperline * pix->height;
+	pix->priv = 0;
+	pix->colorspace = V4L2_COLORSPACE_JPEG;
+
+	vout->bpp = RGB565_BPP;
+	vout->fbuf.fmt.width  =  display->panel.timings.x_res;
+	vout->fbuf.fmt.height =  display->panel.timings.y_res;
+
+	/* Set the data structures for the overlay parameters*/
+	vout->win.global_alpha = 255;
+	vout->fbuf.flags = 0;
+	vout->fbuf.capability = V4L2_FBUF_CAP_LOCAL_ALPHA |
+		V4L2_FBUF_CAP_SRC_CHROMAKEY | V4L2_FBUF_CAP_CHROMAKEY;
+	vout->win.chromakey = 0;
+
+	omap_vout_new_format(pix, &vout->fbuf, &vout->crop, &vout->win);
+
+	/*Disable the rotation. */
+	control = vout->control;
+
+	control[0].id = V4L2_CID_ROTATE;
+	control[0].value = 0;
+	vout->rotation = -1;
+	vout->mirror = 0;
+	vout->vrfb_bpp = 2;
+
+	control[1].id = V4L2_CID_BG_COLOR;
+	control[1].value = 0;
+
+	/* initialize the video_device struct */
+	vfd = vout->vfd = video_device_alloc();
+
+	if (!vfd) {
+		printk(KERN_ERR VOUT_NAME ": could not allocate\
+				video device struct\n");
+		return -ENOMEM;
+	}
+	vfd->release = video_device_release;
+	vfd->ioctl_ops = &vout_ioctl_ops;
+
+	strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
+	vfd->vfl_type = VID_TYPE_OVERLAY | VID_TYPE_CHROMAKEY;
+
+	/* need to register for a VID_HARDWARE_* ID in videodev.h */
+	vfd->fops = &omap_vout_fops;
+	mutex_init(&vout->lock);
+
+	vfd->minor = -1;
+	return 0;
+
+}
+
+/* Setup video buffers */
+static int __init omap_vout_setup_video_bufs(struct platform_device *pdev,
+		int vid_num)
+{
+	struct omap2video_device *vid_dev = platform_get_drvdata(pdev);
+	struct omap_vout_device *vout;
+	int i, j, r = 0;
+	int image_width, image_height;
+	unsigned numbuffers;
+	struct video_device *vfd;
+	int static_vrfb_allocation = 0, vrfb_num_bufs = OMAP_VOUT_MAX_BUFFERS;
+
+	vout = vid_dev->vouts[vid_num];
+	vfd = vout->vfd;
+
+	numbuffers = (vid_num == 0) ? video1_numbuffers : video2_numbuffers;
+	vout->buffer_size = (vid_num == 0) ? video1_bufsize : video2_bufsize;
+	printk(KERN_INFO VOUT_NAME "Buffer Size = %d\n", vout->buffer_size);
+	for (i = 0; i < numbuffers; i++) {
+		vout->buf_virt_addr[i] =
+			omap_vout_alloc_buffer(vout->buffer_size,
+					(u32 *) &vout->buf_phy_addr[i]);
+		if (!vout->buf_virt_addr[i]) {
+			numbuffers = i;
+			r = -ENOMEM;
+			goto free_buffers;
+		}
+	}
+
+	for (i = 0; i < OMAP_VOUT_MAX_VBUF_CTXT; i++) {
+
+		if (omap_vrfb_request_ctx(&vout->vrfb_context[i])) {
+			printk(KERN_INFO VOUT_NAME ": VRFB Region allocation \
+					for rotation failed\n");
+			r = -ENOMEM;
+			break;
+		}
+	}
+	if (r == -ENOMEM) {
+		for (j = 0; j < i; j++)
+			omap_vrfb_release_ctx(&vout->vrfb_context[j]);
+
+		goto free_buffers;
+	}
+
+	vout->cropped_offset = 0;
+
+	/* Calculate VRFB memory size */
+	/* allocate for worst case size */
+	image_width = VID_MAX_WIDTH / TILE_SIZE;
+	if (VID_MAX_WIDTH % TILE_SIZE)
+		image_width++;
+
+	image_width = image_width * TILE_SIZE;
+	image_height = VID_720P_HEIGHT / TILE_SIZE;
+
+	if (VID_720P_HEIGHT % TILE_SIZE)
+		image_height++;
+
+	image_height = image_height * TILE_SIZE;
+	vout->smsshado_size = PAGE_ALIGN(image_width * image_height * 2 * 2);
+
+	/*
+	 * Request and Initialize DMA, for DMA based VRFB transfer
+	 */
+	vout->vrfb_dma_tx.dev_id = OMAP_DMA_NO_DEVICE;
+	vout->vrfb_dma_tx.dma_ch = -1;
+	vout->vrfb_dma_tx.req_status = DMA_CHAN_ALLOTED;
+	r = omap_request_dma(vout->vrfb_dma_tx.dev_id, "VRFB DMA TX",
+			omap_vout_vrfb_dma_tx_callback,
+			(void *) &vout->vrfb_dma_tx, &vout->vrfb_dma_tx.dma_ch);
+	if (r < 0) {
+		vout->vrfb_dma_tx.req_status = DMA_CHAN_NOT_ALLOTED;
+		printk(KERN_INFO VOUT_NAME ": DMA Channel not alloted\
+				for video%d [v4l2]\n", vfd->minor);
+	}
+	init_waitqueue_head(&vout->vrfb_dma_tx.wait);
+
+	/* Allocate VRFB buffers if selected through bootargs */
+	static_vrfb_allocation = (vid_num == 0) ?
+		vid1_static_vrfb_alloc : vid2_static_vrfb_alloc;
+
+	/* statically allocated the VRFB buffer is done through
+	   commands line aruments */
+	if (static_vrfb_allocation) {
+		if (omap_vout_allocate_vrfb_buffers(vout, vrfb_num_bufs)) {
+			r =  -ENOMEM;
+			goto free_buffers;
+		}
+		vout->vrfb_static_allocation = 1;
+	}
+	return 0;
+
+free_buffers:
+	for (i = 0; i < numbuffers; i++) {
+		omap_vout_free_buffer(vout->buf_virt_addr[i],
+				vout->buf_phy_addr[i], vout->buffer_size);
+		vout->buf_virt_addr[i] = 0;
+		vout->buf_phy_addr[i] = 0;
+	}
+	return r;
+
+}
+
+/* Create video out devices */
+static int __init omap_vout_create_video_devices(struct platform_device *pdev)
+{
+	int r = 0, k;
+	struct omap_vout_device *vout;
+	struct video_device *vfd = NULL;
+	struct omap2video_device *vid_dev = platform_get_drvdata(pdev);
+
+	for (k = 0; k < pdev->num_resources; k++) {
+
+		vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
+		if (!vout) {
+			printk(KERN_ERR VOUT_NAME ": could not allocate \
+					memory\n");
+			return -ENOMEM;
+		}
+
+		memset(vout, 0, sizeof(struct omap_vout_device));
+
+		vout->dev = &pdev->dev;
+		vout->vid = k;
+		vid_dev->vouts[k] = vout;
+		vout->vid_info.vid_dev = vid_dev;
+		vout->vid_info.overlays[0] = vid_dev->overlays[k + 1];
+		vout->vid_info.num_overlays = 1;
+		vout->vid_info.id = k + 1;
+		vid_dev->num_videos++;
+
+		/* Setup the default configuration for the video devices
+		 */
+		if (omap_vout_setup_video_data(vout) != 0) {
+			r = -ENOMEM;
+			goto error;
+		}
+
+		/* Allocate default number of buffers for the video streaming
+		 * and reserve the VRFB space for rotation
+		 */
+		if (omap_vout_setup_video_bufs(pdev, k) != 0) {
+			r = -ENOMEM;
+			goto error1;
+		}
+
+		/* Register the Video device with V4L2
+		 */
+		vfd = vout->vfd;
+		if (video_register_device(vfd, VFL_TYPE_GRABBER, k + 1) < 0) {
+			printk(KERN_ERR VOUT_NAME ": could not register \
+					Video for Linux device\n");
+			vfd->minor = -1;
+			r = -ENODEV;
+			goto error2;
+		}
+		video_set_drvdata(vfd, vout);
+
+		/* Configure the overlay structure */
+		r = omapvid_init(vid_dev->vouts[k], 0);
+
+		if (r)
+			goto error2;
+		else
+			goto success;
+error2:
+	omap_vout_release_vrfb(vout);
+	omap_vout_free_buffers(vout);
+error1:
+	video_device_release(vfd);
+error:
+	kfree(vout);
+	return r;
+
+success:
+	printk(KERN_INFO VOUT_NAME ": registered and initialized\
+			video device %d [v4l2]\n", vfd->minor);
+	if (k == (pdev->num_resources - 1))
+		return 0;
+	}
+	return -ENODEV;
+
+}
+/* Driver functions */
+static int omap_vout_remove(struct platform_device *pdev)
+{
+
+	struct omap2video_device *vid_dev = platform_get_drvdata(pdev);
+	int k;
+
+	for (k = 0; k < pdev->num_resources; k++)
+		omap_vout_cleanup_device(vid_dev->vouts[k]);
+
+	for (k = 0; k < vid_dev->num_displays; k++) {
+		if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
+			vid_dev->displays[k]->disable(vid_dev->displays[k]);
+
+		omap_dss_put_device(vid_dev->displays[k]);
+	}
+	kfree(vid_dev);
+	return 0;
+}
+
+static int __init omap_vout_probe(struct platform_device *pdev)
+{
+	int r = 0, i;
+	struct omap2video_device *vid_dev = NULL;
+	struct omap_overlay *ovl;
+	struct omap_dss_device *def_display;
+	struct omap_dss_device *display = NULL;
+
+	if (pdev->num_resources == 0) {
+		dev_err(&pdev->dev, "probed for an unknown device\n");
+		r = -ENODEV;
+		return r;
+	}
+
+	vid_dev = kzalloc(sizeof(struct omap2video_device), GFP_KERNEL);
+	if (vid_dev == NULL) {
+		r = -ENOMEM;
+		return r;
+	}
+
+	platform_set_drvdata(pdev, vid_dev);
+
+	vid_dev->num_displays = 0;
+	for_each_dss_dev(display) {
+		omap_dss_get_device(display);
+		if (!display) {
+			dev_err(&pdev->dev, "probed for an unknown device\n");
+			r = -EINVAL;
+			goto error0;
+		}
+		vid_dev->displays[vid_dev->num_displays++] = display;
+	}
+
+	if (vid_dev->num_displays == 0) {
+		dev_err(&pdev->dev, "probed for an unknown device\n");
+		r = -EINVAL;
+		goto error0;
+	}
+
+	vid_dev->num_overlays = omap_dss_get_num_overlays();
+	for (i = 0; i < vid_dev->num_overlays; i++)
+		vid_dev->overlays[i] = omap_dss_get_overlay(i);
+
+	vid_dev->num_managers = omap_dss_get_num_overlay_managers();
+	for (i = 0; i < vid_dev->num_managers; i++)
+		vid_dev->managers[i] = omap_dss_get_overlay_manager(i);
+
+	/* Get the Video1 overlay and video2 overlay.
+	 * Setup the Display attached to that overlays
+	 */
+	 for (i = 1; i < 3; i++) {
+		ovl = omap_dss_get_overlay(i);
+		if (ovl->manager && ovl->manager->device) {
+			def_display = ovl->manager->device;
+		} else {
+			dev_err(&pdev->dev, "probed for an unknown device\n");
+			r = -EINVAL;
+			goto error0;
+		}
+		r = def_display->enable(def_display);
+		if (r) {
+			/* Here we are not considering a error as display may be
+			enabled by frame buffer driver */
+			printk(KERN_WARNING VOUT_NAME
+					"Display already enabled\n");
+		}
+		/* set the update mode */
+		if (def_display->caps & OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
+#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
+			if (def_display->set_update_mode)
+				def_display->set_update_mode(def_display,
+						OMAP_DSS_UPDATE_AUTO);
+			if (def_display->enable_te)
+				def_display->enable_te(def_display, 1);
+#else
+			if (def_display->set_update_mode)
+				def_display->set_update_mode(def_display,
+						OMAP_DSS_UPDATE_MANUAL);
+			if (def_display->enable_te)
+				def_display->enable_te(def_display, 0);
+#endif
+		} else {
+			if (def_display->set_update_mode)
+				def_display->set_update_mode(def_display,
+						OMAP_DSS_UPDATE_AUTO);
+		}
+	 }
+
+	r = omap_vout_create_video_devices(pdev);
+	if (r)
+		goto error0;
+
+	for (i = 0; i < vid_dev->num_displays; i++) {
+		struct omap_dss_device *display = vid_dev->displays[i];
+
+		if (display->update)
+			display->update(display, 0, 0,
+			display->panel.timings.x_res,
+			display->panel.timings.y_res);
+	}
+	printk(KERN_INFO VOUT_NAME "display->updated\n");
+	return 0;
+
+error0:
+	kfree(vid_dev);
+	return r;
+}
+
+static struct platform_driver omap_vout_driver = {
+	.driver = {
+		   .name = VOUT_NAME,
+		   },
+	.probe = omap_vout_probe,
+	.remove = omap_vout_remove,
+};
+
+void omap_vout_isr(void *arg, unsigned int irqstatus)
+{
+	int r;
+	struct timeval timevalue;
+	struct omap_vout_device *vout =
+	    (struct omap_vout_device *) arg;
+	u32 addr, fid;
+	struct omapvideo_info *ovid;
+	struct omap_overlay *ovl;
+	struct omap_dss_device *cur_display;
+
+	if (!vout->streaming)
+		return;
+
+	ovid = &(vout->vid_info);
+	ovl = ovid->overlays[0];
+	/* get the display device attached to the overlay */
+	if (!ovl->manager || !ovl->manager->device)
+		return;
+	cur_display = ovl->manager->device;
+
+	spin_lock(&vout->vbq_lock);
+	do_gettimeofday(&timevalue);
+	if ((cur_display->type == OMAP_DISPLAY_TYPE_DSI &&
+	     irqstatus & DISPC_IRQ_FRAMEDONE) ||
+	    ((cur_display->type == OMAP_DISPLAY_TYPE_DPI ||
+	      cur_display->type == OMAP_DISPLAY_TYPE_HDMI) &&
+	     irqstatus & DISPC_IRQ_VSYNC)) {
+
+		if (!vout->first_int && (vout->cur_frm != vout->next_frm)) {
+			vout->cur_frm->ts = timevalue;
+			vout->cur_frm->state = VIDEOBUF_DONE;
+			wake_up_interruptible(&vout->cur_frm->done);
+			vout->cur_frm = vout->next_frm;
+		}
+		vout->first_int = 0;
+		if (list_empty(&vout->dma_queue)) {
+			/* TODO: only update on new frame */
+			omapvid_apply_changes(vout);
+			spin_unlock(&vout->vbq_lock);
+			return;
+		}
+		vout->next_frm = list_entry(vout->dma_queue.next,
+					struct videobuf_buffer, queue);
+		list_del(&vout->next_frm->queue);
+
+		vout->next_frm->state = VIDEOBUF_ACTIVE;
+		addr = (unsigned long) vout->queued_buf_addr[vout->next_frm->i]
+			+ vout->cropped_offset;
+		/* First save the configuration in ovelray structure */
+		r = omapvid_init(vout, addr);
+		if (r)
+			printk(KERN_ERR VOUT_NAME "failed to set overlay info\n");
+		/* Enable the pipeline and set the Go bit */
+		r = omapvid_apply_changes(vout);
+		if (r)
+			printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+	} else {
+
+		if (vout->first_int) {
+			vout->first_int = 0;
+			spin_unlock(&vout->vbq_lock);
+			return;
+		}
+		if (irqstatus & DISPC_IRQ_EVSYNC_ODD) {
+			fid = 1;
+		} else if (irqstatus & DISPC_IRQ_EVSYNC_EVEN) {
+			fid = 0;
+		} else {
+			spin_unlock(&vout->vbq_lock);
+			return;
+		}
+		vout->field_id ^= 1;
+		if (fid != vout->field_id) {
+			if (0 == fid)
+				vout->field_id = fid;
+
+			spin_unlock(&vout->vbq_lock);
+			return;
+		}
+		if (0 == fid) {
+			if (vout->cur_frm == vout->next_frm) {
+				spin_unlock(&vout->vbq_lock);
+				return;
+			}
+			vout->cur_frm->ts = timevalue;
+			vout->cur_frm->state = VIDEOBUF_DONE;
+			wake_up_interruptible(&vout->cur_frm->done);
+			vout->cur_frm = vout->next_frm;
+		} else if (1 == fid) {
+			if (list_empty(&vout->dma_queue) ||
+			    (vout->cur_frm != vout->next_frm)) {
+				spin_unlock(&vout->vbq_lock);
+				return;
+			}
+			vout->next_frm = list_entry(vout->dma_queue.next,
+					   struct videobuf_buffer, queue);
+			list_del(&vout->next_frm->queue);
+
+			vout->next_frm->state = VIDEOBUF_ACTIVE;
+			addr = (unsigned long)
+			    vout->queued_buf_addr[vout->next_frm->i] +
+			    vout->cropped_offset;
+			/* First save the configuration in ovelray structure */
+			r = omapvid_init(vout, addr);
+			if (r)
+				printk(KERN_ERR VOUT_NAME "failed to set overlay info\n");
+			/* Enable the pipeline and set the Go bit */
+			r = omapvid_apply_changes(vout);
+			if (r)
+				printk(KERN_ERR VOUT_NAME "failed to change mode\n");
+		}
+
+	}
+	spin_unlock(&vout->vbq_lock);
+}
+
+static void omap_vout_cleanup_device(struct omap_vout_device *vout)
+{
+
+	struct video_device *vfd;
+
+	if (!vout)
+		return;
+	vfd = vout->vfd;
+
+	if (vfd) {
+		if (vfd->minor == -1) {
+			/*
+			 * The device was never registered, so release the
+			 * video_device struct directly.
+			 */
+			video_device_release(vfd);
+		} else {
+			/*
+			 * The unregister function will release the video_device
+			 * struct as well as unregistering it.
+			 */
+			video_unregister_device(vfd);
+		}
+	}
+
+	omap_vout_release_vrfb(vout);
+
+	omap_vout_free_buffers(vout);
+	/* Free the VRFB buffer if allocated
+	 * init time
+	 */
+	if (vout->vrfb_static_allocation)
+		omap_vout_free_vrfb_buffers(vout);
+
+	kfree(vout);
+}
+
+static int __init omap_vout_init(void)
+{
+
+	if (platform_driver_register(&omap_vout_driver) != 0) {
+		printk(KERN_ERR VOUT_NAME ": could not register \
+				Video driver\n");
+		return -EINVAL;
+	}
+	return 0;
+}
+
+static void omap_vout_cleanup(void)
+{
+	platform_driver_unregister(&omap_vout_driver);
+}
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP Video for Linux Video out driver");
+MODULE_LICENSE("GPL");
+
+late_initcall(omap_vout_init);
+module_exit(omap_vout_cleanup);
diff --git a/drivers/media/video/omap/omap_voutdef.h b/drivers/media/video/omap/omap_voutdef.h
new file mode 100644
index 0000000..df313c1
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutdef.h
@@ -0,0 +1,153 @@
+/*
+ * drivers/media/video/omap/omap_voutdef.h
+ *
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef OMAP_VOUTDEF_H
+#define OMAP_VOUTDEF_H
+
+#include <mach/display.h>
+#include <mach/omap-pm.h>
+#include <mach/vrfb.h>
+#include <media/videobuf-core.h>
+
+#define YUYV_BPP        2
+#define RGB565_BPP      2
+#define RGB24_BPP       3
+#define RGB32_BPP       4
+#define TILE_SIZE       32
+#define YUYV_VRFB_BPP   2
+#define RGB_VRFB_BPP    1
+#define MAX_CID			3
+
+
+#define OMAP_VOUT_MAX_BUFFERS	6
+
+/*
+ * Currently VBUF context and Data Buffers are mapped 1:1
+ */
+#define OMAP_VOUT_MAX_VBUF_CTXT	OMAP_VOUT_MAX_BUFFERS
+/*
+ * This structure is used to store the DMA transfer parameters
+ * for VRFB hidden buffer
+ */
+struct vid_vrfb_dma {
+	int dev_id;
+	int dma_ch;
+	int req_status;
+	int tx_status;
+	wait_queue_head_t wait;
+};
+
+struct omapvideo_info {
+	int id;
+	int num_overlays;
+	struct omap_overlay *overlays[3];
+	struct omap2video_device *vid_dev;
+};
+
+struct omap2video_device {
+	struct device *dev;
+	struct mutex  mtx;
+
+	int state;
+
+	int num_videos;
+	struct omap_vout_device *vouts[10];
+
+	int num_displays;
+	struct omap_dss_device *displays[10];
+	int num_overlays;
+	struct omap_overlay *overlays[10];
+	int num_managers;
+	struct omap_overlay_manager *managers[10];
+};
+
+/* per-device data structure */
+struct omap_vout_device {
+
+	struct omapvideo_info vid_info;
+	struct device *dev;
+	struct video_device *vfd;
+	int vid;
+	int opened;
+
+	/* we don't allow to change image fmt/size once buffer has
+	 * been allocated
+	 */
+	int buffer_allocated;
+	/* allow to reuse previosuly allocated buffer which is big enough */
+	int buffer_size;
+	/* keep buffer info accross opens */
+	unsigned long buf_virt_addr[VIDEO_MAX_FRAME];
+	unsigned long buf_phy_addr[VIDEO_MAX_FRAME];
+	enum omap_color_mode dss_mode;
+
+	/* we don't allow to request new buffer when old buffers are
+	 * still mmaped
+	 */
+	int mmap_count;
+
+	spinlock_t vbq_lock;		/* spinlock for videobuf queues */
+	unsigned long field_count;	/* field counter for videobuf_buffer */
+
+	/* non-NULL means streaming is in progress. */
+	bool streaming;
+
+	struct v4l2_pix_format pix;
+	struct v4l2_rect crop;
+	struct v4l2_window win;
+	struct v4l2_framebuffer fbuf;
+
+	/* Lock to protect the shared data structures in ioctl */
+	struct mutex lock;
+
+	/* V4L2 control structure for different control id */
+	struct v4l2_control control[MAX_CID];
+	int rotation;
+	int mirror;
+	int flicker_filter;
+	/* V4L2 control structure for different control id */
+
+	int bpp; /* bytes per pixel */
+	int vrfb_bpp; /* bytes per pixel with respect to VRFB */
+
+	struct vid_vrfb_dma vrfb_dma_tx;
+	unsigned int smsshado_phy_addr[OMAP_VOUT_MAX_BUFFERS];
+	unsigned int smsshado_virt_addr[OMAP_VOUT_MAX_BUFFERS];
+	struct vrfb vrfb_context[OMAP_VOUT_MAX_VBUF_CTXT];
+	bool vrfb_static_allocation;
+	unsigned int smsshado_size;
+	unsigned char pos;
+
+	int ps, vr_ps, line_length, first_int, field_id;
+	enum v4l2_memory memory;
+	struct videobuf_buffer *cur_frm, *next_frm;
+	struct list_head dma_queue;
+	u8 *queued_buf_addr[32];
+	u32 cropped_offset;
+	s32 tv_field1_offset;
+	void *isr_handle;
+
+	/* Buffer queue variabled */
+	struct omap_vout_device *vout;
+	enum v4l2_buf_type type;
+	struct videobuf_queue vbq;
+	int io_allowed;
+
+};
+
+struct vout_platform_data {
+	void (*set_min_bus_tput)(struct device *dev, u8 agent_id,
+						unsigned long r);
+	void (*set_max_mpu_wakeup_lat)(struct device *dev, long t);
+	void (*set_vdd1_opp) (struct device *dev, unsigned long);
+	void (*set_cpu_freq)(unsigned long f);
+};
+
+#endif	/* ifndef OMAP_VOUTDEF_H */
diff --git a/drivers/media/video/omap/omap_voutlib.c b/drivers/media/video/omap/omap_voutlib.c
new file mode 100644
index 0000000..5a31884
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutlib.c
@@ -0,0 +1,320 @@
+/*
+ * drivers/media/video/omap/omap_voutlib.c
+ *
+ * Copyright (C) 2005-2009 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ * Based on the OMAP2 camera driver
+ * Video-for-Linux (Version 2) camera capture driver for
+ * the OMAP24xx camera controller.
+ *
+ * Author: Andy Lowe (source@mvista.com)
+ *
+ * Copyright (C) 2004 MontaVista Software, Inc.
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/smp_lock.h>
+#include <linux/kdev_t.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/videodev2.h>
+#include <linux/semaphore.h>
+#include <mach/cpu.h>
+
+/* Return the default overlay cropping rectangle in crop given the image
+ * size in pix and the video display size in fbuf.  The default
+ * cropping rectangle is the largest rectangle no larger than the capture size
+ * that will fit on the display.  The default cropping rectangle is centered in
+ * the image.  All dimensions and offsets are rounded down to even numbers.
+ */
+void omap_vout_default_crop(struct v4l2_pix_format *pix,
+		  struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop)
+{
+	crop->width = (pix->width < fbuf->fmt.width) ?
+		pix->width : fbuf->fmt.width;
+	crop->height = (pix->height < fbuf->fmt.height) ?
+		pix->height : fbuf->fmt.height;
+	crop->width &= ~1;
+	crop->height &= ~1;
+	crop->left = ((pix->width - crop->width) >> 1) & ~1;
+	crop->top = ((pix->height - crop->height) >> 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(omap_vout_default_crop);
+
+/* Given a new render window in new_win, adjust the window to the
+ * nearest supported configuration.  The adjusted window parameters are
+ * returned in new_win.
+ * Returns zero if succesful, or -EINVAL if the requested window is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+			struct v4l2_window *new_win)
+{
+	struct v4l2_rect try_win;
+
+	/* make a working copy of the new_win rectangle */
+	try_win = new_win->w;
+
+	/* adjust the preview window so it fits on the display by clipping any
+	 * offscreen areas
+	 */
+	if (try_win.left < 0) {
+		try_win.width += try_win.left;
+		try_win.left = 0;
+	}
+	if (try_win.top < 0) {
+		try_win.height += try_win.top;
+		try_win.top = 0;
+	}
+	try_win.width = (try_win.width < fbuf->fmt.width) ?
+		try_win.width : fbuf->fmt.width;
+	try_win.height = (try_win.height < fbuf->fmt.height) ?
+		try_win.height : fbuf->fmt.height;
+	if (try_win.left + try_win.width > fbuf->fmt.width)
+		try_win.width = fbuf->fmt.width - try_win.left;
+	if (try_win.top + try_win.height > fbuf->fmt.height)
+		try_win.height = fbuf->fmt.height - try_win.top;
+	try_win.width &= ~1;
+	try_win.height &= ~1;
+
+	if (try_win.width <= 0 || try_win.height <= 0)
+		return -EINVAL;
+
+	/* We now have a valid preview window, so go with it */
+	new_win->w = try_win;
+	new_win->field = V4L2_FIELD_ANY;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_try_window);
+
+/* Given a new render window in new_win, adjust the window to the
+ * nearest supported configuration.  The image cropping window in crop
+ * will also be adjusted if necessary.  Preference is given to keeping the
+ * the window as close to the requested configuration as possible.  If
+ * successful, new_win, vout->win, and crop are updated.
+ * Returns zero if succesful, or -EINVAL if the requested preview window is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_new_window(struct v4l2_rect *crop,
+		struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win)
+{
+	int err;
+
+	err = omap_vout_try_window(fbuf, new_win);
+	if (err)
+		return err;
+
+	/* update our preview window */
+	win->w = new_win->w;
+	win->field = new_win->field;
+	win->chromakey = new_win->chromakey;
+
+	if (cpu_is_omap24xx()) {
+		/* adjust the cropping window to allow for resizing
+		 * limitations. 24xx allow 8x to 1/2x scaling.
+		 */
+		if ((crop->height/win->w.height) >= 2) {
+			/* The maximum vertical downsizing ratio is 2:1 */
+			crop->height = win->w.height * 2;
+		}
+		if ((crop->width/win->w.width) >= 2) {
+			/* The maximum horizontal downsizing ratio is 2:1 */
+			crop->width = win->w.width * 2;
+		}
+		if (crop->width > 768) {
+			/* The OMAP2420 vertical resizing line buffer is 768
+			 * pixels  wide.  If the cropped image is wider than
+			 * 768 pixels then it cannot be vertically resized.
+			 */
+			if (crop->height != win->w.height)
+				crop->width = 768;
+		}
+	} else if (cpu_is_omap34xx()) {
+		/* adjust the cropping window to allow for resizing
+		 * limitations 34xx allow 8x to 1/4x scaling.
+		 */
+		if ((crop->height/win->w.height) >= 4) {
+			/* The maximum vertical downsizing ratio is 4:1 */
+			crop->height = win->w.height * 4;
+		}
+		if ((crop->width/win->w.width) >= 4) {
+			/* The maximum horizontal downsizing ratio is 4:1 */
+			crop->width = win->w.width * 4;
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_window);
+
+/* Given a new cropping rectangle in new_crop, adjust the cropping rectangle to
+ * the nearest supported configuration.  The image render window in win will
+ * also be adjusted if necessary.  The preview window is adjusted such that the
+ * horizontal and vertical rescaling ratios stay constant.  If the render
+ * window would fall outside the display boundaries, the cropping rectangle
+ * will also be adjusted to maintain the rescaling ratios.  If successful, crop
+ * and win are updated.
+ * Returns zero if succesful, or -EINVAL if the requested cropping rectangle is
+ * impossible and cannot reasonably be adjusted.
+ */
+int omap_vout_new_crop(struct v4l2_pix_format *pix,
+	      struct v4l2_rect *crop, struct v4l2_window *win,
+	      struct v4l2_framebuffer *fbuf, const struct v4l2_rect *new_crop)
+{
+	struct v4l2_rect try_crop;
+	unsigned long vresize, hresize;
+
+	/* make a working copy of the new_crop rectangle */
+	try_crop = *new_crop;
+
+	/* adjust the cropping rectangle so it fits in the image */
+	if (try_crop.left < 0) {
+		try_crop.width += try_crop.left;
+		try_crop.left = 0;
+	}
+	if (try_crop.top < 0) {
+		try_crop.height += try_crop.top;
+		try_crop.top = 0;
+	}
+	try_crop.width = (try_crop.width < pix->width) ?
+		try_crop.width : pix->width;
+	try_crop.height = (try_crop.height < pix->height) ?
+		try_crop.height : pix->height;
+	if (try_crop.left + try_crop.width > pix->width)
+		try_crop.width = pix->width - try_crop.left;
+	if (try_crop.top + try_crop.height > pix->height)
+		try_crop.height = pix->height - try_crop.top;
+	try_crop.width &= ~1;
+	try_crop.height &= ~1;
+	if (try_crop.width <= 0 || try_crop.height <= 0)
+		return -EINVAL;
+	if (cpu_is_omap24xx()) {
+		if (crop->height != win->w.height) {
+			/* If we're resizing vertically, we can't support a
+			 * crop width wider than 768 pixels.
+			 */
+			if (try_crop.width > 768)
+				try_crop.width = 768;
+		}
+	}
+	/* vertical resizing */
+	vresize = (1024 * crop->height) / win->w.height;
+	if (cpu_is_omap24xx()) {
+		if (vresize > 2048)
+			vresize = 2048;
+	} else if (cpu_is_omap34xx()) {
+		if (vresize > 4096)
+			vresize = 4096;
+	}
+	win->w.height = ((1024 * try_crop.height) / vresize) & ~1;
+	if (win->w.height == 0)
+		win->w.height = 2;
+	if (win->w.height + win->w.top > fbuf->fmt.height) {
+		/* We made the preview window extend below the bottom of the
+		 * display, so clip it to the display boundary and resize the
+		 * cropping height to maintain the vertical resizing ratio.
+		 */
+		win->w.height = (fbuf->fmt.height - win->w.top) & ~1;
+		if (try_crop.height == 0)
+			try_crop.height = 2;
+	}
+	/* horizontal resizing */
+	hresize = (1024 * crop->width) / win->w.width;
+	if (cpu_is_omap24xx()) {
+		if (hresize > 2048)
+			hresize = 2048;
+	} else if (cpu_is_omap34xx()) {
+		if (hresize > 4096)
+			hresize = 4096;
+	}
+	win->w.width = ((1024 * try_crop.width) / hresize) & ~1;
+	if (win->w.width == 0)
+		win->w.width = 2;
+	if (win->w.width + win->w.left > fbuf->fmt.width) {
+		/* We made the preview window extend past the right side of the
+		 * display, so clip it to the display boundary and resize the
+		 * cropping width to maintain the horizontal resizing ratio.
+		 */
+		win->w.width = (fbuf->fmt.width - win->w.left) & ~1;
+		if (try_crop.width == 0)
+			try_crop.width = 2;
+	}
+	if (cpu_is_omap24xx()) {
+		/* Check for resizing constraints
+		 * 24xx allow 8x to 1/2x scaling.
+		 */
+		if ((try_crop.height/win->w.height) >= 2) {
+			/* The maximum vertical downsizing ratio is 2:1 */
+			try_crop.height = win->w.height * 2;
+		}
+		if ((try_crop.width/win->w.width) >= 2) {
+			/* The maximum horizontal downsizing ratio is 2:1 */
+			try_crop.width = win->w.width * 2;
+		}
+		if (try_crop.width > 768) {
+			/* The OMAP2420 vertical resizing line buffer is
+			 * 768 pixels wide.  If the cropped image is wider
+			 * than 768 pixels then it cannot be vertically resized.
+			 */
+			if (try_crop.height != win->w.height)
+				try_crop.width = 768;
+		}
+	} else if (cpu_is_omap34xx()) {
+		/* Check for resizing constraints
+		 * 34xx allow 8x to 1/4x scaling.
+		 */
+		if ((try_crop.height/win->w.height) >= 4) {
+			/* The maximum vertical downsizing ratio is 4:1 */
+			try_crop.height = win->w.height * 4;
+		}
+		if ((try_crop.width/win->w.width) >= 4) {
+			/* The maximum horizontal downsizing ratio is 4:1 */
+			try_crop.width = win->w.width * 4;
+		}
+	}
+	/* update our cropping rectangle and we're done */
+	*crop = try_crop;
+	return 0;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_crop);
+
+/* Given a new format in pix and fbuf,  crop and win
+ * structures are initialized to default values. crop
+ * is initialized to the largest window size that will fit on the display.  The
+ * crop window is centered in the image. win is initialized to
+ * the same size as crop and is centered on the display.
+ * All sizes and offsets are constrained to be even numbers.
+ */
+void omap_vout_new_format(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
+		struct v4l2_window *win)
+{
+	/* crop defines the preview source window in the image capture
+	 * buffer
+	 */
+	omap_vout_default_crop(pix, fbuf, crop);
+
+	/* win defines the preview target window on the display */
+	win->w.width = crop->width;
+	win->w.height = crop->height;
+	win->w.left = ((fbuf->fmt.width - win->w.width) >> 1) & ~1;
+	win->w.top = ((fbuf->fmt.height - win->w.height) >> 1) & ~1;
+}
+EXPORT_SYMBOL_GPL(omap_vout_new_format);
+
+MODULE_AUTHOR("Texas Instruments.");
+MODULE_DESCRIPTION("OMAP Video library");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/omap/omap_voutlib.h b/drivers/media/video/omap/omap_voutlib.h
new file mode 100644
index 0000000..8ef6e25
--- /dev/null
+++ b/drivers/media/video/omap/omap_voutlib.h
@@ -0,0 +1,34 @@
+/*
+ * drivers/media/video/omap/omap_voutlib.h
+ *
+ * Copyright (C) 2009 Texas Instruments.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ *
+ */
+
+#ifndef OMAP_VOUTLIB_H
+#define OMAP_VOUTLIB_H
+
+extern void omap_vout_default_crop(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop);
+
+extern int omap_vout_new_crop(struct v4l2_pix_format *pix,
+		struct v4l2_rect *crop, struct v4l2_window *win,
+		struct v4l2_framebuffer *fbuf,
+		const struct v4l2_rect *new_crop);
+
+extern int omap_vout_try_window(struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win);
+
+extern int omap_vout_new_window(struct v4l2_rect *crop,
+		struct v4l2_window *win, struct v4l2_framebuffer *fbuf,
+		struct v4l2_window *new_win);
+
+extern void omap_vout_new_format(struct v4l2_pix_format *pix,
+		struct v4l2_framebuffer *fbuf, struct v4l2_rect *crop,
+		struct v4l2_window *win);
+#endif	/* #ifndef OMAP_LIB_H */
+
diff --git a/drivers/media/video/omap34xxcam.c b/drivers/media/video/omap34xxcam.c
index b7e0e74..1ae6ab1 100644
--- a/drivers/media/video/omap34xxcam.c
+++ b/drivers/media/video/omap34xxcam.c
@@ -32,32 +32,22 @@
  *
  */
 
-#include <linux/io.h>
-#include <linux/clk.h>
-#include <linux/pci.h>		/* needed for videobufs */
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
 #include <linux/videodev2.h>
 #include <linux/version.h>
-#include <linux/platform_device.h>
+#include <linux/ktime.h>
+#include <asm/pgalloc.h>
 
 #include <media/v4l2-common.h>
 #include <media/v4l2-ioctl.h>
 
 #include "omap34xxcam.h"
 #include "isp/isp.h"
-#include "isp/ispmmu.h"
-#include "isp/ispreg.h"
-#include "isp/ispccdc.h"
-#include "isp/isph3a.h"
-#include "isp/isp_af.h"
-#include "isp/isphist.h"
-#include "isp/isppreview.h"
-#include "isp/ispresizer.h"
 
 #define OMAP34XXCAM_VERSION KERNEL_VERSION(0, 0, 0)
 
+#define to_omap34xxcam_fh(vfh)				\
+	container_of(vfh, struct omap34xxcam_fh, vfh)
+
 /* global variables */
 static struct omap34xxcam_device *omap34xxcam;
 
@@ -77,14 +67,23 @@
 				       int mask)
 {
 	int rval = 0, i = 0;
+	int start, end, dir;
 
 	BUG_ON(!mutex_is_locked(&vdev->mutex));
 
-#ifdef OMAP34XXCAM_POWEROFF_DELAY
-	vdev->power_state_wish = -1;
-#endif
+	if (power != V4L2_POWER_OFF) {
+		/* Sensor has to be powered on first */
+		start = 0;
+		end = OMAP34XXCAM_SLAVE_FLASH;
+		dir = 1;
+	} else {
+		/* Sensor has to be powered off last */
+		start = OMAP34XXCAM_SLAVE_FLASH;
+		end = 0;
+		dir = -1;
+	}
 
-	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
+	for (i = start; i != end + dir; i += dir) {
 		if (vdev->slave[i] == v4l2_int_device_dummy())
 			continue;
 
@@ -105,7 +104,7 @@
 	return 0;
 
 out:
-	for (i--; i >= 0; i--) {
+	for (i -= dir; i != start - dir; i -= dir) {
 		if (vdev->slave[i] == v4l2_int_device_dummy())
 			continue;
 
@@ -119,51 +118,6 @@
 	return rval;
 }
 
-#ifdef OMAP34XXCAM_POWEROFF_DELAY
-static void omap34xxcam_slave_power_work(struct work_struct *work)
-{
-	struct omap34xxcam_videodev *vdev =
-		container_of(work, struct omap34xxcam_videodev, poweroff_work);
-
-	mutex_lock(&vdev->mutex);
-
-	if (vdev->power_state_wish != -1)
-		omap34xxcam_slave_power_set(vdev, vdev->power_state_wish,
-					    vdev->power_state_mask);
-
-	mutex_unlock(&vdev->mutex);
-}
-
-static void omap34xxcam_slave_power_timer(unsigned long ptr)
-{
-	struct omap34xxcam_videodev *vdev = (void *)ptr;
-
-	schedule_work(&vdev->poweroff_work);
-}
-
-/**
- * omap34xxcam_slave_power_suggest - delayed power state change
- *
- * @vdev: per-video device data structure
- * @power: new power state
- */
-static void omap34xxcam_slave_power_suggest(struct omap34xxcam_videodev *vdev,
-					    enum v4l2_power power,
-					    int mask)
-{
-	BUG_ON(!mutex_is_locked(&vdev->mutex));
-
-	del_timer(&vdev->poweroff_timer);
-
-	vdev->power_state_wish = power;
-	vdev->power_state_mask = mask;
-
-	mod_timer(&vdev->poweroff_timer, jiffies + OMAP34XXCAM_POWEROFF_DELAY);
-}
-#else /* OMAP34XXCAM_POWEROFF_DELAY */
-#define omap34xxcam_slave_power_suggest(a, b, c) do {} while (0)
-#endif /* OMAP34XXCAM_POWEROFF_DELAY */
-
 /**
  * omap34xxcam_update_vbq - Updates VBQ with completed input buffer
  * @vb: ptr. to standard V4L2 video buffer structure
@@ -174,10 +128,12 @@
  */
 void omap34xxcam_vbq_complete(struct videobuf_buffer *vb, void *priv)
 {
-	struct omap34xxcam_fh *fh = priv;
+	struct v4l2_fh *vfh = priv;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 
 	do_gettimeofday(&vb->ts);
-	vb->field_count = atomic_add_return(2, &fh->field_count);
+	vb->field_count = atomic_add_return(2, &ofh->field_count);
+	vb->state = VIDEOBUF_DONE;
 
 	wake_up(&vb->done);
 }
@@ -194,8 +150,9 @@
 static int omap34xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
 				 unsigned int *size)
 {
-	struct omap34xxcam_fh *fh = vbq->priv_data;
-	struct omap34xxcam_videodev *vdev = fh->vdev;
+	struct v4l2_fh *vfh = vbq->priv_data;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
 
 	if (*cnt <= 0)
 		*cnt = VIDEO_MAX_FRAME;	/* supply a default number of buffers */
@@ -205,10 +162,65 @@
 
 	*size = vdev->pix.sizeimage;
 
-	while (*size * *cnt > fh->vdev->vdev_sensor_config.capture_mem)
+	while (*size * *cnt > ofh->vdev->vdev_sensor_config.capture_mem)
 		(*cnt)--;
 
-	return isp_vbq_setup(vbq, cnt, size);
+	return isp_vbq_setup(vdev->cam->isp, vbq, cnt, size);
+}
+
+static int omap34xxcam_vb_lock_vma(struct videobuf_buffer *vb, int lock)
+{
+	unsigned long start, end;
+	struct vm_area_struct *vma;
+	int rval = 0;
+
+	if (vb->memory == V4L2_MEMORY_MMAP)
+		return 0;
+
+	if (!current || !current->mm) {
+		/**
+		 * We are called from interrupt or workqueue context.
+		 *
+		 * For locking, we return error.
+		 * For unlocking, the subsequent release of
+		 * buffer should set things right
+		 */
+		if (lock)
+			return -EINVAL;
+		else
+			return 0;
+	}
+
+	end = vb->baddr + vb->bsize;
+
+	down_write(&current->mm->mmap_sem);
+	spin_lock(&current->mm->page_table_lock);
+
+	for (start = vb->baddr; ; ) {
+		unsigned int newflags;
+
+		vma = find_vma(current->mm, start);
+		if (!vma || vma->vm_start > start) {
+				rval = -ENOMEM;
+			goto out;
+		}
+
+		newflags = vma->vm_flags | VM_LOCKED;
+		if (!lock)
+			newflags &= ~VM_LOCKED;
+
+		vma->vm_flags = newflags;
+
+		if (vma->vm_end >= end)
+			break;
+
+		start = vma->vm_end;
+	}
+
+out:
+	spin_unlock(&current->mm->page_table_lock);
+	up_write(&current->mm->mmap_sem);
+	return rval;
 }
 
 /**
@@ -222,8 +234,14 @@
 static void omap34xxcam_vbq_release(struct videobuf_queue *vbq,
 				    struct videobuf_buffer *vb)
 {
+	struct v4l2_fh *vfh = vbq->priv_data;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
+
 	if (!vbq->streaming) {
-		isp_vbq_release(vbq, vb);
+		isp_vbq_release(isp, vbq, vb);
+		omap34xxcam_vb_lock_vma(vb, 0);
 		videobuf_dma_unmap(vbq, videobuf_to_dma(vb));
 		videobuf_dma_free(videobuf_to_dma(vb));
 		vb->state = VIDEOBUF_NEEDS_INIT;
@@ -245,8 +263,11 @@
 				   struct videobuf_buffer *vb,
 				   enum v4l2_field field)
 {
-	struct omap34xxcam_fh *fh = vbq->priv_data;
-	struct omap34xxcam_videodev *vdev = fh->vdev;
+	struct v4l2_fh *vfh = vbq->priv_data;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
+
 	int err = 0;
 
 	/*
@@ -274,13 +295,19 @@
 	vb->field = field;
 
 	if (vb->state == VIDEOBUF_NEEDS_INIT) {
+		err = omap34xxcam_vb_lock_vma(vb, 1);
+		if (err)
+			goto buf_init_err;
+
 		err = videobuf_iolock(vbq, vb, NULL);
-		if (!err) {
-			/* isp_addr will be stored locally inside isp code */
-			err = isp_vbq_prepare(vbq, vb, field);
-		}
+		if (err)
+			goto buf_init_err;
+
+		/* isp_addr will be stored locally inside isp code */
+		err = isp_vbq_prepare(isp, vbq, vb, field);
 	}
 
+buf_init_err:
 	if (!err)
 		vb->state = VIDEOBUF_PREPARED;
 	else
@@ -301,11 +328,12 @@
 static void omap34xxcam_vbq_queue(struct videobuf_queue *vbq,
 				  struct videobuf_buffer *vb)
 {
-	struct omap34xxcam_fh *fh = vbq->priv_data;
+	struct v4l2_fh *vfh = vbq->priv_data;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 
-	vb->state = VIDEOBUF_ACTIVE;
-
-	isp_buf_queue(vb, omap34xxcam_vbq_complete, (void *)fh);
+	isp_buf_queue(isp, vb, omap34xxcam_vbq_complete, (void *)vfh);
 }
 
 static struct videobuf_queue_ops omap34xxcam_vbq_ops = {
@@ -329,10 +357,11 @@
  *
  * Fill in the V4L2 capabliity structure for the camera device
  */
-static int vidioc_querycap(struct file *file, void *fh,
+static int vidioc_querycap(struct file *file, void *_fh,
 			   struct v4l2_capability *cap)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 
 	strlcpy(cap->driver, CAM_SHORT_NAME, sizeof(cap->driver));
@@ -353,10 +382,11 @@
  * Fills in enumerate format capabilities information for sensor (if SOC
  * sensor attached) or ISP (if raw sensor attached).
  */
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *_fh,
 				   struct v4l2_fmtdesc *f)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	int rval;
 
@@ -380,10 +410,11 @@
  * Fills in format capabilities for sensor (if SOC sensor attached) or ISP
  * (if raw sensor attached).
  */
-static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *_fh,
 				struct v4l2_format *f)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 
 	if (vdev->vdev_sensor == v4l2_int_device_dummy())
@@ -405,6 +436,7 @@
 	int fmtd_index;
 	int rval;
 	struct v4l2_pix_format best_pix_out;
+	struct device *isp = vdev->cam->isp;
 
 	if (best_ival->numerator == 0
 	    || best_ival->denominator == 0)
@@ -412,6 +444,8 @@
 
 	fps = best_ival->denominator / best_ival->numerator;
 
+	memset(best_pix_in, 0, sizeof(*best_pix_in));
+
 	best_ival->denominator = 0;
 	best_pix_out.height = INT_MAX >> 1;
 	best_pix_out.width = best_pix_out.height;
@@ -425,8 +459,8 @@
 		rval = vidioc_int_enum_fmt_cap(vdev->vdev_sensor, &fmtd);
 		if (rval)
 			break;
-		dev_info(&vdev->vfd->dev, "trying fmt %8.8x (%d)\n",
-			 fmtd.pixelformat, fmtd_index);
+		dev_dbg(&vdev->vfd->dev, "trying fmt %8.8x (%d)\n",
+			fmtd.pixelformat, fmtd_index);
 		/*
 		 * Get supported resolutions.
 		 */
@@ -447,19 +481,19 @@
 			pix_tmp_in.width = frms.discrete.width;
 			pix_tmp_in.height = frms.discrete.height;
 			pix_tmp_out = *wanted_pix_out;
-			rval = isp_try_fmt_cap(&pix_tmp_in, &pix_tmp_out);
+			rval = isp_try_fmt_cap(isp, &pix_tmp_in, &pix_tmp_out);
 			if (rval)
 				return rval;
 
-			dev_info(&vdev->vfd->dev, "this w %d\th %d\tfmt %8.8x\t"
-				 "-> w %d\th %d\t fmt %8.8x"
-				 "\twanted w %d\th %d\t fmt %8.8x\n",
-				 pix_tmp_in.width, pix_tmp_in.height,
-				 pix_tmp_in.pixelformat,
-				 pix_tmp_out.width, pix_tmp_out.height,
-				 pix_tmp_out.pixelformat,
-				 wanted_pix_out->width, wanted_pix_out->height,
-				 wanted_pix_out->pixelformat);
+			dev_dbg(&vdev->vfd->dev, "this w %d\th %d\tfmt %8.8x\t"
+				"-> w %d\th %d\t fmt %8.8x"
+				"\twanted w %d\th %d\t fmt %8.8x\n",
+				pix_tmp_in.width, pix_tmp_in.height,
+				pix_tmp_in.pixelformat,
+				pix_tmp_out.width, pix_tmp_out.height,
+				pix_tmp_out.pixelformat,
+				wanted_pix_out->width, wanted_pix_out->height,
+				wanted_pix_out->pixelformat);
 
 #define IS_SMALLER_OR_EQUAL(pix1, pix2)				\
 			((pix1)->width + (pix1)->height		\
@@ -474,11 +508,11 @@
 			 */
 			if (SIZE_DIFF(&pix_tmp_out, wanted_pix_out)
 			    > SIZE_DIFF(&best_pix_out, wanted_pix_out)) {
-				dev_info(&vdev->vfd->dev, "size diff bigger: "
-					 "w %d\th %d\tw %d\th %d\n",
-					 pix_tmp_out.width, pix_tmp_out.height,
-					 best_pix_out.width,
-					 best_pix_out.height);
+				dev_dbg(&vdev->vfd->dev, "size diff bigger: "
+					"w %d\th %d\tw %d\th %d\n",
+					pix_tmp_out.width, pix_tmp_out.height,
+					best_pix_out.width,
+					best_pix_out.height);
 				continue;
 			}
 
@@ -490,11 +524,11 @@
 			    < SIZE_DIFF(&best_pix_out, wanted_pix_out)) {
 				/* Force renegotation of fps etc. */
 				best_ival->denominator = 0;
-				dev_info(&vdev->vfd->dev, "renegotiate: "
-					 "w %d\th %d\tw %d\th %d\n",
-					 pix_tmp_out.width, pix_tmp_out.height,
-					 best_pix_out.width,
-					 best_pix_out.height);
+				dev_dbg(&vdev->vfd->dev, "renegotiate: "
+					"w %d\th %d\tw %d\th %d\n",
+					pix_tmp_out.width, pix_tmp_out.height,
+					best_pix_out.width,
+					best_pix_out.height);
 			}
 
 			for (ival_index = 0; ; ival_index++) {
@@ -512,13 +546,16 @@
 				if (rval)
 					break;
 
-				dev_info(&vdev->vfd->dev, "fps %d\n",
-					 frmi.discrete.denominator
-					 / frmi.discrete.numerator);
+				dev_dbg(&vdev->vfd->dev, "fps %d\n",
+					frmi.discrete.denominator
+					/ frmi.discrete.numerator);
 
 				if (best_ival->denominator == 0)
 					goto do_it_now;
 
+				if (best_pix_in->width == 0)
+					goto do_it_now;
+
 				/*
 				 * We aim to use maximum resolution
 				 * from the sensor, provided that the
@@ -530,11 +567,11 @@
 				/* Select mode with closest fps. */
 				if (FPS_ABS_DIFF(fps, frmi.discrete)
 				    < FPS_ABS_DIFF(fps, *best_ival)) {
-					dev_info(&vdev->vfd->dev, "closer fps: "
-						 "fps %d\t fps %d\n",
-						 FPS_ABS_DIFF(fps,
-							      frmi.discrete),
-						 FPS_ABS_DIFF(fps, *best_ival));
+					dev_dbg(&vdev->vfd->dev, "closer fps: "
+						"fps %d\t fps %d\n",
+						FPS_ABS_DIFF(fps,
+							     frmi.discrete),
+						FPS_ABS_DIFF(fps, *best_ival));
 					goto do_it_now;
 				}
 
@@ -546,16 +583,16 @@
 				    > best_pix_in->width + best_pix_in->height
 				    && FPS_ABS_DIFF(fps, frmi.discrete)
 				    <= FPS_ABS_DIFF(fps, *best_ival)) {
-					dev_info(&vdev->vfd->dev, "bigger res, "
-						 "same fps: "
-						 "w %d\th %d\tw %d\th %d\n",
-						 frmi.width, frmi.height,
-						 best_pix_in->width,
-						 best_pix_in->height);
+					dev_dbg(&vdev->vfd->dev, "bigger res, "
+						"same fps: "
+						"w %d\th %d\tw %d\th %d\n",
+						frmi.width, frmi.height,
+						best_pix_in->width,
+						best_pix_in->height);
 					goto do_it_now;
 				}
 
-				dev_info(&vdev->vfd->dev, "falling through\n");
+				dev_dbg(&vdev->vfd->dev, "falling through\n");
 
 				continue;
 
@@ -566,14 +603,14 @@
 				best_pix_in->height = frmi.height;
 				best_pix_in->pixelformat = frmi.pixel_format;
 
-				dev_info(&vdev->vfd->dev,
-					 "best_pix_in: w %d\th %d\tfmt %8.8x"
-					 "\tival %d/%d\n",
-					 best_pix_in->width,
-					 best_pix_in->height,
-					 best_pix_in->pixelformat,
-					 best_ival->numerator,
-					 best_ival->denominator);
+				dev_dbg(&vdev->vfd->dev,
+					"best_pix_in: w %d\th %d\tfmt %8.8x"
+					"\tival %d/%d\n",
+					best_pix_in->width,
+					best_pix_in->height,
+					best_pix_in->pixelformat,
+					best_ival->numerator,
+					best_ival->denominator);
 			}
 		}
 	}
@@ -588,7 +625,7 @@
 		 best_pix_in->pixelformat,
 		 best_pix_out.width, best_pix_out.height);
 
-	return isp_try_fmt_cap(best_pix_in, wanted_pix_out);
+	return 0;
 }
 
 static int s_pix_parm(struct omap34xxcam_videodev *vdev,
@@ -596,20 +633,23 @@
 		      struct v4l2_pix_format *pix,
 		      struct v4l2_fract *best_ival)
 {
+	struct device *isp = vdev->cam->isp;
 	struct v4l2_streamparm a;
 	struct v4l2_format fmt;
+	struct v4l2_format old_fmt;
 	int rval;
 
 	rval = try_pix_parm(vdev, best_pix, pix, best_ival);
 	if (rval)
 		return rval;
 
-	rval = isp_s_fmt_cap(best_pix, pix);
+	rval = isp_s_fmt_cap(isp, best_pix, pix);
 	if (rval)
 		return rval;
 
 	fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
 	fmt.fmt.pix = *best_pix;
+	vidioc_int_g_fmt_cap(vdev->vdev_sensor, &old_fmt);
 	rval = vidioc_int_s_fmt_cap(vdev->vdev_sensor, &fmt);
 	if (rval)
 		return rval;
@@ -630,10 +670,11 @@
  * Attempts to set input format with the sensor driver (first) and then the
  * ISP.  Returns the return code from vidioc_g_fmt_vid_cap().
  */
-static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *_fh,
 				struct v4l2_format *f)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	struct v4l2_pix_format pix_tmp;
 	struct v4l2_fract timeperframe;
@@ -671,10 +712,11 @@
  * Checks if the given format is supported by the sensor driver and
  * by the ISP.
  */
-static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *_fh,
 				  struct v4l2_format *f)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	struct v4l2_pix_format pix_tmp;
 	struct v4l2_fract timeperframe;
@@ -703,10 +745,11 @@
  * Attempts to get a buffer from the buffer queue associated with the
  * fh through the video buffer library API.
  */
-static int vidioc_reqbufs(struct file *file, void *fh,
+static int vidioc_reqbufs(struct file *file, void *_fh,
 			  struct v4l2_requestbuffers *b)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	int rval;
 
@@ -743,9 +786,10 @@
  * Attempts to fill in the v4l2_buffer structure for the buffer queue
  * associated with the fh through the video buffer library API.
  */
-static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
+static int vidioc_querybuf(struct file *file, void *_fh, struct v4l2_buffer *b)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 
 	return videobuf_querybuf(&ofh->vbq, b);
 }
@@ -759,9 +803,10 @@
  * Attempts to queue the v4l2_buffer on the buffer queue
  * associated with the fh through the video buffer library API.
  */
-static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+static int vidioc_qbuf(struct file *file, void *_fh, struct v4l2_buffer *b)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 
 	return videobuf_qbuf(&ofh->vbq, b);
 }
@@ -777,33 +822,45 @@
  * buffer is a user space buffer, then this function will also requeue it,
  * as user does not expect to do this.
  */
-static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
+static int vidioc_dqbuf(struct file *file, void *_fh, struct v4l2_buffer *b)
 {
-	struct omap34xxcam_fh *ofh = fh;
-	int rval;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 
-videobuf_dqbuf_again:
-	rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
-
-	/*
-	 * This is a hack. We don't want to show -EIO to the user
-	 * space. Requeue the buffer and try again if we're not doing
-	 * this in non-blocking mode.
-	 */
-	if (rval == -EIO) {
-		videobuf_qbuf(&ofh->vbq, b);
-		if (!(file->f_flags & O_NONBLOCK))
-			goto videobuf_dqbuf_again;
-		/*
-		 * We don't have a videobuf_buffer now --- maybe next
-		 * time...
-		 */
-		rval = -EAGAIN;
-	}
-
-	return rval;
+	return videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);;
 }
 
+static void omap34xxcam_event_queue(struct omap34xxcam_fh *fh, u32 type)
+{
+	struct v4l2_event event;
+
+	dev_dbg(&fh->vdev->vfd->dev, "event type %8.8x\n", type);
+
+	event.type = type;
+	ktime_get_ts(&event.timestamp);
+
+	v4l2_event_queue(fh->vdev->vfd, &event);
+}
+
+static void omap34xxcam_event_cb(unsigned long status, int (*arg1)
+				 (struct videobuf_buffer *vb), void *arg2)
+{
+	struct v4l2_fh *vfh = (struct v4l2_fh *)arg1;
+	struct omap34xxcam_fh *fh = to_omap34xxcam_fh(vfh);
+
+	if (status & HIST_DONE)
+		omap34xxcam_event_queue(fh, V4L2_EVENT_OMAP3ISP_HIST);
+	if (status & H3A_AWB_DONE)
+		omap34xxcam_event_queue(fh, V4L2_EVENT_OMAP3ISP_AEWB);
+	if (status & H3A_AF_DONE)
+		omap34xxcam_event_queue(fh, V4L2_EVENT_OMAP3ISP_AF);
+	if (status & HS_VS)
+		omap34xxcam_event_queue(fh, V4L2_EVENT_OMAP3ISP_HS_VS);
+
+	wake_up_all(&fh->vdev->poll_event);
+}
+
+
 /**
  * vidioc_streamon - V4L2 streamon IOCTL handler
  * @file: ptr. to system file structure
@@ -814,10 +871,12 @@
  * on video buffer streaming through the video buffer library API.  Upon
  * success the function returns 0, otherwise an error code is returned.
  */
-static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+static int vidioc_streamon(struct file *file, void *_fh, enum v4l2_buf_type i)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 	int rval;
 
 	if (vdev->vdev_sensor == v4l2_int_device_dummy())
@@ -830,19 +889,24 @@
 	}
 
 	rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
-					   OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
+					   OMAP34XXCAM_SLAVE_POWER_ALL);
 	if (rval) {
 		dev_dbg(&vdev->vfd->dev,
 			"omap34xxcam_slave_power_set failed\n");
 		goto out;
 	}
 
+	isp_set_callback(isp, CBK_CATCHALL, omap34xxcam_event_cb,
+			 (void *)vfh, NULL);
+	isp_start(isp);
+
 	rval = videobuf_streamon(&ofh->vbq);
-	if (rval)
+	if (rval) {
+		isp_stop(isp);
 		omap34xxcam_slave_power_set(
-			vdev, V4L2_POWER_OFF,
-			OMAP34XXCAM_SLAVE_POWER_SENSOR_LENS);
-	else
+			vdev, V4L2_POWER_STANDBY,
+			OMAP34XXCAM_SLAVE_POWER_ALL);
+	} else
 		vdev->streaming = file;
 
 out:
@@ -862,26 +926,27 @@
  * off video buffer streaming through the video buffer library API.  Upon
  * success the function returns 0, otherwise an error code is returned.
  */
-static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
+static int vidioc_streamoff(struct file *file, void *_fh, enum v4l2_buf_type i)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 	struct videobuf_queue *q = &ofh->vbq;
 	int rval;
 
 	mutex_lock(&vdev->mutex);
 
 	if (vdev->streaming == file)
-		isp_stop();
+		isp_stop(isp);
 
 	rval = videobuf_streamoff(q);
 	if (!rval) {
+		isp_unset_callback(isp, CBK_CATCHALL);
 		vdev->streaming = NULL;
 
 		omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
-					    OMAP34XXCAM_SLAVE_POWER_SENSOR);
-		omap34xxcam_slave_power_suggest(vdev, V4L2_POWER_STANDBY,
-						OMAP34XXCAM_SLAVE_POWER_LENS);
+					    OMAP34XXCAM_SLAVE_POWER_ALL);
 	}
 
 	mutex_unlock(&vdev->mutex);
@@ -897,7 +962,7 @@
  *
  * Fills in v4l2_input structure.  Returns 0.
  */
-static int vidioc_enum_input(struct file *file, void *fh,
+static int vidioc_enum_input(struct file *file, void *_fh,
 			     struct v4l2_input *inp)
 {
 	if (inp->index > 0)
@@ -917,7 +982,7 @@
  *
  * Sets index to 0.
  */
-static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+static int vidioc_g_input(struct file *file, void *_fh, unsigned int *i)
 {
 	*i = 0;
 
@@ -932,7 +997,7 @@
  *
  * 0 is only index supported.
  */
-static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+static int vidioc_s_input(struct file *file, void *_fh, unsigned int i)
 {
 	if (i > 0)
 		return -EINVAL;
@@ -953,10 +1018,11 @@
  * queried and if it does not support the requested control, the request
  * is forwarded to the "raw" sensor driver to see if it supports it.
  */
-static int vidioc_queryctrl(struct file *file, void *fh,
+static int vidioc_queryctrl(struct file *file, void *_fh,
 			    struct v4l2_queryctrl *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	struct v4l2_queryctrl a_tmp;
 	int best_slave = -1;
@@ -1018,10 +1084,11 @@
  * menu control, the request is forwarded to the "raw" sensor driver to
  * see if it supports it.
  */
-static int vidioc_querymenu(struct file *file, void *fh,
+static int vidioc_querymenu(struct file *file, void *_fh,
 			    struct v4l2_querymenu *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	int i;
 
@@ -1036,11 +1103,13 @@
 	return isp_querymenu(a);
 }
 
-static int vidioc_g_ext_ctrls(struct file *file, void *fh,
+static int vidioc_g_ext_ctrls(struct file *file, void *_fh,
 			      struct v4l2_ext_controls *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 	int i, ctrl_idx, rval = 0;
 
 	mutex_lock(&vdev->mutex);
@@ -1061,7 +1130,7 @@
 		}
 
 		if (rval)
-			rval = isp_g_ctrl(&ctrl);
+			rval = isp_g_ctrl(isp, &ctrl);
 
 		if (rval) {
 			a->error_idx = ctrl_idx;
@@ -1076,11 +1145,13 @@
 	return rval;
 }
 
-static int vidioc_s_ext_ctrls(struct file *file, void *fh,
+static int vidioc_s_ext_ctrls(struct file *file, void *_fh,
 			      struct v4l2_ext_controls *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 	int i, ctrl_idx, rval = 0;
 
 	mutex_lock(&vdev->mutex);
@@ -1102,7 +1173,7 @@
 		}
 
 		if (rval)
-			rval = isp_s_ctrl(&ctrl);
+			rval = isp_s_ctrl(isp, &ctrl);
 
 		if (rval) {
 			a->error_idx = ctrl_idx;
@@ -1126,9 +1197,11 @@
  * If request is for video capture buffer type, handles request by
  * forwarding to sensor driver.
  */
-static int vidioc_g_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+static int vidioc_g_parm(struct file *file, void *_fh,
+			 struct v4l2_streamparm *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	int rval;
 
@@ -1154,9 +1227,11 @@
  * enable the sensor interface with the new parameters.  If this fails, it
  * reverts back to the previous parameters.
  */
-static int vidioc_s_parm(struct file *file, void *fh, struct v4l2_streamparm *a)
+static int vidioc_s_parm(struct file *file, void *_fh,
+			 struct v4l2_streamparm *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	struct v4l2_pix_format pix_tmp_sensor, pix_tmp;
 	int rval;
@@ -1195,9 +1270,10 @@
  * If using a "smart" sensor, just forwards request to the sensor driver,
  * otherwise fills in the v4l2_cropcap values locally.
  */
-static int vidioc_cropcap(struct file *file, void *fh, struct v4l2_cropcap *a)
+static int vidioc_cropcap(struct file *file, void *_fh, struct v4l2_cropcap *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
 	struct v4l2_cropcap *cropcap = a;
 	int rval;
@@ -1211,6 +1287,7 @@
 
 	if (rval && !vdev->vdev_sensor_config.sensor_isp) {
 		struct v4l2_format f;
+		struct v4l2_rect pixel_size;
 
 		/* cropcap failed, try to do this via g_fmt_cap */
 		rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &f);
@@ -1220,8 +1297,30 @@
 			cropcap->bounds.width = f.fmt.pix.width;
 			cropcap->bounds.height = f.fmt.pix.height;
 			cropcap->defrect = cropcap->bounds;
-			cropcap->pixelaspect.numerator = 1;
-			cropcap->pixelaspect.denominator = 1;
+		}
+
+		rval = vidioc_int_priv_g_pixelsize(vdev->vdev_sensor,
+						   &pixel_size);
+		if (!rval) {
+			if (pixel_size.width && pixel_size.height) {
+				/* Normalize value */
+				while (!((pixel_size.width |
+					pixel_size.height) & 0x01)) {
+
+					pixel_size.width >>= 1;
+					pixel_size.height >>= 1;
+				}
+				cropcap->pixelaspect.numerator =
+					pixel_size.width;
+				cropcap->pixelaspect.denominator =
+					pixel_size.height;
+			} else {
+				dev_err(&vdev->vfd->dev, "Sensor return invalid"
+					" result for pixelsize: %d x %d",
+					pixel_size.width, pixel_size.height);
+				cropcap->pixelaspect.numerator = 1;
+				cropcap->pixelaspect.denominator = 1;
+			}
 		}
 	}
 
@@ -1239,10 +1338,12 @@
  * If using a "smart" sensor, just forwards request to the sensor driver,
  * otherwise calls the isp functions to fill in current crop values.
  */
-static int vidioc_g_crop(struct file *file, void *fh, struct v4l2_crop *a)
+static int vidioc_g_crop(struct file *file, void *_fh, struct v4l2_crop *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 	int rval = 0;
 
 	if (vdev->vdev_sensor == v4l2_int_device_dummy())
@@ -1253,7 +1354,7 @@
 	if (vdev->vdev_sensor_config.sensor_isp)
 		rval = vidioc_int_g_crop(vdev->vdev_sensor, a);
 	else
-		rval = isp_g_crop(a);
+		rval = isp_g_crop(isp, a);
 
 	mutex_unlock(&vdev->mutex);
 
@@ -1269,10 +1370,12 @@
  * If using a "smart" sensor, just forwards request to the sensor driver,
  * otherwise calls the isp functions to set the current crop values.
  */
-static int vidioc_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
+static int vidioc_s_crop(struct file *file, void *_fh, struct v4l2_crop *a)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 	int rval = 0;
 
 	if (vdev->vdev_sensor == v4l2_int_device_dummy())
@@ -1283,59 +1386,176 @@
 	if (vdev->vdev_sensor_config.sensor_isp)
 		rval = vidioc_int_s_crop(vdev->vdev_sensor, a);
 	else
-		rval = isp_s_crop(a, &vdev->pix);
+		rval = isp_s_crop(isp, a);
 
 	mutex_unlock(&vdev->mutex);
 
 	return rval;
 }
 
-static int vidioc_enum_framesizes(struct file *file, void *fh,
+static int vidioc_enum_framesizes(struct file *file, void *_fh,
 				  struct v4l2_frmsizeenum *frms)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct v4l2_pix_format pix_in;
+	struct v4l2_pix_format pix_out;
+	struct v4l2_fract ival;
 	u32 pixel_format;
 	int rval;
 
+	if (vdev->vdev_sensor == v4l2_int_device_dummy())
+		return -EINVAL;
+
 	mutex_lock(&vdev->mutex);
 
 	if (vdev->vdev_sensor_config.sensor_isp) {
 		rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
-	} else {
-		pixel_format = frms->pixel_format;
-		frms->pixel_format = -1;	/* ISP does format conversion */
-		rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
-		frms->pixel_format = pixel_format;
+		goto done;
 	}
 
+	pixel_format = frms->pixel_format;
+	frms->pixel_format = -1;	/* ISP does format conversion */
+	rval = vidioc_int_enum_framesizes(vdev->vdev_sensor, frms);
+	frms->pixel_format = pixel_format;
+
+	if (rval < 0)
+		goto done;
+
+	/* Let the ISP pipeline mangle the frame size as it sees fit. */
+	memset(&pix_out, 0, sizeof(pix_out));
+	pix_out.width = frms->discrete.width;
+	pix_out.height = frms->discrete.height;
+	pix_out.pixelformat = frms->pixel_format;
+
+	ival = vdev->want_timeperframe;
+	rval = try_pix_parm(vdev, &pix_in, &pix_out, &ival);
+	if (rval < 0)
+		goto done;
+
+	frms->discrete.width = pix_out.width;
+	frms->discrete.height = pix_out.height;
+
+done:
 	mutex_unlock(&vdev->mutex);
 	return rval;
 }
 
-static int vidioc_enum_frameintervals(struct file *file, void *fh,
+static int vidioc_enum_frameintervals(struct file *file, void *_fh,
 				      struct v4l2_frmivalenum *frmi)
 {
-	struct omap34xxcam_fh *ofh = fh;
+	struct v4l2_fh *vfh = _fh;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct v4l2_frmsizeenum frms;
+	unsigned int frmi_width;
+	unsigned int frmi_height;
+	unsigned int uninitialized_var(width);
+	unsigned int uninitialized_var(height);
+	unsigned int max_dist;
+	unsigned int dist;
 	u32 pixel_format;
+	unsigned int i;
 	int rval;
 
 	mutex_lock(&vdev->mutex);
 
 	if (vdev->vdev_sensor_config.sensor_isp) {
 		rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
-	} else {
-		pixel_format = frmi->pixel_format;
-		frmi->pixel_format = -1;	/* ISP does format conversion */
-		rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
-		frmi->pixel_format = pixel_format;
+		goto done;
 	}
 
+	/*
+	 * Frame size enumeration returned sizes mangled by the ISP.
+	 * We can't pass the size directly to the sensor for frame
+	 * interval enumeration, as they will not be recognized by the
+	 * sensor driver. Enumerate the native sensor sizes and select
+	 * the one closest to the requested size.
+	 */
+
+	for (i = 0, max_dist = (unsigned int)-1; ; ++i) {
+		frms.index = i;
+		frms.pixel_format = -1;
+		rval = vidioc_int_enum_framesizes(vdev->vdev_sensor,
+			&frms);
+		if (rval < 0)
+			break;
+
+		/*
+		 * The distance between frame sizes is the size in
+		 * pixels of the non-overlapping regions.
+		 */
+		dist = min(frms.discrete.width, frmi->width)
+		     * min(frms.discrete.height, frmi->height);
+		dist = frms.discrete.width * frms.discrete.height
+		     + frmi->width * frmi->height
+		     - 2*dist;
+
+		if (dist < max_dist) {
+			width = frms.discrete.width;
+			height = frms.discrete.height;
+			max_dist = dist;
+		}
+	}
+
+	if (max_dist == (unsigned int)-1) {
+		rval = -EINVAL;
+		goto done;
+	}
+
+	pixel_format = frmi->pixel_format;
+	frmi_width = frmi->width;
+	frmi_height = frmi->height;
+
+	frmi->pixel_format = -1;	/* ISP does format conversion */
+	frmi->width = width;
+	frmi->height = height;
+	rval = vidioc_int_enum_frameintervals(vdev->vdev_sensor, frmi);
+
+	frmi->pixel_format = pixel_format;
+	frmi->height = frmi_height;
+	frmi->width = frmi_width;
+
+done:
 	mutex_unlock(&vdev->mutex);
 	return rval;
 }
 
+
+int vidioc_dqevent(struct v4l2_fh *vfh, struct v4l2_event *ev)
+{
+	return v4l2_event_dequeue(&vfh->events, ev);
+}
+
+int vidioc_subscribe_event(struct v4l2_fh *vfh,
+			   struct v4l2_event_subscription *sub)
+{
+	struct omap34xxcam_fh *fh = to_omap34xxcam_fh(vfh);
+
+	switch (sub->type) {
+	case V4L2_EVENT_OMAP3ISP_AF:
+	case V4L2_EVENT_OMAP3ISP_AEWB:
+	case V4L2_EVENT_OMAP3ISP_HIST:
+	case V4L2_EVENT_OMAP3ISP_HS_VS:
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return v4l2_event_subscribe(&fh->vfh.events, sub);
+}
+
+int vidioc_unsubscribe_event(struct v4l2_fh *vfh,
+			     struct v4l2_event_subscription *sub)
+{
+	struct omap34xxcam_fh *fh = to_omap34xxcam_fh(vfh);
+
+	v4l2_event_unsubscribe(&fh->vfh.events, sub);
+
+	return 0;
+}
+
 /**
  * vidioc_default - private IOCTL handler
  * @file: ptr. to system file structure
@@ -1350,12 +1570,54 @@
  * feedback. The request is then passed on to the ISP private IOCTL handler,
  * isp_handle_private()
  */
-static long vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+static long vidioc_default(struct file *file, void *_fh, int cmd, void *arg)
 {
-	struct omap34xxcam_fh *ofh = file->private_data;
+	struct v4l2_fh *vfh = file->private_data;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
 	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 	int rval;
 
+	if (cmd == VIDIOC_PRIVATE_OMAP34XXCAM_SENSOR_INFO) {
+		u32 pixclk;
+		struct v4l2_rect active_size, full_size, pixel_size;
+		struct omap34xxcam_sensor_info *ret_sensor_info;
+
+		ret_sensor_info = (struct omap34xxcam_sensor_info *)arg;
+		mutex_lock(&vdev->mutex);
+		rval = vidioc_int_priv_g_pixclk(vdev->vdev_sensor, &pixclk);
+		mutex_unlock(&vdev->mutex);
+		if (rval)
+			goto out;
+		mutex_lock(&vdev->mutex);
+		rval = vidioc_int_priv_g_activesize(vdev->vdev_sensor,
+					    &active_size);
+		mutex_unlock(&vdev->mutex);
+		if (rval)
+			goto out;
+		mutex_lock(&vdev->mutex);
+		rval = vidioc_int_priv_g_fullsize(vdev->vdev_sensor,
+						  &full_size);
+		mutex_unlock(&vdev->mutex);
+		if (rval)
+			goto out;
+		mutex_lock(&vdev->mutex);
+		rval = vidioc_int_priv_g_pixelsize(vdev->vdev_sensor,
+						  &pixel_size);
+		mutex_unlock(&vdev->mutex);
+		if (rval)
+			goto out;
+		ret_sensor_info->current_xclk = pixclk;
+		memcpy(&ret_sensor_info->active_size, &active_size,
+			sizeof(struct v4l2_rect));
+		memcpy(&ret_sensor_info->full_size, &full_size,
+			sizeof(struct v4l2_rect));
+		memcpy(&ret_sensor_info->pixel_size, &pixel_size,
+			sizeof(struct v4l2_rect));
+		rval = 0;
+		goto out;
+	}
+
 	if (vdev->vdev_sensor_config.sensor_isp) {
 		rval = -EINVAL;
 	} else {
@@ -1421,9 +1683,7 @@
 			break;
 		}
 
-		mutex_lock(&vdev->mutex);
-		rval = isp_handle_private(cmd, arg);
-		mutex_unlock(&vdev->mutex);
+		rval = isp_handle_private(isp, &vdev->mutex, cmd, arg);
 	}
 out:
 	return rval;
@@ -1444,31 +1704,29 @@
 static unsigned int omap34xxcam_poll(struct file *file,
 				     struct poll_table_struct *wait)
 {
-	struct omap34xxcam_fh *fh = file->private_data;
-	struct omap34xxcam_videodev *vdev = fh->vdev;
-	struct videobuf_buffer *vb;
+	struct v4l2_fh *vfh = file->private_data;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+	unsigned int ret = 0;
 
-	mutex_lock(&vdev->mutex);
-	if (vdev->streaming != file) {
-		mutex_unlock(&vdev->mutex);
-		return POLLERR;
+	poll_wait(file, &ofh->vdev->poll_event, wait);
+
+	if (v4l2_event_pending(&vfh->events))
+		ret |= POLLPRI;
+
+	poll_wait(file, &ofh->poll_vb, wait);
+
+	mutex_lock(&ofh->vbq.vb_lock);
+	if (!list_empty(&ofh->vbq.stream)) {
+		struct videobuf_buffer *vb =
+			list_entry(ofh->vbq.stream.next,
+				   struct videobuf_buffer, stream);
+		if (vb->state == VIDEOBUF_DONE
+		    || vb->state == VIDEOBUF_ERROR)
+			ret |= POLLIN | POLLRDNORM;
 	}
-	mutex_unlock(&vdev->mutex);
+	mutex_unlock(&ofh->vbq.vb_lock);
 
-	mutex_lock(&fh->vbq.vb_lock);
-	if (list_empty(&fh->vbq.stream)) {
-		mutex_unlock(&fh->vbq.vb_lock);
-		return POLLERR;
-	}
-	vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
-	mutex_unlock(&fh->vbq.vb_lock);
-
-	poll_wait(file, &vb->done, wait);
-
-	if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
-		return POLLIN | POLLRDNORM;
-
-	return 0;
+	return ret;
 }
 
 /**
@@ -1480,8 +1738,10 @@
  */
 static int omap34xxcam_mmap(struct file *file, struct vm_area_struct *vma)
 {
-	struct omap34xxcam_fh *fh = file->private_data;
-	return videobuf_mmap_mapper(&fh->vbq, vma);
+	struct v4l2_fh *vfh = file->private_data;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+
+	return videobuf_mmap_mapper(&ofh->vbq, vma);
 }
 
 /**
@@ -1502,9 +1762,11 @@
 {
 	int rval = 0;
 	struct omap34xxcam_videodev *vdev = NULL;
+	struct omap34xxcam_fh *ofh;
 	struct omap34xxcam_device *cam = omap34xxcam;
-	struct omap34xxcam_fh *fh;
-	struct v4l2_format format;
+	struct device *isp;
+	struct v4l2_format sensor_format;
+	int first_user = 0;
 	int i;
 
 	for (i = 0; i < OMAP34XXCAM_VIDEODEVS; i++) {
@@ -1519,10 +1781,17 @@
 	if (!vdev || !vdev->vfd)
 		return -ENODEV;
 
-	fh = kzalloc(sizeof(*fh), GFP_KERNEL);
-	if (fh == NULL)
+	ofh = kzalloc(sizeof(*ofh), GFP_KERNEL);
+	if (ofh == NULL)
 		return -ENOMEM;
 
+	if (v4l2_fh_add(vdev->vfd, &ofh->vfh)) {
+		rval = -ENOMEM;
+		goto out_v4l2_fh_add;
+	}
+
+	ofh->vdev = vdev;
+
 	mutex_lock(&vdev->mutex);
 	for (i = 0; i <= OMAP34XXCAM_SLAVE_FLASH; i++) {
 		if (vdev->slave[i] != v4l2_int_device_dummy()
@@ -1536,56 +1805,62 @@
 	}
 
 	if (atomic_inc_return(&vdev->users) == 1) {
-		rval = isp_get();
-		if (rval < 0) {
+		first_user = 1;
+		isp = isp_get();
+		if (!isp) {
+			rval = -EBUSY;
 			dev_err(&vdev->vfd->dev, "can't get isp\n");
 			goto out_isp_get;
 		}
-		if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
+		cam->isp = isp;
+		if (omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
 						OMAP34XXCAM_SLAVE_POWER_ALL)) {
 			dev_err(&vdev->vfd->dev, "can't power up slaves\n");
 			rval = -EBUSY;
 			goto out_slave_power_set_standby;
 		}
-		omap34xxcam_slave_power_set(
-			vdev, V4L2_POWER_STANDBY,
-			OMAP34XXCAM_SLAVE_POWER_SENSOR);
-		omap34xxcam_slave_power_suggest(
-			vdev, V4L2_POWER_STANDBY,
-			OMAP34XXCAM_SLAVE_POWER_LENS);
 	}
 
-	fh->vdev = vdev;
+	if (vdev->vdev_sensor == v4l2_int_device_dummy() || !first_user)
+		goto out_no_pix;
 
-	if (!vdev->pix.width
-	    && vdev->vdev_sensor != v4l2_int_device_dummy()) {
-		memset(&format, 0, sizeof(format));
-		if (vidioc_int_g_fmt_cap(vdev->vdev_sensor, &format)) {
+	/* Get the format the sensor is using. */
+	rval = vidioc_int_g_fmt_cap(vdev->vdev_sensor, &sensor_format);
+	if (rval) {
+		dev_err(&vdev->vfd->dev,
+			"can't get current pix from sensor!\n");
+		goto out_vidioc_int_g_fmt_cap;
+	}
+
+	if (!vdev->pix.width)
+		vdev->pix = sensor_format.fmt.pix;
+
+	if (!vdev->vdev_sensor_config.sensor_isp) {
+		struct v4l2_pix_format pix;
+		struct v4l2_fract timeperframe =
+			vdev->want_timeperframe;
+
+		rval = s_pix_parm(vdev, &pix, &vdev->pix, &timeperframe);
+		if (rval) {
 			dev_err(&vdev->vfd->dev,
-				"can't get current pix from sensor!\n");
-			goto out_vidioc_int_g_fmt_cap;
+				"isp doesn't like the sensor!\n");
+			goto out_isp_s_fmt_cap;
 		}
-		if (!vdev->vdev_sensor_config.sensor_isp) {
-			struct v4l2_pix_format pix = format.fmt.pix;
-			if (isp_s_fmt_cap(&pix, &format.fmt.pix)) {
-				dev_err(&vdev->vfd->dev,
-					"isp doesn't like the sensor!\n");
-				goto out_isp_s_fmt_cap;
-			}
-		}
-		vdev->pix = format.fmt.pix;
 	}
 
+out_no_pix:
 	mutex_unlock(&vdev->mutex);
 
-	file->private_data = fh;
+	file->private_data = &ofh->vfh;
 
-	spin_lock_init(&fh->vbq_lock);
+	spin_lock_init(&ofh->vbq_lock);
 
-	videobuf_queue_sg_init(&fh->vbq, &omap34xxcam_vbq_ops, NULL,
-				&fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
-				V4L2_FIELD_NONE,
-				sizeof(struct videobuf_buffer), fh);
+	videobuf_queue_sg_init(&ofh->vbq, &omap34xxcam_vbq_ops, NULL,
+			       &ofh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+			       V4L2_FIELD_NONE,
+			       sizeof(struct videobuf_buffer), &ofh->vfh);
+
+	init_waitqueue_head(&ofh->poll_vb);
 
 	return 0;
 
@@ -1605,7 +1880,10 @@
 		if (vdev->slave[i] != v4l2_int_device_dummy())
 			module_put(vdev->slave[i]->module);
 
-	kfree(fh);
+out_v4l2_fh_add:
+	v4l2_fh_del(vdev->vfd, &ofh->vfh);
+
+	kfree(ofh);
 
 	return rval;
 }
@@ -1625,20 +1903,19 @@
  */
 static int omap34xxcam_release(struct file *file)
 {
-	struct omap34xxcam_fh *fh = file->private_data;
-	struct omap34xxcam_videodev *vdev = fh->vdev;
+	struct v4l2_fh *vfh = file->private_data;
+	struct omap34xxcam_fh *ofh = to_omap34xxcam_fh(vfh);
+	struct omap34xxcam_videodev *vdev = ofh->vdev;
+	struct device *isp = vdev->cam->isp;
 	int i;
 
 	mutex_lock(&vdev->mutex);
 	if (vdev->streaming == file) {
-		isp_stop();
-		videobuf_streamoff(&fh->vbq);
-		omap34xxcam_slave_power_set(
-			vdev, V4L2_POWER_STANDBY,
-			OMAP34XXCAM_SLAVE_POWER_SENSOR);
-		omap34xxcam_slave_power_suggest(
-			vdev, V4L2_POWER_STANDBY,
-			OMAP34XXCAM_SLAVE_POWER_LENS);
+		isp_stop(isp);
+		videobuf_streamoff(&ofh->vbq);
+		isp_unset_callback(isp, CBK_CATCHALL);
+		omap34xxcam_slave_power_set(vdev, V4L2_POWER_STANDBY,
+					    OMAP34XXCAM_SLAVE_POWER_ALL);
 		vdev->streaming = NULL;
 	}
 
@@ -1655,7 +1932,9 @@
 		if (vdev->slave[i] != v4l2_int_device_dummy())
 			module_put(vdev->slave[i]->module);
 
-	kfree(fh);
+	v4l2_fh_del(vdev->vfd, vfh);
+
+	kfree(ofh);
 
 	return 0;
 }
@@ -1752,6 +2031,9 @@
 	.vidioc_s_crop			= vidioc_s_crop,
 	.vidioc_enum_framesizes		= vidioc_enum_framesizes,
 	.vidioc_enum_frameintervals	= vidioc_enum_frameintervals,
+	.vidioc_dqevent			= vidioc_dqevent,
+	.vidioc_subscribe_event		= vidioc_subscribe_event,
+	.vidioc_unsubscribe_event	= vidioc_unsubscribe_event,
 	.vidioc_default			= vidioc_default,
 };
 
@@ -1771,6 +2053,7 @@
 {
 	struct omap34xxcam_videodev *vdev = s->u.slave->master->priv;
 	struct omap34xxcam_hw_config hwc;
+	struct device *isp;
 	int rval;
 
 	/* We need to check rval just once. The place is here. */
@@ -1799,17 +2082,18 @@
 	vdev->slave_config[hwc.dev_type] = hwc;
 
 	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
-		rval = isp_get();
-		if (rval < 0) {
+		isp = isp_get();
+		if (!isp) {
+			rval = -EBUSY;
 			printk(KERN_ERR "%s: can't get ISP, "
 			       "sensor init failed\n", __func__);
 			goto err;
 		}
+		vdev->cam->isp = isp;
 	}
-	rval = omap34xxcam_slave_power_set(vdev, V4L2_POWER_ON,
-					   1 << hwc.dev_type);
+	rval = vidioc_int_dev_init(s);
 	if (rval)
-		goto err_omap34xxcam_slave_power_set;
+		goto err_omap34xxcam_slave_init;
 	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR) {
 		struct v4l2_format format;
 
@@ -1824,11 +2108,10 @@
 	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
 		isp_put();
 
-	if (rval)
-		goto err;
-
 	/* Are we the first slave? */
 	if (vdev->slaves == 1) {
+		init_waitqueue_head(&vdev->poll_event);
+
 		/* initialize the video_device struct */
 		vdev->vfd = video_device_alloc();
 		if (!vdev->vfd) {
@@ -1859,7 +2142,7 @@
 
 	return 0;
 
-err_omap34xxcam_slave_power_set:
+err_omap34xxcam_slave_init:
 	if (hwc.dev_type == OMAP34XXCAM_SLAVE_SENSOR)
 		isp_put();
 
@@ -1936,11 +2219,6 @@
 		vdev->vdev_sensor =
 			vdev->vdev_lens =
 			vdev->vdev_flash = v4l2_int_device_dummy();
-#ifdef OMAP34XXCAM_POWEROFF_DELAY
-		setup_timer(&vdev->poweroff_timer,
-			    omap34xxcam_slave_power_timer, (unsigned long)vdev);
-		INIT_WORK(&vdev->poweroff_work, omap34xxcam_slave_power_work);
-#endif /* OMAP34XXCAM_POWEROFF_DELAY */
 
 		if (v4l2_int_device_register(m))
 			goto err;
diff --git a/drivers/media/video/omap34xxcam.h b/drivers/media/video/omap34xxcam.h
index 9859d15..72ff434 100644
--- a/drivers/media/video/omap34xxcam.h
+++ b/drivers/media/video/omap34xxcam.h
@@ -36,13 +36,12 @@
 #define OMAP34XXCAM_H
 
 #include <media/v4l2-int-device.h>
+#include <media/v4l2-fh.h>
 #include "isp/isp.h"
 
 #define CAM_NAME			"omap34xxcam"
 #define CAM_SHORT_NAME			"omap3"
 
-#define OMAP_ISP_AF     	(1 << 4)
-#define OMAP_ISP_HIST   	(1 << 5)
 #define OMAP34XXCAM_XCLK_NONE	-1
 #define OMAP34XXCAM_XCLK_A	0
 #define OMAP34XXCAM_XCLK_B	1
@@ -61,13 +60,16 @@
 
 #define OMAP34XXCAM_VIDEODEVS		4
 
-/* #define OMAP34XXCAM_POWEROFF_DELAY (2 * HZ) */
-
 struct omap34xxcam_device;
 struct omap34xxcam_videodev;
 
+/**
+ * struct omap34xxcam_sensor_config - struct for vidioc_int_g_priv ioctl
+ * @sensor_isp: Is sensor smart/SOC or raw
+ * @capture_mem: Size limit to mmap buffers.
+ * @ival_default: Default frame interval for sensor.
+ */
 struct omap34xxcam_sensor_config {
-	int xclk;
 	int sensor_isp;
 	u32 capture_mem;
 	struct v4l2_fract ival_default;
@@ -79,13 +81,6 @@
 struct omap34xxcam_flash_config {
 };
 
-/**
- * struct omap34xxcam_hw_config - struct for vidioc_int_g_priv ioctl
- * @xclk: OMAP34XXCAM_XCLK_A or OMAP34XXCAM_XCLK_B
- * @sensor_isp: Is sensor smart/SOC or raw
- * @s_pix_sparm: Access function to set pix and sparm.
- * Pix will override sparm
- */
 struct omap34xxcam_hw_config {
 	int dev_index; /* Index in omap34xxcam_sensors */
 	int dev_minor; /* Video device minor number */
@@ -107,8 +102,6 @@
  * @flash: flash device
  * @slaves: how many slaves we have at the moment
  * @vfd: our video device
- * @capture_mem: maximum kernel-allocated capture memory
- * @if_u: sensor interface stuff
  * @index: index of this structure in cam->vdevs
  * @users: how many users we have
  * @power_state: Current power state
@@ -119,10 +112,10 @@
  * @sensor_config: ISP-speicific sensor configuration
  * @lens_config: ISP-speicific lens configuration
  * @flash_config: ISP-speicific flash configuration
+ * @streaming: streaming file handle, if streaming is enabled
  * @want_timeperframe: Desired timeperframe
  * @want_pix: Desired pix
  * @pix: Current pix
- * @streaming: streaming file handle, if streaming is enabled
  */
 struct omap34xxcam_videodev {
 	struct mutex mutex; /* serialises access to this structure */
@@ -140,54 +133,32 @@
 
 	/*** video device parameters ***/
 	struct video_device *vfd;
-	int capture_mem;
 
 	/*** general driver state information ***/
 	int index;
 	atomic_t users;
 	enum v4l2_power power_state[OMAP34XXCAM_SLAVE_FLASH + 1];
-#ifdef OMAP34XXCAM_POWEROFF_DELAY
-	enum v4l2_power power_state_wish;
-	int power_state_mask;
-	struct timer_list poweroff_timer;
-	struct work_struct poweroff_work;
-#endif /* OMAP34XXCAM_POWEROFF_DELAY */
-
 #define vdev_sensor_config slave_config[OMAP34XXCAM_SLAVE_SENSOR].u.sensor
 #define vdev_lens_config slave_config[OMAP34XXCAM_SLAVE_LENS].u.lens
 #define vdev_flash_config slave_config[OMAP34XXCAM_SLAVE_FLASH].u.flash
 	struct omap34xxcam_hw_config slave_config[OMAP34XXCAM_SLAVE_FLASH + 1];
 
+	wait_queue_head_t poll_event;
+
 	/*** capture data ***/
 	struct file *streaming;
 	struct v4l2_fract want_timeperframe;
 	struct v4l2_pix_format want_pix;
-	spinlock_t pix_lock;
 	struct v4l2_pix_format pix;
 };
 
 /**
  * struct omap34xxcam_device - per-device data structure
- * @mutex: mutex serialises access to this structure
- * @sgdma_in_queue: Number or sgdma requests in scatter-gather queue,
- * protected by the lock above.
- * @sgdma: ISP sgdma subsystem information structure
- * @dma_notify: DMA notify flag
- * @dev: device structure
  * @vdevs: /dev/video specific structures
- * @fck: camera module fck clock information
- * @ick: camera module ick clock information
  */
 struct omap34xxcam_device {
-	struct mutex mutex; /* serialises access to this structure */
-
-	/*** interfaces and device ***/
 	struct omap34xxcam_videodev vdevs[OMAP34XXCAM_VIDEODEVS];
-
-	/*** camera module clocks ***/
-	struct clk *fck;
-	struct clk *ick;
-	bool sensor_if_enabled;
+	struct device *isp;
 };
 
 /**
@@ -199,9 +170,11 @@
  */
 struct omap34xxcam_fh {
 	spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+	struct v4l2_fh vfh;
 	struct videobuf_queue vbq;
 	atomic_t field_count;
 	struct omap34xxcam_videodev *vdev;
+	wait_queue_head_t poll_vb;
 };
 
 #endif /* ifndef OMAP34XXCAM_H */
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 110376b..032b232 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -1049,6 +1049,9 @@
 	case VIDIOC_DBG_G_CHIP_IDENT:
 	case VIDIOC_G_CHIP_IDENT_OLD:
 	case VIDIOC_S_HW_FREQ_SEEK:
+	case VIDIOC_DQEVENT:
+	case VIDIOC_SUBSCRIBE_EVENT:
+	case VIDIOC_UNSUBSCRIBE_EVENT:
 		ret = do_video_ioctl(file, cmd, arg);
 		break;
 
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 13f87c2..36de838 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -373,6 +373,10 @@
 	if (!vdev || !vdev->release)
 		return -EINVAL;
 
+	ret = v4l2_fh_init(vdev);
+	if (ret < 0)
+		return ret;
+
 	/* Part 1: check device type */
 	switch (type) {
 	case VFL_TYPE_GRABBER:
@@ -511,6 +515,7 @@
 	return 0;
 
 cleanup:
+	v4l2_fh_exit(vdev);
 	mutex_lock(&videodev_lock);
 	if (vdev->cdev)
 		cdev_del(vdev->cdev);
@@ -565,6 +570,8 @@
 		return -EIO;
 	}
 
+	v4l2_event_init();
+
 	return 0;
 }
 
@@ -572,6 +579,8 @@
 {
 	dev_t dev = MKDEV(VIDEO_MAJOR, 0);
 
+	v4l2_event_exit();
+
 	class_unregister(&video_class);
 	unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
 }
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
new file mode 100644
index 0000000..5d8d259
--- /dev/null
+++ b/drivers/media/video/v4l2-event.c
@@ -0,0 +1,250 @@
+/*
+ * drivers/media/video/v4l2-event.c
+ *
+ * V4L2 events.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus at maxwell.research.nokia.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-event.h>
+
+#include <linux/sched.h>
+
+static struct kmem_cache *event_kmem;
+
+int v4l2_event_init(void)
+{
+	event_kmem = kmem_cache_create("event_kmem",
+				       sizeof(struct _v4l2_event), 0,
+				       SLAB_HWCACHE_ALIGN,
+				       NULL);
+
+	if (!event_kmem)
+		return -ENOMEM;
+
+	return 0;
+}
+
+void v4l2_event_exit(void)
+{
+	if (!event_kmem)
+		kmem_cache_destroy(event_kmem);
+
+	event_kmem = NULL;
+}
+
+void v4l2_event_init_fh(struct v4l2_events *events)
+{
+	init_waitqueue_head(&events->wait);
+	spin_lock_init(&events->lock);
+
+	INIT_LIST_HEAD(&events->available);
+	INIT_LIST_HEAD(&events->subscribed);
+
+	atomic_set(&events->navailable, 0);
+	events->sequence = 0;
+};
+
+void v4l2_event_del(struct v4l2_events *events)
+{
+	while (!list_empty(&events->available)) {
+		struct _v4l2_event *ev;
+
+		ev = list_entry(events->available.next,
+				struct _v4l2_event, list);
+
+		list_del(&ev->list);
+
+		kmem_cache_free(event_kmem, ev);
+	}
+
+	while (!list_empty(&events->subscribed)) {
+		struct v4l2_subscribed_event *sub;
+
+		sub = list_entry(events->subscribed.next,
+				struct v4l2_subscribed_event, list);
+
+		list_del(&sub->list);
+
+		kfree(sub);
+	}
+}
+
+int v4l2_event_dequeue(struct v4l2_events *events, struct v4l2_event *event)
+{
+	struct _v4l2_event *ev;
+	int ret = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&events->lock, flags);
+
+	if (list_empty(&events->available)) {
+		spin_unlock_irqrestore(&events->lock, flags);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	ev = list_first_entry(&events->available, struct _v4l2_event, list);
+	list_del(&ev->list);
+
+	atomic_dec(&events->navailable);
+	ev->event.count = atomic_read(&events->navailable);
+
+	spin_unlock_irqrestore(&events->lock, flags);
+
+	memcpy(event, &ev->event, sizeof(ev->event));
+
+	kmem_cache_free(event_kmem, ev);
+
+out:
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
+
+static struct v4l2_subscribed_event *__v4l2_event_subscribed(
+	struct v4l2_events *events, u32 type)
+{
+	struct v4l2_subscribed_event *ev;
+
+	list_for_each_entry(ev, &events->subscribed, list) {
+		if (ev->type == type)
+			return ev;
+	}
+
+	return NULL;
+}
+
+struct v4l2_subscribed_event *v4l2_event_subscribed(
+	struct v4l2_events *events, u32 type)
+{
+	struct v4l2_subscribed_event *ev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&events->lock, flags);
+
+	ev = __v4l2_event_subscribed(events, type);
+
+	spin_unlock_irqrestore(&events->lock, flags);
+
+	return ev;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_subscribed);
+
+void v4l2_event_queue(struct video_device *vdev, struct v4l2_event *ev)
+{
+	struct v4l2_fh *fh;
+	unsigned long flags;
+
+	spin_lock_irqsave(&vdev->fh_lock, flags);
+
+	list_for_each_entry(fh, &vdev->fh, list) {
+		struct _v4l2_event *_ev;
+
+		if (atomic_read(&fh->events.navailable) >= V4L2_MAX_EVENTS)
+			continue;
+
+		if (!v4l2_event_subscribed(&fh->events, ev->type))
+			continue;
+
+		_ev = kmem_cache_alloc(event_kmem, GFP_ATOMIC);
+		if (!_ev)
+			continue;
+
+		_ev->event = *ev;
+
+		spin_lock(&fh->events.lock);
+		_ev->event.sequence = fh->events.sequence;
+		fh->events.sequence++;
+		list_add_tail(&_ev->list, &fh->events.available);
+		spin_unlock(&fh->events.lock);
+
+		atomic_inc(&fh->events.navailable);
+
+		wake_up_all(&fh->events.wait);
+	}
+
+	spin_unlock_irqrestore(&vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_event_queue);
+
+int v4l2_event_pending(struct v4l2_events *events)
+{
+	unsigned long flags;
+	int ret;
+
+	spin_lock_irqsave(&events->lock, flags);
+	ret = !list_empty(&events->available);
+	spin_unlock_irqrestore(&events->lock, flags);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_pending);
+
+int v4l2_event_subscribe(struct v4l2_events *events,
+			 struct v4l2_event_subscription *sub)
+{
+	int ret = 0;
+	unsigned long flags;
+	struct v4l2_subscribed_event *ev;
+
+	ev = kmalloc(sizeof(*ev), GFP_KERNEL);
+	if (!ev)
+		return -ENOMEM;
+
+	spin_lock_irqsave(&events->lock, flags);
+
+	if (__v4l2_event_subscribed(events, sub->type) != NULL) {
+		ret = -EBUSY;
+		goto out;
+	}
+
+	INIT_LIST_HEAD(&ev->list);
+	ev->type = sub->type;
+
+	list_add(&ev->list, &events->subscribed);
+
+out:
+	spin_unlock_irqrestore(&events->lock, flags);
+
+	if (ret)
+		kfree(ev);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_subscribe);
+
+int v4l2_event_unsubscribe(struct v4l2_events *events,
+			   struct v4l2_event_subscription *sub)
+{
+	struct v4l2_subscribed_event *ev;
+	unsigned long flags;
+
+	spin_lock_irqsave(&events->lock, flags);
+
+	ev = __v4l2_event_subscribed(events, sub->type);
+
+	if (ev != NULL)
+		list_del(&ev->list);
+
+	spin_unlock_irqrestore(&events->lock, flags);
+
+	return ev == NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_event_unsubscribe);
diff --git a/drivers/media/video/v4l2-fh.c b/drivers/media/video/v4l2-fh.c
new file mode 100644
index 0000000..ee2abb1
--- /dev/null
+++ b/drivers/media/video/v4l2-fh.c
@@ -0,0 +1,68 @@
+/*
+ * drivers/media/video/v4l2-fh.c
+ *
+ * V4L2 file handles.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus at maxwell.research.nokia.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-fh.h>
+
+#include <linux/sched.h>
+#include <linux/vmalloc.h>
+
+int v4l2_fh_add(struct video_device *vdev, struct v4l2_fh *fh)
+{
+	unsigned long flags;
+
+	v4l2_event_init_fh(&fh->events);
+
+	spin_lock_irqsave(&vdev->fh_lock, flags);
+	list_add(&fh->list, &vdev->fh);
+	spin_unlock_irqrestore(&vdev->fh_lock, flags);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_add);
+
+void v4l2_fh_del(struct video_device *vdev, struct v4l2_fh *fh)
+{
+	unsigned long flags;
+
+	v4l2_event_del(&fh->events);
+
+	spin_lock_irqsave(&vdev->fh_lock, flags);
+	list_del(&fh->list);
+	spin_unlock_irqrestore(&vdev->fh_lock, flags);
+}
+EXPORT_SYMBOL_GPL(v4l2_fh_del);
+
+int v4l2_fh_init(struct video_device *vdev)
+{
+	spin_lock_init(&vdev->fh_lock);
+	INIT_LIST_HEAD(&vdev->fh);
+
+	return 0;
+}
+
+void v4l2_fh_exit(struct video_device *vdev)
+{
+}
+
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 52d687b..31b90a0 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -268,6 +268,9 @@
 
 	[_IOC_NR(VIDIOC_DBG_G_CHIP_IDENT)] = "VIDIOC_DBG_G_CHIP_IDENT",
 	[_IOC_NR(VIDIOC_S_HW_FREQ_SEEK)]   = "VIDIOC_S_HW_FREQ_SEEK",
+	[_IOC_NR(VIDIOC_DQEVENT)]	   = "VIDIOC_DQEVENT",
+	[_IOC_NR(VIDIOC_SUBSCRIBE_EVENT)]  = "VIDIOC_SUBSCRIBE_EVENT",
+	[_IOC_NR(VIDIOC_UNSUBSCRIBE_EVENT)] = "VIDIOC_UNSUBSCRIBE_EVENT",
 #endif
 };
 #define V4L2_IOCTLS ARRAY_SIZE(v4l2_ioctls)
@@ -1837,7 +1840,55 @@
 		}
 		break;
 	}
+	case VIDIOC_DQEVENT:
+	{
+		struct v4l2_event *ev = arg;
 
+		if (!ops->vidioc_dqevent)
+			break;
+
+		ret = ops->vidioc_dqevent(file->private_data, ev);
+		if (ret < 0) {
+			dbgarg(cmd, "no pending events?");
+			break;
+		}
+		dbgarg(cmd,
+		       "count=%d, type=0x%08x, sequence=%d, "
+		       "timestamp=%lu.%09lu ",
+		       ev->count, ev->type, ev->sequence,
+		       ev->timestamp.tv_sec, ev->timestamp.tv_nsec);
+		break;
+	}
+	case VIDIOC_SUBSCRIBE_EVENT:
+	{
+		struct v4l2_event_subscription *sub = arg;
+
+		if (!ops->vidioc_subscribe_event)
+			break;
+
+		ret = ops->vidioc_subscribe_event(file->private_data, sub);
+		if (ret < 0) {
+			dbgarg(cmd, "failed, ret=%ld", ret);
+			break;
+		}
+		dbgarg(cmd, "type=0x%8.8x", sub->type);
+		break;
+	}
+	case VIDIOC_UNSUBSCRIBE_EVENT:
+	{
+		struct v4l2_event_subscription *sub = arg;
+
+		if (!ops->vidioc_unsubscribe_event)
+			break;
+
+		ret = ops->vidioc_unsubscribe_event(file->private_data, sub);
+		if (ret < 0) {
+			dbgarg(cmd, "failed, ret=%ld", ret);
+			break;
+		}
+		dbgarg(cmd, "type=0x%8.8x", sub->type);
+		break;
+	}
 	default:
 	{
 		if (!ops->vidioc_default)
diff --git a/drivers/mfd/twl4030-core.c b/drivers/mfd/twl4030-core.c
index 769b34b..2db2f19 100644
--- a/drivers/mfd/twl4030-core.c
+++ b/drivers/mfd/twl4030-core.c
@@ -756,6 +756,7 @@
 	int				status;
 	unsigned			i;
 	struct twl4030_platform_data	*pdata = client->dev.platform_data;
+	u8 temp;
 
 	if (!pdata) {
 		dev_dbg(&client->dev, "no platform data?\n");
@@ -810,6 +811,16 @@
 			goto fail;
 	}
 
+	/* Disable GAIA I2C Pull-up on I2C1 and I2C4(SR) interface
+	 * Program I2C_SCL_CTRL_PU(bit 0)=0, I2C_SDA_CTRL_PU (bit 2)=0,
+	 * SR_I2C_SCL_CTRL_PU(bit 4)=0 and SR_I2C_SDA_CTRL_PU(bit 6)=0.
+	 */
+
+	twl4030_i2c_read_u8(TWL4030_MODULE_INTBR, &temp, REG_GPPUPDCTR1);
+	temp &= ~(SR_I2C_SDA_CTRL_PU | SR_I2C_SCL_CTRL_PU | \
+				I2C_SDA_CTRL_PU | I2C_SCL_CTRL_PU);
+	twl4030_i2c_write_u8(TWL4030_MODULE_INTBR, temp, REG_GPPUPDCTR1);
+
 	status = add_children(pdata, id->driver_data);
 fail:
 	if (status < 0)
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 07e40dc..d17a844 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -184,7 +184,7 @@
 					R_P2_SW_EVENTS);
 
 	if (machine_is_omap_3430sdp() || machine_is_omap_ldp() ||
-	    machine_is_omap_zoom2()) {
+	    machine_is_omap_zoom2() || machine_is_omap_zoom3()) {
 		u8 data;
 		/* Disabling AC charger effect on sleep-active transitions */
 		err |= twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &data,
@@ -331,6 +331,56 @@
 	return err;
 }
 
+int twl4030_remove_script(u8 flags)
+{
+	int err;
+
+	err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_1,
+			R_PROTECT_KEY);
+	if (err) {
+		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
+		return err;
+	}
+
+	err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, KEY_2,
+			R_PROTECT_KEY);
+	if (err) {
+		pr_err("twl4030: unable to unlock PROTECT_KEY\n");
+		return err;
+	}
+
+	if (flags & TRITON_WRST_SCRIPT) {
+		err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+				END_OF_SCRIPT, R_SEQ_ADD_WARM);
+		if (err)
+			return err;
+	}
+	if (flags & TRITON_WAKEUP12_SCRIPT) {
+		err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+				END_OF_SCRIPT, R_SEQ_ADD_SA12);
+		if (err)
+			return err;
+	}
+	if (flags & TRITON_WAKEUP3_SCRIPT) {
+		err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+				END_OF_SCRIPT, R_SEQ_ADD_S2A3);
+		if (err)
+			return err;
+	}
+	if (flags & TRITON_SLEEP_SCRIPT) {
+		err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER,
+				END_OF_SCRIPT, R_SEQ_ADD_A2S);
+		if (err)
+			return err;
+	}
+
+	err = twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, R_PROTECT_KEY);
+	if (err)
+		pr_err("TWL4030 Unable to relock registers\n");
+
+	return 0;
+}
+
 void __init twl4030_power_init(struct twl4030_power_data *triton2_scripts)
 {
 	int err = 0;
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index f023fa1..7d4f2dc 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -260,7 +260,26 @@
 	 Creates an rfkill entry in sysfs for power control of Bluetooth
 	 TI wl127x chips.
 
+config APANIC
+	bool "Android kernel panic diagnostics driver"
+	default n
+	---help---
+	 Driver which handles kernel panics and attempts to write
+	 critical debugging data to flash.
+
+config APANIC_PLABEL
+	string "Android panic dump flash partition label"
+	default "kpanic"
+	---help---
+	 If your platform uses a different flash partition label for storing
+ 	 crashdumps, enter it here.
+
+config BUILD_TI_ST
+         tristate "Build option for BT shared Transport driver"
+         default n
+
 source "drivers/misc/c2port/Kconfig"
 source "drivers/misc/eeprom/Kconfig"
+source "drivers/misc/ti-st/Kconfig"
 
 endif # MISC_DEVICES
diff --git a/drivers/misc/Makefile b/drivers/misc/Makefile
index c09735a..dffdff3 100644
--- a/drivers/misc/Makefile
+++ b/drivers/misc/Makefile
@@ -25,3 +25,5 @@
 obj-$(CONFIG_C2PORT)		+= c2port/
 obj-y				+= eeprom/
 obj-$(CONFIG_WL127X_RFKILL)	+= wl127x-rfkill.o
+obj-$(CONFIG_APANIC)		+= apanic.o
+obj-y				+= ti-st/
diff --git a/drivers/misc/apanic.c b/drivers/misc/apanic.c
new file mode 100644
index 0000000..ca875f8
--- /dev/null
+++ b/drivers/misc/apanic.c
@@ -0,0 +1,606 @@
+/* drivers/misc/apanic.c
+ *
+ * Copyright (C) 2009 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.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/types.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <linux/wakelock.h>
+#include <linux/platform_device.h>
+#include <linux/uaccess.h>
+#include <linux/mtd/mtd.h>
+#include <linux/notifier.h>
+#include <linux/mtd/mtd.h>
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/proc_fs.h>
+#include <linux/mutex.h>
+#include <linux/workqueue.h>
+#include <linux/preempt.h>
+
+extern void ram_console_enable_console(int);
+
+struct panic_header {
+	u32 magic;
+#define PANIC_MAGIC 0xdeadf00d
+
+	u32 version;
+#define PHDR_VERSION   0x01
+
+	u32 console_offset;
+	u32 console_length;
+
+	u32 threads_offset;
+	u32 threads_length;
+};
+
+struct apanic_data {
+	struct mtd_info		*mtd;
+	struct panic_header	curr;
+	void			*bounce;
+	struct proc_dir_entry	*apanic_console;
+	struct proc_dir_entry	*apanic_threads;
+};
+
+static struct apanic_data drv_ctx;
+static struct work_struct proc_removal_work;
+static DEFINE_MUTEX(drv_mutex);
+
+static unsigned int *apanic_bbt;
+static unsigned int apanic_erase_blocks;
+static unsigned int apanic_good_blocks;
+
+static void set_bb(unsigned int block, unsigned int *bbt)
+{
+	unsigned int flag = 1;
+
+	BUG_ON(block >= apanic_erase_blocks);
+
+	flag = flag << (block%32);
+	apanic_bbt[block/32] |= flag;
+	apanic_good_blocks--;
+}
+
+static unsigned int get_bb(unsigned int block, unsigned int *bbt)
+{
+	unsigned int flag;
+
+	BUG_ON(block >= apanic_erase_blocks);
+
+	flag = 1 << (block%32);
+	return apanic_bbt[block/32] & flag;
+}
+
+static void alloc_bbt(struct mtd_info *mtd, unsigned int *bbt)
+{
+	int bbt_size;
+	apanic_erase_blocks = (mtd->size)>>(mtd->erasesize_shift);
+	bbt_size = (apanic_erase_blocks+32)/32;
+
+	apanic_bbt = kmalloc(bbt_size*4, GFP_KERNEL);
+	memset(apanic_bbt, 0, bbt_size*4);
+	apanic_good_blocks = apanic_erase_blocks;
+}
+static void scan_bbt(struct mtd_info *mtd, unsigned int *bbt)
+{
+	int i;
+
+	for (i = 0; i < apanic_erase_blocks; i++) {
+		if (mtd->block_isbad(mtd, i*mtd->erasesize))
+			set_bb(i, apanic_bbt);
+	}
+}
+
+#define APANIC_INVALID_OFFSET 0xFFFFFFFF
+
+static unsigned int phy_offset(struct mtd_info *mtd, unsigned int offset)
+{
+	unsigned int logic_block = offset>>(mtd->erasesize_shift);
+	unsigned int phy_block;
+	unsigned good_block = 0;
+
+	for (phy_block = 0; phy_block < apanic_erase_blocks; phy_block++) {
+		if (!get_bb(phy_block, apanic_bbt))
+			good_block++;
+		if (good_block == (logic_block + 1))
+			break;
+	}
+
+	if (good_block != (logic_block + 1))
+		return APANIC_INVALID_OFFSET;
+
+	return offset + ((phy_block-logic_block)<<mtd->erasesize_shift);
+}
+
+static void apanic_erase_callback(struct erase_info *done)
+{
+	wait_queue_head_t *wait_q = (wait_queue_head_t *) done->priv;
+	wake_up(wait_q);
+}
+
+static int apanic_proc_read(char *buffer, char **start, off_t offset,
+			       int count, int *peof, void *dat)
+{
+	struct apanic_data *ctx = &drv_ctx;
+	size_t file_length;
+	off_t file_offset;
+	unsigned int page_no;
+	off_t page_offset;
+	int rc;
+	size_t len;
+
+	if (!count)
+		return 0;
+
+	mutex_lock(&drv_mutex);
+
+	switch ((int) dat) {
+	case 1:	/* apanic_console */
+		file_length = ctx->curr.console_length;
+		file_offset = ctx->curr.console_offset;
+		break;
+	case 2:	/* apanic_threads */
+		file_length = ctx->curr.threads_length;
+		file_offset = ctx->curr.threads_offset;
+		break;
+	default:
+		pr_err("Bad dat (%d)\n", (int) dat);
+		mutex_unlock(&drv_mutex);
+		return -EINVAL;
+	}
+
+	if ((offset + count) > file_length) {
+		mutex_unlock(&drv_mutex);
+		return 0;
+	}
+
+	/* We only support reading a maximum of a flash page */
+	if (count > ctx->mtd->writesize)
+		count = ctx->mtd->writesize;
+
+	page_no = (file_offset + offset) / ctx->mtd->writesize;
+	page_offset = (file_offset + offset) % ctx->mtd->writesize;
+
+
+	if (phy_offset(ctx->mtd, (page_no * ctx->mtd->writesize))
+		== APANIC_INVALID_OFFSET) {
+		pr_err("apanic: reading an invalid address\n");
+		mutex_unlock(&drv_mutex);
+		return -EINVAL;
+	}
+	rc = ctx->mtd->read(ctx->mtd,
+		phy_offset(ctx->mtd, (page_no * ctx->mtd->writesize)),
+		ctx->mtd->writesize,
+		&len, ctx->bounce);
+
+	if (page_offset)
+		count -= page_offset;
+	memcpy(buffer, ctx->bounce + page_offset, count);
+
+	*start = count;
+
+	if ((offset + count) == file_length)
+		*peof = 1;
+
+	mutex_unlock(&drv_mutex);
+	return count;
+}
+
+static void mtd_panic_erase(void)
+{
+	struct apanic_data *ctx = &drv_ctx;
+	struct erase_info erase;
+	DECLARE_WAITQUEUE(wait, current);
+	wait_queue_head_t wait_q;
+	int rc, i;
+
+	init_waitqueue_head(&wait_q);
+	erase.mtd = ctx->mtd;
+	erase.callback = apanic_erase_callback;
+	erase.len = ctx->mtd->erasesize;
+	erase.priv = (u_long)&wait_q;
+	for (i = 0; i < ctx->mtd->size; i += ctx->mtd->erasesize) {
+		erase.addr = i;
+		set_current_state(TASK_INTERRUPTIBLE);
+		add_wait_queue(&wait_q, &wait);
+
+		if (get_bb(erase.addr>>ctx->mtd->erasesize_shift, apanic_bbt)) {
+			printk(KERN_WARNING
+			       "apanic: Skipping erase of bad "
+			       "block @%llx\n", erase.addr);
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&wait_q, &wait);
+			continue;
+		}
+
+		rc = ctx->mtd->erase(ctx->mtd, &erase);
+		if (rc) {
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&wait_q, &wait);
+			printk(KERN_ERR
+			       "apanic: Erase of 0x%llx, 0x%llx failed\n",
+			       (unsigned long long) erase.addr,
+			       (unsigned long long) erase.len);
+			if (rc == -EIO) {
+				if (ctx->mtd->block_markbad(ctx->mtd,
+							    erase.addr)) {
+					printk(KERN_ERR
+					       "apanic: Err marking blk bad\n");
+					goto out;
+				}
+				printk(KERN_INFO
+				       "apanic: Marked a bad block"
+				       " @%llx\n", erase.addr);
+				set_bb(erase.addr>>ctx->mtd->erasesize_shift,
+					apanic_bbt);
+				continue;
+			}
+			goto out;
+		}
+		schedule();
+		remove_wait_queue(&wait_q, &wait);
+	}
+	printk(KERN_DEBUG "apanic: %s partition erased\n",
+	       CONFIG_APANIC_PLABEL);
+out:
+	return;
+}
+
+static void apanic_remove_proc_work(struct work_struct *work)
+{
+	struct apanic_data *ctx = &drv_ctx;
+
+	mutex_lock(&drv_mutex);
+	mtd_panic_erase();
+	memset(&ctx->curr, 0, sizeof(struct panic_header));
+	if (ctx->apanic_console) {
+		remove_proc_entry("apanic_console", NULL);
+		ctx->apanic_console = NULL;
+	}
+	if (ctx->apanic_threads) {
+		remove_proc_entry("apanic_threads", NULL);
+		ctx->apanic_threads = NULL;
+	}
+	mutex_unlock(&drv_mutex);
+}
+
+static int apanic_proc_write(struct file *file, const char __user *buffer,
+				unsigned long count, void *data)
+{
+	schedule_work(&proc_removal_work);
+	return count;
+}
+
+static void mtd_panic_notify_add(struct mtd_info *mtd)
+{
+	struct apanic_data *ctx = &drv_ctx;
+	struct panic_header *hdr = ctx->bounce;
+	size_t len;
+	int rc;
+	int    proc_entry_created = 0;
+
+	if (strcmp(mtd->name, CONFIG_APANIC_PLABEL))
+		return;
+
+	ctx->mtd = mtd;
+
+	alloc_bbt(mtd, apanic_bbt);
+	scan_bbt(mtd, apanic_bbt);
+
+	if (apanic_good_blocks == 0) {
+		printk(KERN_ERR "apanic: no any good blocks?!\n");
+		goto out_err;
+	}
+
+	rc = mtd->read(mtd, phy_offset(mtd, 0), mtd->writesize,
+			&len, ctx->bounce);
+	if (rc && rc == -EBADMSG) {
+		printk(KERN_WARNING
+		       "apanic: Bad ECC on block 0 (ignored)\n");
+	} else if (rc && rc != -EUCLEAN) {
+		printk(KERN_ERR "apanic: Error reading block 0 (%d)\n", rc);
+		goto out_err;
+	}
+
+	if (len != mtd->writesize) {
+		printk(KERN_ERR "apanic: Bad read size (%d)\n", rc);
+		goto out_err;
+	}
+
+	printk(KERN_INFO "apanic: Bound to mtd partition '%s'\n", mtd->name);
+
+	if (hdr->magic != PANIC_MAGIC) {
+		printk(KERN_INFO "apanic: No panic data available\n");
+		mtd_panic_erase();
+		return;
+	}
+
+	if (hdr->version != PHDR_VERSION) {
+		printk(KERN_INFO "apanic: Version mismatch (%d != %d)\n",
+		       hdr->version, PHDR_VERSION);
+		mtd_panic_erase();
+		return;
+	}
+
+	memcpy(&ctx->curr, hdr, sizeof(struct panic_header));
+
+	printk(KERN_INFO "apanic: c(%u, %u) t(%u, %u)\n",
+	       hdr->console_offset, hdr->console_length,
+	       hdr->threads_offset, hdr->threads_length);
+
+	if (hdr->console_length) {
+		ctx->apanic_console = create_proc_entry("apanic_console",
+						      S_IFREG | S_IRUGO, NULL);
+		if (!ctx->apanic_console)
+			printk(KERN_ERR "%s: failed creating procfile\n",
+			       __func__);
+		else {
+			ctx->apanic_console->read_proc = apanic_proc_read;
+			ctx->apanic_console->write_proc = apanic_proc_write;
+			ctx->apanic_console->size = hdr->console_length;
+			ctx->apanic_console->data = (void *) 1;
+			proc_entry_created = 1;
+		}
+	}
+
+	if (hdr->threads_length) {
+		ctx->apanic_threads = create_proc_entry("apanic_threads",
+						       S_IFREG | S_IRUGO, NULL);
+		if (!ctx->apanic_threads)
+			printk(KERN_ERR "%s: failed creating procfile\n",
+			       __func__);
+		else {
+			ctx->apanic_threads->read_proc = apanic_proc_read;
+			ctx->apanic_threads->write_proc = apanic_proc_write;
+			ctx->apanic_threads->size = hdr->threads_length;
+			ctx->apanic_threads->data = (void *) 2;
+			proc_entry_created = 1;
+		}
+	}
+
+	if (!proc_entry_created)
+		mtd_panic_erase();
+
+	return;
+out_err:
+	ctx->mtd = NULL;
+}
+
+static void mtd_panic_notify_remove(struct mtd_info *mtd)
+{
+	struct apanic_data *ctx = &drv_ctx;
+	if (mtd == ctx->mtd) {
+		ctx->mtd = NULL;
+		printk(KERN_INFO "apanic: Unbound from %s\n", mtd->name);
+	}
+}
+
+static struct mtd_notifier mtd_panic_notifier = {
+	.add	= mtd_panic_notify_add,
+	.remove	= mtd_panic_notify_remove,
+};
+
+static int in_panic = 0;
+
+static int apanic_writeflashpage(struct mtd_info *mtd, loff_t to,
+				 const u_char *buf)
+{
+	int rc;
+	size_t wlen;
+	int panic = in_interrupt() | in_atomic();
+
+	if (panic && !mtd->panic_write) {
+		printk(KERN_EMERG "%s: No panic_write available\n", __func__);
+		return 0;
+	} else if (!panic && !mtd->write) {
+		printk(KERN_EMERG "%s: No write available\n", __func__);
+		return 0;
+	}
+
+	to = phy_offset(mtd, to);
+	if (to == APANIC_INVALID_OFFSET) {
+		printk(KERN_EMERG "apanic: write to invalid address\n");
+		return 0;
+	}
+
+	if (panic)
+		rc = mtd->panic_write(mtd, to, mtd->writesize, &wlen, buf);
+	else
+		rc = mtd->write(mtd, to, mtd->writesize, &wlen, buf);
+
+	if (rc) {
+		printk(KERN_EMERG
+		       "%s: Error writing data to flash (%d)\n",
+		       __func__, rc);
+		return rc;
+	}
+
+	return wlen;
+}
+
+extern int log_buf_copy(char *dest, int idx, int len);
+extern void log_buf_clear(void);
+
+/*
+ * Writes the contents of the console to the specified offset in flash.
+ * Returns number of bytes written
+ */
+static int apanic_write_console(struct mtd_info *mtd, unsigned int off)
+{
+	struct apanic_data *ctx = &drv_ctx;
+	int saved_oip;
+	int idx = 0;
+	int rc, rc2;
+	unsigned int last_chunk = 0;
+
+	while (!last_chunk) {
+		saved_oip = oops_in_progress;
+		oops_in_progress = 1;
+		rc = log_buf_copy(ctx->bounce, idx, mtd->writesize);
+		if (rc < 0)
+			break;
+
+		if (rc != mtd->writesize)
+			last_chunk = rc;
+
+		oops_in_progress = saved_oip;
+		if (rc <= 0)
+			break;
+		if (rc != mtd->writesize)
+			memset(ctx->bounce + rc, 0, mtd->writesize - rc);
+
+		rc2 = apanic_writeflashpage(mtd, off, ctx->bounce);
+		if (rc2 <= 0) {
+			printk(KERN_EMERG
+			       "apanic: Flash write failed (%d)\n", rc2);
+			return idx;
+		}
+		if (!last_chunk)
+			idx += rc2;
+		else
+			idx += last_chunk;
+		off += rc2;
+	}
+	return idx;
+}
+
+static int apanic(struct notifier_block *this, unsigned long event,
+			void *ptr)
+{
+	struct apanic_data *ctx = &drv_ctx;
+	struct panic_header *hdr = (struct panic_header *) ctx->bounce;
+	int console_offset = 0;
+	int console_len = 0;
+	int threads_offset = 0;
+	int threads_len = 0;
+	int rc;
+
+	if (in_panic)
+		return NOTIFY_DONE;
+	in_panic = 1;
+#ifdef CONFIG_PREEMPT
+	/* Ensure that cond_resched() won't try to preempt anybody */
+	add_preempt_count(PREEMPT_ACTIVE);
+#endif
+	touch_softlockup_watchdog();
+
+	if (!ctx->mtd)
+		goto out;
+
+	if (ctx->curr.magic) {
+		printk(KERN_EMERG "Crash partition in use!\n");
+		goto out;
+	}
+	console_offset = ctx->mtd->writesize;
+
+	/*
+	 * Write out the console
+	 */
+	console_len = apanic_write_console(ctx->mtd, console_offset);
+	if (console_len < 0) {
+		printk(KERN_EMERG "Error writing console to panic log! (%d)\n",
+		       console_len);
+		console_len = 0;
+	}
+
+	/*
+	 * Write out all threads
+	 */
+	threads_offset = ALIGN(console_offset + console_len,
+			       ctx->mtd->writesize);
+	if (!threads_offset)
+		threads_offset = ctx->mtd->writesize;
+
+	ram_console_enable_console(0);
+
+	log_buf_clear();
+	show_state_filter(0);
+	threads_len = apanic_write_console(ctx->mtd, threads_offset);
+	if (threads_len < 0) {
+		printk(KERN_EMERG "Error writing threads to panic log! (%d)\n",
+		       threads_len);
+		threads_len = 0;
+	}
+
+	/*
+	 * Finally write the panic header
+	 */
+	memset(ctx->bounce, 0, PAGE_SIZE);
+	hdr->magic = PANIC_MAGIC;
+	hdr->version = PHDR_VERSION;
+
+	hdr->console_offset = console_offset;
+	hdr->console_length = console_len;
+
+	hdr->threads_offset = threads_offset;
+	hdr->threads_length = threads_len;
+
+	rc = apanic_writeflashpage(ctx->mtd, 0, ctx->bounce);
+	if (rc <= 0) {
+		printk(KERN_EMERG "apanic: Header write failed (%d)\n",
+		       rc);
+		goto out;
+	}
+
+	printk(KERN_EMERG "apanic: Panic dump sucessfully written to flash\n");
+
+ out:
+#ifdef CONFIG_PREEMPT
+	sub_preempt_count(PREEMPT_ACTIVE);
+#endif
+	in_panic = 0;
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block panic_blk = {
+	.notifier_call	= apanic,
+};
+
+static int panic_dbg_get(void *data, u64 *val)
+{
+	apanic(NULL, 0, NULL);
+	return 0;
+}
+
+static int panic_dbg_set(void *data, u64 val)
+{
+	BUG();
+	return -1;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(panic_dbg_fops, panic_dbg_get, panic_dbg_set, "%llu\n");
+
+int __init apanic_init(void)
+{
+	register_mtd_user(&mtd_panic_notifier);
+	atomic_notifier_chain_register(&panic_notifier_list, &panic_blk);
+	debugfs_create_file("apanic", 0644, NULL, NULL, &panic_dbg_fops);
+	memset(&drv_ctx, 0, sizeof(drv_ctx));
+	drv_ctx.bounce = (void *) __get_free_page(GFP_KERNEL);
+	INIT_WORK(&proc_removal_work, apanic_remove_proc_work);
+	printk(KERN_INFO "Android kernel panic handler initialized (bind=%s)\n",
+	       CONFIG_APANIC_PLABEL);
+	return 0;
+}
+
+module_init(apanic_init);
diff --git a/drivers/misc/pmem.c b/drivers/misc/pmem.c
index ec7db34..55c4de8 100644
--- a/drivers/misc/pmem.c
+++ b/drivers/misc/pmem.c
@@ -795,7 +795,7 @@
 
 	id = get_id(file);
 	data = (struct pmem_data *)file->private_data;
-	if (!pmem[id].cached)
+	if (!pmem[id].cached || file->f_flags & O_SYNC)
 		return;
 
 	down_read(&data->sem);
diff --git a/drivers/misc/ti-st/Kconfig b/drivers/misc/ti-st/Kconfig
new file mode 100644
index 0000000..25c8203
--- /dev/null
+++ b/drivers/misc/ti-st/Kconfig
@@ -0,0 +1,39 @@
+#
+# TI's shared transport line discipline and the protocol
+# drivers (BT, FM and GPS)
+#
+menu "Texas Instruments shared transport line discipline"
+    config TI_ST
+    tristate "shared transport core driver"
+    select FW_LOADER
+    help
+        This enables the shared transport core driver for TI
+	    BT / FM and GPS combo chips.This enables protocol drivers
+	    to register themselves with core and send data, the responses
+	    are returned to relevant protocol drivers based on their
+	    packet types.
+
+    config TI_ST_BT
+    tristate "BlueZ bluetooth driver for ST"
+    select BT
+    select TI_ST
+    help
+       This enables the Bluetooth driver for TI BT/FM/GPS combo devices
+       This makes use of shared transport line discipline core driver to
+       communicate with the BT core of the combo chip.
+
+     config TI_ST_FM
+     tristate "fm driver for ST"
+     select TI_ST
+     help
+        This enables the FM driver for TI BT/FM/GPS combo devices
+        This makes use of shared transport line discipline core driver to
+        communicate with the FM core of the combo chip.
+   config TI_ST_GPS
+   tristate "GPS driver for ST"
+   select TI_ST
+   help
+       This enables the GPS driver for TI BT/FM/GPS combo devices
+       It will provide a character device for TI GPS Host software to access
+       GPS functionality of Connectivity chip via ST driver
+endmenu
diff --git a/drivers/misc/ti-st/Makefile b/drivers/misc/ti-st/Makefile
new file mode 100644
index 0000000..0a33069
--- /dev/null
+++ b/drivers/misc/ti-st/Makefile
@@ -0,0 +1,10 @@
+#
+# Makefile for TI's shared transport line discipline
+# and it's protocol drivers (BT, FM, GPS)
+#
+obj-$(CONFIG_TI_ST) += st_drv.o
+st_drv-objs			:= st_core.o st_kim.o st_ll.o
+obj-$(CONFIG_TI_ST_BT) += bt_drv.o
+obj-$(CONFIG_TI_ST_FM) += fm_drv.o
+fm_drv-objs     := fmdrv_core.o fmdrv_v4l2.o fmdrv_st.o fmdrv_mixer.o fmdrv_chr.o
+obj-$(CONFIG_TI_ST_GPS) += gps_drv.o
diff --git a/drivers/misc/ti-st/bt_drv.c b/drivers/misc/ti-st/bt_drv.c
new file mode 100644
index 0000000..b8984f2
--- /dev/null
+++ b/drivers/misc/ti-st/bt_drv.c
@@ -0,0 +1,502 @@
+/*
+ *  Texas Instrument's Bluetooth Driver For Shared Transport.
+ *
+ *  Bluetooth Driver acts as interface between HCI CORE and
+ *  TI Shared Transport Layer.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+
+#include "st.h"
+#include "bt_drv.h"
+
+/* Define this macro to get debug msg */
+#undef DEBUG
+
+#ifdef DEBUG
+#define BT_DRV_DBG(fmt, arg...)  printk(KERN_INFO "(btdrv):"fmt"\n" , ## arg)
+#define BTDRV_API_START()        printk(KERN_INFO "(btdrv): %s Start\n", \
+	__func__)
+#define BTDRV_API_EXIT(errno)    printk(KERN_INFO "(btdrv): %s Exit(%d)\n", \
+	__func__, errno)
+#else
+#define BT_DRV_DBG(fmt, arg...)
+#define BTDRV_API_START()
+#define BTDRV_API_EXIT(errno)
+#endif
+
+#define BT_DRV_ERR(fmt, arg...)  printk(KERN_ERR "(btdrv):"fmt"\n" , ## arg)
+
+static int reset;
+static struct hci_st *hst;
+
+/* Increments HCI counters based on pocket ID (cmd,acl,sco) */
+static inline void hci_st_tx_complete(struct hci_st *hst, int pkt_type)
+{
+	struct hci_dev *hdev;
+
+	BTDRV_API_START();
+
+	hdev = hst->hdev;
+
+	/* Update HCI stat counters */
+	switch (pkt_type) {
+	case HCI_COMMAND_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+
+	case HCI_ACLDATA_PKT:
+		hdev->stat.acl_tx++;
+		break;
+
+	case HCI_SCODATA_PKT:
+		hdev->stat.cmd_tx++;
+		break;
+	}
+
+	BTDRV_API_EXIT(0);
+}
+
+/* ------- Interfaces to Shared Transport ------ */
+
+/* Called by ST layer to indicate protocol registration completion
+ * status.hci_st_open() function will wait for signal from this
+ * API when st_register() function returns ST_PENDING.
+ */
+static void hci_st_registration_completion_cb(char data)
+{
+	BTDRV_API_START();
+
+	/* hci_st_open() function needs value of 'data' to know
+	 * the registration status(success/fail),So have a back
+	 * up of it.
+	 */
+	hst->streg_cbdata = data;
+
+	/* Got a feedback from ST for BT driver registration
+	 * request.Wackup hci_st_open() function to continue
+	 * it's open operation.
+	 */
+	complete(&hst->wait_for_btdrv_reg_completion);
+
+	BTDRV_API_EXIT(0);
+}
+
+/* Called by Shared Transport layer when receive data is
+ * available */
+static long hci_st_receive(struct sk_buff *skb)
+{
+	int err;
+	int len;
+
+	BTDRV_API_START();
+
+	err = 0;
+	len = 0;
+
+	if (skb == NULL) {
+		BT_DRV_ERR("Invalid SKB received from ST");
+		BTDRV_API_EXIT(-EFAULT);
+		return -EFAULT;
+	}
+	if (!hst) {
+		kfree_skb(skb);
+		BT_DRV_ERR("Invalid hci_st memory,freeing SKB");
+		BTDRV_API_EXIT(-EFAULT);
+		return -EFAULT;
+	}
+	if (!test_bit(BT_DRV_RUNNING, &hst->flags)) {
+		kfree_skb(skb);
+		BT_DRV_ERR("Device is not running,freeing SKB");
+		BTDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+
+	len = skb->len;
+	skb->dev = (struct net_device *)hst->hdev;
+
+	/* Forward skb to HCI CORE layer */
+	err = hci_recv_frame(skb);
+	if (err) {
+		kfree_skb(skb);
+		BT_DRV_ERR("Unable to push skb to HCI CORE(%d),freeing SKB",
+			   err);
+		BTDRV_API_EXIT(err);
+		return err;
+	}
+	hst->hdev->stat.byte_rx += len;
+
+	BTDRV_API_EXIT(0);
+	return 0;
+}
+
+/* ------- Interfaces to HCI layer ------ */
+
+/* Called from HCI core to initialize the device */
+static int hci_st_open(struct hci_dev *hdev)
+{
+	static struct st_proto_s hci_st_proto;
+	unsigned long timeleft;
+	int err;
+
+	BTDRV_API_START();
+
+	err = 0;
+
+	BT_DRV_DBG("%s %p", hdev->name, hdev);
+
+	/* Already registered with ST ? */
+	if (test_bit(BT_ST_REGISTERED, &hst->flags)) {
+		BT_DRV_ERR("Registered with ST already,open called again?");
+		BTDRV_API_EXIT(0);
+		return 0;
+	}
+
+	/* Populate BT driver info required by ST */
+	memset(&hci_st_proto, 0, sizeof(hci_st_proto));
+
+	/* BT driver ID */
+	hci_st_proto.type = ST_BT;
+
+	/* Receive function which called from ST */
+	hci_st_proto.recv = hci_st_receive;
+
+	/* Packet match function may used in future */
+	hci_st_proto.match_packet = NULL;
+
+	/* Callback to be called when registration is pending */
+	hci_st_proto.reg_complete_cb = hci_st_registration_completion_cb;
+
+	/* This is write function pointer of ST. BT driver will make use of this
+	 * for sending any packets to chip. ST will assign and give to us, so
+	 * make it as NULL */
+	hci_st_proto.write = NULL;
+
+	/* Register with ST layer */
+	err = st_register(&hci_st_proto);
+	if (err == ST_ERR_PENDING) {
+		/* Prepare wait-for-completion handler data structures.
+		 * Needed to syncronize this and st_registration_completion_cb()
+		 * functions.
+		 */
+		init_completion(&hst->wait_for_btdrv_reg_completion);
+
+		/* Reset ST registration callback status flag , this value
+		 * will be updated in hci_st_registration_completion_cb()
+		 * function whenever it called from ST driver.
+		 */
+		hst->streg_cbdata = -EINPROGRESS;
+
+		/* ST is busy with other protocol registration(may be busy with
+		 * firmware download).So,Wait till the registration callback
+		 * (passed as a argument to st_register() function) getting
+		 * called from ST.
+		 */
+		BT_DRV_DBG(" %s waiting for reg completion signal from ST",
+			   __func__);
+
+		timeleft =
+		    wait_for_completion_timeout
+		    (&hst->wait_for_btdrv_reg_completion,
+		     msecs_to_jiffies(BT_REGISTER_TIMEOUT));
+		if (!timeleft) {
+			BT_DRV_ERR("Timeout(%ld sec),didn't get reg"
+				   "completion signal from ST",
+				   BT_REGISTER_TIMEOUT / 1000);
+			BTDRV_API_EXIT(-ETIMEDOUT);
+			return -ETIMEDOUT;
+		}
+
+		/* Is ST registration callback called with ERROR value? */
+		if (hst->streg_cbdata != 0) {
+			BT_DRV_ERR("ST reg completion CB called with invalid"
+				   "status %d", hst->streg_cbdata);
+			BTDRV_API_EXIT(-EAGAIN);
+			return -EAGAIN;
+		}
+		err = 0;
+	} else if (err == ST_ERR_FAILURE) {
+		BT_DRV_ERR("st_register failed %d", err);
+		BTDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+
+	/* Do we have proper ST write function? */
+	if (hci_st_proto.write != NULL) {
+		/* We need this pointer for sending any Bluetooth pkts */
+		hst->st_write = hci_st_proto.write;
+	} else {
+		BT_DRV_ERR("failed to get ST write func pointer");
+
+		/* Undo registration with ST */
+		err = st_unregister(ST_BT);
+		if (err < 0)
+			BT_DRV_ERR("st_unregister failed %d", err);
+
+		hst->st_write = NULL;
+		BTDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+
+	/* Registration with ST layer is completed successfully,
+	 * now chip is ready to accept commands from HCI CORE.
+	 * Mark HCI Device flag as RUNNING
+	 */
+	set_bit(HCI_RUNNING, &hdev->flags);
+
+	/* Registration with ST successful */
+	set_bit(BT_ST_REGISTERED, &hst->flags);
+
+	BTDRV_API_EXIT(err);
+	return err;
+}
+
+/* Close device */
+static int hci_st_close(struct hci_dev *hdev)
+{
+	int err;
+
+	BTDRV_API_START();
+
+	err = 0;
+
+	/* Unregister from ST layer */
+	if (test_and_clear_bit(BT_ST_REGISTERED, &hst->flags)) {
+		err = st_unregister(ST_BT);
+		if (err != ST_SUCCESS) {
+			BT_DRV_ERR("st_unregister failed %d", err);
+			BTDRV_API_EXIT(-EBUSY);
+			return -EBUSY;
+		}
+	}
+
+	hst->st_write = NULL;
+
+	/* ST layer would have moved chip to inactive state.
+	 * So,clear HCI device RUNNING flag.
+	 */
+	if (!test_and_clear_bit(HCI_RUNNING, &hdev->flags)) {
+		BTDRV_API_EXIT(0);
+		return 0;
+	}
+
+	BTDRV_API_EXIT(err);
+	return err;
+}
+
+/* Called from HCI CORE , Sends frames to Shared Transport */
+static int hci_st_send_frame(struct sk_buff *skb)
+{
+	struct hci_dev *hdev;
+	struct hci_st *hst;
+	long len;
+
+	BTDRV_API_START();
+
+	if (skb == NULL) {
+		BT_DRV_ERR("Invalid skb received from HCI CORE");
+		BTDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	hdev = (struct hci_dev *)skb->dev;
+	if (!hdev) {
+		BT_DRV_ERR("SKB received for invalid HCI Device (hdev=NULL)");
+		BTDRV_API_EXIT(-ENODEV);
+		return -ENODEV;
+	}
+	if (!test_bit(HCI_RUNNING, &hdev->flags)) {
+		BT_DRV_ERR("Device is not running");
+		BTDRV_API_EXIT(-EBUSY);
+		return -EBUSY;
+	}
+
+	hst = (struct hci_st *)hdev->driver_data;
+
+	/* Prepend skb with frame type */
+	memcpy(skb_push(skb, 1), &bt_cb(skb)->pkt_type, 1);
+
+	BT_DRV_DBG(" %s: type %d len %d", hdev->name, bt_cb(skb)->pkt_type,
+		   skb->len);
+
+	/* Insert skb to shared transport layer's transmit queue.
+	 * Freeing skb memory is taken care in shared transport layer,
+	 * so don't free skb memory here.
+	 */
+	if (!hst->st_write) {
+		kfree_skb(skb);
+		BT_DRV_ERR(" Can't write to ST, st_write null?");
+		BTDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+	len = hst->st_write(skb);
+	if (len < 0) {
+		/* Something went wrong in st write , free skb memory */
+		kfree_skb(skb);
+		BT_DRV_ERR(" ST write failed (%ld)", len);
+		BTDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+
+	/* ST accepted our skb. So, Go ahead and do rest */
+	hdev->stat.byte_tx += len;
+	hci_st_tx_complete(hst, bt_cb(skb)->pkt_type);
+
+	BTDRV_API_EXIT(0);
+	return 0;
+}
+
+static void hci_st_destruct(struct hci_dev *hdev)
+{
+	BTDRV_API_START();
+
+	if (!hdev) {
+		BT_DRV_ERR("Destruct called with invalid HCI Device"
+			   "(hdev=NULL)");
+		BTDRV_API_EXIT(0);
+		return;
+	}
+
+	BT_DRV_DBG("%s", hdev->name);
+
+	/* free hci_st memory */
+	if (hdev->driver_data != NULL)
+		kfree(hdev->driver_data);
+
+	BTDRV_API_EXIT(0);
+	return;
+}
+
+/* Creates new HCI device */
+static int hci_st_register_dev(struct hci_st *hst)
+{
+	struct hci_dev *hdev;
+
+	BTDRV_API_START();
+
+	/* Initialize and register HCI device */
+	hdev = hci_alloc_dev();
+	if (!hdev) {
+		BT_DRV_ERR("Can't allocate HCI device");
+		BTDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	BT_DRV_DBG(" HCI device allocated. hdev= %p", hdev);
+
+	hst->hdev = hdev;
+	hdev->type = HCI_UART;
+	hdev->driver_data = hst;
+	hdev->open = hci_st_open;
+	hdev->close = hci_st_close;
+	hdev->flush = NULL;
+	hdev->send = hci_st_send_frame;
+	hdev->destruct = hci_st_destruct;
+	hdev->owner = THIS_MODULE;
+
+	if (reset)
+		set_bit(HCI_QUIRK_NO_RESET, &hdev->quirks);
+
+	if (hci_register_dev(hdev) < 0) {
+		BT_DRV_ERR("Can't register HCI device");
+		hci_free_dev(hdev);
+		BTDRV_API_EXIT(-ENODEV);
+		return -ENODEV;
+	}
+
+	BT_DRV_DBG(" HCI device registered. hdev= %p", hdev);
+	BTDRV_API_EXIT(0);
+	return 0;
+}
+
+/* ------- Module Init interface ------ */
+
+static int __init bt_drv_init(void)
+{
+	int err;
+
+	BTDRV_API_START();
+
+	err = 0;
+
+	BT_DRV_DBG(" Bluetooth Driver Version %s", VERSION);
+
+	/* Allocate local resource memory */
+	hst = kzalloc(sizeof(struct hci_st), GFP_KERNEL);
+	if (!hst) {
+		BT_DRV_ERR("Can't allocate control structure");
+		BTDRV_API_EXIT(-ENFILE);
+		return -ENFILE;
+	}
+
+	/* Expose "hciX" device to user space */
+	err = hci_st_register_dev(hst);
+	if (err) {
+		/* Release local resource memory */
+		kfree(hst);
+
+		BT_DRV_ERR("Unable to expose hci0 device(%d)", err);
+		BTDRV_API_EXIT(err);
+		return err;
+	}
+	set_bit(BT_DRV_RUNNING, &hst->flags);
+
+	BTDRV_API_EXIT(err);
+	return err;
+}
+
+/* ------- Module Exit interface ------ */
+
+static void __exit bt_drv_exit(void)
+{
+	BTDRV_API_START();
+
+	/* Deallocate local resource's memory  */
+	if (hst) {
+		struct hci_dev *hdev = hst->hdev;
+
+		if (hdev == NULL) {
+			BT_DRV_ERR("Invalid hdev memory");
+			kfree(hst);
+		} else {
+			hci_st_close(hdev);
+			if (test_and_clear_bit(BT_DRV_RUNNING, &hst->flags)) {
+				/* Remove HCI device (hciX) created
+				 * in module init.
+				 */
+				hci_unregister_dev(hdev);
+
+				/* Free HCI device memory */
+				hci_free_dev(hdev);
+			}
+		}
+	}
+	BTDRV_API_EXIT(0);
+}
+
+module_init(bt_drv_init);
+module_exit(bt_drv_exit);
+
+/* ------ Module Info ------ */
+
+module_param(reset, bool, 0644);
+MODULE_PARM_DESC(reset, "Send HCI reset command on initialization");
+MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
+MODULE_DESCRIPTION("Bluetooth Driver for TI Shared Transport" VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/bt_drv.h b/drivers/misc/ti-st/bt_drv.h
new file mode 100644
index 0000000..a0beebe
--- /dev/null
+++ b/drivers/misc/ti-st/bt_drv.h
@@ -0,0 +1,61 @@
+/*
+ *  Texas Instrument's Bluetooth Driver For Shared Transport.
+ *
+ *  Bluetooth Driver acts as interface between HCI CORE and
+ *  TI Shared Transport Layer.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _BT_DRV_H
+#define _BT_DRV_H
+
+/* Bluetooth Driver Version */
+#define VERSION               "1.0"
+
+/* Defines number of seconds to wait for reg completion
+ * callback getting called from ST (in case,registration
+ * with ST returns PENDING status)
+ */
+#define BT_REGISTER_TIMEOUT   msecs_to_jiffies(6000)	/* 6 sec */
+
+/* BT driver's local status */
+#define BT_DRV_RUNNING        0
+#define BT_ST_REGISTERED      1
+
+/* BT driver operation structure */
+struct hci_st {
+
+	/* hci device pointer which binds to bt driver */
+	struct hci_dev *hdev;
+
+	/* used locally,to maintain various BT driver status */
+	unsigned long flags;
+
+	/* to hold ST registration callback  status */
+	char streg_cbdata;
+
+	/* write function pointer of ST driver */
+	long (*st_write) (struct sk_buff *);
+
+	/* Wait on comepletion handler needed to synchronize
+	 * hci_st_open() and hci_st_registration_completion_cb()
+	 * functions.*/
+	struct completion wait_for_btdrv_reg_completion;
+};
+
+#endif
diff --git a/drivers/misc/ti-st/fm.h b/drivers/misc/ti-st/fm.h
new file mode 100644
index 0000000..be41453
--- /dev/null
+++ b/drivers/misc/ti-st/fm.h
@@ -0,0 +1,13 @@
+struct fm_event_hdr {
+	unsigned char plen;
+} __attribute__ ((packed));
+
+#define FM_MAX_FRAME_SIZE 0xFF	/* TODO: */
+#define FM_EVENT_HDR_SIZE 1	/* size of fm_event_hdr */
+#define ST_FM_CH8_PKT 0x8
+
+/* gps stuff */
+struct gps_event_hdr {
+unsigned char opcode;
+unsigned short plen;
+} __attribute__ ((packed));
diff --git a/drivers/misc/ti-st/fmdrv.h b/drivers/misc/ti-st/fmdrv.h
new file mode 100644
index 0000000..88e95fb
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv.h
@@ -0,0 +1,258 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  Common header for all FM driver sub-modules.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FM_DRV_H
+#define _FM_DRV_H
+
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <linux/timer.h>
+#include <linux/version.h>
+
+/* Driver version */
+#define FM_DRV_VERSION            "0.01"
+
+/* Should match with FM_DRV_VERSION */
+#define FM_DRV_RADIO_VERSION      KERNEL_VERSION(0, 0, 1)
+
+/* Driver name */
+#define FM_DRV_NAME               "ti_fmdrv"
+
+/* Card short name */
+#define FM_DRV_CARD_SHORT_NAME    "TI FM Radio"
+
+/* Card long name */
+#define FM_DRV_CARD_LONG_NAME     "Texas Instruments FM Radio"
+
+/* Define this macro to get debug msg */
+#ifdef DEBUG
+#define FM_DRV_DBG(fmt, arg...)  \
+	pr_info("(fmdrv): "fmt"\n" , ## arg)
+#define FMDRV_API_START()        \
+	pr_info("(fmdrv): %s Start\n", __func__)
+#define FMDRV_API_EXIT(errno)    \
+	pr_info("(fmdrv): %s Exit(%d)\n", __func__, errno)
+#define FM_DUMP_TXRX_PKT
+#else
+#define FM_DRV_DBG(fmt, arg...)
+#define FMDRV_API_START()
+#define FMDRV_API_EXIT(errno)
+#endif
+
+#define FM_DRV_ERR(fmt, arg...)  \
+	pr_err("(fmdrv): "fmt"\n" , ## arg)
+
+#define FM_ST_NOT_CLAIMED  0
+#define FM_ST_CLAIMED      1
+
+#define FM_ST_SUCCESS      0
+#define FM_ST_FAILED      -1
+
+/* Flag info */
+#define FM_INTTASK_RUNNING            0
+#define FM_INTTASK_SCHEDULE_PENDING   1
+#define FM_FIRMWARE_DW_INPROGRESS     2
+#define FM_CORE_READY                 3
+#define FM_CORE_TRANSPORT_READY       4
+#define FM_AF_SWITCH_INPROGRESS	      5
+#define FM_CORE_TX_XMITING	      6
+
+/* FM packet TX timeout */
+#define FM_DRV_TX_TIMEOUT      (5*HZ)	/* 5 seconds */
+
+/* Seek operation timeout */
+#define FM_DRV_RX_SEEK_TIMEOUT (20*HZ)	/* 20 seconds */
+
+/* Firmware download option */
+enum {
+	FM_MODE_OFF,
+	FM_MODE_TX,
+	FM_MODE_RX,
+	FM_MODE_ENTRY_MAX
+};
+
+#define FM_RX_RDS_INFO_FIELD_MAX	8	/* 4 Group * 2 Bytes */
+
+/* RX RDS data format */
+struct fm_rdsdata_format {
+	union {
+		struct {
+			unsigned char rdsBuff[FM_RX_RDS_INFO_FIELD_MAX];
+		} groupDataBuff;
+		struct {
+			unsigned short piData;
+			unsigned char blockB_byte1;
+			unsigned char blockB_byte2;
+			unsigned char blockC_byte1;
+			unsigned char blockC_byte2;
+			unsigned char blockD_byte1;
+			unsigned char blockD_byte2;
+		} groupGeneral;
+		struct {
+			unsigned short piData;
+			unsigned char blockB_byte1;
+			unsigned char blockB_byte2;
+			unsigned char firstAf;
+			unsigned char secondAf;
+			unsigned char firstPsByte;
+			unsigned char secondPsByte;
+		} group0A;
+
+		struct {
+			unsigned short piData;
+			unsigned char blockB_byte1;
+			unsigned char blockB_byte2;
+			unsigned short piData2;
+			unsigned char firstPsByte;
+			unsigned char secondPsByte;
+		} group0B;
+	} rdsData;
+};
+
+typedef void (*Int_Handler_ProtoType) (void);
+
+/* FM region (Europe/US, Japan) info */
+struct region_info {
+	unsigned int channel_spacing;
+	unsigned int bottom_frequency;
+	unsigned int top_frequency;
+	unsigned char region_index;
+};
+/* FM Interrupt processing related info */
+struct fm_irq {
+	unsigned char stage_index;
+	unsigned short flag;	/* FM interrupt flag */
+	unsigned short mask;	/* FM interrupt mask */
+	/* Interrupt process timeout handler */
+	struct timer_list int_timeout_timer;
+	unsigned char irq_service_timeout_retry;
+	Int_Handler_ProtoType *fm_IntActionHandlerTable;
+};
+
+/* RDS info */
+struct fm_rds {
+	unsigned char flag;	/* RX RDS on/off status */
+	unsigned char last_block_index;	/* Last received RDS block */
+
+	/* RDS buffer */
+	wait_queue_head_t read_queue;
+	unsigned int buf_size;	/* Size is always multiple of 3 */
+	unsigned int wr_index;
+	unsigned int rd_index;
+	unsigned char *buffer;
+};
+
+#define FM_RDS_MAX_AF_LIST		25
+
+/* Current RX channel Alternate Frequency cache.
+ * This info is used to switch to other freq (AF)
+ * when current channel signal strengh is below RSSI threshold.
+ */
+struct tuned_station_info {
+	unsigned short picode;
+	unsigned int af_cache[FM_RDS_MAX_AF_LIST];
+	unsigned char no_of_items_in_afcache;
+	unsigned char af_list_max;
+};
+
+/* FM RX mode info */
+struct fm_rx {
+	struct region_info region;	/* Current selected band */
+	unsigned int curr_freq;	/* Current RX frquency */
+	unsigned char curr_mute_mode;	/* Current mute mode */
+	/* RF dependent soft mute mode */
+	unsigned char curr_rf_depend_mute;
+	unsigned short curr_volume;	/* Current volume level */
+	short curr_rssi_threshold;	/* Current RSSI threshold level */
+	/* Holds the index of the current AF jump */
+	unsigned char cur_Afjump_index;
+	/* Will hold the frequency before the jump */
+	unsigned int freq_before_jump;
+	unsigned char rds_mode;	/* RDS operation mode (RDS/RDBS) */
+	unsigned char af_mode;	/* Alternate frequency on/off */
+	struct tuned_station_info cur_station_info;
+	struct fm_rds rds;
+};
+
+/*
+ * FM TX RDS data
+ *
+ * @ text_type: is the text following PS or RT
+ * @ text: radio text string which could either be PS or RT
+ * @ af_freq: alternate frequency for Tx
+ * TODO: to be declared in application
+ */
+struct tx_rds {
+	unsigned char text_type;
+	unsigned char text[25];
+	unsigned int af_freq;
+};
+/*
+ * FM TX global data
+ *
+ * @ pwr_lvl: Power Level of the Transmission from mixer control
+ * @ xmit_state: Transmission state = Updated locally upon Start/Stop
+ * @ audio_io: i2S/Analog
+ * @ tx_frq: Transmission frequency
+ */
+struct fmtx_data {
+	unsigned char pwr_lvl;
+	unsigned char xmit_state;
+	unsigned char audio_io;
+	unsigned long tx_frq;
+	struct tx_rds rds;
+};
+
+/* FM driver operation structure */
+struct fmdrv_ops {
+	struct video_device *v4l2dev;	/* V4L2 video device pointer */
+	struct snd_card *card;	/* Card which holds FM mixer controls */
+	unsigned short asci_id;
+	spinlock_t rds_buff_lock;
+	spinlock_t resp_skb_lock;
+
+	long flag;		/*  FM driver state machine info */
+
+	struct sk_buff_head rx_q;	/* RX queue */
+	struct tasklet_struct rx_task;	/* RX Tasklet */
+
+	struct sk_buff_head tx_q;	/* TX queue */
+	struct tasklet_struct tx_task;	/* TX Tasklet */
+	unsigned long last_tx_jiffies;	/* Timestamp of last pkt sent */
+	atomic_t tx_cnt;	/* Number of packets can send at a time */
+
+	struct sk_buff *response_skb;	/* Response from the chip */
+	/* Main task completion handler */
+	struct completion maintask_completion;
+	/* Opcode of last command sent to the chip */
+	unsigned char last_sent_pkt_opcode;
+	/* Handler used for wakeup when response packet is received */
+	struct completion *response_completion;
+	struct fm_irq irq_info;
+	unsigned char curr_fmmode; /* Current FM chip mode (TX, RX, OFF) */
+	struct fm_rx rx;	/* FM receiver info */
+	struct fmtx_data tx_data;
+};
+
+#endif
diff --git a/drivers/misc/ti-st/fmdrv_chr.c b/drivers/misc/ti-st/fmdrv_chr.c
new file mode 100644
index 0000000..8755728
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_chr.c
@@ -0,0 +1,776 @@
+/*
+ *   FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *   Copyright (C) 2009 Texas Instruments
+ *   Written by Raghavendra Shenoy (x0099675@ti.com)
+ *
+ *   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, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+
+#include <linux/tty.h>
+#include <linux/sched.h>
+
+#include <linux/poll.h>
+#include <linux/delay.h>
+#include <linux/skbuff.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+
+#include <linux/uaccess.h>
+
+#include "fmdrv_st.h"
+#include "fmdrv_chr.h"
+
+/* Structure that has FM character driver data */
+struct fm_chrdrv_ops *fm_chr_dev;
+
+/* File operations structure initialization */
+const struct file_operations fm_chr_ops = {
+	.owner = THIS_MODULE,
+	.fasync = fm_chr_fasync,
+	.open = fm_chr_open,
+	.read = fm_chr_read,
+	.write = fm_chr_write,
+	.poll = fm_chr_poll,
+	.ioctl = fm_chr_ioctl,
+	.release = fm_chr_release,
+};
+
+/* Converting Channel-8 response to Channel-4 response */
+static struct sk_buff *convert2_channel_4(struct sk_buff *ch8_skb)
+{
+	struct evt_cmd_complete *evt;
+	struct sk_buff *ch4_skb;
+
+	unsigned char ncmds;	/* num_hci cmds */
+	unsigned char status;
+	unsigned char pkt_type;
+
+	unsigned short opcode;
+	unsigned short hci_vs_opcode;
+
+	unsigned char *ptr, *chan4_mem;
+	unsigned char chan4_index, chan8_index;
+	unsigned char num_hci, param_len, fm_opcode;
+	unsigned char read_write, evt_code, cmd_len, int_len, chan8_cmd_len;
+
+	FM_CHR_DRV_START();
+
+	fm_opcode = read_write = 0;
+	chan8_index = chan4_index = 0;
+	int_len = num_hci = cmd_len = param_len = 0;
+	opcode = 0x0000;
+
+	ptr = NULL;
+	ch4_skb = NULL;
+	chan4_mem = NULL;
+
+	chan8_cmd_len = ch8_skb->data[CHAN8_RESP_CMD_LEN_POS];
+	if ((chan8_cmd_len + CHAN8_RESP_CMD_LEN_SIZE + CHAN8_RESP_TYPE_SIZE) !=
+	    ch8_skb->len) {
+		FM_CHR_DRV_ERR(" Channel-8 response length mismatch ");
+
+		return NULL;
+	}
+
+	/* Copy the opcode from Channel-1 command packet.
+	 * Channel-8 response packets can only be converted into Channel-4
+	 * HCI command complete event packets.
+	 *
+	 * Mark the packet type as Channel-4 packet type.
+	 */
+	evt_code = CHAN4_CMD_COMPLETE_TYPE;
+
+	/* Copy the opcode from Channel-8 reponse packet */
+	fm_opcode = ch8_skb->data[CHAN8_RESP_FM_OPCODE_POS];
+
+	/* Conversion logic for response packets with Power mode opcode */
+	if (fm_opcode == CHAN8_FM_PWR_OPCODE) {
+		ch4_skb = alloc_skb(7, GFP_ATOMIC);
+		if (ch4_skb == NULL) {
+			FM_CHR_DRV_ERR(" SKB allocation failed ");
+			return NULL;
+		}
+
+		/* Copy from Channel-8 reponse packet */
+		pkt_type = CHAN4_PKT_TYPE;
+		evt_code = CHAN4_CMD_COMPLETE_TYPE;	/* cmd complete event */
+		ncmds = ch8_skb->data[CHAN8_RESP_NUM_HCI_POS];/* num_hci cmds */
+		param_len = 4;	/* fd37 + num hci cmds */
+		hci_vs_opcode = CHAN1_FM_PWR_OPCODE;
+		status = ch8_skb->data[CHAN8_RESP_STATUS_POS];
+
+		/* Copy to Channel-4 response packet */
+		memcpy(skb_put(ch4_skb, 1), &pkt_type, 1);
+		memcpy(skb_put(ch4_skb, 1), &evt_code, 1);
+		memcpy(skb_put(ch4_skb, 1), &param_len, 1);
+		memcpy(skb_put(ch4_skb, 1), &ncmds, 1);
+		memcpy(skb_put(ch4_skb, 2), &hci_vs_opcode, 2);
+		memcpy(skb_put(ch4_skb, 1), &status, 1);
+
+		/* Trim the data to specified length */
+		skb_trim(ch4_skb, 7);
+
+		return ch4_skb;
+	}
+
+	/* To accomodate an extra 0 that Channel-4 response sends */
+	ch4_skb = alloc_skb((ch8_skb->len + 1), GFP_ATOMIC);
+	if (ch4_skb == NULL) {
+		FM_CHR_DRV_ERR(" SKB allocation failed ");
+
+		return NULL;
+	}
+	skb_put(ch4_skb, ch8_skb->len + 1);
+
+	/*  Copy the command length, NUM_HCI, R/W values from Channl-8 reponse
+	 *  packet
+	 */
+	cmd_len = ch8_skb->data[CHAN8_RESP_CMD_LEN_POS];
+	num_hci = ch8_skb->data[CHAN8_RESP_NUM_HCI_POS];
+	read_write = ch8_skb->data[CHAN8_RESP_RW_POS];
+
+	/* Update Channel-4 response packet's opcode bit */
+	if (read_write == CHAN8_RD_RESP)
+		opcode = CHAN1_READ_OPCODE;
+	else
+		opcode = CHAN1_WRITE_OPCODE;
+
+	param_len = ch8_skb->data[CHAN8_RESP_PARAM_LEN_POS];
+
+	/* Copying the header-data to Channel-4 response packet */
+	ch4_skb->data[CHAN4_TYPE_POS] = CHAN4_PKT_TYPE;
+	ch4_skb->data[CHAN4_EVT_TYPE_POS] = evt_code;
+
+	/* Copying the parameters from Channel-8 response packets to Channel-4
+	 * response packets.
+	 */
+	evt = (void *)&ch4_skb->data[CHAN4_EVT_POS];
+	evt->opcode = opcode;
+	evt->ncmd = num_hci;
+
+	chan8_index = CHAN8_RESP_PARAM_POS;
+	chan4_index = CHAN4_PARAM_POS;
+
+	/* Allocate memory to copy the parameters. The parameters are
+	 * copied from Channel-8 response packet to this memory and then
+	 * copied to Channel-4 response packet.
+	 */
+	chan4_mem = kzalloc((param_len) * (sizeof(unsigned char)), GFP_ATOMIC);
+
+	if (chan4_mem == NULL) {
+		FM_CHR_DRV_ERR(" chan4_mem == NULL ");
+
+		return ch8_skb;
+	}
+
+	int_len = param_len;
+	ptr = (void *)chan4_mem;
+
+	/* The parameters are copied from Channel-8 response packet to the
+	*  intermediate memory location.
+	*/
+	while (param_len--) {
+		*ptr = ch8_skb->data[chan8_index];
+		ptr++;
+		chan8_index++;
+	}
+
+	/* Copy the extra 0 */
+	ch4_skb->data[chan4_index] = 0x00;
+	chan4_index++;
+
+	param_len = int_len;
+	ptr = (void *)chan4_mem;
+
+	/* The parameters are copied from intermediate memory location
+	 * to Channel-4 response packet.
+	 */
+	while (param_len--) {
+		ch4_skb->data[chan4_index++] = *ptr;
+		ptr++;
+	}
+	kfree(chan4_mem);
+	/* plen would be chan8_index - pkt_type - evt code */
+	ch4_skb->data[CHAN4_PLEN_POS] =
+	    chan8_index - CHAN4_PKT_TYPE_SIZE - CHAN4_EVT_TYPE_SIZE;
+
+	return ch4_skb;
+
+}
+
+/* Convert the Channel-1 commands into Channel-8 commands */
+static int convert2_channel_8(struct sk_buff *skb)
+{
+	struct hci_command_hdr *hdr;
+
+	unsigned short chan8_index, chan1_index;
+	unsigned char fm_opcode, read_write, num_params, chan1_cmd_len;
+
+	/* FM power ON/OFF commands */
+	unsigned char fm_pwr_on[] = { 0x08, 0x05, 0xFE, 0x00,
+				      0x02, 0x00, 0x01 };
+	unsigned char fm_pwr_off[] = { 0x08, 0x05, 0xFE, 0x00,
+				      0x02, 0x00, 0x00 };
+
+	FM_CHR_DRV_START();
+
+	hdr = NULL;
+	fm_opcode = 0;
+	read_write = 0;
+	num_params = 0;
+	chan8_index = 0;
+	chan1_index = 0;
+
+	chan1_cmd_len = skb->data[CHAN1_CMD_LEN_POS];
+
+	if ((chan1_cmd_len + CHAN1_TYPE_SIZE + CHAN1_OPCODE_SIZE +
+	     CHAN1_CMD_LEN_SIZE) != skb->len) {
+		FM_CHR_DRV_ERR(" Channel-1 length mismatch ");
+
+		return -1;
+	}
+
+	/* Copy the opcode from Channel-1 command packet */
+	hdr = (void *)&skb->data[CHAN1_TYPE_POS];
+
+	/* Conversion for commands with Power mode opcode */
+	if (hdr->opcode == CHAN1_FM_PWR_OPCODE) {
+		/* Set skb length to zero and skb tail pointer
+		 * to data pointer.
+		 */
+		skb_trim(skb, 0);
+
+		/* For FM Power ON command */
+		if (skb->data[CHAN1_FM_OPCODE_POS] == 0x01) {
+			memcpy(skb_put(skb, sizeof(fm_pwr_on)), fm_pwr_on,
+			       sizeof(fm_pwr_on));
+		} else {
+			/* For Power OFF command */
+			memcpy(skb_put(skb, sizeof(fm_pwr_off)), fm_pwr_off,
+			       sizeof(fm_pwr_off));
+		}
+
+		return 0;
+	}
+
+	/* Copy the parameters from Channel-1 command packet */
+	/* Only the LSB of this value will be used */
+	num_params = skb->data[CHAN1_PARAM_LEN_POS];
+	fm_opcode = skb->data[CHAN1_FM_OPCODE_POS];
+	chan1_index = CHAN1_PARAM_POS;
+
+	/* Copy the Channel-1 header data to Channel-8 header fields */
+	read_write =
+	    (hdr->opcode == CHAN1_READ_OPCODE) ? CHAN8_RD_CMD : CHAN8_WR_CMD;
+	skb->data[CHAN8_TYPE_POS] = CHAN8_PKT_TYPE;
+
+	/* cmd_length/skb->data[1] = fm_opcode + read_write + param_len
+	 * in addition to num_params
+	 */
+	skb->data[CHAN8_FM_OPCODE_POS] = fm_opcode;
+	skb->data[CHAN8_RW_POS] = read_write;
+	chan8_index = CHAN8_PARAM_POS;
+
+	skb->data[CHAN8_CMD_LEN_POS] = num_params + CHAN8_OPCODE_SIZE +
+	    CHAN8_RD_WR_SIZE + CHAN8_PARAM_LEN_SIZE;
+
+	/* Copy the Channel-1 parameters to Channel-8 parameter field */
+
+	/* READ command except read_hw_register */
+	if ((read_write == CHAN8_RD_CMD) &&
+	    (fm_opcode != CHAN1_HW_REG_OPCODE)) {
+		/* Expected bytes to read */
+		skb->data[CHAN8_PARAM_LEN_POS] = num_params;
+
+		chan8_index = CHAN8_PARAM_POS;
+		skb->data[CHAN8_CMD_LEN_POS] = CHAN8_OPCODE_SIZE +
+		    CHAN8_RD_WR_SIZE + CHAN8_PARAM_LEN_SIZE;
+	} else {
+
+		/* skb->data[4] contains length of parameters following */
+		skb->data[CHAN8_PARAM_LEN_POS] = num_params;
+
+		while (num_params) {
+			skb->data[chan8_index] = skb->data[chan1_index];
+			chan8_index++;
+			chan1_index++;
+			num_params--;
+		}
+	}
+
+	skb_trim(skb, chan8_index);
+
+	return 0;
+}
+
+/* Tasklet function which will be scheduled by FM ST sub-module
+ * when data is received
+ */
+long fm_rx_task(void)
+{
+	struct sk_buff *skb;
+
+#ifdef VERBOSE
+	int len;
+#endif
+
+	FM_CHR_DRV_START();
+
+	skb = NULL;
+	spin_lock(&fm_chr_dev->lock);
+
+	if (skb_queue_empty(&fm_chr_dev->rx_q)) {
+		FM_CHR_DRV_ERR(" Rx Queue empty ");
+		spin_unlock(&fm_chr_dev->lock);
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+
+	/* Dequeue the skb received from the FM_ST interface */
+	skb = skb_dequeue(&fm_chr_dev->rx_q);
+	if (skb == NULL) {
+		FM_CHR_DRV_ERR(" Dequeued skb from Rx queue is NULL ");
+		spin_unlock(&fm_chr_dev->lock);
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+
+	/* Send a signal to TI FM stack when an Interrupt packet arrives */
+	if (skb->data[CHAN8_RESP_FM_OPCODE_POS] == CHAN8_FM_INTERRUPT) {
+		FM_CHR_DRV_VER(" Interrupt arrived: ");
+
+#ifdef VERBOSE
+		for (len = 0; ((skb) && (len < skb->len)); len++)
+			printk(KERN_INFO " 0x%02x ", skb->data[len]);
+		printk("\n");
+#endif
+
+		kfree_skb(skb);
+
+		/* kill_fasync here - Sends the signal. Check if the queue is
+		 * empty. If not, it means that command complete response for
+		 * the previous command is not sent to the stack. Don't send
+		 * the Signal. Set the SIGNAL_PENDING bit. This bit is cleared
+		 * in the read() of the stack, when it reads the command
+		 * complete response.
+		 */
+		if (likely(skb_queue_empty(&fm_chr_dev->rx_q))) {
+			/* Should come here most often */
+			kill_fasync(&fm_chr_dev->fm_fasync, SIGIO, POLLIN);
+			clear_bit(SIGNAL_PENDING, &fm_chr_dev->state_flags);
+		} else {
+			FM_CHR_DRV_VER(" signal not sent..");
+			set_bit(SIGNAL_PENDING, &fm_chr_dev->state_flags);
+		}
+
+		spin_unlock(&fm_chr_dev->lock);
+
+		return FM_CHR_DRV_SUCCESS;
+	}
+
+	/* Queue it back to the queue if the received packet
+	 * is not an interrupt packet
+	 */
+	skb_queue_head(&fm_chr_dev->rx_q, skb);
+	wake_up_interruptible(&fm_chr_dev->fm_data_q);
+
+	spin_unlock(&fm_chr_dev->lock);
+
+	return FM_CHR_DRV_SUCCESS;
+}
+
+/* Functions called from the TI-FM stack */
+int fm_chr_fasync(int fd, struct file *file, int on)
+{
+	FM_CHR_DRV_START();
+
+	return fasync_helper(fd, file, on, &fm_chr_dev->fm_fasync);
+}
+
+int fm_chr_open(struct inode *inod, struct file *fil)
+{
+	int err;
+	int err_st_release;
+
+	FM_CHR_DRV_START();
+
+	err = FM_CHR_DRV_SUCCESS;
+	err_st_release = FM_CHR_DRV_SUCCESS;
+
+	/* Check if V4L2 FM device is already using ST driver */
+	if (fm_st_claim() < FM_CHR_DRV_SUCCESS) {
+		FM_CHR_DRV_ERR(" Other FM device is already active ");
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+
+	/* Register with the FM_ST interface, which will register with the
+	 * ST driver
+	 */
+	err = fm_st_register(&fm_chr_dev->rx_q, &fm_chr_dev->rx_task);
+	if (err < FM_CHR_DRV_SUCCESS) {
+		FM_CHR_DRV_ERR(" Registration with ST Failed ");
+		FM_CHR_DRV_VER(" Releasing FM ST Interface... ");
+
+		err_st_release = fm_st_release();
+		if (err_st_release < FM_CHR_DRV_SUCCESS) {
+			FM_CHR_DRV_ERR(" Failed to release FM ST (%d)",
+				       err_st_release);
+
+			return err;
+		}
+		FM_CHR_DRV_VER(" Successfully released FM_ST interface ");
+
+		return err;
+	}
+
+	/* Initialize the wait queue and the Rx tasklets */
+	init_waitqueue_head(&fm_chr_dev->fm_data_q);
+	tasklet_init(&fm_chr_dev->rx_task, (void *)fm_rx_task,
+		     (unsigned long)fm_chr_dev);
+
+	FM_CHR_DRV_VER(" st_register completed");
+
+	return FM_CHR_DRV_SUCCESS;
+}
+
+int fm_chr_release(struct inode *inod, struct file *fil)
+{
+	int err;
+
+	FM_CHR_DRV_START();
+
+	err = 0;
+
+	/* Clear the asynchronous notifications to the process linked
+	 * with the file descriptor 'fil'
+	 */
+	fm_chr_fasync(-1, fil, 0);
+
+	/* Release the tasklets and the queues */
+	tasklet_kill(&fm_chr_dev->rx_task);
+	skb_queue_purge(&fm_chr_dev->rx_q);
+
+	/* Unregister FM with ST driver */
+	err = fm_st_unregister();
+	if (err < FM_CHR_DRV_SUCCESS) {
+		FM_CHR_DRV_ERR(" Unable to unregister from ST ");
+
+		return err;
+	}
+	FM_CHR_DRV_VER(" Successfully unregistered from ST ");
+
+	/* Release FM ST - FM character driver is not using
+	 * the ST driver
+	 */
+	err = fm_st_release();
+	if (err < FM_CHR_DRV_SUCCESS) {
+		FM_CHR_DRV_ERR(" Failed to release FM ST ");
+
+		return err;
+	}
+	FM_CHR_DRV_VER(" Successfully released FM_ST interface ");
+
+	return FM_CHR_DRV_SUCCESS;
+}
+
+ssize_t fm_chr_write(struct file *fil, const char __user *data,
+		     size_t size, loff_t *offset)
+{
+	int err;
+	struct sk_buff *skb;
+
+#ifdef VERBOSE
+	int len;
+#endif
+
+	FM_CHR_DRV_START();
+
+	err = FM_CHR_DRV_SUCCESS;
+
+	if (data[CHAN1_TYPE_POS] != CHAN1_PKT_TYPE) {
+		FM_CHR_DRV_ERR(" Packet type is not Channel-1 ");
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+
+	/* Allocate the SKB */
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb) {
+		FM_CHR_DRV_ERR(" Did not allocate SKB ");
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+
+	/* Forward the data from the user space to ST core */
+	if (copy_from_user(skb_put(skb, size), data, size)) {
+		FM_CHR_DRV_ERR(" Unable to copy from user space");
+		kfree_skb(skb);
+
+		return -EFAULT;
+	}
+#ifdef VERBOSE
+	printk(KERN_INFO "Write: Before conversion\n");
+	for (len = 0; ((skb) && (len < skb->len)); len++)
+		printk(KERN_INFO "0x%02x ", skb->data[len]);
+	printk("\n");
+#endif
+
+	/* Convert the Channel-1 command packet to Channel-8 command packet */
+	if (convert2_channel_8(skb) < 0) {
+		FM_CHR_DRV_ERR(" Conversion to Channel-8 failed ");
+		kfree_skb(skb);
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+#ifdef VERBOSE
+	printk(KERN_INFO "Write: After conversion\n");
+	for (len = 0; ((skb) && (len < skb->len)); len++)
+		printk(KERN_INFO "0x%02x ", skb->data[len]);
+	printk("\n");
+#endif
+
+	/* Write to ST driver through FM_ST interface */
+	err = fm_st_send(skb);
+	if (err < FM_CHR_DRV_SUCCESS) {
+		FM_CHR_DRV_ERR(" Cannot write to ST, fm_st_send failed (%d)",
+			       err);
+		kfree_skb(skb);
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+
+	init_waitqueue_head(&fm_chr_dev->fm_data_q);
+
+	return size;
+}
+
+ssize_t fm_chr_read(struct file *fil, char __user *data, size_t size,
+		    loff_t *offset)
+{
+	int len;
+	struct sk_buff *skb;
+	struct sk_buff *ch4_skb;
+
+	FM_CHR_DRV_START();
+
+	skb = NULL;
+	ch4_skb = NULL;
+
+	/* Wait till the data is available */
+	if (!wait_event_interruptible_timeout(fm_chr_dev->fm_data_q,
+					      !skb_queue_empty
+					      (&fm_chr_dev->rx_q), 500)) {
+
+		FM_CHR_DRV_ERR(" Read timed out ");
+
+		return -EAGAIN;
+	}
+	FM_CHR_DRV_VER(" Completed Read wait ");
+
+	spin_lock(&fm_chr_dev->lock);
+
+	/* Dequeue the data from the queue if the data
+	 * is already available
+	 */
+	if (!skb_queue_empty(&fm_chr_dev->rx_q))
+		skb = skb_dequeue(&fm_chr_dev->rx_q);
+
+	spin_unlock(&fm_chr_dev->lock);
+
+	if (unlikely
+	    (skb == NULL || skb->len == 0 || skb->data == NULL
+	     || skb->cb[0] != CHAN8_PKT_TYPE)) {
+		FM_CHR_DRV_VER(" Length of the response packet is invalid ");
+		kfree_skb(skb);
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+#ifdef VERBOSE
+	printk(KERN_INFO "Read: Before conversion\n");
+	for (len = 0; len < skb->len; len++)
+		printk(KERN_INFO "0x%02x ", skb->data[len]);
+	printk("\n");
+#endif
+
+	/* Convert if the response packet is of Channel-8 type */
+	if (!skb->data[CHAN8_RESP_CMD_LEN_POS]) {
+		kfree(skb);
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+
+	/* Convert the Channel-8 response packet to Channel-4 response packet */
+	ch4_skb = convert2_channel_4(skb);
+
+	if (ch4_skb == NULL) {
+		FM_CHR_DRV_ERR(" Converted SKB is NULL ");
+		kfree(skb);
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+#ifdef VERBOSE
+	printk(KERN_INFO "Read: After conversion\n");
+	for (len = 0; (ch4_skb != NULL) && len < (ch4_skb->len); len++)
+		printk(KERN_INFO "0x%02x ", ch4_skb->data[len]);
+	printk("\n");
+#endif
+
+	if (size >= ch4_skb->len) {
+		/* Forward the data to the user */
+		if (copy_to_user(data, ch4_skb->data, ch4_skb->len)) {
+			FM_CHR_DRV_ERR(" Unable to copy to user space ");
+			kfree_skb(skb);
+			kfree_skb(ch4_skb);
+			spin_unlock(&fm_chr_dev->lock);
+
+			return -EFAULT;
+		}
+	} else {
+		FM_CHR_DRV_ERR(" Buffer overflow ");
+		kfree_skb(skb);
+		kfree_skb(ch4_skb);
+
+		return -ENOMEM;
+	}
+
+	len = ch4_skb->len;
+	kfree(skb);
+	kfree(ch4_skb);
+
+	/* Clear the pending bit that was set when an interrupt packet had
+	 * arrived
+	 */
+	if (test_bit(SIGNAL_PENDING, &fm_chr_dev->state_flags)
+	    && skb_queue_empty(&fm_chr_dev->rx_q)) {
+		FM_CHR_DRV_DBG(" Sending signal ");
+
+		kill_fasync(&fm_chr_dev->fm_fasync, SIGIO, POLLIN);
+		clear_bit(SIGNAL_PENDING, &fm_chr_dev->state_flags);
+	}
+
+	return len;
+}
+
+unsigned int fm_chr_poll(struct file *file, poll_table * wait)
+{
+	unsigned long mask;
+
+	FM_CHR_DRV_DBG(" inside %s", __func__);
+
+	mask = 0;
+
+	/* Poll and wait */
+	poll_wait(file, &fm_chr_dev->fm_data_q, wait);
+
+	spin_lock(&fm_chr_dev->lock);
+
+	FM_CHR_DRV_VER(" Completed poll ");
+
+	if (!skb_queue_empty(&fm_chr_dev->rx_q))
+		mask |= POLLIN;
+
+	FM_CHR_DRV_VER(" return 0x%02x \n", (unsigned int)mask);
+
+	spin_unlock(&fm_chr_dev->lock);
+
+	return mask;
+}
+
+int fm_chr_ioctl(struct inode *inode, struct file *file,
+		 unsigned int cmd, unsigned long arg)
+{
+	FM_CHR_DRV_START();
+
+	return FM_CHR_DRV_SUCCESS;
+}
+
+/* FM character driver init: Initializes the FM character driver parametes */
+int fm_chr_init(void)
+{
+	FM_CHR_DRV_START();
+
+	fm_chr_dev = kzalloc(sizeof(struct fm_chrdrv_ops), GFP_ATOMIC);
+
+	if (fm_chr_dev == NULL) {
+		FM_CHR_DRV_ERR
+		    (" Cannot allocate memory for FM character driver ");
+
+		return -ENOMEM;
+	}
+
+	skb_queue_head_init(&fm_chr_dev->rx_q);
+
+	/* Initialize wait queue and a flag, so that the
+	 * wait queue can be used later
+	 */
+	init_completion(&fm_chr_dev->reg_completed);
+	init_waitqueue_head(&fm_chr_dev->fm_data_q);
+
+	/* Expose the device FM_CHAR_DEVICE_NAME to user space
+	 * and obtain the major number for the device
+	 */
+	fm_chr_dev->fm_chr_major =
+	    register_chrdev(0, FM_CHAR_DEVICE_NAME, &fm_chr_ops);
+	FM_CHR_DRV_VER(" allocated %d, %d", fm_chr_dev->fm_chr_major, 0);
+
+	if (fm_chr_dev->fm_chr_major < 0) {
+		FM_CHR_DRV_ERR(" register_chrdev failed ");
+
+		return FM_CHR_DRV_ERR_FAILURE;
+	}
+
+	/* udev */
+	fm_chr_dev->fm_chr_class =
+	    class_create(THIS_MODULE, FM_CHAR_DEVICE_NAME);
+	if (IS_ERR(fm_chr_dev->fm_chr_class)) {
+		FM_CHR_DRV_ERR(" Something went wrong in class_create");
+
+		return FM_CHR_DRV_ERR_CLASS;
+	}
+
+	fm_chr_dev->fm_chr_dev =
+	    device_create(fm_chr_dev->fm_chr_class, NULL,
+			  MKDEV(fm_chr_dev->fm_chr_major, 0), NULL,
+			  FM_CHAR_DEVICE_NAME);
+
+	if (IS_ERR(fm_chr_dev->fm_chr_dev)) {
+		FM_CHR_DRV_ERR(" Cannot create the device %s ",
+			       FM_CHAR_DEVICE_NAME);
+
+		return -ENODEV;
+	}
+
+	return FM_CHR_DRV_SUCCESS;
+}
+
+/* FM character driver init: Destroys the FM character driver parametes */
+void fm_chr_exit(void)
+{
+	FM_CHR_DRV_START();
+
+	FM_CHR_DRV_VER(" Freeing up %d", fm_chr_dev->fm_chr_major);
+
+	skb_queue_purge(&fm_chr_dev->rx_q);
+	device_destroy(fm_chr_dev->fm_chr_class,
+		       MKDEV(fm_chr_dev->fm_chr_major, 0));
+
+	class_unregister(fm_chr_dev->fm_chr_class);
+	class_destroy(fm_chr_dev->fm_chr_class);
+
+	unregister_chrdev(fm_chr_dev->fm_chr_major, FM_CHAR_DEVICE_NAME);
+}
diff --git a/drivers/misc/ti-st/fmdrv_chr.h b/drivers/misc/ti-st/fmdrv_chr.h
new file mode 100644
index 0000000..2b4161b
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_chr.h
@@ -0,0 +1,194 @@
+/*
+ *   FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *   Copyright (C) 2009 Texas Instruments
+ *   Written by Raghavendra Shenoy (x0099675@ti.com)
+ *
+ *   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, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#ifndef _FM_CHR_DRV_H
+#define _FM_CHR_DRV_H
+
+/* #define VERBOSE */
+
+/* Debug macros */
+#define FM_CHR_DRV_ERR(fmt, arg...) \
+	pr_err("(fm_chr_drv):"fmt"\n" , ## arg)
+
+#if defined(DEBUG)	/* limited debug messages */
+#define FM_CHR_DRV_DBG(fmt, arg...) \
+	pr_info("(fm_chr_drv):"fmt"\n" , ## arg)
+#define FM_CHR_DRV_VER(fmt, arg...)
+#define	FM_CHR_DRV_START()	\
+	pr_info("(fm_chr_drv): Inside %s\n", __func__)
+#elif defined(VERBOSE)	/* very verbose */
+#define FM_CHR_DRV_DBG(fmt, arg...) \
+	pr_info("(fm_chr_drv):"fmt"\n" , ## arg)
+#define FM_CHR_DRV_VER(fmt, arg...) \
+	pr_info("(fm_chr_drv):"fmt"\n" , ## arg)
+#define FM_CHR_DRV_START()	\
+	pr_info("(fm_chr_drv): Inside %s\n", __func__)
+#else /* Error msgs only */
+#define FM_CHR_DRV_DBG(fmt, arg...)
+#define FM_CHR_DRV_VER(fmt, arg...)
+#define FM_CHR_DRV_START()
+#endif
+
+/* FM device */
+#define FM_CHAR_DEVICE_NAME 	"tifm"
+
+/* Macros for packet conversion */
+#define	CHAN1_FM_PWR_OPCODE		0xFD37
+#define	CHAN1_READ_OPCODE		0xFD33
+#define	CHAN1_WRITE_OPCODE		0xFD35
+
+#define CHAN1_HW_REG_OPCODE		0x64
+#define CHAN8_FM_PWR_OPCODE		0xFE
+#define CHAN8_FM_INTERRUPT		0xFF
+#define CHAN8_FM_INTERRUPT_OPCODE	0xF0
+
+/* Packet types */
+#define CHAN1_PKT_TYPE		0x01
+#define CHAN8_PKT_TYPE		0x08
+#define CHAN4_PKT_TYPE		0x04
+#define CHAN4_CMD_COMPLETE_TYPE	0x0E
+
+#define CHAN8_RD_CMD	0x01
+#define CHAN8_WR_CMD	0x00
+
+#define CHAN8_RD_RESP	0x01
+#define CHAN8_WR_RESP	0x00
+
+/* Channel-4 data sizes */
+#define CHAN4_PKT_TYPE_SIZE	1
+#define CHAN4_EVT_TYPE_SIZE	1
+
+/* Channel-8 data sizes */
+#define CHAN8_OPCODE_SIZE 	1
+#define CHAN8_RD_WR_SIZE 	1
+#define CHAN8_PARAM_LEN_SIZE 	1
+
+/* Channel-8 response data sizes */
+#define CHAN8_RESP_TYPE_SIZE	1
+#define CHAN8_RESP_CMD_LEN_SIZE 1
+
+/* HCI-VS data sizes */
+#define CHAN1_TYPE_SIZE		1
+#define CHAN1_OPCODE_SIZE	2
+#define CHAN1_CMD_LEN_SIZE	1
+
+/* HCI-VS data positions */
+#define CHAN1_TYPE_POS		0
+#define CHAN1_OPCODE_POS	1
+#define CHAN1_CMD_LEN_POS	3
+#define CHAN1_FM_OPCODE_POS	4
+#define CHAN1_PARAM_LEN_POS	5
+
+/* Because of an extra Zero appended to param_len */
+#define CHAN1_PARAM_POS		7
+
+/* Channel-8 command positions */
+#define CHAN8_TYPE_POS		0
+#define CHAN8_CMD_LEN_POS	1
+#define CHAN8_FM_OPCODE_POS	2
+#define CHAN8_RW_POS		3
+#define CHAN8_PARAM_LEN_POS	4
+#define CHAN8_PARAM_POS		5
+
+/* Channel-8 response positions */
+#define CHAN8_RESP_CMD_LEN_POS		1
+#define CHAN8_RESP_STATUS_POS		2
+#define CHAN8_RESP_NUM_HCI_POS		3
+#define CHAN8_RESP_FM_OPCODE_POS	4
+#define CHAN8_RESP_RW_POS		5
+#define CHAN8_RESP_PARAM_LEN_POS	6
+#define CHAN8_RESP_PARAM_POS		7
+
+/* Channel-4 data positions */
+#define CHAN4_TYPE_POS		0
+#define CHAN4_EVT_TYPE_POS	1
+#define CHAN4_PLEN_POS		2
+#define CHAN4_EVT_POS		3
+#define CHAN4_PARAM_POS		6
+
+/* Forward declaration file operations */
+void fm_chr_exit(void);
+int fm_chr_init(void);
+
+int fm_chr_fasync(int, struct file *, int);
+
+int fm_chr_open(struct inode *, struct file *);
+int fm_chr_release(struct inode *, struct file *);
+
+ssize_t fm_chr_write(struct file *, const char __user *, size_t, loff_t *);
+ssize_t fm_chr_read(struct file *, char __user *, size_t, loff_t *);
+unsigned int fm_chr_poll(struct file *, poll_table *);
+
+int fm_chr_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
+
+long fm_rx_task(void);
+
+/* List of error codes returned by the FM driver */
+enum {
+	FM_CHR_DRV_ERR_FAILURE = -1,	/* check struct */
+	FM_CHR_DRV_SUCCESS,
+	FM_CHR_DRV_ERR_PENDING = -5,	/* to call reg_complete_cb */
+	FM_CHR_DRV_ERR_ALREADY,	/* already registered */
+	FM_CHR_DRV_ERR_INPROGRESS,
+	FM_CHR_DRV_ERR_NOPROTO,	/* protocol not supported */
+	FM_CHR_DRV_ERR_CLASS = -15,
+	FM_CHR_DRV_READ_TIMEOUT,
+};
+
+/* Header structure for HCI command packet */
+struct hci_command_hdr {
+	uint8_t prefix;
+	uint16_t opcode;
+	uint8_t plen;
+} __attribute__ ((packed));
+
+/* Header structure for HCI event packet */
+struct evt_cmd_complete {
+	uint8_t ncmd;
+	uint16_t opcode;
+} __attribute__ ((packed));
+
+/* Flag to send the signal after the command complete
+ * event's skb is removed from the RX queue
+ */
+#define SIGNAL_PENDING	1
+
+/* FM Character driver data */
+struct fm_chrdrv_ops {
+	int fm_chr_major;
+	struct device *fm_chr_dev;
+	struct class *fm_chr_class;
+
+	spinlock_t lock;
+
+	unsigned long state_flags;
+
+	struct sk_buff_head rx_q;
+	struct tasklet_struct rx_task;
+
+	wait_queue_head_t fm_data_q;
+	struct completion reg_completed;
+
+	struct fasync_struct *fm_fasync;
+
+	long (*st_write) (struct sk_buff *);
+};
+
+#endif /*_FM_CHR_DRV_H */
diff --git a/drivers/misc/ti-st/fmdrv_core.c b/drivers/misc/ti-st/fmdrv_core.c
new file mode 100644
index 0000000..cbf3599
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_core.c
@@ -0,0 +1,3715 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  This sub-module of FM driver does,
+ *  1) Forming group of Channel-8 commands to perform particular
+ *     functionality (ex., frequency set require more than
+ *     one Channel-8 command to be sent to the chip).
+ *  2) Sending each Channel-8 command to the chip and reading
+ *     response back over Shared Transport.
+ *  3) Managing TX and RX Queues and Tasklets
+ *  4) Handling FM Interrupt packet and taking appropriate action.
+ *  5) Loading FM firmware to the chip (common, TX, and RX
+ *     firmware files based on mode selection)
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include "fmdrv.h"
+#include "fmdrv_v4l2.h"
+#include "fmdrv_core.h"
+#include "fmdrv_st.h"
+#include "fmdrv_mixer.h"
+#include "fmdrv_chr.h"
+
+/* -- FM chip register table -- */
+static struct fm_reg_table fm_reg_info[] = {
+	/* ----- FM RX registers -------*/
+	/* opcode, type(rd/wr), reg name */
+	{0x00, REG_RD, "STEREO_GET"},
+	{0x01, REG_RD, "RSSI_LVL_GET"},
+	{0x02, REG_RD, "IF_COUNT_GET"},
+	{0x03, REG_RD, "FLAG_GET"},
+	{0x04, REG_RD, "RDS_SYNC_GET"},
+	{0x05, REG_RD, "RDS_DATA_GET"},
+	{0x0a, REG_WR, "FREQ_SET"},
+	{0x0a, REG_RD, "FREQ_GET"},
+	{0x0b, REG_WR, "AF_FREQ_SET"},
+	{0x0b, REG_RD, "AF_FREQ_GET"},
+	{0x0c, REG_WR, "MOST_MODE_SET"},
+	{0x0c, REG_RD, "MOST_MODE_GET"},
+	{0x0d, REG_WR, "MOST_BLEND_SET"},
+	{0x0d, REG_RD, "MOST_BLEND_GET"},
+	{0x0e, REG_WR, "DEMPH_MODE_SET"},
+	{0x0e, REG_RD, "DEMPH_MODE_GET"},
+	{0x0f, REG_WR, "SEARCH_LVL_SET"},
+	{0x0f, REG_RD, "SEARCH_LVL_GET"},
+	{0x10, REG_WR, "RX_BAND_SET"},
+	{0x10, REG_RD, "RX_BAND_GET"},
+	{0x11, REG_WR, "MUTE_STATUS_SET"},
+	{0x11, REG_RD, "MUTE_STATUS_GET"},
+	{0x12, REG_WR, "RDS_PAUSE_LVL_SET"},
+	{0x12, REG_RD, "RDS_PAUSE_LVL_GET"},
+	{0x13, REG_WR, "RDS_PAUSE_DUR_SET"},
+	{0x13, REG_RD, "RDS_PAUSE_DUR_GET"},
+	{0x14, REG_WR, "RDS_MEM_SET"},
+	{0x14, REG_RD, "RDS_MEM_GET"},
+	{0x15, REG_WR, "RDS_BLK_B_SET"},
+	{0x15, REG_RD, "RDS_BLK_B_GET"},
+	{0x16, REG_WR, "RDS_MSK_B_SET"},
+	{0x16, REG_RD, "RDS_MSK_B_GET"},
+	{0x17, REG_WR, "RDS_PI_MASK_SET"},
+	{0x17, REG_RD, "RDS_PI_MASK_GET"},
+	{0x18, REG_WR, "RDS_PI_SET"},
+	{0x18, REG_RD, "RDS_PI_GET"},
+	{0x19, REG_WR, "RDS_SYSTEM_SET"},
+	{0x19, REG_RD, "RDS_SYSTEM_GET"},
+	{0x1a, REG_WR, "INT_MASK_SET"},
+	{0x1a, REG_RD, "INT_MASK_GET"},
+	{0x1b, REG_WR, "SRCH_DIR_SET"},
+	{0x1b, REG_RD, "SRCH_DIR_GET"},
+	{0x1c, REG_WR, "VOLUME_SET"},
+	{0x1c, REG_RD, "VOLUME_GET"},
+	{0x1d, REG_WR, "AUDIO_ENABLE(SET)"},
+	{0x1d, REG_RD, "AUDIO_ENABLE(GET)"},
+	{0x1e, REG_WR, "PCM_MODE_SET"},
+	{0x1e, REG_RD, "PCM_MODE_SET"},
+	{0x1f, REG_WR, "I2S_MD_CFG_SET"},
+	{0x1f, REG_RD, "I2S_MD_CFG_GET"},
+	{0x20, REG_WR, "POWER_SET"},
+	{0x20, REG_RD, "POWER_GET"},
+	{0x21, REG_WR, "INTx_CONFIG_SET"},
+	{0x21, REG_RD, "INTx_CONFIG_GET"},
+	{0x22, REG_WR, "PULL_EN_SET"},
+	{0x22, REG_RD, "PULL_EN_GET"},
+	{0x23, REG_WR, "HILO_SET"},
+	{0x23, REG_RD, "HILO_GET"},
+	{0x24, REG_WR, "SWITCH2FREF"},
+	{0x25, REG_WR, "FREQ_DRIFT_REP"},
+	{0x28, REG_RD, "PCE_GET"},
+	{0x29, REG_RD, "FIRM_VER_GET"},
+	{0x2a, REG_RD, "ASIC_VER_GET"},
+	{0x2b, REG_RD, "ASIC_ID_GET"},
+	{0x2c, REG_RD, "MAIN_ID_GET"},
+	{0x2d, REG_WR, "TUNER_MODE_SET"},
+	{0x2e, REG_WR, "STOP_SEARCH"},
+	{0x2f, REG_WR, "RDS_CNTRL_SET"},
+	{0x64, REG_WR, "WR_HW_REG"},
+	{0x65, REG_WR, "CODE_DOWNLOAD"},
+	{0x66, REG_WR, "RESET"},
+	{0xfe, REG_WR, "FM_POWER_MODE(SET)"},
+	{0xff, REG_RD, "FM_INTERRUPT"},
+
+	/* --- FM TX registers ------ */
+	{0x37, REG_WR, "CHANL_SET"},
+	{0x37, REG_RD, "CHANL_GET"},
+	{0x38, REG_WR, "CHANL_BW_SET"},
+	{0x38, REG_RD, "CHANL_BW_GET"},
+	{0x87, REG_WR, "REF_SET"},
+	{0x87, REG_RD, "REF_GET"},
+	{0x5a, REG_WR, "POWER_ENB_SET"},
+	{0x3a, REG_WR, "POWER_ATT_SET"},
+	{0x3a, REG_RD, "POWER_ATT_GET"},
+	{0x3b, REG_WR, "POWER_LEL_SET"},
+	{0x3b, REG_RD, "POWER_LEL_GET"},
+	{0x3c, REG_WR, "AUDIO_DEV_SET"},
+	{0x3c, REG_RD, "AUDIO_DEV_GET"},
+	{0x3d, REG_WR, "PILOT_DEV_SET"},
+	{0x3d, REG_RD, "PILOT_DEV_GET"},
+	{0x3e, REG_WR, "RDS_DEV_SET"},
+	{0x3e, REG_RD, "RDS_DEV_GET"},
+	{0x5b, REG_WR, "PUPD_SET"},
+	{0x3f, REG_WR, "AUDIO_IO_SET"},
+	{0x40, REG_WR, "PREMPH_SET"},
+	{0x40, REG_RD, "PREMPH_GET"},
+	{0x41, REG_WR, "TX_BAND_SET"},
+	{0x41, REG_RD, "TX_BAND_GET"},
+	{0x42, REG_WR, "MONO_SET"},
+	{0x42, REG_RD, "MONO_GET"},
+	{0x5C, REG_WR, "MUTE"},
+	{0x43, REG_WR, "MPX_LMT_ENABLE"},
+	{0x06, REG_RD, "LOCK_GET"},
+	{0x5d, REG_WR, "REF_ERR_SET"},
+	{0x44, REG_WR, "PI_SET"},
+	{0x44, REG_RD, "PI_GET"},
+	{0x45, REG_WR, "TYPE_SET"},
+	{0x45, REG_RD, "TYPE_GET"},
+	{0x46, REG_WR, "PTY_SET"},
+	{0x46, REG_RD, "PTY_GET"},
+	{0x47, REG_WR, "AF_SET"},
+	{0x47, REG_RD, "AF_GET"},
+	{0x48, REG_WR, "DISPLAY_SIZE_SET"},
+	{0x48, REG_RD, "DISPLAY_SIZE_GET"},
+	{0x49, REG_WR, "RDS_MODE_SET"},
+	{0x49, REG_RD, "RDS_MODE_GET"},
+	{0x4a, REG_WR, "DISPLAY_MODE_SET"},
+	{0x4a, REG_RD, "DISPLAY_MODE_GET"},
+	{0x62, REG_WR, "LENGHT_SET"},
+	{0x4b, REG_RD, "LENGHT_GET"},
+	{0x4c, REG_WR, "TOGGLE_AB_SET"},
+	{0x4c, REG_RD, "TOGGLE_AB_GET"},
+	{0x4d, REG_WR, "RDS_REP_SET"},
+	{0x4d, REG_RD, "RDS_REP_GET"},
+	{0x63, REG_WR, "RDS_DATA_SET"},
+	{0x5e, REG_WR, "RDS_DATA_ENB"},
+	{0x4e, REG_WR, "TA_SET"},
+	{0x4e, REG_RD, "TA_GET"},
+	{0x4f, REG_WR, "TP_SET"},
+	{0x4f, REG_RD, "TP_GET"},
+	{0x50, REG_WR, "DI_SET"},
+	{0x50, REG_RD, "DI_GET"},
+	{0x51, REG_WR, "MS_SET"},
+	{0x51, REG_RD, "MS_GET"},
+	{0x52, REG_WR, "PS_SCROLL_SPEED_SET"},
+	{0x52, REG_RD, "PS_SCROLL_SPEED_GET"},
+};
+
+/* Region info */
+static struct region_info region_configs[] = {
+	/* Europe/US */
+	{
+	 .channel_spacing = 50,	/* 50 KHz */
+	 .bottom_frequency = 87500,	/* 87.5 MHz */
+	 .top_frequency = 108000,	/* 108 MHz */
+	 .region_index = 0,
+	 },
+	/* Japan */
+	{
+	 .channel_spacing = 50,	/* 50 KHz */
+	 .bottom_frequency = 76000,	/* 76 MHz */
+	 .top_frequency = 90000,	/* 90 MHz */
+	 .region_index = 1,
+	 },
+};
+
+/* Band selection */
+static unsigned char default_radio_region;	/* Europe/US */
+module_param(default_radio_region, byte, 0);
+MODULE_PARM_DESC(default_radio_region, "Region: 0=Europe/US, 1=Japan");
+
+/* RDS buffer blocks */
+static unsigned int default_rds_buf = 300;
+module_param(default_rds_buf, uint, 0444);
+MODULE_PARM_DESC(rds_buf, "RDS buffer entries");
+
+/* FM irq handlers forward declaration */
+static void fm_core_irq_send_flag_getcmd(void);
+static void fm_core_irq_handle_flag_getcmd_resp(void);
+static void fm_core_irq_handle_hw_malfunction(void);
+static void fm_core_irq_handle_rds_start(void);
+static void fm_core_irq_send_rdsdata_getcmd(void);
+static void fm_core_irq_handle_rdsdata_getcmd_resp(void);
+static void fm_core_irq_handle_rds_finish(void);
+static void fm_core_irq_handle_tune_op_ended(void);
+static void fm_core_irq_handle_power_enb(void);
+static void fm_core_irq_handle_low_rssi_start(void);
+static void fm_core_irq_afjump_set_pi(void);
+static void fm_core_irq_handle_set_pi_resp(void);
+static void fm_core_irq_afjump_set_pimask(void);
+static void fm_core_irq_handle_set_pimask_resp(void);
+static void fm_core_irq_afjump_setfreq(void);
+static void fm_core_irq_handle_setfreq_resp(void);
+static void fm_core_irq_afjump_enableint(void);
+static void fm_core_irq_afjump_enableint_resp(void);
+static void fm_core_irq_start_afjump(void);
+static void fm_core_irq_handle_start_afjump_resp(void);
+static void fm_core_irq_afjump_rd_freq(void);
+static void fm_core_irq_afjump_rd_freq_resp(void);
+static void fm_core_irq_handle_low_rssi_finish(void);
+static void fm_core_irq_send_intmsk_cmd(void);
+static void fm_core_irq_handle_intmsk_cmd_resp(void);
+
+/* When FM core receives interrupt packet , following handlers
+ * will be executed one after another to service the interrupt(s) */
+
+/* Interrupt handler index */
+enum fm_irq_handler_index{
+
+	FM_SEND_FLAG_GETCMD_INDEX,
+	FM_HANDLE_FLAG_GETCMD_RESP_INDEX,
+
+	/* HW malfunction irq handler */
+	FM_HW_MAL_FUNC_INDEX,
+
+	/* RDS threshold reached irq handler */
+	FM_RDS_START_INDEX,
+	FM_RDS_SEND_RDS_GETCMD_INDEX,
+	FM_RDS_HANDLE_RDS_GETCMD_RESP_INDEX,
+	FM_RDS_FINISH_INDEX,
+
+	/* Tune operation ended irq handler */
+	FM_HW_TUNE_OP_ENDED_INDEX,
+
+	/* TX power enable irq handler */
+	FM_HW_POWER_ENB_INDEX,
+
+	/* Low RSSI irq handler */
+	FM_LOW_RSSI_START_INDEX,
+	FM_AF_JUMP_SETPI_INDEX,
+	FM_AF_JUMP_HANDLE_SETPI_RESP_INDEX,
+	FM_AF_JUMP_SETPI_MASK_INDEX,
+	FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_INDEX,
+	FM_AF_JUMP_SET_AF_FREQ_INDEX,
+	FM_AF_JUMP_HENDLE_SET_AFFREQ_RESP_INDEX,
+	FM_AF_JUMP_ENABLE_INT_INDEX,
+	FM_AF_JUMP_ENABLE_INT_RESP_INDEX,
+	FM_AF_JUMP_START_AFJUMP_INDEX,
+	FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_INDEX,
+	FM_AF_JUMP_RD_FREQ_INDEX,
+	FM_AF_JUMP_RD_FREQ_RESP_INDEX,
+	FM_LOW_RSSI_FINISH_INDEX,
+
+	/* Interrupt process post action */
+	FM_SEND_INTMSK_CMD_INDEX,
+	FM_HANDLE_INTMSK_CMD_RESP_INDEX,
+};
+
+/* FM interrupt handler table */
+static Int_Handler_ProtoType g_IntHandlerTable[] = {
+	fm_core_irq_send_flag_getcmd,
+	fm_core_irq_handle_flag_getcmd_resp,
+
+	/* HW malfunction irq handler */
+	fm_core_irq_handle_hw_malfunction,
+
+	/* RDS threshold reached irq handler */
+	fm_core_irq_handle_rds_start,
+	fm_core_irq_send_rdsdata_getcmd,
+	fm_core_irq_handle_rdsdata_getcmd_resp,
+	fm_core_irq_handle_rds_finish,
+
+	/* Tune operation ended irq handler */
+	fm_core_irq_handle_tune_op_ended,
+
+	/* TX power enable irq handler */
+	fm_core_irq_handle_power_enb,
+
+	/* Low RSSI irq handler */
+	fm_core_irq_handle_low_rssi_start,
+	fm_core_irq_afjump_set_pi,
+	fm_core_irq_handle_set_pi_resp,
+	fm_core_irq_afjump_set_pimask,
+	fm_core_irq_handle_set_pimask_resp,
+	fm_core_irq_afjump_setfreq,
+	fm_core_irq_handle_setfreq_resp,
+	fm_core_irq_afjump_enableint,
+	fm_core_irq_afjump_enableint_resp,
+	fm_core_irq_start_afjump,
+	fm_core_irq_handle_start_afjump_resp,
+	fm_core_irq_afjump_rd_freq,
+	fm_core_irq_afjump_rd_freq_resp,
+	fm_core_irq_handle_low_rssi_finish,
+
+	/* Interrupt process post action */
+	fm_core_irq_send_intmsk_cmd,
+	fm_core_irq_handle_intmsk_cmd_resp
+};
+
+static struct fmdrv_ops *fmdev;
+
+#ifdef FM_DUMP_TXRX_PKT
+
+ /* To dump outgoing FM Channel-8 packets */
+inline void dump_tx_skb_data(struct sk_buff *skb)
+{
+	int len, len_org;
+	char index;
+	struct fm_cmd_msg_hdr *cmd_hdr;
+
+	cmd_hdr = (struct fm_cmd_msg_hdr *)skb->data;
+	printk(KERN_INFO "<<%shdr:%02x len:%02x opcode:%02x type:%s dlen:%02x",
+	       fm_cb(skb)->completion ? " " : "*", cmd_hdr->header,
+	       cmd_hdr->len, cmd_hdr->fm_opcode,
+	       cmd_hdr->rd_wr ? "RD" : "WR", cmd_hdr->dlen);
+
+	len_org = skb->len - FM_CMD_MSG_HDR_SIZE;
+	if (len_org > 0) {
+		printk("\n   data(%d): ", cmd_hdr->dlen);
+		len = min(len_org, 14);
+		for (index = 0; index < len; index++)
+			printk("%x ",
+			       skb->data[FM_CMD_MSG_HDR_SIZE + index]);
+		printk("%s", (len_org > 14) ? ".." : "");
+	}
+	printk("\n");
+}
+
+ /* To dump incoming FM Channel-8 packets */
+inline void dump_rx_skb_data(struct sk_buff *skb)
+{
+	int len, len_org;
+	char index;
+	struct fm_event_msg_hdr *evt_hdr;
+
+	evt_hdr = (struct fm_event_msg_hdr *)skb->data;
+	printk(KERN_INFO ">> hdr:%02x len:%02x sts:%02x numhci:%02x "
+	    "opcode:%02x type:%s dlen:%02x", evt_hdr->header, evt_hdr->len,
+	    evt_hdr->status, evt_hdr->num_fm_hci_cmds, evt_hdr->fm_opcode,
+	    (evt_hdr->rd_wr) ? "RD" : "WR", evt_hdr->dlen);
+
+	len_org = skb->len - FM_EVT_MSG_HDR_SIZE;
+	if (len_org > 0) {
+		printk("\n   data(%d): ", evt_hdr->dlen);
+		len = min(len_org, 14);
+		for (index = 0; index < len; index++)
+			printk("%x ",
+			       skb->data[FM_EVT_MSG_HDR_SIZE + index]);
+		printk("%s", (len_org > 14) ? ".." : "");
+	}
+	printk("\n");
+}
+#endif
+
+/* Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
+ * transmission */
+static int __fm_core_send_cmd(unsigned char fmreg_index, void *payload,
+			      int payload_len,
+			      struct completion *wait_completion)
+{
+	struct sk_buff *skb;
+	struct fm_cmd_msg_hdr *cmd_hdr;
+	int size;
+
+	FMDRV_API_START();
+
+	if (fmreg_index >= FM_REG_MAX_ENTRIES) {
+		FM_DRV_ERR("Invalid fm register index");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	if (test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag) &&
+			payload == NULL) {
+		FM_DRV_ERR("Payload data is NULL during firmware download");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	if (!test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag))
+		size =
+		    FM_CMD_MSG_HDR_SIZE + ((payload == NULL) ? 0 : payload_len);
+	else
+		size = payload_len;
+
+	/* Allocate memory for new packet */
+	skb = alloc_skb(size, GFP_ATOMIC);
+	if (!skb) {
+		FM_DRV_ERR("No memory to create new SKB");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	/* Don't fill FM header info for the commands which come from
+	 * FM firmware file */
+	if (!test_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag) ||
+	    test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
+		/* Fill command header info */
+		cmd_hdr =
+		    (struct fm_cmd_msg_hdr *)skb_put(skb, FM_CMD_MSG_HDR_SIZE);
+		cmd_hdr->header = FM_PKT_LOGICAL_CHAN_NUMBER;	/* 0x08 */
+		/* 3 (fm_opcode,rd_wr,dlen) + payload len) */
+		cmd_hdr->len = ((payload == NULL) ? 0 : payload_len) + 3;
+		/* FM opcode */
+		cmd_hdr->fm_opcode = fm_reg_info[fmreg_index].opcode;
+		/* read/write type */
+		cmd_hdr->rd_wr = fm_reg_info[fmreg_index].type;
+		cmd_hdr->dlen = payload_len;
+		fm_cb(skb)->fm_opcode = fm_reg_info[fmreg_index].opcode;
+	} else {
+		fm_cb(skb)->fm_opcode = *((char *)payload + 2);
+	}
+	/* Fill payload data */
+	if (payload != NULL)
+		memcpy(skb_put(skb, payload_len), payload, payload_len);
+
+	/* Fill completion handler TX tasklet needs
+	 * this info before sending packet to TX Q */
+	fm_cb(skb)->completion = wait_completion;
+
+	/* Add this new packet to TX Q and schedule TX tasklet */
+	skb_queue_tail(&fmdev->tx_q, skb);
+	tasklet_schedule(&fmdev->tx_task);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Sends FM Channel-8 command to the chip and waits for the reponse */
+int fm_core_send_cmd(unsigned char fmreg_index, void *payload, int payload_len,
+		     struct completion *wait_completion, void *reponse,
+		     int *reponse_len)
+{
+	struct sk_buff *skb;
+	struct fm_event_msg_hdr *fm_evt_hdr;
+	unsigned long timeleft;
+	unsigned long flags;
+	int ret;
+
+	FMDRV_API_START();
+
+	init_completion(wait_completion);
+	ret = __fm_core_send_cmd(fmreg_index, payload, payload_len,
+				 wait_completion);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Wait for the reponse from the chip */
+	timeleft = wait_for_completion_timeout(wait_completion,
+					       FM_DRV_TX_TIMEOUT);
+	if (!timeleft) {
+		FM_DRV_ERR("Timeout(%d sec),didn't get reg"
+			   "completion signal from RX tasklet",
+			   jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+		FMDRV_API_EXIT(-ETIMEDOUT);
+		return -ETIMEDOUT;
+	}
+	if (!fmdev->response_skb) {
+		FM_DRV_ERR("Reponse SKB is missing ");
+		FMDRV_API_EXIT(-EFAULT);
+		return -EFAULT;
+	}
+	spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+	skb = fmdev->response_skb;
+	fmdev->response_skb = NULL;
+	spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+	fm_evt_hdr = (void *)skb->data;
+	if (fm_evt_hdr->status != 0) {
+		FM_DRV_ERR("Received event pkt status(%d) is not zero",
+			   fm_evt_hdr->status);
+		kfree_skb(skb);
+		FMDRV_API_EXIT(-EIO);
+		return -EIO;
+	}
+	/* Send reponse data to caller */
+	if (reponse != NULL && reponse_len != NULL && fm_evt_hdr->dlen) {
+		/* Skip header info and copy only response data */
+		skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+		memcpy(reponse, skb->data, fm_evt_hdr->dlen);
+		*reponse_len = fm_evt_hdr->dlen;
+	} else if (reponse_len != NULL && fm_evt_hdr->dlen == 0) {
+		*reponse_len = 0;
+	}
+	kfree_skb(skb);
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Resets RDS cache parameters */
+static inline void fm_core_rx_reset_rds_cache(void)
+{
+	FMDRV_API_START();
+
+	fmdev->rx.rds.flag = FM_RX_RDS_DISABLE;
+	fmdev->rx.rds.last_block_index = 0;
+	fmdev->rx.rds.wr_index = 0;
+	fmdev->rx.rds.rd_index = 0;
+
+	if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+		fmdev->irq_info.mask |= FM_LEV_EVENT;
+
+	FMDRV_API_EXIT(0)
+}
+
+/* Resets current station info */
+static inline void fm_core_rx_reset_curr_station_info(void)
+{
+	FMDRV_API_START();
+
+	fmdev->rx.cur_station_info.picode = FM_NO_PI_CODE;
+	fmdev->rx.cur_station_info.no_of_items_in_afcache = 0;
+	fmdev->rx.cur_station_info.af_list_max = 0;
+
+	FMDRV_API_EXIT(0);
+}
+
+/* --- Helper functions used in FM interrupt handlers ---*/
+
+static inline char fm_core_check_cmdresp_status(struct sk_buff **skb)
+{
+	struct fm_event_msg_hdr *fm_evt_hdr;
+	unsigned long flags;
+
+	FMDRV_API_START();
+
+	spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+	*skb = fmdev->response_skb;
+	fmdev->response_skb = NULL;
+	spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+	fm_evt_hdr = (void *)(*skb)->data;
+	if (fm_evt_hdr->status != 0) {
+		FM_DRV_ERR("irq : opcode %x response status field is not zero",
+			   fm_evt_hdr->fm_opcode);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return FM_ST_FAILED;
+	}
+
+	FMDRV_API_EXIT(FM_ST_SUCCESS);
+	return FM_ST_SUCCESS;
+}
+
+/* Interrupt process timeout handler */
+static void fm_core_int_timeout_handler(unsigned long data)
+{
+	FMDRV_API_START();
+
+	FM_DRV_DBG("irq : timeout,trying to re-enable fm interrupts");
+	fmdev->irq_info.irq_service_timeout_retry++;
+
+	/* One of the irq handler did not get proper response from the chip.
+	 * So take recovery action here. FM interrupts are disabled in the
+	 * beginning of interrupt process. Therefore reset stage index to
+	 * re-enable default interrupts. So that next interrupt will be
+	 * processed as usual.
+	 */
+	if (fmdev->irq_info.irq_service_timeout_retry <=
+	    FM_IRQ_TIMEOUT_RETRY_MAX) {
+		fmdev->irq_info.stage_index = FM_SEND_INTMSK_CMD_INDEX;
+		fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+							 stage_index] ();
+	} else {
+		/* Retry count reached maximum limit.
+		 * Stop recovery action (interrupt
+		 * reenable process) and reset stage
+		 * index & retry count values
+		 */
+		fmdev->irq_info.stage_index = 0;
+		fmdev->irq_info.irq_service_timeout_retry = 0;
+		FM_DRV_ERR("Recovery action failed during \
+		    irq processing,max retry reached");
+	}
+	FMDRV_API_EXIT(0);
+}
+
+/* --------- FM interrupt handlers ------------*/
+
+static void fm_core_irq_send_flag_getcmd(void)
+{
+	unsigned short flag;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Send FLAG_GET command , to know the source of interrupt */
+	ret = __fm_core_send_cmd(FLAG_GET, NULL, sizeof(flag), NULL);
+	if (ret) {
+		/* Failed to send the cmd , Don't update the stage index &
+		 * Trigger the timer to take recovery action */
+		FM_DRV_ERR("irq : failed to send flag_get command,"
+			   "initiating irq recovery process");
+	} else
+		fmdev->irq_info.stage_index = FM_HANDLE_FLAG_GETCMD_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_flag_getcmd_resp(void)
+{
+	struct sk_buff *skb;
+	struct fm_event_msg_hdr *fm_evt_hdr;
+	char ret;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	}
+	fm_evt_hdr = (void *)skb->data;
+
+	/* Skip header info and copy only response data */
+	skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+	memcpy(&fmdev->irq_info.flag, skb->data, fm_evt_hdr->dlen);
+
+	FM_STORE_BE16_TO_LE16(fmdev->irq_info.flag, fmdev->irq_info.flag);
+	FM_DRV_DBG("irq : flag register(0x%x)", fmdev->irq_info.flag);
+
+	/* Continue next function in interrupt handler table */
+	fmdev->irq_info.stage_index = FM_HW_MAL_FUNC_INDEX;
+
+	FMDRV_API_EXIT(0);
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+}
+
+static void fm_core_irq_handle_hw_malfunction(void)
+{
+	FMDRV_API_START();
+
+	if (fmdev->irq_info.flag & FM_MAL_EVENT & fmdev->irq_info.mask)
+		FM_DRV_ERR("irq : Hw MAL interrupt received - do nothing");
+
+	/* Continue next function in interrupt handler table */
+	fmdev->irq_info.stage_index = FM_RDS_START_INDEX;
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_rds_start(void)
+{
+	FMDRV_API_START();
+
+	if (fmdev->irq_info.flag & FM_RDS_EVENT & fmdev->irq_info.mask) {
+		FM_DRV_DBG("irq : rds threshold reached");
+		fmdev->irq_info.stage_index = FM_RDS_SEND_RDS_GETCMD_INDEX;
+	} else {
+		/* Continue next function in interrupt handler table */
+		fmdev->irq_info.stage_index = FM_HW_TUNE_OP_ENDED_INDEX;
+	}
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_send_rdsdata_getcmd(void)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Send the command to read RDS data from the chip */
+	ret = __fm_core_send_cmd(RDS_DATA_GET, NULL,
+				 (FM_RX_RDS_FIFO_THRESHOLD * 3), NULL);
+	if (ret)
+		FM_DRV_ERR("irq : failed to send rds get commandm,"
+			   "initiating irq recovery process");
+	else
+		fmdev->irq_info.stage_index =
+		    FM_RDS_HANDLE_RDS_GETCMD_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+/* Keeps track of current RX channel AF (Alternate Frequency) */
+static void __fm_core_rx_update_af_cache(unsigned char af)
+{
+	unsigned char index;
+	unsigned int freq;
+	FMDRV_API_START();
+
+	/* First AF indicates the number of AF follows. Reset the list */
+	if ((af >= FM_RDS_1_AF_FOLLOWS) && (af <= FM_RDS_25_AF_FOLLOWS)) {
+		fmdev->rx.cur_station_info.af_list_max =
+		    (af - FM_RDS_1_AF_FOLLOWS + 1);
+		fmdev->rx.cur_station_info.no_of_items_in_afcache = 0;
+		FM_DRV_DBG("No of expected AF : %d",
+			   fmdev->rx.cur_station_info.af_list_max);
+	} else if (((af >= FM_RDS_MIN_AF)
+		    && (fmdev->rx.region.region_index == FM_BAND_EUROPE_US)
+		    && (af <= FM_RDS_MAX_AF)) || ((af >= FM_RDS_MIN_AF)
+						  && (fmdev->rx.region.
+						      region_index ==
+						      FM_BAND_JAPAN)
+						  && (af <=
+						      FM_RDS_MAX_AF_JAPAN))) {
+		freq = fmdev->rx.region.bottom_frequency + (af * 100);
+		/* If the AF is the same
+		 * as the tuned station frequency - ignore it
+		 */
+		if (freq == fmdev->rx.curr_freq) {
+			FM_DRV_DBG("Current frequency(%d) is \
+			    matching with received AF(%d)",
+			    fmdev->rx.curr_freq, freq);
+			return;
+		}
+		/* Do check in AF cache */
+		for (index = 0;
+		     index < fmdev->rx.cur_station_info.no_of_items_in_afcache;
+		     index++) {
+			if (fmdev->rx.cur_station_info.af_cache[index] == freq)
+				break;
+		}
+		/* Reached the limit of the list - ignore the next AF */
+		if (index == fmdev->rx.cur_station_info.af_list_max) {
+			FM_DRV_DBG("AF cache is full");
+			return;
+		}
+
+		/* If we reached the end of the list then
+		 * this AF is not in the list - add it
+		 */
+		if (index == fmdev->rx.cur_station_info.
+				   no_of_items_in_afcache) {
+			FM_DRV_DBG("Storing AF %d into AF cache index %d", freq,
+				   index);
+			fmdev->rx.cur_station_info.af_cache[index] = freq;
+			fmdev->rx.cur_station_info.no_of_items_in_afcache++;
+		}
+	}
+	FMDRV_API_EXIT(0);
+}
+
+/* Converts RDS buffer data from big endian format
+ * to little endian format
+ */
+static void __fm_core_rdsparse_swapbytes(struct fm_rdsdata_format *rds_format)
+{
+	unsigned char byte1;
+	unsigned char index = 0;
+	char *rds_buff;
+
+	FMDRV_API_START();
+
+	/* Since in Orca the 2 RDS Data bytes are in little endian and
+	 * in Dolphin they are in big endian, the parsing of the RDS data
+	 * is chip dependent */
+	if (fmdev->asci_id != 0x6350) {
+		rds_buff = &rds_format->rdsData.groupDataBuff.rdsBuff[0];
+		while (index + 1 < FM_RX_RDS_INFO_FIELD_MAX) {
+			byte1 = rds_buff[index];
+			rds_buff[index] = rds_buff[index + 1];
+			rds_buff[index + 1] = byte1;
+			index += 2;
+		}
+	}
+
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_rdsdata_getcmd_resp(void)
+{
+	struct sk_buff *skb;
+	char *rds_data;
+	char metaData;
+	unsigned char type, block_index;
+	unsigned long group_index;
+	struct fm_rdsdata_format rds_format;
+	int rds_len, ret;
+	unsigned short cur_picode;
+	unsigned char tmpbuf[3];
+	unsigned long flags;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	}
+	/* Skip header info */
+	skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+	rds_data = skb->data;
+	rds_len = skb->len;
+
+	/* Parse the RDS data */
+	while (rds_len >= FM_RDS_BLOCK_SIZE) {
+		metaData = rds_data[2];
+		/* Get the type:
+		 * 0=A, 1=B, 2=C, 3=C', 4=D, 5=E */
+		type = (metaData & 0x07);
+
+		/* Transform the block type
+		 * into an index sequence (0, 1, 2, 3, 4) */
+		block_index = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
+		FM_DRV_DBG("Block index:%d(%s) ", block_index,
+			   (metaData & FM_RDS_STATUS_ERROR_MASK) ? "Bad" :
+			   "Ok");
+		if (((metaData & FM_RDS_STATUS_ERROR_MASK) == 0)
+		    && (block_index == FM_RDS_BLOCK_INDEX_A
+			|| (block_index == fmdev->rx.rds.last_block_index + 1
+			    && block_index <= FM_RDS_BLOCK_INDEX_D))) {
+			/* Skip checkword (control) byte
+			 * and copy only data byte */
+			memcpy(&rds_format.rdsData.groupDataBuff.
+			       rdsBuff[block_index * (FM_RDS_BLOCK_SIZE - 1)],
+			       rds_data, (FM_RDS_BLOCK_SIZE - 1));
+			fmdev->rx.rds.last_block_index = block_index;
+
+			/* If completed a whole group then handle it */
+			if (block_index == FM_RDS_BLOCK_INDEX_D) {
+				FM_DRV_DBG("Good block received");
+				__fm_core_rdsparse_swapbytes(&rds_format);
+
+				/* Extract PI code and store in local cache.
+				 * We need this during AF switch processing */
+				cur_picode =
+				    FM_BE16_TO_LE16(rds_format.rdsData.
+						    groupGeneral.piData);
+				if (fmdev->rx.cur_station_info.picode !=
+				    cur_picode)
+					fmdev->rx.cur_station_info.picode =
+					    cur_picode;
+				FM_DRV_DBG("picode:%d", cur_picode);
+
+				group_index =
+				    (rds_format.rdsData.groupGeneral.
+				     blockB_byte1 >> 3);
+				FM_DRV_DBG("Group:%ld%s", group_index / 2,
+					   (group_index % 2) ? "B" : "A");
+
+				group_index =
+				    1 << (rds_format.rdsData.groupGeneral.
+					  blockB_byte1 >> 3);
+				if (group_index == FM_RDS_GROUP_TYPE_MASK_0A) {
+					__fm_core_rx_update_af_cache
+					    (rds_format.rdsData.group0A.
+					     firstAf);
+					__fm_core_rx_update_af_cache(rds_format.
+								     rdsData.
+								     group0A.
+								     secondAf);
+				}
+			}
+		} else {
+			FM_DRV_DBG("Block sequence mismatch");
+			fmdev->rx.rds.last_block_index = -1;
+		}
+		rds_len -= FM_RDS_BLOCK_SIZE;
+		rds_data += FM_RDS_BLOCK_SIZE;
+	}
+
+     /* Copy raw rds data to internal rds buffer */
+	rds_data = skb->data;
+	rds_len = skb->len;
+
+	spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
+	while (rds_len > 0) {
+		/* Fill RDS buffer as per V4L2 specification.
+		 * Store control byte
+		 */
+		type = (rds_data[2] & 0x07);
+		block_index = (type <= FM_RDS_BLOCK_C ? type : (type - 1));
+		tmpbuf[2] = block_index;	/* Offset name */
+		tmpbuf[2] |= block_index << 3;	/* Received offset */
+
+		/* Store data byte */
+		tmpbuf[0] = rds_data[0];
+		tmpbuf[1] = rds_data[1];
+
+		memcpy(&fmdev->rx.rds.buffer[fmdev->rx.rds.wr_index], &tmpbuf,
+		       FM_RDS_BLOCK_SIZE);
+		fmdev->rx.rds.wr_index =
+		    (fmdev->rx.rds.wr_index +
+		     FM_RDS_BLOCK_SIZE) % fmdev->rx.rds.buf_size;
+
+		/* Check for overflow & start over */
+		if (fmdev->rx.rds.wr_index == fmdev->rx.rds.rd_index) {
+			FM_DRV_DBG("RDS buffer overflow");
+			fmdev->rx.rds.wr_index = 0;
+			fmdev->rx.rds.rd_index = 0;
+			break;
+		}
+		rds_len -= FM_RDS_BLOCK_SIZE;
+		rds_data += FM_RDS_BLOCK_SIZE;
+	}
+	spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+
+	/* Wakeup read queue */
+	if (fmdev->rx.rds.wr_index != fmdev->rx.rds.rd_index)
+		wake_up_interruptible(&fmdev->rx.rds.read_queue);
+
+	fmdev->irq_info.stage_index = FM_RDS_FINISH_INDEX;
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_rds_finish(void)
+{
+	FMDRV_API_START();
+
+	/* Continue next function in interrupt handler table */
+	fmdev->irq_info.stage_index = FM_HW_TUNE_OP_ENDED_INDEX;
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_tune_op_ended(void)
+{
+	FMDRV_API_START();
+
+	if (fmdev->irq_info.flag & (FM_FR_EVENT | FM_BL_EVENT) & fmdev->
+	    irq_info.mask) {
+		FM_DRV_DBG("irq : tune ended/bandlimit reached");
+		if (test_and_clear_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag)) {
+			fmdev->irq_info.stage_index = FM_AF_JUMP_RD_FREQ_INDEX;
+		} else {
+			complete(&fmdev->maintask_completion);
+			fmdev->irq_info.stage_index = FM_HW_POWER_ENB_INDEX;
+		}
+	} else
+		fmdev->irq_info.stage_index = FM_HW_POWER_ENB_INDEX;
+
+	FMDRV_API_EXIT(0);
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+}
+
+static void fm_core_irq_handle_power_enb(void)
+{
+	FMDRV_API_START();
+
+	if (fmdev->irq_info.flag & FM_POW_ENB_EVENT) {
+		FM_DRV_DBG("irq : Power Enabled/Disabled");
+		complete(&fmdev->maintask_completion);
+	}
+
+	/* Continue next function in interrupt handler table */
+	fmdev->irq_info.stage_index = FM_LOW_RSSI_START_INDEX;
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_low_rssi_start(void)
+{
+	FMDRV_API_START();
+
+	if ((fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON) &&
+	    (fmdev->irq_info.flag & FM_LEV_EVENT & fmdev->irq_info.mask) &&
+	    (fmdev->rx.curr_freq != FM_UNDEFINED_FREQ) &&
+	    (fmdev->rx.cur_station_info.no_of_items_in_afcache != 0)) {
+		FM_DRV_DBG("irq : rssi level has fallen below threshold level");
+
+		/* Disable further low RSSI interrupts */
+		fmdev->irq_info.mask &= ~FM_LEV_EVENT;
+
+		fmdev->rx.cur_Afjump_index = 0;
+		fmdev->rx.freq_before_jump = fmdev->rx.curr_freq;
+		fmdev->irq_info.stage_index = FM_AF_JUMP_SETPI_INDEX;
+	} else {
+		/* Continue next function in interrupt handler table */
+		fmdev->irq_info.stage_index = FM_SEND_INTMSK_CMD_INDEX;
+	}
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_afjump_set_pi(void)
+{
+	int ret;
+	unsigned short payload;
+
+	FMDRV_API_START();
+
+	/* Set PI code - must be updated if the AF list is not empty */
+	payload = FM_LE16_TO_BE16(fmdev->rx.cur_station_info.picode);
+	ret = __fm_core_send_cmd(RDS_PI_SET, &payload, sizeof(payload), NULL);
+	if (ret)
+		FM_DRV_ERR("irq : failed to set PI,"
+			   "initiating irq recovery process");
+	else
+		fmdev->irq_info.stage_index =
+		    FM_AF_JUMP_HANDLE_SETPI_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_set_pi_resp(void)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	}
+	/* Continue next function in interrupt handler table */
+	fmdev->irq_info.stage_index = FM_AF_JUMP_SETPI_MASK_INDEX;
+
+	FMDRV_API_EXIT(0);
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+}
+
+static void fm_core_irq_afjump_set_pimask(void)
+{
+	int ret;
+	unsigned short payload;
+
+	FMDRV_API_START();
+
+	/* Set PI mask.
+	 * 0xFFFF = Enable PI code matching
+	 * 0x0000 = Disable PI code matching
+	 */
+	payload = 0x0000;
+	ret =
+	    __fm_core_send_cmd(RDS_PI_MASK_SET, &payload, sizeof(payload),
+			       NULL);
+	if (ret < 0)
+		FM_DRV_ERR("irq : failed to set PI mask,"
+			   "initiating irq recovery process");
+	else
+		fmdev->irq_info.stage_index =
+		    FM_AF_JUMP_HANDLE_SETPI_MASK_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_set_pimask_resp(void)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	}
+	/* Continue next function in interrupt handler table */
+	fmdev->irq_info.stage_index = FM_AF_JUMP_SET_AF_FREQ_INDEX;
+	FMDRV_API_EXIT(0);
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+}
+
+static void fm_core_irq_afjump_setfreq(void)
+{
+	unsigned short frq_index;
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("Swtiching to %d KHz\n",
+	       fmdev->rx.cur_station_info.af_cache[fmdev->rx.cur_Afjump_index]);
+	frq_index =
+	    (fmdev->rx.cur_station_info.af_cache[fmdev->rx.cur_Afjump_index] -
+	     fmdev->rx.region.bottom_frequency) /
+	    fmdev->rx.region.channel_spacing;
+
+	FM_STORE_LE16_TO_BE16(payload, frq_index);
+	ret = __fm_core_send_cmd(AF_FREQ_SET, &payload, sizeof(payload), NULL);
+	if (ret < 0)
+		FM_DRV_ERR("irq : failed to set AF freq,"
+			   "initiating irq recovery process");
+	else
+		fmdev->irq_info.stage_index =
+		    FM_AF_JUMP_HENDLE_SET_AFFREQ_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_setfreq_resp(void)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	} else {
+		/* Continue next function in interrupt handler table */
+		fmdev->irq_info.stage_index = FM_AF_JUMP_ENABLE_INT_INDEX;
+	}
+	FMDRV_API_EXIT(0);
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+}
+
+static void fm_core_irq_afjump_enableint(void)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Enable FR (tuning operation ended) interrupt */
+	payload = FM_LE16_TO_BE16(FM_FR_EVENT);
+	ret = __fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload), NULL);
+	if (ret)
+		FM_DRV_ERR("irq : failed to enable FR interrupt,"
+			   "initiating irq recovery process");
+	else
+		fmdev->irq_info.stage_index = FM_AF_JUMP_ENABLE_INT_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_afjump_enableint_resp(void)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	}
+	/* Continue next function in interrupt handler table */
+	fmdev->irq_info.stage_index = FM_AF_JUMP_START_AFJUMP_INDEX;
+	FMDRV_API_EXIT(0);
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+}
+
+static void fm_core_irq_start_afjump(void)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Issue AF switch start command to the chip */
+	FM_STORE_LE16_TO_BE16(payload, FM_TUNER_AF_JUMP_MODE);
+	ret =
+	    __fm_core_send_cmd(TUNER_MODE_SET, &payload, sizeof(payload), NULL);
+	if (ret)
+		FM_DRV_ERR("irq : failed to start af switch,"
+			   "initiating irq recovery process");
+	else
+		fmdev->irq_info.stage_index =
+		    FM_AF_JUMP_HANDLE_START_AFJUMP_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_start_afjump_resp(void)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	}
+	fmdev->irq_info.stage_index = FM_SEND_FLAG_GETCMD_INDEX;
+	set_bit(FM_AF_SWITCH_INPROGRESS, &fmdev->flag);
+	clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_afjump_rd_freq(void)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = __fm_core_send_cmd(FREQ_GET, NULL, sizeof(payload), NULL);
+	if (ret)
+		FM_DRV_ERR("irq : failed to read cur freq,"
+			   "initiating irq recovery process");
+	else
+		fmdev->irq_info.stage_index = FM_AF_JUMP_RD_FREQ_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_afjump_rd_freq_resp(void)
+{
+	struct sk_buff *skb;
+	unsigned short read_freq;
+	unsigned int curr_freq, jumped_freq;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	}
+	/* Skip header info and copy only response data */
+	skb_pull(skb, sizeof(struct fm_event_msg_hdr));
+	memcpy(&read_freq, skb->data, sizeof(read_freq));
+	read_freq = FM_BE16_TO_LE16(read_freq);
+	curr_freq = fmdev->rx.region.bottom_frequency +
+	    ((unsigned int)read_freq * fmdev->rx.region.channel_spacing);
+
+	jumped_freq =
+	    fmdev->rx.cur_station_info.af_cache[fmdev->rx.cur_Afjump_index];
+
+	/* If the frequency was changed the jump succeeded */
+	if ((curr_freq != fmdev->rx.freq_before_jump) &&
+	    (curr_freq == jumped_freq)) {
+		FM_DRV_DBG("Successfully switched to alternate frequency %d",
+			   curr_freq);
+		fmdev->rx.curr_freq = curr_freq;
+
+		/* Reset RDS cache */
+		fm_core_rx_reset_rds_cache();
+
+		/* AF feature is on, enable low level RSSI interrupt */
+		if (fmdev->rx.af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+			fmdev->irq_info.mask |= FM_LEV_EVENT;
+
+		/* Call the next stage of general
+		 * interrupts handler to handle other interrupts
+		 */
+		fmdev->irq_info.stage_index = FM_LOW_RSSI_FINISH_INDEX;
+	} else {		/* jump to the next freq in the AF list */
+
+		/* Go to next index in the AF list */
+		fmdev->rx.cur_Afjump_index++;
+
+		/* If we reached the end of the list - stop searching */
+		if (fmdev->rx.cur_Afjump_index >=
+		    fmdev->rx.cur_station_info.no_of_items_in_afcache) {
+			FM_DRV_DBG("AF switch processing failed");
+			/* Call the next stage of general
+			 * interrupts handler to handle other interrupts
+			 */
+			fmdev->irq_info.stage_index = FM_LOW_RSSI_FINISH_INDEX;
+		} else {	/* AF List is not over - try next one */
+
+			FM_DRV_DBG("Trying next frequency in af cache");
+			fmdev->irq_info.stage_index = FM_AF_JUMP_SETPI_INDEX;
+		}
+	}
+	FMDRV_API_EXIT(0);
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+}
+
+static void fm_core_irq_handle_low_rssi_finish(void)
+{
+	FMDRV_API_START();
+
+	/* Continue next function in interrupt handler table */
+	fmdev->irq_info.stage_index = FM_SEND_INTMSK_CMD_INDEX;
+	fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+						 stage_index] ();
+
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_send_intmsk_cmd(void)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Re-enable FM interrupts */
+	FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+	ret = __fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload), NULL);
+	if (ret)
+		FM_DRV_ERR("irq : failed to send int_mask_set cmd,"
+			   "initiating irq recovery process");
+	else
+		fmdev->irq_info.stage_index = FM_HANDLE_INTMSK_CMD_RESP_INDEX;
+
+	/* Start timer to track timeout */
+	mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+		  FM_DRV_TX_TIMEOUT);
+	FMDRV_API_EXIT(0);
+}
+
+static void fm_core_irq_handle_intmsk_cmd_resp(void)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Stop timeout timer */
+	del_timer(&fmdev->irq_info.int_timeout_timer);
+
+	ret = fm_core_check_cmdresp_status(&skb);
+	if (ret) {
+		FM_DRV_ERR("Initiating irq recovery process");
+		mod_timer(&fmdev->irq_info.int_timeout_timer, jiffies +
+			  FM_DRV_TX_TIMEOUT);
+		FMDRV_API_EXIT(FM_ST_FAILED);
+		return;
+	}
+	/* This is last function in interrupt table to be executed.
+	 * So, reset stage index to 0.
+	 */
+	fmdev->irq_info.stage_index = FM_SEND_FLAG_GETCMD_INDEX;
+
+	/* Start processing any pending interrupt */
+	if (test_and_clear_bit(FM_INTTASK_SCHEDULE_PENDING, &fmdev->flag)) {
+		FMDRV_API_EXIT(0);
+		fmdev->irq_info.fm_IntActionHandlerTable[fmdev->irq_info.
+							 stage_index]
+		    ();
+	} else
+		clear_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+
+	FMDRV_API_EXIT(0);
+}
+
+/* --------------- FM TX tasklet -----------------*/
+
+/* FM V4L2 interface and FM mixer control interface layer
+ * schedule this tasklet whenever it wants to transmit FM packet.
+ */
+static void fm_core_tx_tasklet(unsigned long arg)
+{
+	struct sk_buff *skb;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Check, is there any timeout happenned to last transmitted packet */
+	if (!atomic_read(&fmdev->tx_cnt) &&
+	    ((jiffies - fmdev->last_tx_jiffies) > FM_DRV_TX_TIMEOUT)) {
+		FM_DRV_ERR("TX timeout occurred");
+		atomic_set(&fmdev->tx_cnt, 1);
+	}
+	/* Send queued FM TX packets */
+	if (atomic_read(&fmdev->tx_cnt)) {
+		skb = skb_dequeue(&fmdev->tx_q);
+		if (skb) {
+			atomic_dec(&fmdev->tx_cnt);
+			fmdev->last_sent_pkt_opcode = fm_cb(skb)->fm_opcode;
+
+			if (fmdev->response_completion != NULL)
+				FM_DRV_ERR
+				    ("Response completion handler is not NULL");
+
+			fmdev->response_completion = fm_cb(skb)->completion;
+#ifdef FM_DUMP_TXRX_PKT
+			dump_tx_skb_data(skb);
+#endif
+			/* Forward SKB to FM ST,
+			 * FM ST will internally forward SKB to ST driver.
+			 */
+			ret = fm_st_send(skb);
+			if (ret < 0) {
+				fmdev->response_completion = NULL;
+				FM_DRV_ERR
+				    ("TX tasklet failed to send skb(%p)", skb);
+				atomic_set(&fmdev->tx_cnt, 1);
+			} else
+				fmdev->last_tx_jiffies = jiffies;
+		}
+	}
+	FMDRV_API_EXIT(0);
+}
+
+/* --------------- FM RX tasklet -----------------*/
+
+/* FM ST will schedule this tasklet whenever it receives
+ * FM packet from ST driver.
+ */
+static void fm_core_rx_tasklet(unsigned long arg)
+{
+	struct fm_event_msg_hdr *fm_evt_hdr;
+	struct sk_buff *skb;
+	unsigned char num_fm_hci_cmds;
+	unsigned long flags;
+
+	FMDRV_API_START();
+
+	/* Process all packets in the RX queue */
+	while ((skb = skb_dequeue(&fmdev->rx_q))) {
+		if (skb->len < sizeof(struct fm_event_msg_hdr)) {
+			FM_DRV_ERR("skb(%p) has only %d bytes"
+				   "atleast need %d bytes to decode",
+				   skb, skb->len,
+				   sizeof(struct fm_event_msg_hdr));
+			kfree_skb(skb);
+			continue;
+		}
+
+		fm_evt_hdr = (void *)skb->data;
+		num_fm_hci_cmds = fm_evt_hdr->num_fm_hci_cmds;
+
+#ifdef FM_DUMP_TXRX_PKT
+		dump_rx_skb_data(skb);
+#endif
+		/* FM interrupt packet? */
+		if (fm_evt_hdr->fm_opcode == fm_reg_info[FM_INTERRUPT].opcode) {
+			/* FM interrupt handler started already? */
+			if (!test_bit(FM_INTTASK_RUNNING, &fmdev->flag)) {
+				set_bit(FM_INTTASK_RUNNING, &fmdev->flag);
+				if (fmdev->irq_info.stage_index != 0) {
+					FM_DRV_ERR("Invalid stage index,"
+						   "resetting to zero");
+					fmdev->irq_info.stage_index = 0;
+				}
+
+				/* Execute first function
+				 * in interrupt handler table
+				 */
+				fmdev->irq_info.fm_IntActionHandlerTable
+				    [fmdev->irq_info.stage_index]
+				    ();
+			} else {
+				set_bit(FM_INTTASK_SCHEDULE_PENDING,
+					&fmdev->flag);
+			}
+			kfree_skb(skb);
+		}
+		/* Anyone waiting for this with completion handler? */
+		else if (fm_evt_hdr->fm_opcode == fmdev->last_sent_pkt_opcode &&
+			 fmdev->response_completion != NULL) {
+			if (fmdev->response_skb != NULL)
+				FM_DRV_ERR("Response SKB pointer is not NULL");
+
+			spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+			fmdev->response_skb = skb;
+			spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+			complete(fmdev->response_completion);
+
+			fmdev->response_completion = NULL;
+			atomic_set(&fmdev->tx_cnt, 1);
+		}
+		/* Is this for interrupt handler? */
+		else if (fm_evt_hdr->fm_opcode == fmdev->last_sent_pkt_opcode &&
+			 fmdev->response_completion == NULL) {
+			if (fmdev->response_skb != NULL)
+				FM_DRV_ERR("Response SKB pointer is not NULL");
+
+			spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
+			fmdev->response_skb = skb;
+			spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
+
+			/* Execute interrupt handler where state index points */
+			fmdev->irq_info.fm_IntActionHandlerTable
+			    [fmdev->irq_info.stage_index]
+			    ();
+
+			kfree_skb(skb);
+			atomic_set(&fmdev->tx_cnt, 1);
+		} else {
+			FM_DRV_ERR("Nobody claimed SKB(%p),purging", skb);
+		}
+
+		/* Check flow control field.
+		 * If Num_FM_HCI_Commands field is not zero,
+		 * schedule FM TX tasklet.
+		 */
+		if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt)) {
+			if (!skb_queue_empty(&fmdev->tx_q))
+				tasklet_schedule(&fmdev->tx_task);
+		}
+	}
+	FMDRV_API_EXIT(0);
+}
+
+/* ----- Fucntions exported to FM V4L2 layer ----- */
+int fm_core_tx_set_stereo_mono(unsigned short mode)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("stereo mode: %d", (int)mode);
+
+	/* Set Stereo/Mono mode */
+	FM_STORE_LE16_TO_BE16(payload, (1 - mode));
+	ret = fm_core_send_cmd(MONO_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_tx_set_rds_text(unsigned char *rds_text)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("rds_text: %s", rds_text);
+
+	ret = fm_core_send_cmd(RDS_DATA_SET, rds_text, strlen(rds_text),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Scroll mode */
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)0x1);
+	ret = fm_core_send_cmd(DISPLAY_MODE_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_tx_set_rds_data_mode(unsigned char mode)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("data mode: %d", (int)mode);
+
+	/* Setting unique PI TODO: how unique? */
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)0xcafe);
+	ret = fm_core_send_cmd(PI_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Set decoder id */
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)0xa);
+	ret = fm_core_send_cmd(DI_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* TODO: RDS_MODE_GET? */
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_tx_set_rds_len(unsigned char type, unsigned short len)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("len: %d", (int)len);
+
+	len |= type << 8;
+	FM_STORE_LE16_TO_BE16(payload, len);
+	ret = fm_core_send_cmd(LENGHT_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* TODO: LENGHT_GET? */
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_tx_set_rds_mode(unsigned char rds_en_dis)
+{
+	unsigned short payload;
+	int ret;
+	unsigned char rds_text[] = "Zoom2\n";
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("rds_en_dis:%d(E:%d, D:%d)", rds_en_dis,
+		   FM_RX_RDS_ENABLE, FM_RX_RDS_DISABLE);
+
+	if (rds_en_dis == FM_RX_RDS_ENABLE) {
+		/* Set RDS length */
+		fm_core_tx_set_rds_len(0, strlen(rds_text));
+		/* Set RDS text */
+		fm_core_tx_set_rds_text(rds_text);
+		/* Set RDS mode */
+		fm_core_tx_set_rds_data_mode(0x0);
+	}
+
+	/* Send command to enable RDS */
+	if (rds_en_dis == FM_RX_RDS_ENABLE)
+		FM_STORE_LE16_TO_BE16(payload, 0x01);
+	else
+		FM_STORE_LE16_TO_BE16(payload, 0x00);
+
+	ret = fm_core_send_cmd(RDS_DATA_ENB, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	if (rds_en_dis == FM_RX_RDS_ENABLE) {
+		/* Set RDS length */
+		fm_core_tx_set_rds_len(0, strlen(rds_text));
+		/* Set RDS text */
+		fm_core_tx_set_rds_text(rds_text);
+	}
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_tx_set_radio_text(unsigned char *rds_text, unsigned char rds_type)
+{
+	unsigned short payload;
+	int ret;
+	FMDRV_API_START();
+
+	fm_core_tx_set_rds_mode(0);
+	/* Set RDS length */
+	fm_core_tx_set_rds_len(rds_type, strlen(rds_text));
+	/* Set RDS text */
+	fm_core_tx_set_rds_text(rds_text);
+	/* Set RDS mode */
+	fm_core_tx_set_rds_data_mode(0x0);
+
+	FM_STORE_LE16_TO_BE16(payload, 1);
+	ret = fm_core_send_cmd(RDS_DATA_ENB, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_tx_set_af(unsigned int af)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("AF: %d", af);
+
+	/* Set AF */
+	af = (af - 87500) / 100;
+
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)af);
+	ret = fm_core_send_cmd(TA_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_tx_set_region(unsigned char region_to_set)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("region_to_set %ld(Eu/US %d, Jp %d)",
+		   (unsigned long)region_to_set, FM_BAND_EUROPE_US,
+		   FM_BAND_JAPAN);
+
+	if (region_to_set != FM_BAND_EUROPE_US &&
+	    region_to_set != FM_BAND_JAPAN) {
+		FM_DRV_ERR("Invalid band\n");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+
+	/* Send command to set the band */
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)region_to_set);
+	ret = fm_core_send_cmd(TX_BAND_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_tx_set_mute_mode(unsigned char mute_mode_toset)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("tx: mute mode %ld", (unsigned long)mute_mode_toset);
+	FM_STORE_LE16_TO_BE16(payload, mute_mode_toset);
+	ret = fm_core_send_cmd(MUTE, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set TX Audio I/O */
+static int fm_core_tx_set_audio_io(void)
+{
+	struct fmtx_data *tx = &fmdev->tx_data;
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("tx: audio_io %ld ", (long int)tx->audio_io);
+
+	/* Set Audio I/O Enable */
+	FM_STORE_LE16_TO_BE16(payload, tx->audio_io);
+	ret = fm_core_send_cmd(AUDIO_IO_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* TODO: is audio set? */
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Start TX Transmission */
+static int fm_core_tx_xmit(unsigned char new_xmit_state)
+{
+	struct fmtx_data *tx = &fmdev->tx_data;
+	unsigned short payload;
+	unsigned long timeleft;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Enable POWER_ENB interrupts */
+	FM_STORE_LE16_TO_BE16(payload, FM_POW_ENB_EVENT);
+	ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+
+	/* Set Power Enable */
+	FM_STORE_LE16_TO_BE16(payload, new_xmit_state);
+	ret = fm_core_send_cmd(POWER_ENB_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Wait for Power Enabled */
+	init_completion(&fmdev->maintask_completion);
+	timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
+					       FM_DRV_TX_TIMEOUT);
+	if (!timeleft) {
+		FM_DRV_ERR("Timeout(%d sec),didn't get tune ended interrupt",
+			   jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+		FMDRV_API_EXIT(-ETIMEDOUT);
+		return -ETIMEDOUT;
+	}
+
+	set_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+	tx->xmit_state = new_xmit_state;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set TX power level */
+int fm_core_tx_set_pwr_lvl(unsigned char new_pwr_lvl)
+{
+	unsigned short payload;
+	struct fmtx_data *tx = &fmdev->tx_data;
+	int ret;
+
+	FMDRV_API_START();
+
+	FM_DRV_DBG("tx: pwr_level_to_set %ld ", (long int)new_pwr_lvl);
+	/* If the core isn't ready update global variable */
+	if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+		tx->pwr_lvl = new_pwr_lvl;
+		return 0;
+	}
+
+	/* Set power level */
+	FM_STORE_LE16_TO_BE16(payload, new_pwr_lvl);
+	ret = fm_core_send_cmd(POWER_LEL_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* TODO: is the power level set? */
+	tx->pwr_lvl = new_pwr_lvl;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set TX Frequency */
+static int fm_core_tx_set_frequency(unsigned int freq_to_set)
+{
+	struct fmtx_data *tx = &fmdev->tx_data;
+	unsigned short payload, chanl_index;
+	int ret;
+
+	FMDRV_API_START();
+
+	if (test_bit(FM_CORE_TX_XMITING, &fmdev->flag)) {
+		fm_core_tx_xmit(0);
+		clear_bit(FM_CORE_TX_XMITING, &fmdev->flag);
+	}
+
+	/* Enable FR, BL interrupts */
+	FM_STORE_LE16_TO_BE16(payload, (FM_FR_EVENT | FM_BL_EVENT));
+	ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+
+	tx->tx_frq = (unsigned long)freq_to_set;
+	FM_DRV_DBG("tx: freq_to_set %ld ", (long int)tx->tx_frq);
+
+	chanl_index = freq_to_set / 10;
+	/* Set current tuner channel */
+	FM_STORE_LE16_TO_BE16(payload, chanl_index);
+	ret = fm_core_send_cmd(CHANL_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* TODO:confirm the freq set */
+	fm_core_tx_set_pwr_lvl(tx->pwr_lvl);
+
+	tx->audio_io = 0x01;	/* I2S */
+	fm_core_tx_set_audio_io();
+
+	fm_core_tx_xmit(0x01);	/* Enable transmission */
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Returns availability of RDS data in internel buffer */
+int fm_core_is_rds_data_available(struct file *file,
+				  struct poll_table_struct *pts)
+{
+	FMDRV_API_START();
+
+	poll_wait(file, &fmdev->rx.rds.read_queue, pts);
+	if (fmdev->rx.rds.rd_index != fmdev->rx.rds.wr_index) {
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+
+	FMDRV_API_EXIT(-EAGAIN);
+	return -EAGAIN;
+}
+
+/* Copies RDS data from internal buffer to user buffer */
+int fm_core_transfer_rds_from_internal_buff(struct file *file,
+					    char __user *buf, size_t count)
+{
+	unsigned int block_count;
+	unsigned long flags;
+	int ret;
+	FMDRV_API_START();
+
+	/* Block if no new data available */
+	if (fmdev->rx.rds.wr_index == fmdev->rx.rds.rd_index) {
+		if (file->f_flags & O_NONBLOCK)
+			return -EWOULDBLOCK;
+
+		ret = wait_event_interruptible(fmdev->rx.rds.read_queue,
+					       (fmdev->rx.rds.wr_index !=
+						fmdev->rx.rds.rd_index));
+		if (ret) {
+			FMDRV_API_EXIT(-EINTR);
+			return -EINTR;
+		}
+	}
+
+	/* Calculate block count from byte count */
+	count /= 3;
+	block_count = 0;
+	ret = 0;
+
+	spin_lock_irqsave(&fmdev->rds_buff_lock, flags);
+
+	/* Copy RDS blocks from the internal buffer and to user buffer */
+	while (block_count < count) {
+		if (fmdev->rx.rds.wr_index == fmdev->rx.rds.rd_index)
+			break;
+
+		/* Always transfer complete RDS blocks */
+		if (copy_to_user
+		    (buf, &fmdev->rx.rds.buffer[fmdev->rx.rds.rd_index],
+		     FM_RDS_BLOCK_SIZE))
+			break;
+
+		/* Increment and wrap the read pointer */
+		fmdev->rx.rds.rd_index += FM_RDS_BLOCK_SIZE;
+
+		/* Wrap read pointer */
+		if (fmdev->rx.rds.rd_index >= fmdev->rx.rds.buf_size)
+			fmdev->rx.rds.rd_index = 0;
+
+		/* Increment counters */
+		block_count++;
+		buf += FM_RDS_BLOCK_SIZE;
+		ret += FM_RDS_BLOCK_SIZE;
+	}
+	spin_unlock_irqrestore(&fmdev->rds_buff_lock, flags);
+	return ret;
+}
+
+/* Checks FM core active status and TX/RX/OFF mode status */
+static inline int fm_core_check_mode(unsigned char mode)
+{
+	if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+		FM_DRV_ERR("FM core is not ready");
+		return -EPERM;
+	}
+	if (mode >= FM_MODE_ENTRY_MAX) {
+		FM_DRV_ERR("Invalid fm mode");
+		return -EPERM;
+	}
+	if (fmdev->curr_fmmode != mode) {
+		FM_DRV_ERR("Current mode is not in %s mode",
+			   mode ? ((mode == 1) ? "TX" : "RX") : "OFF");
+		return -EPERM;
+	}
+	return 0;
+}
+
+/* Set RX Frequency */
+static int fm_core_rx_set_frequency(unsigned int freq_to_set)
+{
+	unsigned long timeleft;
+	unsigned short payload, curr_frq, frq_index;
+	unsigned int curr_frq_in_khz;
+	int ret, resp_len;
+
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (freq_to_set < fmdev->rx.region.bottom_frequency ||
+	    freq_to_set > fmdev->rx.region.top_frequency) {
+		FM_DRV_ERR("Invalid frequency %d", freq_to_set);
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	/* Set audio enable */
+	FM_STORE_LE16_TO_BE16(payload, FM_RX_FM_AUDIO_ENABLE_I2S_AND_ANALOG);
+	ret = fm_core_send_cmd(AUDIO_ENABLE_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Set hilo to automatic selection */
+	FM_STORE_LE16_TO_BE16(payload, FM_RX_IFFREQ_HILO_AUTOMATIC);
+	ret = fm_core_send_cmd(HILO_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Calculate frequency index to write */
+	frq_index = (freq_to_set - fmdev->rx.region.bottom_frequency) /
+	    fmdev->rx.region.channel_spacing;
+
+	/* Set frequency index */
+	FM_STORE_LE16_TO_BE16(payload, frq_index);
+	ret = fm_core_send_cmd(FREQ_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Read flags - just to clear any pending interrupts if we had */
+	ret = fm_core_send_cmd(FLAG_GET, NULL, 2,
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Enable FR, BL interrupts */
+	fmdev->irq_info.mask |= (FM_FR_EVENT | FM_BL_EVENT);
+	FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+	ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Start tune */
+	FM_STORE_LE16_TO_BE16(payload, FM_TUNER_PRESET_MODE);
+	ret = fm_core_send_cmd(TUNER_MODE_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Wait for tune ended interrupt */
+	init_completion(&fmdev->maintask_completion);
+	timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
+					       FM_DRV_TX_TIMEOUT);
+	if (!timeleft) {
+		FM_DRV_ERR("Timeout(%d sec),didn't get tune ended interrupt",
+			   jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
+		FMDRV_API_EXIT(-ETIMEDOUT);
+		return -ETIMEDOUT;
+	}
+
+	/* Read freq back to confirm */
+	ret = fm_core_send_cmd(FREQ_GET, NULL, 2,
+			       &fmdev->maintask_completion, &curr_frq,
+			       &resp_len);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	curr_frq = FM_BE16_TO_LE16(curr_frq);
+	curr_frq_in_khz = (fmdev->rx.region.bottom_frequency
+			   +
+			   ((unsigned int)curr_frq *
+			    fmdev->rx.region.channel_spacing));
+
+	/* Re-enable default FM interrupts */
+	fmdev->irq_info.mask &= ~(FM_FR_EVENT | FM_BL_EVENT);
+	FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+	ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	if (curr_frq_in_khz != freq_to_set) {
+		FM_DRV_ERR("Current chip frequency(%d) is not matching with"
+			   " requested frequency(%d)", curr_frq_in_khz,
+			   freq_to_set);
+		FMDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+
+	/* Update local cache  */
+	fmdev->rx.curr_freq = curr_frq_in_khz;
+
+	/* Reset RDS cache and current station pointers */
+	fm_core_rx_reset_rds_cache();
+	fm_core_rx_reset_curr_station_info();
+
+	/* Do we need to reset anything else? */
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_set_frequency(unsigned int freq_to_set)
+{
+	int ret;
+
+	FMDRV_API_START();
+	switch (fmdev->curr_fmmode) {
+	case FM_MODE_RX:
+		ret = fm_core_rx_set_frequency(freq_to_set);
+		break;
+
+	case FM_MODE_TX:
+		ret = fm_core_tx_set_frequency(freq_to_set);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	FMDRV_API_EXIT(ret);
+	return ret;
+}
+
+int fm_core_get_frequency(unsigned int *cur_tuned_frq)
+{
+	int ret;
+
+	FMDRV_API_START();
+	if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+		FM_DRV_ERR("FM core is not ready");
+		FMDRV_API_EXIT(-EPERM);
+		return -EPERM;
+	}
+	if (fmdev->rx.curr_freq == FM_UNDEFINED_FREQ) {
+		FM_DRV_ERR("RX frequency is not set");
+		FMDRV_API_EXIT(-EPERM);
+		return -EPERM;
+	}
+	if (cur_tuned_frq == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	ret = 0;
+	switch (fmdev->curr_fmmode) {
+	case FM_MODE_RX:
+		*cur_tuned_frq = fmdev->rx.curr_freq;
+		ret = 0;
+		break;
+
+	case FM_MODE_TX:
+		*cur_tuned_frq = 0;	/* TODO : Change this later */
+		ret = 0;
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	FMDRV_API_EXIT(ret);
+	return ret;
+}
+
+/* Seek */
+int fm_core_rx_seek(unsigned int seek_upward, unsigned int wrap_around)
+{
+	int resp_len;
+	unsigned short curr_frq, next_frq, last_frq;
+	unsigned short payload, int_reason;
+	char offset;
+	unsigned long timeleft;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Read the current frequency from chip */
+	ret = fm_core_send_cmd(FREQ_GET, NULL, sizeof(curr_frq),
+			       &fmdev->maintask_completion, &curr_frq,
+			       &resp_len);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	curr_frq = FM_BE16_TO_LE16(curr_frq);
+
+	last_frq =
+	    (fmdev->rx.region.top_frequency - fmdev->rx.region.bottom_frequency)
+	    / fmdev->rx.region.channel_spacing;
+
+	/* Check the offset in order to be aligned to the 100KHz steps */
+	offset = curr_frq % 2;
+
+	next_frq = seek_upward ? curr_frq + 2 /* Seek Up */ :
+	    curr_frq - 2 /* Seek Down */ ;
+
+	/* Add or subtract offset (0/1) in order
+	 * to stay aligned to the 100KHz steps
+	 */
+	if ((short)next_frq < 0)
+		next_frq = last_frq - offset;
+	else if (next_frq > last_frq)
+		next_frq = 0 + offset;
+
+	/* Set calculated next frequency to perform seek */
+	FM_STORE_LE16_TO_BE16(payload, next_frq);
+	ret = fm_core_send_cmd(FREQ_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Set search direction (0:Seek Down, 1:Seek Up) */
+	FM_STORE_LE16_TO_BE16(payload, (seek_upward ? FM_SEARCH_DIRECTION_UP :
+					FM_SEARCH_DIRECTION_DOWN));
+	ret = fm_core_send_cmd(SEARCH_DIR_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Read flags - just to clear any pending interrupts if we had */
+	ret = fm_core_send_cmd(FLAG_GET, NULL, 2,
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Enable FR, BL interrupts */
+	fmdev->irq_info.mask |= (FM_FR_EVENT | FM_BL_EVENT);
+	FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+	ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Start seek */
+	FM_STORE_LE16_TO_BE16(payload, FM_TUNER_AUTONOMOUS_SEARCH_MODE);
+	ret = fm_core_send_cmd(TUNER_MODE_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Wait for tune ended/band limit reached interrupt */
+	init_completion(&fmdev->maintask_completion);
+	timeleft = wait_for_completion_timeout(&fmdev->maintask_completion,
+					       FM_DRV_RX_SEEK_TIMEOUT);
+	if (!timeleft) {
+		FM_DRV_ERR("Timeout(%d sec),didn't get tune ended interrupt",
+			   jiffies_to_msecs(FM_DRV_RX_SEEK_TIMEOUT) / 1000);
+		FMDRV_API_EXIT(-ETIMEDOUT);
+		return -ETIMEDOUT;
+	}
+	int_reason = fmdev->irq_info.flag & 0x3;
+
+	/* Re-enable default FM interrupts */
+	fmdev->irq_info.mask &= ~(FM_FR_EVENT | FM_BL_EVENT);
+	FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+	ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Read freq to know where operation tune operation stopped */
+	ret = fm_core_send_cmd(FREQ_GET, NULL, 2,
+			       &fmdev->maintask_completion, &curr_frq,
+			       &resp_len);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	curr_frq = FM_BE16_TO_LE16(curr_frq);
+	fmdev->rx.curr_freq = (fmdev->rx.region.bottom_frequency +
+			       ((unsigned int)curr_frq *
+				fmdev->rx.region.channel_spacing));
+
+	/* Reset RDS cache and current station pointers */
+	fm_core_rx_reset_rds_cache();
+	fm_core_rx_reset_curr_station_info();
+
+	/* Return error if band limit is reached */
+	if (int_reason & FM_BL_EVENT) {
+		FM_DRV_DBG("band limit reached\n");
+		FMDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set volume */
+int fm_core_rx_set_volume(unsigned short vol_to_set)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (vol_to_set > FM_RX_VOLUME_MAX) {
+		FM_DRV_ERR("Volume is not within(%d-%d) range",
+			   FM_RX_VOLUME_MIN, FM_RX_VOLUME_MAX);
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	vol_to_set *= FM_RX_VOLUME_GAIN_STEP;
+
+	FM_STORE_LE16_TO_BE16(payload, vol_to_set);
+	ret = fm_core_send_cmd(VOLUME_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	fmdev->rx.curr_volume = vol_to_set;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Get volume */
+int fm_core_rx_get_volume(unsigned short *curr_vol)
+{
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (curr_vol == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	*curr_vol = fmdev->rx.curr_volume / FM_RX_VOLUME_GAIN_STEP;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Returns current band index (0-Europe/US; 1-Japan) */
+int fm_core_region_get(unsigned char *region)
+{
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (region == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	*region = fmdev->rx.region.region_index;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* To get current band's bottom and top frequency */
+int fm_core_rx_get_currband_lowhigh_freq(unsigned int *bottom_frequency,
+					 unsigned int *top_frequency)
+{
+	FMDRV_API_START();
+
+	if (bottom_frequency != NULL)
+		*bottom_frequency = fmdev->rx.region.bottom_frequency;
+
+	if (top_frequency != NULL)
+		*top_frequency = fmdev->rx.region.top_frequency;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Sets band (0-Europe/US; 1-Japan) */
+int fm_core_rx_region_set(unsigned char region_to_set)
+{
+	unsigned short payload;
+	unsigned int new_frq;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (region_to_set != FM_BAND_EUROPE_US &&
+	    region_to_set != FM_BAND_JAPAN) {
+		FM_DRV_ERR("Invalid band\n");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	if (fmdev->rx.region.region_index == region_to_set) {
+		FM_DRV_ERR("Requested band is already configured\n");
+		FMDRV_API_EXIT(-EPERM);
+		return -EPERM;
+	}
+	/* Send cmd to set the band  */
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)region_to_set);
+	ret = fm_core_send_cmd(RX_BAND_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Update local region info cache */
+	memcpy(&fmdev->rx.region, &region_configs[region_to_set],
+	       sizeof(struct region_info));
+
+	/* Check whether current RX frequency is within band boundary */
+	if (fmdev->curr_fmmode == FM_MODE_RX) {
+		new_frq = 0;
+		if (fmdev->rx.curr_freq < fmdev->rx.region.bottom_frequency)
+			new_frq = fmdev->rx.region.bottom_frequency;
+		else if (fmdev->rx.curr_freq > fmdev->rx.region.top_frequency)
+			new_frq = fmdev->rx.region.top_frequency;
+
+		if (new_frq) {
+			FM_DRV_DBG
+			    ("Current freq is not within band limit boundary,"
+			     "switching to %d KHz", new_frq);
+			/* Current RX frequency is not
+			 * within boundary. So, update it
+			 */
+			ret = fm_core_rx_set_frequency(new_frq);
+			if (ret < 0) {
+				FMDRV_API_EXIT(ret);
+				return ret;
+			}
+		}
+	}
+
+	/* TODO : Add above boundary check in TX mode also */
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_region_set(unsigned char region_to_set)
+{
+	int ret;
+
+	FMDRV_API_START();
+	switch (fmdev->curr_fmmode) {
+	case FM_MODE_RX:
+		ret = fm_core_rx_region_set(region_to_set);
+		break;
+
+	case FM_MODE_TX:
+		ret = fm_core_tx_set_region(region_to_set);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	FMDRV_API_EXIT(ret);
+	return ret;
+}
+
+/* Reads current mute mode (Mute Off/On/Attenuate)*/
+int fm_core_rx_get_mute_mode(unsigned char *curr_mute_mode)
+{
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (curr_mute_mode == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	*curr_mute_mode = fmdev->rx.curr_mute_mode;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int __fm_core_config_rx_mute_reg(void)
+{
+	unsigned short payload, muteval;
+	int ret;
+
+	FMDRV_API_START();
+
+	muteval = 0;
+	switch (fmdev->rx.curr_mute_mode) {
+	case FM_MUTE_ON:
+		muteval = FM_RX_MUTE_AC_MUTE_MODE;
+		break;
+	case FM_MUTE_OFF:
+		muteval = FM_RX_MUTE_UNMUTE_MODE;
+		break;
+	case FM_MUTE_ATTENUATE:
+		muteval = FM_RX_MUTE_SOFT_MUTE_FORCE_MODE;
+		break;
+	}
+	if (fmdev->rx.curr_rf_depend_mute == FM_RX_RF_DEPENDENT_MUTE_ON)
+		muteval |= FM_RX_MUTE_RF_DEP_MODE;
+	else
+		muteval &= ~FM_RX_MUTE_RF_DEP_MODE;
+
+	FM_STORE_LE16_TO_BE16(payload, muteval);
+	ret = fm_core_send_cmd(MUTE_STATUS_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Configures mute mode (Mute Off/On/Attenuate) */
+int fm_core_rx_set_mute_mode(unsigned char mute_mode_toset)
+{
+	unsigned char org_state;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (fmdev->rx.curr_mute_mode == mute_mode_toset) {
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+	org_state = fmdev->rx.curr_mute_mode;
+	fmdev->rx.curr_mute_mode = mute_mode_toset;
+
+	ret = __fm_core_config_rx_mute_reg();
+	if (ret < 0) {
+		fmdev->rx.curr_mute_mode = org_state;
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_set_mute_mode(unsigned char mute_mode_toset)
+{
+	int ret;
+
+	FMDRV_API_START();
+	switch (fmdev->curr_fmmode) {
+	case FM_MODE_RX:
+		ret = fm_core_rx_set_mute_mode(mute_mode_toset);
+		break;
+
+	case FM_MODE_TX:
+		ret = fm_core_tx_set_mute_mode(mute_mode_toset);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	FMDRV_API_EXIT(ret);
+	return ret;
+}
+
+/* Gets RF dependent soft mute mode enable/disable status */
+int fm_core_rx_get_rfdepend_softmute(unsigned char *curr_mute_mode)
+{
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (curr_mute_mode == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	*curr_mute_mode = fmdev->rx.curr_rf_depend_mute;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Sets RF dependent soft mute mode */
+int fm_core_rx_set_rfdepend_softmute(unsigned char rfdepend_mute)
+{
+	unsigned char org_state;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_ON &&
+	    rfdepend_mute != FM_RX_RF_DEPENDENT_MUTE_OFF) {
+		FM_DRV_ERR("Invalid RF dependent soft mute");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	if (fmdev->rx.curr_rf_depend_mute == rfdepend_mute) {
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+
+	org_state = fmdev->rx.curr_rf_depend_mute;
+	fmdev->rx.curr_rf_depend_mute = rfdepend_mute;
+
+	ret = __fm_core_config_rx_mute_reg();
+	if (ret < 0) {
+		fmdev->rx.curr_rf_depend_mute = org_state;
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Returns the signal strength level of current channel */
+int fm_core_rx_get_rssi_level(unsigned short *rssilvl)
+{
+	unsigned short curr_rssi_lel;
+	int resp_len;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (rssilvl == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	/* Read current RSSI level */
+	ret = fm_core_send_cmd(RSSI_LVL_GET, NULL, 2,
+			       &fmdev->maintask_completion, &curr_rssi_lel,
+			       &resp_len);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	*rssilvl = FM_BE16_TO_LE16(curr_rssi_lel);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Sets the signal strength level that once reached
+ * will stop the auto search process
+ */
+int fm_core_rx_set_rssi_threshold(short rssi_lvl_toset)
+{
+	unsigned short payload;
+	int ret;
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (rssi_lvl_toset < FM_RX_RSSI_THRESHOLD_MIN ||
+	    rssi_lvl_toset > FM_RX_RSSI_THRESHOLD_MAX) {
+		FM_DRV_ERR("Invalid RSSI threshold level");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)rssi_lvl_toset);
+	ret = fm_core_send_cmd(SEARCH_LVL_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	fmdev->rx.curr_rssi_threshold = rssi_lvl_toset;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Returns current RX RSSI threshold value */
+int fm_core_rx_get_rssi_threshold(short *curr_rssi_lvl)
+{
+	int ret;
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (curr_rssi_lvl == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	*curr_rssi_lvl = fmdev->rx.curr_rssi_threshold;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Sets RX stereo/mono modes */
+int fm_core_rx_set_stereo_mono(unsigned short mode)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (mode != FM_STEREO_MODE && mode != FM_MONO_MODE) {
+		FM_DRV_ERR("Invalid mode");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	/* Set stereo/mono mode */
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)mode);
+	ret = fm_core_send_cmd(MOST_MODE_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Set stereo blending mode */
+	FM_STORE_LE16_TO_BE16(payload, FM_STEREO_SOFT_BLEND);
+	ret = fm_core_send_cmd(MOST_BLEND_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_set_stereo_mono(unsigned short mode)
+{
+	int ret;
+
+	FMDRV_API_START();
+	switch (fmdev->curr_fmmode) {
+	case FM_MODE_RX:
+		ret = fm_core_rx_set_stereo_mono(mode);
+		break;
+
+	case FM_MODE_TX:
+		ret = fm_core_tx_set_stereo_mono(mode);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	FMDRV_API_EXIT(ret);
+	return ret;
+}
+
+/* Gets current RX stereo/mono mode */
+int fm_core_rx_get_stereo_mono(unsigned short *mode)
+{
+	unsigned short curr_mode;
+	int ret, resp_len;
+
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (mode == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	ret = fm_core_send_cmd(MOST_MODE_GET, NULL, 2,
+			       &fmdev->maintask_completion, &curr_mode,
+			       &resp_len);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	*mode = FM_BE16_TO_LE16(curr_mode);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Chooses RX de-emphasis filter mode (50us/75us) */
+int fm_core_rx_set_deemphasis_mode(unsigned short mode)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (mode != FM_RX_EMPHASIS_FILTER_50_USEC &&
+	    mode != FM_RX_EMPHASIS_FILTER_75_USEC) {
+		FM_DRV_ERR("Invalid rx de-emphasis mode");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	FM_STORE_LE16_TO_BE16(payload, mode);
+	ret = fm_core_send_cmd(DEMPH_MODE_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Gets current RX de-emphasis filter mode */
+int fm_core_rx_get_deemphasis_mode(unsigned short *curr_deemphasis_mode)
+{
+	unsigned short curr_mode;
+	int ret, resp_len;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (curr_deemphasis_mode == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	ret = fm_core_send_cmd(DEMPH_MODE_GET, NULL, 2,
+			       &fmdev->maintask_completion, &curr_mode,
+			       &resp_len);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	*curr_deemphasis_mode = FM_BE16_TO_LE16(curr_mode);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Enable/Disable RX RDS */
+int fm_core_rx_set_rds_mode(unsigned char rds_en_dis)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (rds_en_dis != FM_RX_RDS_ENABLE && rds_en_dis != FM_RX_RDS_DISABLE) {
+		FM_DRV_ERR("Invalid rds option");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	if (rds_en_dis == FM_RX_RDS_ENABLE
+	    && fmdev->rx.rds.flag == FM_RX_RDS_DISABLE) {
+		/* Turn on RX RDS */
+		/* Turn on RDS circuit */
+		FM_STORE_LE16_TO_BE16(payload,
+				      FM_RX_POWET_SET_FM_AND_RDS_BLK_ON);
+		ret =
+		    fm_core_send_cmd(POWER_SET, &payload, sizeof(payload),
+				     &fmdev->maintask_completion, NULL, NULL);
+		FM_CHECK_SEND_CMD_STATUS(ret);
+
+		/* Clear and rest RDS FIFO */
+		FM_STORE_LE16_TO_BE16(payload, FM_RX_RDS_FLUSH_FIFO);
+		ret = fm_core_send_cmd(RDS_CNTRL_SET, &payload, sizeof(payload),
+				       &fmdev->maintask_completion, NULL, NULL);
+		FM_CHECK_SEND_CMD_STATUS(ret);
+
+		/* Read flags - just to clear any
+		 * pending interrupts if we had
+		 */
+		ret = fm_core_send_cmd(FLAG_GET, NULL, 2,
+				       &fmdev->maintask_completion, NULL, NULL);
+		FM_CHECK_SEND_CMD_STATUS(ret);
+
+		/* Set RDS FIFO threshold value */
+		FM_STORE_LE16_TO_BE16(payload, FM_RX_RDS_FIFO_THRESHOLD);
+		ret = fm_core_send_cmd(RDS_MEM_SET, &payload, sizeof(payload),
+				       &fmdev->maintask_completion, NULL, NULL);
+		FM_CHECK_SEND_CMD_STATUS(ret);
+
+		/* Enable RDS interrupt */
+		fmdev->irq_info.mask |= FM_RDS_EVENT;
+		FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+		ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+				       &fmdev->maintask_completion, NULL, NULL);
+		FM_CHECK_SEND_CMD_STATUS(ret);
+
+		/* Update our local flag */
+		fmdev->rx.rds.flag = FM_RX_RDS_ENABLE;
+	} else if (rds_en_dis == FM_RX_RDS_DISABLE
+		   && fmdev->rx.rds.flag == FM_RX_RDS_ENABLE) {
+		/* Turn off RX RDS */
+		/* Turn off RDS circuit */
+		FM_STORE_LE16_TO_BE16(payload, FM_RX_POWER_SET_FM_ON_RDS_OFF);
+		ret = fm_core_send_cmd(POWER_SET, &payload, sizeof(payload),
+				       &fmdev->maintask_completion, NULL, NULL);
+		FM_CHECK_SEND_CMD_STATUS(ret);
+
+		/* Reset RDS pointers */
+		fmdev->rx.rds.last_block_index = 0;
+		fmdev->rx.rds.wr_index = 0;
+		fmdev->rx.rds.rd_index = 0;
+		fm_core_rx_reset_curr_station_info();
+
+		/* Update RDS local cache */
+		fmdev->irq_info.mask &= ~(FM_RDS_EVENT);
+		fmdev->rx.rds.flag = FM_RX_RDS_DISABLE;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_set_rds_mode(unsigned char rds_en_dis)
+{
+	int ret;
+
+	FMDRV_API_START();
+	switch (fmdev->curr_fmmode) {
+	case FM_MODE_RX:
+		ret = fm_core_rx_set_rds_mode(rds_en_dis);
+		break;
+
+	case FM_MODE_TX:
+		ret = fm_core_tx_set_rds_mode(rds_en_dis);
+		break;
+
+	default:
+		ret = -EINVAL;
+	}
+	FMDRV_API_EXIT(ret);
+	return ret;
+}
+
+/* Returns current RX RDS enable/disable status */
+int fm_core_rx_get_rds_mode(unsigned char *curr_rds_en_dis)
+{
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (curr_rds_en_dis == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	*curr_rds_en_dis = fmdev->rx.rds.flag;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Sets RDS operation mode (RDS/RDBS) */
+int fm_core_rx_set_rds_system(unsigned char rds_mode)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (rds_mode != FM_RDS_SYSTEM_RDS && rds_mode != FM_RDS_SYSTEM_RBDS) {
+		FM_DRV_ERR("Invalid rds mode");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	/* Set RDS operation mode */
+	FM_STORE_LE16_TO_BE16(payload, (unsigned short)rds_mode);
+	ret = fm_core_send_cmd(RDS_SYSTEM_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	fmdev->rx.rds_mode = rds_mode;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Returns current RDS operation mode */
+int fm_core_rx_get_rds_system(unsigned char *rds_mode)
+{
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (rds_mode == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	*rds_mode = fmdev->rx.rds_mode;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Sends power off command to the chip */
+int fm_core_power_down(void)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+	if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+		FM_DRV_ERR("FM core is not ready");
+		FMDRV_API_EXIT(-EPERM);
+		return -EPERM;
+	}
+	if (fmdev->curr_fmmode == FM_MODE_OFF) {
+		FM_DRV_ERR("FM chip is already in OFF state");
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+	/* Disable FM functions over Channel-8 */
+	FM_STORE_LE16_TO_BE16(payload, 0x0);
+	ret = fm_core_send_cmd(FM_POWER_MODE, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	/* Unlink from ST. FM GPIO toggling is taken
+	 * care in Shared Transport layer
+	 */
+	ret = fm_core_release();
+	if (ret < 0) {
+		FM_DRV_ERR("FM CORE release failed");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Configures Alternate Frequency switch mode */
+int fm_core_rx_set_af_switch(unsigned char af_mode)
+{
+	unsigned short payload;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (af_mode != FM_RX_RDS_AF_SWITCH_MODE_ON &&
+	    af_mode != FM_RX_RDS_AF_SWITCH_MODE_OFF) {
+		FM_DRV_ERR("Invalid af mode");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	/* Enable/disable low RSSI interrupt based on af_mode */
+	if (af_mode == FM_RX_RDS_AF_SWITCH_MODE_ON)
+		fmdev->irq_info.mask |= FM_LEV_EVENT;
+	else
+		fmdev->irq_info.mask &= ~FM_LEV_EVENT;
+
+	FM_STORE_LE16_TO_BE16(payload, fmdev->irq_info.mask);
+	ret = fm_core_send_cmd(INT_MASK_SET, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	FM_CHECK_SEND_CMD_STATUS(ret);
+
+	fmdev->rx.af_mode = af_mode;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Returns Alternate Frequency switch status */
+int fm_core_rx_get_af_switch(unsigned char *af_mode)
+{
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_check_mode(FM_MODE_RX);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (af_mode == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	*af_mode = fmdev->rx.af_mode;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Reads init command from FM firmware file and loads to the chip */
+static int fm_core_download_firmware(const char *firmware_name)
+{
+	const struct firmware *fw_entry;
+	struct bts_header *fw_header;
+	struct bts_action *action;
+	struct bts_action_delay *delay;
+	char *fw_data;
+	int ret, fw_len, cmd_cnt;
+
+	FMDRV_API_START();
+
+	cmd_cnt = 0;
+	set_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag);
+
+	/* Read firmware data */
+	ret = request_firmware(&fw_entry, firmware_name, &fmdev->v4l2dev->dev);
+	if (unlikely(ret)) {
+		FM_DRV_ERR("Unable to read firmware(%s) content\n",
+			   firmware_name);
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	FM_DRV_DBG("Firmware(%s) length : %d bytes", firmware_name,
+		   fw_entry->size);
+
+	fw_data = (void *)fw_entry->data;
+	fw_len = fw_entry->size;
+
+	/* Check TI's magic number in firmware file */
+	fw_header = (struct bts_header *)fw_data;
+	if (fw_header->magic != FM_FW_FILE_HEADER_MAGIC) {
+		release_firmware(fw_entry);
+		clear_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag);
+		FM_DRV_ERR("%s not a legal TI firmware file", firmware_name);
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	FM_DRV_DBG("Firmware(%s) magic number : 0x%x", firmware_name,
+		   fw_header->magic);
+
+	/* Skip file header info , we already verified it */
+	fw_data += sizeof(struct bts_header);
+	fw_len -= sizeof(struct bts_header);
+
+	while (fw_data && fw_len > 0) {
+		action = (struct bts_action *)fw_data;
+
+		switch (action->type) {
+
+		case ACTION_SEND_COMMAND:	/* Send */
+
+			/* Send the command to chip */
+			ret = fm_core_send_cmd(0, action->data, action->size,
+					       &fmdev->maintask_completion,
+					       NULL, NULL);
+			if (unlikely(ret < 0)) {
+				release_firmware(fw_entry);
+				clear_bit(FM_FIRMWARE_DW_INPROGRESS,
+					  &fmdev->flag);
+				FMDRV_API_EXIT(ret);
+				return ret;
+			}
+			cmd_cnt++;
+			break;
+
+		case ACTION_DELAY:	/* Delay */
+			delay = (struct bts_action_delay *)action->data;
+			mdelay(delay->msec);
+			break;
+		}
+
+		fw_data += (sizeof(struct bts_action) + (action->size));
+		fw_len -= (sizeof(struct bts_action) + (action->size));
+	}
+
+	release_firmware(fw_entry);
+	clear_bit(FM_FIRMWARE_DW_INPROGRESS, &fmdev->flag);
+
+	FM_DRV_DBG("Firmare commands(%d) loaded to the chip", cmd_cnt);
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Loads default RX configuration to the chip */
+static int __fm_core_rx_load_default_configuration(void)
+{
+	int ret;
+	FMDRV_API_START();
+
+	/* Set default RX volume level */
+	ret = fm_core_rx_set_volume(FM_DEFAULT_RX_VOLUME);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Set default RX RSSI level threshold */
+	ret = fm_core_rx_set_rssi_threshold(FM_DEFAULT_RSSI_THRESHOLD);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Does FM power on sequence */
+static int fm_core_power_up(unsigned char fw_option)
+{
+	unsigned short payload, asic_id, asic_ver;
+	int resp_len, ret;
+	char fw_name[50];
+
+	FMDRV_API_START();
+	if (fw_option >= FM_MODE_ENTRY_MAX) {
+		FM_DRV_ERR("Invalid firmware download option");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	/* Initialize FM Core. FM GPIO toggling is
+	 * taken care in Shared Transport
+	 */
+	ret = fm_core_prepare();
+	if (ret < 0) {
+		FM_DRV_ERR("Unable to prepare FM CORE");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Enable Channel-8 communication on chip side. This is must for
+	 * reading ASIC ID and ASIC version of the chip.
+	 */
+	FM_STORE_LE16_TO_BE16(payload, FM_ENABLE);
+
+	ret = fm_core_send_cmd(FM_POWER_MODE, &payload, sizeof(payload),
+			       &fmdev->maintask_completion, NULL, NULL);
+	if (ret < 0) {
+		FM_DRV_ERR("Failed enable FM over Channel 8");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	/* Allow the chip to settle down in Channel-8 mode */
+	msleep(5);
+
+	/* Read ASIC ID */
+	ret = fm_core_send_cmd(ASIC_ID_GET, NULL, sizeof(asic_id),
+			       &fmdev->maintask_completion, &asic_id,
+			       &resp_len);
+	if (ret < 0) {
+		FM_DRV_ERR("Failed read FM chip ASIC ID");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Read ASIC version */
+	ret = fm_core_send_cmd(ASIC_VER_GET, NULL, sizeof(asic_ver),
+			       &fmdev->maintask_completion, &asic_ver,
+			       &resp_len);
+	if (ret < 0) {
+		FM_DRV_ERR("Failed read FM chip ASIC Version");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	FM_DRV_DBG("ASIC ID: 0x%x , ASIC Version: %d", FM_BE16_TO_LE16(asic_id),
+		   FM_BE16_TO_LE16(asic_ver));
+
+	/* Frame common firmware file name and load init commands */
+	sprintf(fw_name, "%s_%x.%d.bts", FM_FMC_FW_FILE_START,
+		FM_BE16_TO_LE16(asic_id), FM_BE16_TO_LE16(asic_ver));
+	ret = fm_core_download_firmware(fw_name);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Frame TX or RX firmware file name
+	 * based on request and load init commands.
+	 */
+	sprintf(fw_name, "%s_%x.%d.bts", (fw_option == FM_MODE_RX) ?
+		FM_RX_FW_FILE_START : FM_TX_FW_FILE_START,
+		FM_BE16_TO_LE16(asic_id), FM_BE16_TO_LE16(asic_ver));
+	ret = fm_core_download_firmware(fw_name);
+	if (ret < 0) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* ----- Fucntions exported to FM mixer control layer ----- */
+
+/* All the functions which are exported from this file
+ * to FM mixer controls layer will check FM Core ready
+ * status. If FM Core is not ready, it will return
+ * immediately with an error.
+ */
+
+/* Set FM Modes(TX, RX, OFF) */
+int fm_core_mode_set(unsigned char fm_mode)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	if (fm_mode >= FM_MODE_ENTRY_MAX) {
+		FM_DRV_ERR("Invalid FM mode");
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	if (fmdev->curr_fmmode == fm_mode) {
+		FM_DRV_DBG("Already fm is in mode(%d)", fm_mode);
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+	switch (fm_mode) {
+	case FM_MODE_OFF:	/* OFF Mode */
+		ret = fm_core_power_down();
+		if (ret < 0) {
+			FM_DRV_ERR("Failed to set OFF mode");
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+		break;
+
+	case FM_MODE_TX:	/* TX Mode */
+	case FM_MODE_RX:	/* RX Mode */
+		/* Power down before switching to TX or RX mode */
+		if (fmdev->curr_fmmode != FM_MODE_OFF) {
+			ret = fm_core_power_down();
+			if (ret < 0) {
+				FM_DRV_ERR("Failed to set OFF mode");
+				FMDRV_API_EXIT(ret);
+				return ret;
+			}
+			msleep(30);
+		}
+		/* Load requested mode's firmware */
+		ret = fm_core_power_up(fm_mode);
+		if (ret < 0) {
+			FM_DRV_ERR("Failed to load firmware\n");
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+	}
+	/* Set current mode */
+	fmdev->curr_fmmode = fm_mode;
+
+	/* Set default configuration */
+	if (fmdev->curr_fmmode == FM_MODE_RX) {
+		FM_DRV_DBG("Loading default rx configuration..\n");
+		ret = __fm_core_rx_load_default_configuration();
+		if (ret < 0) {
+			FM_DRV_ERR("Failed to load default values\n");
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Returns current FM mode (TX, RX, OFF) */
+int fm_core_mode_get(unsigned char *fmmode)
+{
+	FMDRV_API_START();
+
+	if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+		FM_DRV_ERR("FM core is not ready");
+		return -EPERM;
+	}
+	if (fmmode == NULL) {
+		FM_DRV_ERR("Invalid memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+
+	*fmmode = fmdev->curr_fmmode;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* ----------------- FM Core Init -------------- */
+
+/* This function will be called from FM V4L2 open function.
+ * This will request FM ST interface to register with ST driver.
+ */
+int fm_core_prepare(void)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	if (test_bit(FM_CORE_READY, &fmdev->flag)) {
+		FM_DRV_DBG("FM Core is already up");
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+	if (!test_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag)) {
+		FM_DRV_ERR("FM Core transport is not ready");
+		FMDRV_API_EXIT(-EPERM);
+		return -EPERM;
+	}
+
+	/* Request FM ST to get register with ST driver. Send FM Core RX
+	 * queue and RX tasklet pointers to FM ST. FM ST will push
+	 * received FM packet into this queue and schedule this RX
+	 * tasklet.
+	 */
+	ret = fm_st_register(&fmdev->rx_q, &fmdev->rx_task);
+	if (ret < 0) {
+		fm_st_release();
+		FM_DRV_ERR("Unable to register with ST");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	spin_lock_init(&fmdev->rds_buff_lock);
+	spin_lock_init(&fmdev->resp_skb_lock);
+
+	/* Initialize TX queue and TX tasklet */
+	skb_queue_head_init(&fmdev->tx_q);
+	tasklet_init(&fmdev->tx_task, fm_core_tx_tasklet, (unsigned long)fmdev);
+
+	/* Initialize RX Queue and RX tasklet */
+	skb_queue_head_init(&fmdev->rx_q);
+	tasklet_init(&fmdev->rx_task, fm_core_rx_tasklet, (unsigned long)fmdev);
+
+	/* Initialize interrupt related info */
+	fmdev->irq_info.stage_index = 0;
+
+	/* Number of packet can send at a time */
+	atomic_set(&fmdev->tx_cnt, 1);
+
+	fmdev->response_completion = NULL;
+
+	init_timer(&fmdev->irq_info.int_timeout_timer);
+	fmdev->irq_info.int_timeout_timer.function =
+	    &fm_core_int_timeout_handler;
+
+	/* Default interrupt bits to be enabled */
+	fmdev->irq_info.mask =
+	    FM_MAL_EVENT /*| FM_STIC_EVENT <<Enable this later>> */ ;
+
+	/* Region info */
+	memcpy(&fmdev->rx.region, &region_configs[default_radio_region],
+	       sizeof(struct region_info));
+
+	fmdev->rx.curr_mute_mode = FM_MUTE_OFF;
+	fmdev->rx.curr_rf_depend_mute = FM_RX_RF_DEPENDENT_MUTE_OFF;
+	fmdev->rx.rds.flag = FM_RX_RDS_DISABLE;
+	fmdev->rx.curr_freq = FM_UNDEFINED_FREQ;
+	fmdev->rx.rds_mode = FM_RDS_SYSTEM_RDS;
+	fmdev->rx.af_mode = FM_RX_RDS_AF_SWITCH_MODE_OFF;
+	fmdev->irq_info.irq_service_timeout_retry = 0;
+
+	/* RDS ring buffer */
+	fm_core_rx_reset_rds_cache();
+	init_waitqueue_head(&fmdev->rx.rds.read_queue);
+
+	/* Current station info */
+	fm_core_rx_reset_curr_station_info();
+
+	/* FM core is ready */
+	set_bit(FM_CORE_READY, &fmdev->flag);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* -------------- FM Core De-Init ------------- */
+
+/* This function will be called from FM V4L2 release function.
+ * This will request FM ST interface to unregister from ST driver.
+ */
+int fm_core_release(void)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	if (!test_bit(FM_CORE_READY, &fmdev->flag)) {
+		FM_DRV_DBG("FM Core is already down");
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+	/* Sevice pending read */
+	wake_up_interruptible(&fmdev->rx.rds.read_queue);
+
+	/* Stop all tasklets */
+	tasklet_kill(&fmdev->tx_task);
+	tasklet_kill(&fmdev->rx_task);
+
+	/* Flush Tx and Rx queues */
+	skb_queue_purge(&fmdev->tx_q);
+	skb_queue_purge(&fmdev->rx_q);
+
+	fmdev->response_completion = NULL;
+	fmdev->rx.curr_freq = 0;
+
+	/* Unlink from Shared Transport driver */
+	ret = fm_st_unregister();
+	if (ret < 0) {
+		FM_DRV_ERR("Unable to unregister from ST");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	FM_DRV_DBG("Successfully unregistered from ST");
+
+	/* Clear FM Core ready flag */
+	clear_bit(FM_CORE_READY, &fmdev->flag);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_setup_transport(void)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	if (test_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag)) {
+		FM_DRV_ERR("FM Core transport is already up");
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+	/* Check availabilty of FM ST. If FM ST is already claimed
+	 * by FM Char device interface, don't proceed. Both FM Core
+	 * and FM Char device interface can't co-exist.
+	 */
+	ret = fm_st_claim();
+	if (ret < 0) {
+		FM_DRV_ERR
+		    ("FM char device interface is using FM ST, can't coexist");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	set_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_core_release_transport(void)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	if (!test_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag)) {
+		FM_DRV_ERR("FM Core transport is already down");
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+
+	/* Release FM ST */
+	ret = fm_st_release();
+	if (ret < 0) {
+		FM_DRV_ERR("Failed to release FM ST");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	clear_bit(FM_CORE_TRANSPORT_READY, &fmdev->flag);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* ----------- Module Init interface --------- */
+
+static int __init fm_drv_init(void)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = 0;
+
+	FM_DRV_DBG("FM driver version %s", FM_DRV_VERSION);
+
+	/* Allocate local resource memory */
+	fmdev = kzalloc(sizeof(struct fmdrv_ops), GFP_KERNEL);
+	if (!fmdev) {
+		FM_DRV_ERR("Can't allocate operation structure memory");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	fmdev->rx.rds.buf_size = default_rds_buf * FM_RDS_BLOCK_SIZE;
+
+	/* Allocate memory for RDS ring buffer */
+	fmdev->rx.rds.buffer = kzalloc(fmdev->rx.rds.buf_size, GFP_KERNEL);
+	if (fmdev->rx.rds.buffer == NULL) {
+		kfree(fmdev);
+		FM_DRV_ERR("Can't allocate rds ring buffer");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+
+	/* Register with V4L2 subsystem. This will internally
+	 * expose '/dev/radio' device to user space.
+	 */
+	ret = fm_v4l2_init_video_device(fmdev);
+	if (ret < 0) {
+		kfree(fmdev);
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	/* Register with ALSA subsystem. This will internally expose
+	 * set of FM mixer controls via ALSA to user space.
+	 */
+	ret = fm_mixer_init(fmdev);
+	if (ret < 0) {
+		/* Unregister from V4L2 subsystem */
+		fm_v4l2_deinit_video_device(fmdev);
+
+		kfree(fmdev);
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	/* Initialize the FM Character driver */
+	ret = fm_chr_init();
+	if (ret < 0) {
+		FM_DRV_ERR("Can't init FM Character driver");
+		FMDRV_API_EXIT(0);
+		return ret;
+	}
+
+	/* Assign interrupt handling table pointer */
+	fmdev->irq_info.fm_IntActionHandlerTable = g_IntHandlerTable;
+
+	/* Default FM driver mode */
+	fmdev->curr_fmmode = FM_MODE_OFF;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* -------- Module Exit interface -------- */
+
+static void __exit fm_drv_exit(void)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = 0;
+
+	/* Unregister from V4L2 subsystem */
+	ret = fm_v4l2_deinit_video_device(fmdev);
+	if (ret < 0)
+		FM_DRV_ERR("Unable to unregister from V4L2 subsystem(%d)", ret);
+
+	/* Unregister from ALSA subsystem */
+	ret = fm_mixer_deinit(fmdev);
+	if (ret < 0)
+		FM_DRV_ERR("Unable to unregister from ALSA(%d)", ret);
+
+	/* De-initialize the FM Character driver */
+	fm_chr_exit();
+
+	kfree(fmdev->rx.rds.buffer);
+	kfree(fmdev);
+
+	FMDRV_API_EXIT(0);
+}
+
+module_init(fm_drv_init);
+module_exit(fm_drv_exit);
+
+/* ------------- Module Info ------------- */
+
+MODULE_AUTHOR("Raja Mani <raja_mani@ti.com>");
+MODULE_DESCRIPTION("FM Driver for Connectivity chip of Texas Instruments. "
+		   FM_DRV_VERSION);
+MODULE_VERSION(FM_DRV_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/fmdrv_core.h b/drivers/misc/ti-st/fmdrv_core.h
new file mode 100644
index 0000000..687bb29
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_core.h
@@ -0,0 +1,474 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  FM Core module header file
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FM_CORE_H
+#define _FM_CORE_H
+
+#define REG_RD       0x1
+#define REG_WR      0x0
+
+struct fm_reg_table {
+	unsigned char opcode;
+	unsigned char type;
+	char *name;
+};
+
+/* FM register index */
+enum fm_reg_index {
+	/* FM RX registers */
+	STEREO_GET,
+	RSSI_LVL_GET,
+	IF_COUNT_GET,
+	FLAG_GET,
+	RDS_SYNC_GET,
+	RDS_DATA_GET,
+	FREQ_SET,
+	FREQ_GET,
+	AF_FREQ_SET,
+	AF_FREQ_GET,
+	MOST_MODE_SET,
+	MOST_MODE_GET,
+	MOST_BLEND_SET,
+	MOST_BLEND_GET,
+	DEMPH_MODE_SET,
+	DEMPH_MODE_GET,
+	SEARCH_LVL_SET,
+	SEARCH_LVL_GET,
+	RX_BAND_SET,
+	RX_BAND_GET,
+	MUTE_STATUS_SET,
+	MUTE_STATUS_GET,
+	RDS_PAUSE_LVL_SET,
+	RDS_PAUSE_LVL_GET,
+	RDS_PAUSE_DUR_SET,
+	RDS_PAUSE_DUR_GET,
+	RDS_MEM_SET,
+	RDS_MEM_GET,
+	RDS_BLK_B_SET,
+	RDS_BLK_B_GET,
+	RDS_MSK_B_SET,
+	RDS_MSK_B_GET,
+	RDS_PI_MASK_SET,
+	RDS_PI_MASK_GET,
+	RDS_PI_SET,
+	RDS_PI_GET,
+	RDS_SYSTEM_SET,
+	RDS_SYSTEM_GET,
+	INT_MASK_SET,
+	INT_MASK_GET,
+	SEARCH_DIR_SET,
+	SEARCH_DIR_GET,
+	VOLUME_SET,
+	VOLUME_GET,
+	AUDIO_ENABLE_SET,
+	AUDIO_ENABLE_GET,
+	PCM_MODE_SET,
+	PCM_MODE_GET,
+	I2S_MODE_CONFIG_SET,
+	I2S_MODE_CONFIG_GET,
+	POWER_SET,
+	POWER_GET,
+	INTx_CONFIG_SET,
+	INTx_CONFIG_GET,
+	PULL_EN_SET,
+	PULL_EN_GET,
+	HILO_SET,
+	HILO_GET,
+	SWITCH2FREF,
+	FREQ_DRIFT_REPORT,
+	PCE_GET,
+	FIRM_VER_GET,
+	ASIC_VER_GET,
+	ASIC_ID_GET,
+	MAIN_ID_GET,
+	TUNER_MODE_SET,
+	STOP_SEARCH,
+	RDS_CNTRL_SET,
+	WRITE_HARDWARE_REG,
+	CODE_DOWNLOAD,
+	RESET,
+	FM_POWER_MODE,
+	FM_INTERRUPT,
+
+	/* FM TX registers */
+	CHANL_SET,
+	CHANL_GET,
+	CHANL_BW_SET,
+	CHANL_BW_GET,
+	REF_SET,
+	REF_GET,
+	POWER_ENB_SET,
+	POWER_ATT_SET,
+	POWER_ATT_GET,
+	POWER_LEL_SET,
+	POWER_LEL_GET,
+	AUDIO_DEV_SET,
+	AUDIO_DEV_GET,
+	PILOT_DEV_SET,
+	PILOT_DEV_GET,
+	RDS_DEV_SET,
+	RDS_DEV_GET,
+	PUPD_SET,
+	AUDIO_IO_SET,
+	PREMPH_SET,
+	PREMPH_GET,
+	TX_BAND_SET,
+	TX_BAND_GET,
+	MONO_SET,
+	MONO_GET,
+	MUTE,
+	MPX_LMT_ENABLE,
+	LOCK_GET,
+	REF_ERR_SET,
+	PI_SET,
+	PI_GET,
+	TYPE_SET,
+	TYPE_GET,
+	PTY_SET,
+	PTY_GET,
+	AF_SET,
+	AF_GET,
+	DISPLAY_SIZE_SET,
+	DISPLAY_SIZE_GET,
+	RDS_MODE_SET,
+	RDS_MODE_GET,
+	DISPLAY_MODE_SET,
+	DISPLAY_MODE_GET,
+	LENGHT_SET,
+	LENGHT_GET,
+	TOGGLE_AB_SET,
+	TOGGLE_AB_GET,
+	RDS_REP_SET,
+	RDS_REP_GET,
+	RDS_DATA_SET,
+	RDS_DATA_ENB,
+	TA_SET,
+	TA_GET,
+	TP_SET,
+	TP_GET,
+	DI_SET,
+	DI_GET,
+	MS_SET,
+	MS_GET,
+	PS_SCROLL_SPEED_SET,
+	PS_SCROLL_SPEED_GET,
+
+	FM_REG_MAX_ENTRIES
+};
+
+/* SKB helpers */
+struct fm_skb_cb {
+	__u8 fm_opcode;
+	struct completion *completion;
+};
+
+#define fm_cb(skb) ((struct fm_skb_cb *)(skb->cb))
+
+/* FM Channel-8 command message format */
+struct fm_cmd_msg_hdr {
+	__u8 header;		/* Logical Channel-8 */
+	__u8 len;		/* Number of bytes follows */
+	__u8 fm_opcode;		/* FM Opcode */
+	__u8 rd_wr;		/* Read/Write command */
+	__u8 dlen;		/* Length of payload */
+} __attribute__ ((packed));
+
+#define FM_CMD_MSG_HDR_SIZE    5	/* sizeof(struct fm_cmd_msg_hdr) */
+
+/* FM Channel-8 event messgage format */
+struct fm_event_msg_hdr {
+	__u8 header;		/* Logical Channel-8 */
+	__u8 len;		/* Number of bytes follows */
+	__u8 status;		/* Event status */
+	__u8 num_fm_hci_cmds;	/* Number of pkts the host allowed to send */
+	__u8 fm_opcode;		/* FM Opcode */
+	__u8 rd_wr;		/* Read/Write command */
+	__u8 dlen;		/* Length of payload */
+} __attribute__ ((packed));
+
+#define FM_EVT_MSG_HDR_SIZE     7	/* sizeof(struct fm_event_msg_hdr) */
+
+/* TI's magic number in firmware file */
+#define FM_FW_FILE_HEADER_MAGIC	     0x42535442
+
+/* Firmware header */
+struct bts_header {
+	uint32_t magic;
+	uint32_t version;
+	uint8_t future[24];
+	uint8_t actions[0];
+} __attribute__ ((packed));
+
+/* Firmware action */
+struct bts_action {
+	uint16_t type;
+	uint16_t size;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+/* Firmware delay */
+struct bts_action_delay {
+	uint32_t msec;
+} __attribute__ ((packed));
+
+#define ACTION_SEND_COMMAND	1
+#define ACTION_WAIT_EVENT	2
+#define ACTION_SERIAL		3
+#define ACTION_DELAY		4
+#define ACTION_REMARKS		6
+
+/* Converts little endian to big endian */
+#define FM_STORE_LE16_TO_BE16(data, value)   \
+	(data = ((value >> 8) | ((value & 0xFF) << 8)))
+#define FM_LE16_TO_BE16(value)   (((value >> 8) | ((value & 0xFF) << 8)))
+
+/* Converts big endian to little endian */
+#define FM_STORE_BE16_TO_LE16(data, value)   \
+	(data = ((value & 0xFF) << 8) | ((value >> 8)))
+#define FM_BE16_TO_LE16(value)   (((value & 0xFF) << 8) | ((value >> 8)))
+
+#define FM_ENABLE   1
+#define FM_DISABLE  0
+
+/* FLAG_GET register bits */
+#define FM_FR_EVENT		(1 << 0)
+#define FM_BL_EVENT		(1 << 1)
+#define FM_RDS_EVENT		(1 << 2)
+#define FM_BBLK_EVENT		(1 << 3)
+#define FM_LSYNC_EVENT		(1 << 4)
+#define FM_LEV_EVENT		(1 << 5)
+#define FM_IFFR_EVENT		(1 << 6)
+#define FM_PI_EVENT		(1 << 7)
+#define FM_PD_EVENT		(1 << 8)
+#define FM_STIC_EVENT		(1 << 9)
+#define FM_MAL_EVENT		(1 << 10)
+#define FM_POW_ENB_EVENT	(1 << 11)
+
+/* Firmware files of the FM, ASIC ID and
+ * ASIC version will be appened to this later
+ */
+#define FM_FMC_FW_FILE_START      ("fmc_ch8")
+#define FM_RX_FW_FILE_START       ("fm_rx_ch8")
+#define FM_TX_FW_FILE_START       ("fm_tx_ch8")
+
+#define FM_CHECK_SEND_CMD_STATUS(ret)  \
+	if (ret < 0) {\
+		FMDRV_API_EXIT(ret);\
+		return ret;\
+	}
+#define FM_UNDEFINED_FREQ		   0xFFFFFFFF
+
+/* Band types */
+#define FM_BAND_EUROPE_US	   	   0
+#define FM_BAND_JAPAN		    	   1
+
+/* Seek directions */
+#define FM_SEARCH_DIRECTION_DOWN    	   0
+#define FM_SEARCH_DIRECTION_UP      	   1
+
+/* Tunner modes */
+#define FM_TUNER_STOP_SEARCH_MODE          0
+#define FM_TUNER_PRESET_MODE               1
+#define FM_TUNER_AUTONOMOUS_SEARCH_MODE    2
+#define FM_TUNER_AF_JUMP_MODE              3
+
+/* Min and Max volume */
+#define FM_RX_VOLUME_MIN            	   0
+#define FM_RX_VOLUME_MAX           	  70
+
+/* Volume gain step */
+#define FM_RX_VOLUME_GAIN_STEP  	0x370
+
+/* Mute modes */
+#define FM_MUTE_ON			 0
+#define	FM_MUTE_OFF			 1
+#define	FM_MUTE_ATTENUATE		 2
+
+#define FM_RX_MUTE_UNMUTE_MODE		 0x00
+#define FM_RX_MUTE_RF_DEP_MODE		 0x01
+#define FM_RX_MUTE_AC_MUTE_MODE		 0x02
+#define FM_RX_MUTE_HARD_MUTE_LEFT_MODE	 0x04
+#define FM_RX_MUTE_HARD_MUTE_RIGHT_MODE	 0x08
+#define FM_RX_MUTE_SOFT_MUTE_FORCE_MODE	 0x10
+
+/* RF dependent mute mode */
+#define FM_RX_RF_DEPENDENT_MUTE_ON     	 1
+#define FM_RX_RF_DEPENDENT_MUTE_OFF    	 0
+
+/* RSSI threshold min and max */
+#define FM_RX_RSSI_THRESHOLD_MIN       -128
+#define FM_RX_RSSI_THRESHOLD_MAX    	127
+
+/* Stereo/Mono mode */
+#define FM_STEREO_MODE       	         0
+#define FM_MONO_MODE         		 1
+#define FM_STEREO_SOFT_BLEND 		 1
+
+/* FM RX De-emphasis filter modes */
+#define FM_RX_EMPHASIS_FILTER_50_USEC 	0
+#define FM_RX_EMPHASIS_FILTER_75_USEC 	1
+
+/* FM RX RDS modes */
+#define FM_RX_RDS_DISABLE   		0
+#define FM_RX_RDS_ENABLE    		1
+
+#define FM_NO_PI_CODE			0
+
+/* FM and RX RDS block enable/disable  */
+#define FM_RX_POWER_SET_FM_ON_RDS_OFF        0x1
+#define FM_RX_POWET_SET_FM_AND_RDS_BLK_ON    0x3
+#define FM_RX_POWET_SET_FM_AND_RDS_BLK_OFF   0x0
+
+/* RX RDS */
+#define FM_RX_RDS_FLUSH_FIFO        	     0x1
+#define FM_RX_RDS_FIFO_THRESHOLD             64	/* tuples */
+#define FM_RDS_BLOCK_SIZE		     3	/* 3 bytes */
+
+/* RDS block types */
+#define FM_RDS_BLOCK_A			    0
+#define FM_RDS_BLOCK_B			    1
+#define FM_RDS_BLOCK_C			    2
+#define FM_RDS_BLOCK_Ctag		    3
+#define FM_RDS_BLOCK_D			    4
+#define FM_RDS_BLOCK_E			    5
+
+#define FM_RDS_BLOCK_INDEX_A		    0
+#define FM_RDS_BLOCK_INDEX_B		    1
+#define FM_RDS_BLOCK_INDEX_C		    2
+#define FM_RDS_BLOCK_INDEX_D		    3
+#define FM_RDS_BLOCK_INDEX_UNKNOWN          0xF0
+
+#define FM_RDS_STATUS_ERROR_MASK	    0x18
+
+/* Represents an RDS group type & version.
+ * There are 15 groups, each group has 2
+ * versions: A and B.
+ */
+#define FM_RDS_GROUP_TYPE_MASK_0A	    ((unsigned long)1<<0)
+#define FM_RDS_GROUP_TYPE_MASK_0B	    ((unsigned long)1<<1)
+#define FM_RDS_GROUP_TYPE_MASK_1A	    ((unsigned long)1<<2)
+#define FM_RDS_GROUP_TYPE_MASK_1B	    ((unsigned long)1<<3)
+#define FM_RDS_GROUP_TYPE_MASK_2A	    ((unsigned long)1<<4)
+#define FM_RDS_GROUP_TYPE_MASK_2B	    ((unsigned long)1<<5)
+#define FM_RDS_GROUP_TYPE_MASK_3A	    ((unsigned long)1<<6)
+#define FM_RDS_GROUP_TYPE_MASK_3B           ((unsigned long)1<<7)
+#define FM_RDS_GROUP_TYPE_MASK_4A	    ((unsigned long)1<<8)
+#define FM_RDS_GROUP_TYPE_MASK_4B	    ((unsigned long)1<<9)
+#define FM_RDS_GROUP_TYPE_MASK_5A	    ((unsigned long)1<<10)
+#define FM_RDS_GROUP_TYPE_MASK_5B	    ((unsigned long)1<<11)
+#define FM_RDS_GROUP_TYPE_MASK_6A	    ((unsigned long)1<<12)
+#define FM_RDS_GROUP_TYPE_MASK_6B	    ((unsigned long)1<<13)
+#define FM_RDS_GROUP_TYPE_MASK_7A	    ((unsigned long)1<<14)
+#define FM_RDS_GROUP_TYPE_MASK_7B	    ((unsigned long)1<<15)
+#define FM_RDS_GROUP_TYPE_MASK_8A           ((unsigned long)1<<16)
+#define FM_RDS_GROUP_TYPE_MASK_8B	    ((unsigned long)1<<17)
+#define FM_RDS_GROUP_TYPE_MASK_9A	    ((unsigned long)1<<18)
+#define FM_RDS_GROUP_TYPE_MASK_9B	    ((unsigned long)1<<19)
+#define FM_RDS_GROUP_TYPE_MASK_10A	    ((unsigned long)1<<20)
+#define FM_RDS_GROUP_TYPE_MASK_10B	    ((unsigned long)1<<21)
+#define FM_RDS_GROUP_TYPE_MASK_11A	    ((unsigned long)1<<22)
+#define FM_RDS_GROUP_TYPE_MASK_11B	    ((unsigned long)1<<23)
+#define FM_RDS_GROUP_TYPE_MASK_12A	    ((unsigned long)1<<24)
+#define FM_RDS_GROUP_TYPE_MASK_12B	    ((unsigned long)1<<25)
+#define FM_RDS_GROUP_TYPE_MASK_13A	    ((unsigned long)1<<26)
+#define FM_RDS_GROUP_TYPE_MASK_13B	    ((unsigned long)1<<27)
+#define FM_RDS_GROUP_TYPE_MASK_14A	    ((unsigned long)1<<28)
+#define FM_RDS_GROUP_TYPE_MASK_14B	    ((unsigned long)1<<29)
+#define FM_RDS_GROUP_TYPE_MASK_15A	    ((unsigned long)1<<30)
+#define FM_RDS_GROUP_TYPE_MASK_15B	    ((unsigned long)1<<31)
+
+/* RX Alternate Frequency info */
+#define FM_RDS_MIN_AF		          1
+#define FM_RDS_MAX_AF		        204
+#define FM_RDS_MAX_AF_JAPAN	        140
+#define FM_RDS_1_AF_FOLLOWS	        225
+#define FM_RDS_25_AF_FOLLOWS	        249
+
+/* RDS system type (RDS/RBDS) */
+#define FM_RDS_SYSTEM_RDS		0
+#define FM_RDS_SYSTEM_RBDS		1
+
+/* AF on/off */
+#define FM_RX_RDS_AF_SWITCH_MODE_ON	1
+#define FM_RX_RDS_AF_SWITCH_MODE_OFF	0
+
+/* Retry count when interrupt process goes wrong */
+#define FM_IRQ_TIMEOUT_RETRY_MAX	5	/* 5 times */
+
+/* Audio IO set values */
+#define FM_RX_FM_AUDIO_ENABLE_I2S 	       0x01
+#define FM_RX_FM_AUDIO_ENABLE_ANALOG	       0x02
+#define FM_RX_FM_AUDIO_ENABLE_I2S_AND_ANALOG   0x03
+#define FM_RX_FM_AUDIO_ENABLE_DISABLE	       0x00
+
+/* HI/LO set values */
+#define FM_RX_IFFREQ_TO_HI_SIDE                0x0
+#define FM_RX_IFFREQ_TO_LO_SIDE                0x1
+#define FM_RX_IFFREQ_HILO_AUTOMATIC            0x2
+
+/* Default RX mode configuration. Chip will be configured
+ * with this default values after loading RX firmware.
+ */
+#define FM_DEFAULT_RX_VOLUME    	    10
+#define FM_DEFAULT_RSSI_THRESHOLD   	    3
+
+/* Functions exported to FM V4L2 layer */
+int fm_core_prepare(void);
+int fm_core_release(void);
+int fm_core_setup_transport(void);
+int fm_core_release_transport(void);
+int fm_core_is_rds_data_available(struct file *, struct poll_table_struct *);
+int fm_core_transfer_rds_from_internal_buff(struct file *,
+					    char __user *, size_t);
+int fm_core_set_frequency(unsigned int);
+int fm_core_get_frequency(unsigned int *);
+int fm_core_rx_get_rssi_level(unsigned short *);
+int fm_core_rx_seek(unsigned int, unsigned int);
+int fm_core_rx_set_volume(unsigned short);
+int fm_core_rx_get_volume(unsigned short *);
+int fm_core_region_get(unsigned char *);
+int fm_core_region_set(unsigned char);
+int fm_core_rx_get_currband_lowhigh_freq(unsigned int *, unsigned int *);
+int fm_core_rx_get_mute_mode(unsigned char *);
+int fm_core_set_mute_mode(unsigned char);
+int fm_core_rx_get_rfdepend_softmute(unsigned char *);
+int fm_core_rx_set_rfdepend_softmute(unsigned char);
+int fm_core_rx_set_rssi_threshold(short);
+int fm_core_rx_get_rssi_threshold(short *);
+int fm_core_set_stereo_mono(unsigned short);
+int fm_core_rx_get_stereo_mono(unsigned short *);
+int fm_core_rx_set_deemphasis_mode(unsigned short);
+int fm_core_rx_get_deemphasis_mode(unsigned short *);
+int fm_core_rx_get_rds_mode(unsigned char *);
+int fm_core_set_rds_mode(unsigned char);
+int fm_core_rx_set_rds_system(unsigned char);
+int fm_core_rx_get_rds_system(unsigned char *);
+int fm_core_rx_set_af_switch(unsigned char);
+int fm_core_rx_get_af_switch(unsigned char *);
+
+int fm_core_mode_set(unsigned char);
+int fm_core_mode_get(unsigned char *);
+
+int fm_core_tx_set_pwr_lvl(unsigned char new_pwr_lvl);
+int fm_core_tx_set_radio_text(unsigned char *, unsigned char);
+int fm_core_tx_set_af(unsigned int);
+#endif
diff --git a/drivers/misc/ti-st/fmdrv_mixer.c b/drivers/misc/ti-st/fmdrv_mixer.c
new file mode 100644
index 0000000..1427853
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_mixer.c
@@ -0,0 +1,725 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  This file manages FM driver's ALSA mixer controls.
+ *
+ *  The standard V4L2 subsystem provides limited V4L2 IOCTLs
+ *  to perform FM operation. So, this module will expose
+ *  some of mixer controls (ex., Band Selection,
+ *  FM TX/RX Mode Switch, etc) via ALSA to user space.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+#include <linux/version.h>
+#include <sound/core.h>
+#include <sound/control.h>
+
+#include "fmdrv.h"
+#include "fmdrv_mixer.h"
+#include "fmdrv_core.h"
+
+static int fm_mixer_mode_info(struct snd_kcontrol *kcontrol,
+			      struct snd_ctl_elem_info *uinfo)
+{
+	static char *fm_modes[] = { "Off", "Tx", "Rx" };
+
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 3;
+	if (uinfo->value.enumerated.item > 2)
+		uinfo->value.enumerated.item = 2;
+	strcpy(uinfo->value.enumerated.name,
+	       fm_modes[uinfo->value.enumerated.item]);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_mode_get(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	unsigned char current_fmmode;
+
+	FMDRV_API_START();
+	ret = fm_core_mode_get(&current_fmmode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ucontrol->value.enumerated.item[0] = current_fmmode & 3;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_mode_put(struct snd_kcontrol *kcontrol,
+			     struct snd_ctl_elem_value *ucontrol)
+{
+	int changed;
+	unsigned char mode;
+	int ret;
+
+	FMDRV_API_START();
+
+	mode = ucontrol->value.integer.value[0] & 3;
+	ret = fm_core_mode_set(mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static int fm_mixer_region_info(struct snd_kcontrol *kcontrol,
+				struct snd_ctl_elem_info *uinfo)
+{
+	static char *region[] = { "Europe/US", "Japan" };
+
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name,
+	       region[uinfo->value.enumerated.item]);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_region_get(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned char region;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_region_get(&region);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ucontrol->value.enumerated.item[0] = region & 0x1;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_region_put(struct snd_kcontrol *kcontrol,
+			       struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	unsigned char region;
+	int changed;
+
+	FMDRV_API_START();
+
+	region = ucontrol->value.integer.value[0] & 0x1;
+	ret = fm_core_region_set(region);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static int fm_mixer_rfdepend_mute_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	static char *region[] = { "Off", "On" };
+
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name,
+	       region[uinfo->value.enumerated.item]);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rfdepend_mute_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned char en_dis;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_rx_get_rfdepend_softmute(&en_dis);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ucontrol->value.enumerated.item[0] = en_dis & 0x1;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rfdepend_mute_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned char en_dis;
+	int changed, ret;
+
+	FMDRV_API_START();
+
+	en_dis = ucontrol->value.integer.value[0] & 0x1;
+	ret = fm_core_rx_set_rfdepend_softmute(en_dis);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static int fm_mixer_rssi_level_info(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_info *uinfo)
+{
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = -16;
+	uinfo->value.integer.max = 15;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rssi_level_get(struct snd_kcontrol *kcontrol,
+				   struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned short curr_rssi_lvl;
+	int ret;
+	FMDRV_API_START();
+
+	ret = fm_core_rx_get_rssi_level(&curr_rssi_lvl);
+	if (ret)
+		return ret;
+
+	ucontrol->value.integer.value[0] = curr_rssi_lvl;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_rssi_threshold_info(struct snd_kcontrol *kcontrol,
+					   struct snd_ctl_elem_info *uinfo)
+{
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = -16;
+	uinfo->value.integer.max = 15;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_rssi_threshold_get(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	short curr_rssi_threshold;
+	int ret;
+	FMDRV_API_START();
+
+	ret = fm_core_rx_get_rssi_threshold(&curr_rssi_threshold);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	ucontrol->value.integer.value[0] = curr_rssi_threshold;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_rssi_threshold_put(struct snd_kcontrol *kcontrol,
+					  struct snd_ctl_elem_value *ucontrol)
+{
+	short rssi_threshold_toset;
+	int changed, ret;
+
+	FMDRV_API_START();
+
+	rssi_threshold_toset = ucontrol->value.integer.value[0];
+	ret = fm_core_rx_set_rssi_threshold(rssi_threshold_toset);
+	if (ret)
+		return ret;
+
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static int fm_mixer_stereo_mono_info(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_info *uinfo)
+{
+	static char *modes[] = { "Stereo", "Mono" };
+
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name,
+	       modes[uinfo->value.enumerated.item]);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_stereo_mono_get(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned short mode;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_rx_get_stereo_mono(&mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ucontrol->value.enumerated.item[0] = mode & 0x1;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_stereo_mono_put(struct snd_kcontrol *kcontrol,
+				    struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	unsigned short mode;
+	int changed;
+
+	FMDRV_API_START();
+
+	mode = ucontrol->value.integer.value[0] & 0x1;
+	ret = fm_core_set_stereo_mono(mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static int fm_mixer_rx_deemphasis_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	static char *filter_mode[] = { "50 us", "75 us" };
+
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name,
+	       filter_mode[uinfo->value.enumerated.item]);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_deemphasis_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned short mode;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_rx_get_deemphasis_mode(&mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ucontrol->value.enumerated.item[0] = mode & 0x1;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_deemphasis_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	unsigned short mode;
+	int changed;
+
+	FMDRV_API_START();
+
+	mode = ucontrol->value.integer.value[0] & 0x1;
+	ret = fm_core_rx_set_deemphasis_mode(mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static int fm_mixer_rx_rds_switch_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	static char *rds_mode[] = { "Off", "On" };
+
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name,
+	       rds_mode[uinfo->value.enumerated.item]);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_rds_switch_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned char rds_onoff;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_rx_get_rds_mode(&rds_onoff);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ucontrol->value.enumerated.item[0] = rds_onoff & 0x1;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_rds_switch_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	unsigned char rds_onoff;
+	int changed;
+
+	FMDRV_API_START();
+
+	rds_onoff = ucontrol->value.integer.value[0] & 0x1;
+	ret = fm_core_set_rds_mode(rds_onoff);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static int fm_mixer_rx_rds_opmode_info(struct snd_kcontrol *kcontrol,
+				       struct snd_ctl_elem_info *uinfo)
+{
+	static char *rds_mode[] = { "RDS", "RDBS" };
+
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name,
+	       rds_mode[uinfo->value.enumerated.item]);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_rds_opmode_get(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned char rds_mode;
+	int ret;
+
+	FMDRV_API_START();
+	ret = fm_core_rx_get_rds_system(&rds_mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ucontrol->value.enumerated.item[0] = rds_mode & 0x1;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_rds_opmode_put(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_value *ucontrol)
+{
+	int ret;
+	unsigned char rds_mode;
+	int changed;
+
+	FMDRV_API_START();
+
+	rds_mode = ucontrol->value.integer.value[0] & 0x1;
+	ret = fm_core_rx_set_rds_system(rds_mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static int fm_mixer_rx_af_switch_info(struct snd_kcontrol *kcontrol,
+				      struct snd_ctl_elem_info *uinfo)
+{
+	static char *af_mode[] = { "Off", "On" };
+
+	FMDRV_API_START();
+
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+	uinfo->count = 1;
+	uinfo->value.enumerated.items = 2;
+	if (uinfo->value.enumerated.item > 1)
+		uinfo->value.enumerated.item = 1;
+	strcpy(uinfo->value.enumerated.name,
+	       af_mode[uinfo->value.enumerated.item]);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_af_switch_get(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned char af_mode;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_rx_get_af_switch(&af_mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ucontrol->value.enumerated.item[0] = af_mode & 0x1;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static int fm_mixer_rx_af_switch_put(struct snd_kcontrol *kcontrol,
+				     struct snd_ctl_elem_value *ucontrol)
+{
+	unsigned char af_mode;
+	int changed, ret;
+
+	FMDRV_API_START();
+
+	af_mode = ucontrol->value.integer.value[0] & 0x1;
+	ret = fm_core_rx_set_af_switch(af_mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	changed = 1;
+
+	FMDRV_API_EXIT(changed);
+	return changed;
+}
+
+static struct snd_kcontrol_new snd_fm_controls[] = {
+	{
+	 .name = "Mode Switch",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_mode_info,
+	 .get = fm_mixer_mode_get,
+	 .put = fm_mixer_mode_put,
+	 },
+	{
+	 .name = "Region Switch",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_region_info,
+	 .get = fm_mixer_region_get,
+	 .put = fm_mixer_region_put,
+	 },
+	{
+	 .name = "RF Dependent Mute",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_rfdepend_mute_info,
+	 .get = fm_mixer_rfdepend_mute_get,
+	 .put = fm_mixer_rfdepend_mute_put,
+	 },
+	{
+	 .name = "RSSI Level",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READ,
+	 .info = fm_mixer_rssi_level_info,
+	 .get = fm_mixer_rssi_level_get,
+	 },
+	{
+	 .name = "RSSI Threshold",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_rx_rssi_threshold_info,
+	 .get = fm_mixer_rx_rssi_threshold_get,
+	 .put = fm_mixer_rx_rssi_threshold_put,
+	 },
+	{
+	 .name = "Stereo/Mono",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_stereo_mono_info,
+	 .get = fm_mixer_stereo_mono_get,
+	 .put = fm_mixer_stereo_mono_put,
+	 },
+	{
+	 .name = "De-emphasis Filter",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_rx_deemphasis_info,
+	 .get = fm_mixer_rx_deemphasis_get,
+	 .put = fm_mixer_rx_deemphasis_put,
+	 },
+	{
+	 .name = "RDS Switch",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_rx_rds_switch_info,
+	 .get = fm_mixer_rx_rds_switch_get,
+	 .put = fm_mixer_rx_rds_switch_put,
+	 },
+	{
+	 .name = "RDS Operation Mode",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_rx_rds_opmode_info,
+	 .get = fm_mixer_rx_rds_opmode_get,
+	 .put = fm_mixer_rx_rds_opmode_put,
+	 },
+	{
+	 .name = "AF Switch",
+	 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+	 .index = 0,
+	 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+	 .info = fm_mixer_rx_af_switch_info,
+	 .get = fm_mixer_rx_af_switch_get,
+	 .put = fm_mixer_rx_af_switch_put,
+	 },
+};
+
+int fm_mixer_init(struct fmdrv_ops *fmdev)
+{
+	int idx;
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Allocate new card for FM driver */
+	fmdev->card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+				   THIS_MODULE, 0);
+	if (!fmdev->card) {
+		FM_DRV_ERR("No memory to allocate new card");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	fmdev->card->private_data = fmdev;
+
+	/* Add FM mixer controls to the card */
+	strcpy(fmdev->card->mixername, FM_DRV_MIXER_NAME);
+	for (idx = 0; idx < ARRAY_SIZE(snd_fm_controls); idx++) {
+		ret = snd_ctl_add(fmdev->card,
+				  snd_ctl_new1(&snd_fm_controls[idx], fmdev));
+		if (ret < 0) {
+			snd_card_free(fmdev->card);
+			FM_DRV_ERR("Failed to add mixer controls");
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+	}
+
+	/* Register FM card with ALSA */
+	ret = snd_card_register(fmdev->card);
+	if (ret) {
+		snd_card_free(fmdev->card);
+		FM_DRV_ERR("Failed to register new card");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	strcpy(fmdev->card->driver, FM_DRV_NAME);
+	strcpy(fmdev->card->shortname, FM_DRV_CARD_SHORT_NAME);
+	sprintf(fmdev->card->longname, FM_DRV_CARD_LONG_NAME);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_mixer_deinit(struct fmdrv_ops *fmdev)
+{
+	FMDRV_API_START();
+
+	/* Unregister FM card from ALSA */
+	snd_card_free(fmdev->card);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
diff --git a/drivers/misc/ti-st/fmdrv_mixer.h b/drivers/misc/ti-st/fmdrv_mixer.h
new file mode 100644
index 0000000..92dcadf
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_mixer.h
@@ -0,0 +1,30 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FM_MIXER_H
+#define _FM_MIXER_H
+
+/* FM mixer name */
+#define FM_DRV_MIXER_NAME   "tifm_mixer"
+
+int fm_mixer_init(struct fmdrv_ops *fmdev);
+int fm_mixer_deinit(struct fmdrv_ops *fmdev);
+
+#endif
diff --git a/drivers/misc/ti-st/fmdrv_st.c b/drivers/misc/ti-st/fmdrv_st.c
new file mode 100644
index 0000000..383a1e4
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_st.c
@@ -0,0 +1,320 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  This file provide interfaces to Shared Transport.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/kernel.h>
+
+#include "st.h"
+#include "fmdrv.h"
+#include "fmdrv_st.h"
+
+static char streg_cbdata;
+
+/* Wait on comepletion handler needed to synchronize
+ * fm_st_register() and fm_st_registration_completion_cb()
+ * functions.
+ */
+static struct completion wait_for_fmdrv_reg_completion;
+
+/* Write function pointer of ST driver */
+long (*g_st_write) (struct sk_buff *skb);
+
+/* RX Queue and RX Tasklet pointer */
+static struct sk_buff_head *g_rx_q;
+static struct tasklet_struct *g_rx_task;
+
+/* Flag to maintain whether FM ST is claimed or not */
+static char is_fm_st_claimed;
+
+/* Called from FM Core and FM Char device interface to claim
+ * FM ST. Who ever comes first, ownership of FM ST will be
+ * given to them.
+ */
+int fm_st_claim(void)
+{
+	FMDRV_API_START();
+
+	/* Give ownership of FM ST to first caller */
+	if (is_fm_st_claimed == FM_ST_NOT_CLAIMED) {
+		is_fm_st_claimed = FM_ST_CLAIMED;
+
+		FMDRV_API_EXIT(FM_ST_SUCCESS);
+		return FM_ST_SUCCESS;
+	}
+
+	FM_DRV_DBG("FM ST claimed already");
+
+	FMDRV_API_EXIT(FM_ST_FAILED);
+	return FM_ST_FAILED;
+}
+
+/* Called from FM Core and FM Char device interface
+ * to release FM ST.
+ */
+int fm_st_release(void)
+{
+	FMDRV_API_START();
+
+	/* Release FM ST if it is already claimed */
+	if (is_fm_st_claimed == FM_ST_CLAIMED) {
+		is_fm_st_claimed = FM_ST_NOT_CLAIMED;
+
+		FMDRV_API_EXIT(FM_ST_SUCCESS);
+		return FM_ST_SUCCESS;
+
+	}
+
+	FM_DRV_ERR("FM ST is not claimed,called again?");
+
+	FMDRV_API_EXIT(FM_ST_FAILED);
+	return FM_ST_FAILED;
+}
+
+/* Called by Shared Transport layer when FM packet is
+ * available
+ */
+static long fm_st_receive(struct sk_buff *skb)
+{
+	FMDRV_API_START();
+
+	if (skb == NULL) {
+		FM_DRV_ERR("Invalid SKB received from ST");
+		FMDRV_API_EXIT(-EFAULT);
+		return -EFAULT;
+	}
+
+	/* Is this FM Channel-8 packet? */
+	if (skb->cb[0] != FM_PKT_LOGICAL_CHAN_NUMBER) {
+		FM_DRV_ERR("Received SKB(%p) is not FM Channel 8 pkt", skb);
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+
+	/* One byte is already reserved for Channel-8 in skb,
+	 * so prepend skb with Channel-8 packet type byte.
+	 */
+	memcpy(skb_push(skb, 1), &skb->cb[0], 1);
+
+	if (g_rx_q != NULL && g_rx_task != NULL) {
+		/* Queue FM packet for FM RX task */
+		skb_queue_tail(g_rx_q, skb);
+		tasklet_schedule(g_rx_task);
+	} else {
+		FM_DRV_ERR
+		    ("Invalid RX queue and RX tasklet pointer,puring skb");
+		kfree_skb(skb);
+		FMDRV_API_EXIT(-EFAULT);
+		return -EFAULT;
+	}
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Forwards FM Packets to Shared Transport */
+int fm_st_send(struct sk_buff *skb)
+{
+	long len;
+
+	FMDRV_API_START();
+
+	if (skb == NULL) {
+		FM_DRV_ERR("Invalid skb, can't send");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+
+	/* Is anyone called without claiming FM ST? */
+	if (is_fm_st_claimed == FM_ST_CLAIMED && g_st_write != NULL) {
+		/* Forward FM packet(SKB) to ST for the transmission */
+		len = g_st_write(skb);
+		if (len < 0) {
+			/* Something went wrong in st write , free skb memory */
+			kfree_skb(skb);
+			FM_DRV_ERR(" ST write failed (%ld)", len);
+			FMDRV_API_EXIT(-EAGAIN);
+			return -EAGAIN;
+		}
+	} else {		/* Nobody calimed FM ST */
+
+		kfree_skb(skb);
+		FM_DRV_ERR("FM ST is not claimed, Can't send skb");
+		FMDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Called by ST layer to indicate protocol registration completion
+ * status. fm_st_register() function will wait for signal from this
+ * API when st_register() function returns ST_PENDING.
+ */
+static void fm_st_registration_completion_cb(char data)
+{
+	FMDRV_API_START();
+
+	/* fm_st_register() function needs value of 'data' to know
+	 * the registration status(success/fail). So, have a back
+	 * up of it.
+	 */
+	streg_cbdata = data;
+
+	/* Got a feedback from ST for FM driver registration
+	 * request. Wackup fm_st_register() function to continue
+	 * it's open operation.
+	 */
+	complete(&wait_for_fmdrv_reg_completion);
+
+	FMDRV_API_EXIT(0);
+}
+
+/* Called from V4L2 RADIO open function (fm_fops_open()) to
+ * register FM driver with Shared Transport
+ */
+int fm_st_register(struct sk_buff_head *rx_q, struct tasklet_struct *rx_task)
+{
+	static struct st_proto_s fm_st_proto;
+	unsigned long timeleft;
+	int ret;
+
+	ret = 0;
+
+	FMDRV_API_START();
+
+	/* Populate FM driver info required by ST */
+	memset(&fm_st_proto, 0, sizeof(fm_st_proto));
+
+	/* FM driver ID */
+	fm_st_proto.type = ST_FM;
+
+	/* Receive function which called from ST */
+	fm_st_proto.recv = fm_st_receive;
+
+	/* Packet match function may used in future */
+	fm_st_proto.match_packet = NULL;
+
+	/* Callback to be called when registration is pending */
+	fm_st_proto.reg_complete_cb = fm_st_registration_completion_cb;
+
+	/* This is write function pointer of ST. BT driver will make use of this
+	 * for sending any packets to chip. ST will assign and give to us, so
+	 * make it as NULL
+	 */
+	fm_st_proto.write = NULL;
+
+	/* Register with ST layer */
+	ret = st_register(&fm_st_proto);
+	if (ret == ST_ERR_PENDING) {
+		/* Prepare wait-for-completion handler data structures.
+		 * Needed to syncronize this and
+		 * fm_st_registration_completion_cb() functions.
+		 */
+		init_completion(&wait_for_fmdrv_reg_completion);
+
+		/* Reset ST registration callback status flag. This value
+		 * will be updated in fm_st_registration_completion_cb()
+		 * function whenever it is called from ST driver.
+		 */
+		streg_cbdata = -EINPROGRESS;
+
+		/* ST is busy with other protocol registration (may be busy with
+		 * firmware download). So, wait till the registration callback
+		 * (passed as a argument to st_register() function) getting
+		 * called from ST.
+		 */
+		FM_DRV_DBG(" %s waiting for reg completion signal from ST",
+			   __func__);
+
+		timeleft =
+		    wait_for_completion_timeout(&wait_for_fmdrv_reg_completion,
+						FM_ST_REGISTER_TIMEOUT);
+		if (!timeleft) {
+			FM_DRV_ERR("Timeout(%d sec), didn't get reg"
+				   "completion signal from ST",
+				   jiffies_to_msecs(FM_ST_REGISTER_TIMEOUT) /
+				   1000);
+			FMDRV_API_EXIT(-ETIMEDOUT);
+			return -ETIMEDOUT;
+		}
+
+		/* Is ST registration callback called with ERROR value? */
+		if (streg_cbdata != 0) {
+			FM_DRV_ERR("ST reg completion CB called with invalid"
+				   "status %d", streg_cbdata);
+			FMDRV_API_EXIT(-EAGAIN);
+			return -EAGAIN;
+		}
+		ret = 0;
+	} else if (ret == ST_ERR_FAILURE) {
+		FM_DRV_ERR("st_register failed %d", ret);
+		FMDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+
+	/* Do we have proper ST write function? */
+	if (fm_st_proto.write != NULL) {
+		/* We need this pointer for sending any FM pkts */
+		g_st_write = fm_st_proto.write;
+	} else {
+		FM_DRV_ERR("Failed to get ST write func pointer");
+
+		/* Undo registration with ST */
+		ret = st_unregister(ST_FM);
+		if (ret < 0)
+			FM_DRV_ERR("st_unregister failed %d", ret);
+
+		FMDRV_API_EXIT(-EAGAIN);
+		return -EAGAIN;
+	}
+
+	/* Store Rx Q and Rx tasklet pointers. This pointers should
+	 * already initialized by caller
+	 */
+	g_rx_task = rx_task;
+	g_rx_q = rx_q;
+
+	FMDRV_API_EXIT(ret);
+	return ret;
+}
+
+/* Unregister FM Driver from Shared Transport */
+int fm_st_unregister(void)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Unregister FM Driver from ST */
+	ret = st_unregister(ST_FM);
+	if (ret != ST_SUCCESS) {
+		FM_DRV_ERR("st_unregister failed %d", ret);
+		FMDRV_API_EXIT(-EBUSY);
+		return -EBUSY;
+	}
+
+	g_rx_task = NULL;
+	g_rx_q = NULL;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
diff --git a/drivers/misc/ti-st/fmdrv_st.h b/drivers/misc/ti-st/fmdrv_st.h
new file mode 100644
index 0000000..86a4007
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_st.h
@@ -0,0 +1,50 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FM_ST_H
+#define _FM_ST_H
+
+#include <linux/interrupt.h>
+
+/* Defines number of seconds to wait for reg completion
+ * callback getting called from ST (in case, registration
+ * with ST returns PENDING status)
+ */
+#define FM_ST_REGISTER_TIMEOUT   msecs_to_jiffies(6000)	/* 6 sec */
+
+#define FM_PKT_LOGICAL_CHAN_NUMBER  0x08   /* Logical channel 8 */
+
+/* Claim ownership of FM ST */
+int fm_st_claim(void);
+
+/* To release FM ST */
+int fm_st_release(void);
+
+/* Forwards FM Packets to Shared Transport */
+int fm_st_send(struct sk_buff *skb);
+
+/* Register with Shared Transport */
+int fm_st_register(struct sk_buff_head  *rx_q,
+		   struct tasklet_struct *rx_task);
+
+/* Unregister from Shared Transport */
+int fm_st_unregister(void);
+
+#endif
diff --git a/drivers/misc/ti-st/fmdrv_v4l2.c b/drivers/misc/ti-st/fmdrv_v4l2.c
new file mode 100644
index 0000000..3fcc0f0
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_v4l2.c
@@ -0,0 +1,581 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  This file provides interfaces to V4L2 subsystem.
+ *
+ *  This module registers with V4L2 subsystem as Radio
+ *  data system interface (/dev/radio). During the registration,
+ *  it will expose two set of function pointers to V4L2 subsystem.
+ *
+ *    1) File operation related API (open, close, read, write, poll...etc).
+ *    2) Set of V4L2 IOCTL complaint API.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "fmdrv.h"
+#include "fmdrv_v4l2.h"
+#include "fmdrv_core.h"
+
+static unsigned char radio_disconnected;
+
+/* Query control */
+static struct v4l2_queryctrl fmdrv_v4l2_queryctrl[] = {
+	{
+	 .id = V4L2_CID_AUDIO_VOLUME,
+	 .type = V4L2_CTRL_TYPE_INTEGER,
+	 .name = "Volume",
+	 .minimum = FM_RX_VOLUME_MIN,
+	 .maximum = FM_RX_VOLUME_MAX,
+	 .step = 1,
+	 .default_value = FM_DEFAULT_RX_VOLUME,
+	 },
+	{
+	 .id = V4L2_CID_AUDIO_BALANCE,
+	 .flags = V4L2_CTRL_FLAG_DISABLED,
+	 },
+	{
+	 .id = V4L2_CID_AUDIO_BASS,
+	 .flags = V4L2_CTRL_FLAG_DISABLED,
+	 },
+	{
+	 .id = V4L2_CID_AUDIO_TREBLE,
+	 .flags = V4L2_CTRL_FLAG_DISABLED,
+	 },
+	{
+	 .id = V4L2_CID_AUDIO_MUTE,
+	 .type = V4L2_CTRL_TYPE_BOOLEAN,
+	 .name = "Mute",
+	 .minimum = 0,
+	 .maximum = 2,
+	 .step = 1,
+	 .default_value = FM_MUTE_OFF,
+	 },
+	{
+	 .id = V4L2_CID_AUDIO_LOUDNESS,
+	 .flags = V4L2_CTRL_FLAG_DISABLED,
+	 },
+};
+
+/* -- V4L2 RADIO (/dev/radioX) device file operation interfaces --- */
+
+/* Read RDS data */
+static ssize_t fm_v4l2_fops_read(struct file *file, char __user * buf,
+				 size_t count, loff_t *ppos)
+{
+	unsigned char rds_mode;
+	int ret, noof_bytes_copied;
+	FMDRV_API_START();
+
+	if (!radio_disconnected) {
+		FM_DRV_ERR("FM device is already disconnected\n");
+		FMDRV_API_EXIT(-EIO);
+		return -EIO;
+	}
+	/* Turn on RDS mode , if it is disabled */
+	ret = fm_core_rx_get_rds_mode(&rds_mode);
+	if (ret) {
+		FM_DRV_ERR("Unable to read current rds mode");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	if (rds_mode == FM_RX_RDS_DISABLE) {
+		ret = fm_core_set_rds_mode(FM_RX_RDS_ENABLE);
+		if (ret < 0) {
+			FM_DRV_ERR("Unable to enable rds mode");
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+	}
+	/* Copy RDS data from internal buffer to user buffer */
+	noof_bytes_copied =
+	    fm_core_transfer_rds_from_internal_buff(file, buf, count);
+
+	FMDRV_API_EXIT(noof_bytes_copied);
+	return noof_bytes_copied;
+}
+
+/* Write RDS data */
+static ssize_t fm_v4l2_fops_write(struct file *file, const char __user * buf,
+				  size_t count, loff_t *ppos)
+{
+	struct tx_rds rds;
+	int ret;
+	FMDRV_API_START();
+
+	ret = copy_from_user(&rds, buf, sizeof(rds));
+	FM_DRV_DBG("(%d)type: %d, text %s, af %d",
+		   ret, rds.text_type, rds.text, rds.af_freq);
+
+	fm_core_tx_set_radio_text(rds.text, rds.text_type);
+	fm_core_tx_set_af(rds.af_freq);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Poll RDS data */
+static unsigned int fm_v4l2_fops_poll(struct file *file,
+				      struct poll_table_struct *pts)
+{
+	int ret;
+	FMDRV_API_START();
+
+	ret = fm_core_is_rds_data_available(file, pts);
+	if (!ret) {
+		FMDRV_API_EXIT(POLLIN | POLLRDNORM);
+		return POLLIN | POLLRDNORM;
+	}
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* File Open */
+static int fm_v4l2_fops_open(struct file *file)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	/* Don't allow multiple open */
+	if (radio_disconnected) {
+		FM_DRV_ERR("FM device is already opened\n");
+		FMDRV_API_EXIT(-EBUSY);
+		return -EBUSY;
+	}
+
+	/* Request FM Core to link with FM ST */
+	ret = fm_core_setup_transport();
+	if (ret) {
+		FM_DRV_ERR("Unable to setup FM Core transport");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Initialize FM Core */
+	ret = fm_core_prepare();
+	if (ret) {
+		FM_DRV_ERR("Unable to prepare FM CORE");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	FM_DRV_DBG("Load FM RX firmware..");
+	/* By default load FM RX firmware */
+	ret = fm_core_mode_set(FM_MODE_RX);
+	if (ret) {
+		FM_DRV_ERR("Unable to load FM RX firmware");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	radio_disconnected = 1;
+	FM_DRV_DBG("FM CORE is ready");
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* File Release */
+static int fm_v4l2_fops_release(struct file *file)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	if (!radio_disconnected) {
+		FM_DRV_DBG("FM device already closed,close called again?");
+		FMDRV_API_EXIT(0);
+		return 0;
+	}
+
+	FM_DRV_DBG("Turning off..");
+	ret = fm_core_mode_set(FM_MODE_OFF);
+	if (ret) {
+		FM_DRV_ERR("Unable to turn off the chip");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Request FM Core to unlink from ST driver */
+	ret = fm_core_release();
+	if (ret) {
+		FM_DRV_ERR("FM CORE release failed");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	/* Release FM Core transport */
+	ret = fm_core_release_transport();
+	if (ret) {
+		FM_DRV_ERR("Unable to setup FM Core transport");
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	radio_disconnected = 0;
+	FM_DRV_DBG("FM CORE released successfully");
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* V4L2 RADIO (/dev/radioX) device IOCTL interfaces */
+
+/* Query device capabilities */
+static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
+				   struct v4l2_capability *capability)
+{
+	FMDRV_API_START();
+
+	strlcpy(capability->driver, FM_DRV_NAME, sizeof(capability->driver));
+	strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
+		sizeof(capability->card));
+	sprintf(capability->bus_info, "UART");
+	capability->version = FM_DRV_RADIO_VERSION;
+	capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+	    V4L2_CAP_RADIO | V4L2_CAP_READWRITE | V4L2_CAP_AUDIO;
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Enumerate control items */
+static int fm_v4l2_vidioc_queryctrl(struct file *file, void *priv,
+				    struct v4l2_queryctrl *qc)
+{
+	int index;
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = -EINVAL;
+	if (qc->id < V4L2_CID_BASE) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	/* Search control ID and copy its properties */
+	for (index = 0; index < ARRAY_SIZE(fmdrv_v4l2_queryctrl); index++) {
+		if (qc->id && qc->id == fmdrv_v4l2_queryctrl[index].id) {
+			memcpy(qc, &(fmdrv_v4l2_queryctrl[index]), sizeof(*qc));
+			ret = 0;
+			break;
+		}
+	}
+	FMDRV_API_EXIT(ret);
+	return ret;
+}
+
+/* Get the value of a control */
+static int fm_v4l2_vidioc_g_ctrl(struct file *file, void *priv,
+				 struct v4l2_control *ctrl)
+{
+	int ret;
+	unsigned short curr_vol;
+	unsigned char curr_mute_mode;
+
+	FMDRV_API_START();
+
+	switch (ctrl->id) {
+
+	case V4L2_CID_AUDIO_MUTE:	/* get mute mode */
+		ret = fm_core_rx_get_mute_mode(&curr_mute_mode);
+		if (ret < 0) {
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+		ctrl->value = curr_mute_mode;
+		break;
+
+	case V4L2_CID_AUDIO_VOLUME:	/* get volume */
+		ret = fm_core_rx_get_volume(&curr_vol);
+		if (ret < 0) {
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+		ctrl->value = curr_vol;
+		break;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set the value of a control */
+static int fm_v4l2_vidioc_s_ctrl(struct file *file, void *priv,
+				 struct v4l2_control *ctrl)
+{
+	int ret;
+	FMDRV_API_START();
+
+	switch (ctrl->id) {
+
+	case V4L2_CID_AUDIO_MUTE:	/* set mute */
+		ret = fm_core_set_mute_mode((unsigned char)ctrl->value);
+		if (ret < 0) {
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+		break;
+
+	case V4L2_CID_AUDIO_VOLUME:	/* set volume */
+		ret = fm_core_rx_set_volume((unsigned short)ctrl->value);
+		if (ret < 0) {
+			FMDRV_API_EXIT(ret);
+			return ret;
+		}
+		break;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Get audio attributes */
+static int fm_v4l2_vidioc_g_audio(struct file *file, void *priv,
+				  struct v4l2_audio *audio)
+{
+	FMDRV_API_START();
+
+	memset(audio, 0, sizeof(*audio));
+	audio->index = 0;
+	strcpy(audio->name, "Radio");
+	audio->capability = V4L2_AUDCAP_STEREO;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set audio attributes */
+static int fm_v4l2_vidioc_s_audio(struct file *file, void *priv,
+				  struct v4l2_audio *audio)
+{
+	FMDRV_API_START();
+
+	if (audio->index != 0) {
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Get tuner attributes */
+static int fm_v4l2_vidioc_g_tuner(struct file *file, void *priv,
+				  struct v4l2_tuner *tuner)
+{
+	unsigned int bottom_frequency;
+	unsigned int top_frequency;
+	unsigned short stereo_mono_mode;
+	unsigned short rssilvl;
+	int ret;
+
+	FMDRV_API_START();
+
+	if (tuner->index != 0) {
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	ret =
+	    fm_core_rx_get_currband_lowhigh_freq(&bottom_frequency,
+						 &top_frequency);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ret = fm_core_rx_get_stereo_mono(&stereo_mono_mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	ret = fm_core_rx_get_rssi_level(&rssilvl);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	strcpy(tuner->name, "FM");
+	tuner->type = V4L2_TUNER_RADIO;
+	/* Store rangelow and rangehigh freq in unit of 62.5 KHz */
+	tuner->rangelow = (bottom_frequency * 10000) / 625;
+	tuner->rangehigh = (top_frequency * 10000) / 625;
+	tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+	tuner->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
+	tuner->audmode = (stereo_mono_mode ?
+			  V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO);
+
+	/* Actual rssi value lies in between -128 to +127.
+	 * Convert this range from 0 to 255 by adding +128
+	 */
+	rssilvl += 128;
+
+	/* Return signal strength value should be within 0 to 65535.
+	 * Find out correct signal radio by multiplying (65535/255) = 257
+	 */
+	tuner->signal = rssilvl * 257;
+	tuner->afc = 0;
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set tuner attributes */
+static int fm_v4l2_vidioc_s_tuner(struct file *file, void *priv,
+				  struct v4l2_tuner *tuner)
+{
+	unsigned short mode;
+	int ret;
+
+	FMDRV_API_START();
+
+	if ((tuner->index != 0) ||
+	    (tuner->audmode != V4L2_TUNER_MODE_MONO &&
+	     tuner->audmode != V4L2_TUNER_MODE_STEREO)) {
+		FMDRV_API_EXIT(-EINVAL);
+		return -EINVAL;
+	}
+	/* Map V4L2 stereo/mono macro to our local stereo/mono macro */
+	mode = (tuner->audmode == V4L2_TUNER_MODE_STEREO) ?
+	    FM_STEREO_MODE : FM_MONO_MODE;
+	ret = fm_core_set_stereo_mono(mode);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Get tuner or modulator radio frequency */
+static int fm_v4l2_vidioc_g_frequency(struct file *file, void *priv,
+				      struct v4l2_frequency *freq)
+{
+	int ret;
+	FMDRV_API_START();
+
+	ret = fm_core_get_frequency(&freq->frequency);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set tuner or modulator radio frequency */
+static int fm_v4l2_vidioc_s_frequency(struct file *file, void *priv,
+				      struct v4l2_frequency *freq)
+{
+	int ret;
+	FMDRV_API_START();
+
+	ret = fm_core_set_frequency(freq->frequency);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+/* Set hardware frequency seek */
+static int fm_v4l2_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+					 struct v4l2_hw_freq_seek *seek)
+{
+	int ret;
+
+	FMDRV_API_START();
+
+	ret = fm_core_rx_seek(seek->seek_upward, seek->wrap_around);
+	if (ret) {
+		FMDRV_API_EXIT(ret);
+		return ret;
+	}
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+static const struct v4l2_file_operations fm_drv_fops = {
+	.owner = THIS_MODULE,
+	.read = fm_v4l2_fops_read,
+	.write = fm_v4l2_fops_write,
+	.poll = fm_v4l2_fops_poll,
+	.ioctl = video_ioctl2,
+	.open = fm_v4l2_fops_open,
+	.release = fm_v4l2_fops_release,
+};
+
+static const struct v4l2_ioctl_ops fm_drv_ioctl_ops = {
+	.vidioc_querycap = fm_v4l2_vidioc_querycap,
+	.vidioc_queryctrl = fm_v4l2_vidioc_queryctrl,
+	.vidioc_g_ctrl = fm_v4l2_vidioc_g_ctrl,
+	.vidioc_s_ctrl = fm_v4l2_vidioc_s_ctrl,
+	.vidioc_g_audio = fm_v4l2_vidioc_g_audio,
+	.vidioc_s_audio = fm_v4l2_vidioc_s_audio,
+	.vidioc_g_tuner = fm_v4l2_vidioc_g_tuner,
+	.vidioc_s_tuner = fm_v4l2_vidioc_s_tuner,
+	.vidioc_g_frequency = fm_v4l2_vidioc_g_frequency,
+	.vidioc_s_frequency = fm_v4l2_vidioc_s_frequency,
+	.vidioc_s_hw_freq_seek = fm_v4l2_vidioc_s_hw_freq_seek,
+};
+
+/*
+ * V4L2 RADIO device parent structure
+ */
+static struct video_device fm_viddev_template = {
+	.fops = &fm_drv_fops,
+	.ioctl_ops = &fm_drv_ioctl_ops,
+	.name = FM_DRV_NAME,
+	.release = video_device_release,
+};
+
+int fm_v4l2_init_video_device(struct fmdrv_ops *fmdev)
+{
+	FMDRV_API_START();
+
+	/* Allocate new video device */
+	fmdev->v4l2dev = video_device_alloc();
+	if (!fmdev->v4l2dev) {
+		FM_DRV_ERR("Can't allocate video device");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+
+	/* Setup FM driver's V4L2 properties */
+	memcpy(fmdev->v4l2dev, &fm_viddev_template, sizeof(fm_viddev_template));
+
+	video_set_drvdata(fmdev->v4l2dev, fmdev);
+
+	/* Register with V4L2 subsystem as RADIO device */
+	if (video_register_device(fmdev->v4l2dev, VFL_TYPE_RADIO, 0)) {
+		video_device_release(fmdev->v4l2dev);
+		fmdev->v4l2dev = NULL;
+
+		FM_DRV_ERR("Could not register video device");
+		FMDRV_API_EXIT(-ENOMEM);
+		return -ENOMEM;
+	}
+	FMDRV_API_EXIT(0);
+	return 0;
+}
+
+int fm_v4l2_deinit_video_device(struct fmdrv_ops *fmdev)
+{
+	FMDRV_API_START();
+
+	/* Unregister RADIO device from V4L2 subsystem */
+	video_unregister_device(fmdev->v4l2dev);
+
+	FMDRV_API_EXIT(0);
+	return 0;
+}
diff --git a/drivers/misc/ti-st/fmdrv_v4l2.h b/drivers/misc/ti-st/fmdrv_v4l2.h
new file mode 100644
index 0000000..1345a58
--- /dev/null
+++ b/drivers/misc/ti-st/fmdrv_v4l2.h
@@ -0,0 +1,32 @@
+/*
+ *  FM Driver for Connectivity chip of Texas Instruments.
+ *
+ *  FM V4L2 module header.
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef _FM_V4L2_DRV_H
+#define _FM_V4L2_DRV_H
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+
+int fm_v4l2_init_video_device(struct fmdrv_ops *fmdev);
+int fm_v4l2_deinit_video_device(struct fmdrv_ops *fmdev);
+
+#endif
diff --git a/drivers/misc/ti-st/gps_drv.c b/drivers/misc/ti-st/gps_drv.c
new file mode 100644
index 0000000..a5abe20
--- /dev/null
+++ b/drivers/misc/ti-st/gps_drv.c
@@ -0,0 +1,714 @@
+/*
+ *   GPS Char Driver for Texas Instrument's Connectivity Chip.
+ *   Copyright (C) 2009 Texas Instruments
+ *
+ *   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, write to the Free Software
+ *   Foundation, Inc.,59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/cdev.h>
+#include <linux/fs.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <linux/tty.h>
+#include <linux/sched.h>
+
+#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/platform_device.h>
+#include <linux/poll.h>
+#include <linux/skbuff.h>
+#include <linux/interrupt.h>
+
+#include "gps_drv.h"
+#include "st.h"
+
+#define DEVICE_NAME     "tigps"
+
+/* Initialization TaskLet for performing GPS Write */
+DECLARE_TASKLET_DISABLED(gpsdrv_tx_tsklet, gpsdrv_tsklet_write, 0);
+
+/* Structure declerations for GPS char Driver Data */
+static struct gpsdrv_data *hgps;
+
+/***********Functions called from ST driver**********************************/
+
+/*  gpsdrv_st_recv Function
+ *  This is Called in from -- ST Core when a data is received
+ *  This is a registered callback with ST core when the gps driver
+ *  registers with ST.
+ *  Parameters:
+ *  @skb    : SKB buffer pointer which contains the incoming Ch-9 GPS data.
+ *  Returns:
+ *          GPS_SUCCESS - On Success
+ *          else suitable error code
+ */
+long gpsdrv_st_recv(struct sk_buff *skb)
+{
+	struct gpsdrv_event_hdr gpsdrv_hdr = { 0x00, 0x0000 };
+	GPSDRV_DBG(" Inside %s", __func__);
+
+	/* SKB is NULL */
+	if (NULL == skb) {
+		GPSDRV_ERR("Input SKB is NULL");
+		return GPS_ERR_FAILURE;
+	}
+
+	/* Sanity Check - To Check if the Rx Pkt is Channel -9 or not */
+	if (GPS_CH9_PKT_NUMBER != skb->cb[0]) {
+		GPSDRV_ERR("Input SKB is not a Channel-9 packet");
+		return GPS_ERR_FAILURE;
+	}
+	/* Copy Ch-9 info to local structure */
+	memcpy(&gpsdrv_hdr, skb->data, GPS_CH9_PKT_HDR_SIZE - 1);
+	skb_pull(skb, GPS_CH9_PKT_HDR_SIZE - 1);
+
+	/* check if skb->len and gpsdrv_hdr.plen are equal */
+	if (skb->len != gpsdrv_hdr.plen) {
+		GPSDRV_ERR("Received corrupted packet - Length Mismatch");
+		return -EINVAL;
+	}
+	/* Check the Opcode */
+	if ((gpsdrv_hdr.opcode != GPS_CH9_OP_READ) &&
+	    (gpsdrv_hdr.opcode != GPS_CH9_OP_COMPLETED_EVT)) {
+		GPSDRV_ERR("Received corrupted packet - Wrong opcode %x ",
+			   gpsdrv_hdr.opcode);
+		return -EINVAL;
+	}
+	/* Strip Channel 9 packet information from SKB only
+	 * if the opcode is GPS_CH9_OP_READ and get AI2 packet
+	 */
+	if (GPS_CH9_OP_READ == gpsdrv_hdr.opcode) {
+		spin_lock(&hgps->lock);
+		skb_queue_tail(&hgps->rx_list, skb);
+		spin_unlock(&hgps->lock);
+		wake_up_interruptible(&hgps->gpsdrv_data_q);
+	} else {
+		/* Copy Ch-9 info to local structure */
+		memcpy(&hgps->tx_count, skb->data, 1);
+		GPSDRV_VER(" Tx count = %x", hgps->tx_count);
+		/* Check if Tx queue and Tx count not empty */
+		if ((0 != hgps->tx_count) &&
+				(!skb_queue_empty(&hgps->tx_list))) {
+			/* Schedule the Tx-task let */
+			GPSDRV_VER(" Scheduling tasklet to write");
+			tasklet_schedule(&gpsdrv_tx_tsklet);
+		}
+		/* Free the received command complete SKB */
+		kfree(skb);
+	}
+
+	return GPS_SUCCESS;
+
+}
+
+/*  gpsdrv_st_cb Function
+ *  This is Called in from -- ST Core when the state is pending
+ *  during st_register.
+ *  This is a registered callback with ST core when the gps driver
+ *  registers with ST.
+ *
+ *  Parameters:
+ *  @data   Status update of GPS registration
+ *  Returns: NULL
+ */
+void gpsdrv_st_cb(char data)
+{
+	GPSDRV_DBG(" Inside %s", __func__);
+	hgps->streg_cbdata = data;	/* ST registration callback  status */
+	complete_all(&hgps->gpsdrv_reg_completed);
+	return;
+}
+
+static struct st_proto_s gpsdrv_proto = {
+	.type = ST_GPS,
+	.recv = gpsdrv_st_recv,
+	.reg_complete_cb = gpsdrv_st_cb,
+};
+
+/** gpsdrv_tsklet_write Function
+ *  This tasklet function will be scheduled when there is a data in Tx queue
+ *  and GPS chip sent an command completion packet with non zero value.
+ *
+ *  Parameters:
+ *  @data  : data passed to tasklet function
+ *  Returns : NULL
+ */
+void gpsdrv_tsklet_write(unsigned long data)
+{
+	struct sk_buff *skb = NULL;
+
+	GPSDRV_DBG(" Inside %s", __func__);
+
+	/* Perform sanity check of verifying the status to perform
+	 * an st_write
+	 */
+	if (((!hgps->st_write) || (0 == hgps->tx_count))
+	    || ((skb_queue_empty(&hgps->tx_list)))) {
+		GPSDRV_ERR("Sanity check Failed exiting %s", __func__);
+		return;
+	}
+	/* hgps->tx_list not empty skb already present
+	 * dequeue the tx-data and perform a st_write
+	 */
+	spin_lock(&hgps->lock);
+	skb = skb_dequeue(&hgps->tx_list);
+	spin_unlock(&hgps->lock);
+	hgps->st_write(skb);
+	hgps->tx_count--;
+
+	/* Check if Tx queue and Tx count not empty */
+	if ((0 != hgps->tx_count) && (!skb_queue_empty(&hgps->tx_list))) {
+		/* Schedule the Tx-task let */
+		tasklet_schedule(&gpsdrv_tx_tsklet);
+	}
+
+	return;
+}
+
+/*********Functions Called from GPS host***************************************/
+
+/** gpsdrv_open Function
+ *  This function will perform an register on ST driver.
+ *  Parameters :
+ *  @file  : File pointer for GPS char driver
+ *  @inod  :
+ *  Returns  GPS_SUCCESS -  on success
+ *           else suitable error code
+ */
+int gpsdrv_open(struct inode *inod, struct file *file)
+{
+	int ret = 0;
+	unsigned long timeout = GPSDRV_REG_TIMEOUT;
+
+	GPSDRV_DBG(" Inside %s", __func__);
+
+	/* Check if GPS is already registered with ST */
+	if (test_and_set_bit(GPS_ST_REGISTERED, &hgps->state)) {
+		GPSDRV_ERR("GPS Registered/Registration in progress ,\
+				with ST open called again?");
+		return GPS_ERR_ALREADY;
+	}
+
+	/* Initialize  gpsdrv_reg_completed so as to wait for
+	 * completion on the same
+	 * if st_register returns with a PENDING status
+	 */
+	INIT_COMPLETION(hgps->gpsdrv_reg_completed);
+
+	/* Resgister GPS with ST */
+	ret = st_register(&gpsdrv_proto);
+
+	GPSDRV_VER(" st_register returned %d", ret);
+
+	/* If GPS Registration returned with error, then clear GPS_ST_REGISTERED
+	 * for future open calls and return the appropriate error code
+	 */
+	if (ret < 0 && ret != ST_ERR_PENDING) {
+		GPSDRV_ERR(" st_register failed");
+		clear_bit(GPS_ST_REGISTERED, &hgps->state);
+
+		if (ret == ST_ERR_ALREADY)
+			return GPS_ERR_ALREADY;
+
+		return GPS_ERR_FAILURE;
+	}
+
+	/* if returned status is pending, wait for the completion */
+	if (ret == ST_ERR_PENDING) {
+		GPSDRV_VER(" GPS Register waiting for completion ");
+		timeout =
+		    wait_for_completion_timeout(&hgps->gpsdrv_reg_completed,
+						msecs_to_jiffies(timeout));
+		/* Check for timed out condition */
+		if (0 == timeout) {
+			GPSDRV_ERR("st_register timed out");
+			clear_bit(GPS_ST_REGISTERED, &hgps->state);
+			return GPS_ERR_TIMEOUT;
+		}
+
+		if (0 > hgps->streg_cbdata) {
+			GPSDRV_ERR
+			    ("GPS Device Registration Failed-ST Reg CB called"
+			     "with invalid value %d", hgps->streg_cbdata);
+			clear_bit(GPS_ST_REGISTERED, &hgps->state);
+			return -EAGAIN;
+		}
+	}
+	GPSDRV_DBG(" gps registration complete ");
+
+	/* Assign the write callback pointer */
+	hgps->st_write = gpsdrv_proto.write;
+	hgps->tx_count = 1;
+	tasklet_enable(&gpsdrv_tx_tsklet);
+	set_bit(GPS_ST_RUNNING, &hgps->state);
+
+	return GPS_SUCCESS;
+}
+
+/** gpsdrv_release Function
+ *  This function will un-registers from the ST driver.
+ *
+ *  Parameters :
+ *  @file  : File pointer for GPS char driver
+ *  @inod  :
+ *  Returns  GPS_SUCCESS -  on success
+ *           else suitable error code
+ */
+int gpsdrv_release(struct inode *inod, struct file *file)
+{
+	GPSDRV_DBG(" Inside %s", __func__);
+	/* Disabling task-let 1st & then un-reg to avoid
+	 * tasklet getting scheduled
+	 */
+	tasklet_disable(&gpsdrv_tx_tsklet);
+	/* Cleat registered bit if already registered */
+	if (test_and_clear_bit(GPS_ST_REGISTERED, &hgps->state)) {
+		if (st_unregister(gpsdrv_proto.type) < 0) {
+			GPSDRV_ERR(" st_unregister failed");
+			/* Re-Enable the task-let if un-register fails */
+			tasklet_enable(&gpsdrv_tx_tsklet);
+			return GPS_ERR_FAILURE;
+		}
+	}
+
+	/* Reset Tx count value and st_write function pointer */
+	hgps->tx_count = 0;
+	hgps->st_write = NULL;
+	clear_bit(GPS_ST_RUNNING, &hgps->state);
+	GPSDRV_VER(" st_unregister success");
+
+	return GPS_SUCCESS;
+}
+
+/** gpsdrv_read Function
+ *  This function will wait till the data received from the ST driver
+ *  and then strips the GPS-Channel-9 header from the
+ *  incoming AI2 packet and then send it to GPS host application.
+ *
+ *  Parameters :
+ *  @file  : File pointer for GPS char driver
+ *  @data  : Data which needs to be passed to APP
+ *  @size  : Length of the data passesd
+ *  offset :
+ *  Returns  Size of AI2 packet received -  on success
+ *           else suitable error code
+ */
+ssize_t gpsdrv_read(struct file *file, char __user *data, size_t size,
+		    loff_t *offset)
+{
+	int len = 0;
+	struct sk_buff *skb = NULL;
+	unsigned long timeout = GPSDRV_READ_TIMEOUT;
+
+	GPSDRV_DBG(" Inside %s", __func__);
+
+	/* Validate input parameters */
+	if ((NULL == file) || (((NULL == data) || (0 == size)))) {
+		GPSDRV_ERR("Invalid input parameters passed to %s",
+			   __func__);
+		return -EINVAL;
+	}
+
+	/* Check if GPS is registered to perform read operation */
+	if (!test_bit(GPS_ST_RUNNING, &hgps->state)) {
+		GPSDRV_ERR("GPS Device is not running");
+		return -EINVAL;
+	}
+
+	/* cannot come here if poll-ed before reading
+	 * if not poll-ed wait on the same wait_q
+	 */
+	timeout = wait_event_interruptible_timeout(hgps->gpsdrv_data_q,
+						   !skb_queue_empty(&hgps->
+								    rx_list),
+						   msecs_to_jiffies(timeout));
+	/* Check for timed out condition */
+	if (0 == timeout) {
+		GPSDRV_ERR("GPS Device Read timed out");
+		return GPS_ERR_TIMEOUT;
+	}
+
+	GPSDRV_VER(" Read wait completed ");
+
+	/* hgps->rx_list not empty skb already present */
+	spin_lock(&hgps->lock);
+	skb = skb_dequeue(&hgps->rx_list);
+	spin_unlock(&hgps->lock);
+
+	if (!skb) {
+		GPSDRV_ERR("Dequed SKB is NULL?");
+		return GPS_ERR_UNKNOWN;
+	}
+
+	if (skb->len > size) {
+		GPSDRV_ERR("SKB length is Greater than requested size"
+			   "Returning the available length of SKB");
+		spin_lock(&hgps->lock);
+		skb_queue_head(&hgps->rx_list, skb);
+		spin_unlock(&hgps->lock);
+		return skb->len;
+	}
+#ifdef VERBOSE
+	for (len = 0; (skb) && (len < skb->len); len++)
+		GPSDRV_DBG(" %x ", skb->data[len]);
+#endif
+
+	/* Forward the data to the user */
+	if (skb->len <= size) {
+		if (copy_to_user(data, skb->data, skb->len)) {
+			GPSDRV_ERR(" Unable to copy to user space");
+			/* Queue the skb back to head */
+			spin_lock(&hgps->lock);
+			skb_queue_head(&hgps->rx_list, skb);
+			spin_unlock(&hgps->lock);
+			return GPS_ERR_CPY_TO_USR;
+		}
+	}
+
+	len = skb->len;
+	kfree(skb);
+	return len;
+}
+
+/** gpsdrv_write Function
+ *  This function will pre-pend the GPS-Channel-9 header to the
+ *  incoming AI2 packet sent from the GPS host application.
+ *
+ *  Parameters :
+ *  @file   : File pointer for GPS char driver
+ *  @data   : AI2 packet data from GPS application
+ *  @size   : Size of the AI2 packet data
+ *  @offset :
+ *  Returns  Size of AI2 packet on success
+ *           else suitable error code
+ */
+ssize_t gpsdrv_write(struct file *file, const char __user *data,
+		     size_t size, loff_t *offset)
+{
+#ifdef VERBOSE
+	long count = 0;
+#endif
+	unsigned char channel = GPS_CH9_PKT_NUMBER;	/* GPS Channel number */
+	/* Initialize gpsdrv_event_hdr with write opcode */
+	struct gpsdrv_event_hdr gpsdrv_hdr = { GPS_CH9_OP_WRITE, 0x0000 };
+	struct sk_buff *skb = NULL;
+
+	GPSDRV_DBG(" Inside %s", __func__);
+
+	/* Validate input parameters */
+	if ((NULL == file) || (((NULL == data) || (0 == size)))) {
+		GPSDRV_ERR("Invalid input parameters passed to %s",
+			   __func__);
+		return -EINVAL;
+	}
+
+	/* Check if GPS is registered to perform write operation */
+	if (!test_bit(GPS_ST_RUNNING, &hgps->state)) {
+		GPSDRV_ERR("GPS Device is not running");
+		return -EINVAL;
+	}
+
+	if (!hgps->st_write) {
+		GPSDRV_ERR(" Can't write to ST, hgps->st_write null ?");
+		return -EINVAL;
+	}
+
+	skb = alloc_skb(size + GPS_CH9_PKT_HDR_SIZE, GFP_ATOMIC);
+	/* Validate Created SKB */
+	if (NULL == skb) {
+		GPSDRV_ERR("Error aaloacting SKB");
+		return -ENOMEM;
+	}
+
+	/* Update chnl-9 information with plen=AI2 pckt size which is "size" */
+	gpsdrv_hdr.plen = size;
+
+	/* PrePend Channel-9 header to AI2 packet and write to SKB */
+	memcpy(skb_put(skb, 1), &channel, 1);
+	memcpy(skb_put(skb, GPS_CH9_PKT_HDR_SIZE - 1), &gpsdrv_hdr,
+	       GPS_CH9_PKT_HDR_SIZE - 1);
+
+	/* Forward the data from the user space to ST core */
+	if (copy_from_user(skb_put(skb, size), data, size)) {
+		GPSDRV_ERR(" Unable to copy from user space");
+		kfree_skb(skb);
+		return GPS_ERR_CPY_FRM_USR;
+	}
+#ifdef VERBOSE
+	GPSDRV_VER("start data..");
+	for (count = 0; count < size; count++)
+		GPSDRV_VER(" 0x%02x ", skb->data[count]);
+	GPSDRV_VER("\n..end data");
+#endif
+
+	/* Check if data can be sent to GPS chip
+	 * If not, add it to queue and that can be sent later
+	 */
+	if (0 != hgps->tx_count) {
+		/* If TX Q is empty send current SKB;
+		 *  else, queue current SKB at end of tx_list queue and
+		 *  send first SKB in tx_list queue.
+		 */
+		if (skb_queue_empty(&hgps->tx_list)) {
+			hgps->st_write(skb);
+		} else {
+			spin_lock(&hgps->lock);
+			skb_queue_tail(&hgps->tx_list, skb);
+			hgps->st_write(skb_dequeue(&hgps->tx_list));
+			spin_unlock(&hgps->lock);
+		}
+
+		hgps->tx_count--;
+		/* Check if Tx queue and Tx count not empty and
+		 * schedule wriet tsklet accordingly
+		 */
+		if ((0 != hgps->tx_count) &&
+				(!skb_queue_empty(&hgps->tx_list))) {
+			/* Schedule the Tx-task let */
+			tasklet_schedule(&gpsdrv_tx_tsklet);
+		}
+	} else {
+		/* Add it to TX queue */
+		GPSDRV_VER(" SKB added to Tx queue");
+		spin_lock(&hgps->lock);
+		skb_queue_tail(&hgps->tx_list, skb);
+		spin_unlock(&hgps->lock);
+	}
+
+	return size;
+}
+
+/** gpsdrv_ioctl Function
+ *  This will peform the functions as directed by the command and command
+ *  argument.
+ *
+ *  Parameters :
+ *  @file  : File pointer for GPS char driver
+ *  @cmd   : IOCTL Command
+ *  @arg   : Command argument for IOCTL command
+ *  Returns  GPS_SUCCESS on success
+ *           else suitable error code
+ */
+static int gpsdrv_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct sk_buff *skb = NULL;
+	int retCode = GPS_SUCCESS;
+	GPSDRV_DBG(" Inside %s", __func__);
+
+	/* Validate input parameters */
+	if ((NULL == file) || (0 == cmd)) {
+		GPSDRV_ERR("Invalid input parameters passed to %s",
+			   __func__);
+		return -EINVAL;
+	}
+	/* Check if GPS is registered to perform IOCTL operation */
+	if (!test_bit(GPS_ST_RUNNING, &hgps->state)) {
+		GPSDRV_ERR("GPS Device is not running");
+		return -EINVAL;
+	}
+
+	switch (cmd) {
+	case TCFLSH:
+		GPSDRV_VER(" IOCTL TCFLSH invoked with %ld argument", arg);
+		spin_lock(&hgps->lock);
+		switch (arg) {
+			/* purge Rx/Tx SKB list queues depending on arg value */
+		case TCIFLUSH:
+			skb_queue_purge(&hgps->rx_list);
+			break;
+		case TCOFLUSH:
+			skb_queue_purge(&hgps->tx_list);
+			break;
+		case TCIOFLUSH:
+			skb_queue_purge(&hgps->rx_list);
+			skb_queue_purge(&hgps->tx_list);
+			break;
+		default:
+			GPSDRV_ERR("Invalid Command passed for tcflush");
+			retCode = -EINVAL;
+			break;
+		}
+		spin_unlock(&hgps->lock);
+		break;
+	case FIONREAD:
+		/* Deque the SKB from the head if rx_list is not empty
+		 * And update the argument with skb->len to provide
+		 * amount of data
+		 * available in the available SKB
+		 */
+		spin_lock(&hgps->lock);
+		if (!skb_queue_empty(&hgps->tx_list)) {
+			skb = skb_dequeue(&hgps->rx_list);
+			*(unsigned int *)arg = skb->len;
+			/* Re-Store the SKB for furtur Read operations */
+			skb_queue_head(&hgps->rx_list, skb);
+		} else {
+			*(unsigned int *)arg = 0;
+		}
+		spin_unlock(&hgps->lock);
+		break;
+	default:
+		GPSDRV_DBG("Un-Identified command provided for IOCTL");
+		retCode = -EINVAL;
+		break;
+	}
+
+	return retCode;
+}
+
+/** gpsdrv_poll Function
+ *  This function will wait till some data is received to the gps driver from ST
+ *
+ *  Parameters :
+ *  @file  : File pointer for GPS char driver
+ *  @wait  : POLL wait information
+ *  Returns  status of POLL on success
+ *           else suitable error code
+ */
+static unsigned int gpsdrv_poll(struct file *file, poll_table * wait)
+{
+	unsigned long mask = 0;
+	GPSDRV_DBG(" inside %s", __func__);
+
+	/* Check if GPS is registered to perform read operation */
+	if (!test_bit(GPS_ST_RUNNING, &hgps->state)) {
+		GPSDRV_ERR("GPS Device is not running");
+		return -EINVAL;
+	}
+
+	/* Wait till data is signalled from gpsdrv_st_recv function
+	 * with AI2 packet */
+	poll_wait(file, &hgps->gpsdrv_data_q, wait);
+
+	GPSDRV_VER(" Poll wait completed");
+
+	if (!skb_queue_empty(&hgps->rx_list))
+		mask |= POLLIN;	/* TODO: check app for mask */
+
+	GPSDRV_DBG(" return 0x%02x \n", (unsigned int)mask);
+	return mask;
+}
+
+/* GPS Char driver function pointers
+ * These functions are called from USER space by pefroming File Operations
+ * on /dev/gps node exposed by this driver during init
+ */
+const struct file_operations gpsdrv_chrdev_ops = {
+	.owner = THIS_MODULE,
+	.open = gpsdrv_open,
+	.read = gpsdrv_read,
+	.write = gpsdrv_write,
+	.ioctl = gpsdrv_ioctl,
+	.poll = gpsdrv_poll,
+	.release = gpsdrv_release,
+};
+
+/*********Functions called during insmod and delmod****************************/
+
+/** gpsdrv_init Function
+ *  This function Initializes the gps driver parametes and exposes
+ *  /dev/gps node to user space
+ *
+ *  Parameters : NULL
+ *  Returns  GPS_SUCCESS on success
+ *           else suitable error code
+ */
+static int __init gpsdrv_init(void)
+{
+	long err = 0;
+
+	GPSDRV_DBG(" Inside %s", __func__);
+
+	/* Allocate local resource memory */
+	hgps = kzalloc(sizeof(struct gpsdrv_data), GFP_KERNEL);
+	if (!(hgps)) {
+		GPSDRV_ERR("Can't allocate GPS data structure");
+		return -ENOMEM;
+	}
+
+	/* Expose the device DEVICE_NAME to user space
+	 * And obtain the major number for the device
+	 */
+	hgps->gpsdrv_major =
+	    register_chrdev(0, DEVICE_NAME, &gpsdrv_chrdev_ops);
+	if (0 > hgps->gpsdrv_major) {
+		err = hgps->gpsdrv_major;
+		GPSDRV_ERR("Error when registering to char dev. Error = %ld.",
+			   err);
+		kfree(hgps);
+		return err;
+	}
+	GPSDRV_VER(" %ld: allocated %d, %d", err, hgps->gpsdrv_major, 0);
+
+	/*  udev */
+	hgps->gpsdrv_class = class_create(THIS_MODULE, DEVICE_NAME);
+	if (IS_ERR(hgps->gpsdrv_class)) {
+		GPSDRV_ERR(" Something went wrong in class_create");
+		unregister_chrdev(hgps->gpsdrv_major, DEVICE_NAME);
+		kfree(hgps);
+		return GPS_ERR_CLASS;
+	}
+
+	hgps->gpsdrv_dev =
+	    device_create(hgps->gpsdrv_class, NULL,
+			  MKDEV(hgps->gpsdrv_major, 0), NULL, DEVICE_NAME);
+	if (IS_ERR(hgps->gpsdrv_dev)) {
+		err = PTR_ERR(hgps->gpsdrv_dev);
+		GPSDRV_ERR(" Error in class_create. Error = %ld", err);
+		class_unregister(hgps->gpsdrv_class);
+		class_destroy(hgps->gpsdrv_class);
+		unregister_chrdev(hgps->gpsdrv_major, DEVICE_NAME);
+		kfree(hgps);
+		return err;
+	}
+
+	/* Initialize wait queue, skb queue head and
+	 * registration complete strucuture
+	 */
+	skb_queue_head_init(&hgps->rx_list);
+	skb_queue_head_init(&hgps->tx_list);
+	init_completion(&hgps->gpsdrv_reg_completed);
+	init_waitqueue_head(&hgps->gpsdrv_data_q);
+	spin_lock_init(&hgps->lock);
+
+	return GPS_SUCCESS;
+}
+
+/** gpsdrv_exit Function
+ *  This function Destroys the gps driver parametes and /dev/gps node
+ *
+ *  Parameters : NULL
+ *  Returns   NULL
+ */
+static void __exit gpsdrv_exit(void)
+{
+	GPSDRV_DBG(" Inside %s", __func__);
+	GPSDRV_VER(" Bye.. freeing up %d", hgps->gpsdrv_major);
+
+	skb_queue_purge(&hgps->rx_list);
+	skb_queue_purge(&hgps->tx_list);
+	device_destroy(hgps->gpsdrv_class, MKDEV(hgps->gpsdrv_major, 0));
+
+	class_unregister(hgps->gpsdrv_class);
+	class_destroy(hgps->gpsdrv_class);
+
+	unregister_chrdev(hgps->gpsdrv_major, DEVICE_NAME);
+	tasklet_kill(&gpsdrv_tx_tsklet);
+	kfree(hgps);
+}
+
+module_init(gpsdrv_init);
+module_exit(gpsdrv_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/gps_drv.h b/drivers/misc/ti-st/gps_drv.h
new file mode 100644
index 0000000..c227163
--- /dev/null
+++ b/drivers/misc/ti-st/gps_drv.h
@@ -0,0 +1,105 @@
+/*
+ *   GPS Char Driver for Texas Instrument's Connectivity Chip.
+ *   Copyright (C) 2009 Texas Instruments
+ *
+ *   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, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+*/
+
+#ifndef GPSDRV_H
+#define GPSDRV_H
+
+#define VERBOSE
+
+/* Debug macros*/
+#define GPSDRV_ERR(fmt, arg...)  printk(KERN_ERR "(gpsdrv):"fmt"\n" , ## arg)
+#if defined(DEBUG)		/* limited debug messages */
+#define GPSDRV_DBG(fmt, arg...)  printk(KERN_INFO "(gpsdrv):"fmt"\n" , ## arg)
+#define GPSDRV_VER(fmt, arg...)
+#elif defined(VERBOSE)		/* very verbose */
+#define GPSDRV_DBG(fmt, arg...)  printk(KERN_INFO "(gpsdrv):"fmt"\n" , ## arg)
+#define GPSDRV_VER(fmt, arg...)  printk(KERN_INFO "(gpsdrv):"fmt"\n" , ## arg)
+#else /* Error msgs only */
+#define GPSDRV_DBG(fmt, arg...)
+#define GPSDRV_VER(fmt, arg...)
+#endif
+
+/* List of error codes returned by the gps driver*/
+enum {
+	GPS_ERR_FAILURE = -1,	/* check struct */
+	GPS_SUCCESS,
+	GPS_ERR_PENDING = -5,	/* to call reg_complete_cb */
+	GPS_ERR_ALREADY,	/* already registered */
+	GPS_ERR_INPROGRESS,
+	GPS_ERR_NOPROTO,	/* protocol not supported */
+	GPS_ERR_CLASS = -15,
+	GPS_ERR_CPY_TO_USR,
+	GPS_ERR_CPY_FRM_USR,
+	GPS_ERR_TIMEOUT,
+	GPS_ERR_UNKNOWN,
+};
+
+/* Channel-9 details for GPS */
+#define GPS_CH9_PKT_HDR_SIZE		4
+#define GPS_CH9_PKT_NUMBER		0x9
+#define GPS_CH9_OP_WRITE		0x1
+#define GPS_CH9_OP_READ			0x2
+#define GPS_CH9_OP_COMPLETED_EVT      	0x3
+
+/* Macros for Syncronising GPS registration and other R/W/ICTL operations */
+#define GPS_ST_REGISTERED		0
+#define GPS_ST_RUNNING  		1
+
+/* Read time out defined to 10 seconds */
+#define GPSDRV_READ_TIMEOUT 		10000
+/* Reg time out defined to 6 seconds */
+#define GPSDRV_REG_TIMEOUT 		6000
+
+struct gpsdrv_event_hdr {
+	uint8_t opcode;
+	uint16_t plen;
+} __attribute__ ((packed));
+
+/* BT driver operation structure */
+struct gpsdrv_data {
+
+	int gpsdrv_major;	/* GPS major number */
+	struct class *gpsdrv_class;	/* GPS class during class_create */
+	struct device *gpsdrv_dev;	/* GPS dev during device_create */
+	struct completion gpsdrv_reg_completed;	/* comepletion handler
+						   to synchronize
+						   gpsdrv_chrdev_open */
+	unsigned char streg_cbdata;	/* ST registration callback  status */
+
+	unsigned long state;	/* used locally,to maintain various
+				   GPS driver status */
+
+	unsigned char tx_count;	/* Count value which gives number
+				   of Tx GPS commands that can be sent
+				   to GPS chip
+				 */
+	long (*st_write) (struct sk_buff *skb);	/* write function pointer
+							   of ST driver */
+	struct sk_buff_head rx_list;	/* Rx data SKB queue */
+	struct sk_buff_head tx_list;	/* Tx data SKB queue */
+
+	wait_queue_head_t gpsdrv_data_q;	/* Used to syncronize read
+						   call and poll */
+
+	spinlock_t lock;	/* spin lock data for safe-gaurding
+				   operations on SKB */
+
+};
+/* Function prototype for TaskLet-Write function */
+void gpsdrv_tsklet_write(unsigned long);
+#endif /*GPS_H */
diff --git a/drivers/misc/ti-st/st.h b/drivers/misc/ti-st/st.h
new file mode 100644
index 0000000..7661e0d
--- /dev/null
+++ b/drivers/misc/ti-st/st.h
@@ -0,0 +1,85 @@
+/*
+ *  Shared Transport Header file
+ *  	To be included by the protocol stack drivers for
+ *  	Texas Instruments BT,FM and GPS combo chip drivers
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ST_H
+#define ST_H
+
+#include <linux/skbuff.h>
+/*
+ * st.h
+ */
+
+/* some gpios have active high, others like fm have
+ * active low
+ */
+enum kim_gpio_state {
+	KIM_GPIO_INACTIVE,
+	KIM_GPIO_ACTIVE,
+};
+/*
+ * the list of protocols on chip
+ */
+enum proto_type {
+	ST_BT,
+	ST_FM,
+	ST_GPS,
+	ST_MAX,
+};
+
+enum {
+	ST_ERR_FAILURE = -1,	/* check struct */
+	ST_SUCCESS,
+	ST_ERR_PENDING = -5,	/* to call reg_complete_cb */
+	ST_ERR_ALREADY,		/* already registered */
+	ST_ERR_INPROGRESS,
+	ST_ERR_NOPROTO,		/* protocol not supported */
+};
+
+/* per protocol structure
+ * for BT/FM and GPS
+ */
+struct st_proto_s {
+	enum proto_type type;
+/*
+ * to be called by ST when data arrives
+ */
+	long (*recv) (struct sk_buff *);
+/*
+ * for future use, logic now to be in ST
+ */
+	unsigned char (*match_packet) (const unsigned char *data);
+/*
+ * subsequent registration return PENDING,
+ * signalled complete by this callback function
+ */
+	void (*reg_complete_cb) (char data);
+/*
+ * write function, sent in as NULL and to be returned to
+ * protocol drivers
+ */
+	long (*write) (struct sk_buff *skb);
+};
+
+extern long st_register(struct st_proto_s *new_proto);
+extern long st_unregister(enum proto_type type);
+
+#endif /* ST_H */
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
new file mode 100644
index 0000000..b4c7b96
--- /dev/null
+++ b/drivers/misc/ti-st/st_core.c
@@ -0,0 +1,1055 @@
+/*
+ *  Shared Transport Line discipline driver Core
+ *	This hooks up ST KIM driver and ST LL driver
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/tty.h>
+
+/* understand BT, FM and GPS for now */
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+#include "fm.h"
+/*
+ * packet formats for fm and gps
+ * #include "gps.h"
+ */
+#include "st_core.h"
+#include "st_kim.h"
+#include "st_ll.h"
+#include "st.h"
+
+/* all debug macros go in here */
+#define ST_DRV_ERR(fmt, arg...)  printk(KERN_ERR "(stc):"fmt"\n" , ## arg)
+#if defined(DEBUG)		/* limited debug messages */
+#define ST_DRV_DBG(fmt, arg...)  printk(KERN_INFO "(stc):"fmt"\n" , ## arg)
+#define ST_DRV_VER(fmt, arg...)
+#elif defined(VERBOSE)		/* very verbose */
+#define ST_DRV_DBG(fmt, arg...)  printk(KERN_INFO "(stc):"fmt"\n" , ## arg)
+#define ST_DRV_VER(fmt, arg...)  printk(KERN_INFO "(stc):"fmt"\n" , ## arg)
+#else /* error msgs only */
+#define ST_DRV_DBG(fmt, arg...)
+#define ST_DRV_VER(fmt, arg...)
+#endif
+
+#ifdef DEBUG
+/* strings to be used for rfkill entries and by
+ * ST Core to be used for sysfs debug entry
+ */
+#define PROTO_ENTRY(type, name)	name
+const unsigned char *protocol_strngs[] = {
+	PROTO_ENTRY(ST_BT, "Bluetooth"),
+	PROTO_ENTRY(ST_FM, "FM"),
+	PROTO_ENTRY(ST_GPS, "GPS"),
+};
+#endif
+/*
+ * local data instances
+ */
+static struct st_data_s *st_gdata;
+/* function pointer pointing to either,
+ * st_kim_recv during registration to receive fw download responses
+ * st_int_recv after registration to receive proto stack responses
+ */
+void (*st_recv) (const unsigned char *data, long count);
+
+/********************************************************************/
+/* internal misc functions */
+bool is_protocol_list_empty(void)
+{
+	unsigned char i = 0;
+	ST_DRV_DBG(" %s ", __func__);
+	spin_lock(&st_gdata->lock);
+	for (i = 0; i < ST_MAX; i++) {
+		if (st_gdata->list[i] != NULL) {
+			spin_unlock(&st_gdata->lock);
+			return ST_NOTEMPTY;
+		}
+		/* not empty */
+	}
+	spin_unlock(&st_gdata->lock);
+	/* list empty */
+	return ST_EMPTY;
+}
+
+/* can be called in from
+ * -- KIM (during fw download)
+ * -- ST Core (during st_write)
+ *
+ *  This is the internal write function - a wrapper
+ *  to tty->ops->write
+ */
+int st_int_write(const unsigned char *data, int count)
+{
+#ifdef VERBOSE			/* for debug */
+	int i;
+#endif
+	struct tty_struct *tty;
+	if (unlikely(st_gdata == NULL || st_gdata->tty == NULL)) {
+		ST_DRV_ERR("tty unavailable to perform write");
+		return ST_ERR_FAILURE;
+	}
+	tty = st_gdata->tty;
+#ifdef VERBOSE
+	printk(KERN_ERR "start data.. \n");
+	for (i = 0; i < count; i++)	/* no newlines for each datum */
+		printk(" %x", data[i]);
+	printk(KERN_ERR "\n ..end data\n");
+#endif
+
+	return tty->ops->write(tty, data, count);
+
+}
+
+/*
+ * push the skb received to relevant
+ * protocol stacks
+ */
+void st_send_frame(enum proto_type protoid, struct sk_buff *skb)
+{
+	ST_DRV_DBG(" %s(prot:%d) ", __func__, protoid);
+
+	if (unlikely
+	    (st_gdata == NULL || skb == NULL
+	     || st_gdata->list[protoid] == NULL)) {
+		ST_DRV_ERR("protocol %d not registered, no data to send?",
+			   protoid);
+		kfree_skb(skb);
+		return;
+	}
+	/* this cannot fail
+	 * this shouldn't take long
+	 * - should be just skb_queue_tail for the
+	 *   protocol stack driver
+	 */
+	if (likely(st_gdata->list[protoid]->recv != NULL)) {
+		if (unlikely(st_gdata->list[protoid]->recv(skb)
+			     != ST_SUCCESS)) {
+			ST_DRV_ERR(" proto stack %d's ->recv failed", protoid);
+			kfree_skb(skb);
+			return;
+		}
+	} else {
+		ST_DRV_ERR(" proto stack %d's ->recv null", protoid);
+		kfree_skb(skb);
+	}
+	ST_DRV_DBG(" done %s", __func__);
+	return;
+}
+
+/*
+ * to call registration complete callbacks
+ * of all protocol stack drivers
+ */
+void st_reg_complete(char err)
+{
+	unsigned char i = 0;
+	ST_DRV_DBG(" %s ", __func__);
+	for (i = 0; i < ST_MAX; i++) {
+		if (likely(st_gdata != NULL && st_gdata->list[i] != NULL &&
+			   st_gdata->list[i]->reg_complete_cb != NULL))
+			st_gdata->list[i]->reg_complete_cb(err);
+	}
+}
+
+static inline int st_check_data_len(int protoid, int len)
+{
+	register int room = skb_tailroom(st_gdata->rx_skb);
+
+	ST_DRV_DBG("len %d room %d", len, room);
+
+	if (!len) {
+		/* Received packet has only packet header and
+		 * has zero length payload. So, ask ST CORE to
+		 * forward the packet to protocol driver (BT/FM/GPS)
+		 */
+		st_send_frame(protoid, st_gdata->rx_skb);
+
+	} else if (len > room) {
+		/* Received packet's payload length is larger.
+		 * We can't accommodate it in created skb.
+		 */
+		ST_DRV_ERR("Data length is too large len %d room %d", len,
+			   room);
+		kfree_skb(st_gdata->rx_skb);
+	} else {
+		/* Packet header has non-zero payload length and
+		 * we have enough space in created skb. Lets read
+		 * payload data */
+		st_gdata->rx_state = ST_BT_W4_DATA;
+		st_gdata->rx_count = len;
+		return len;
+	}
+
+	/* Change ST state to continue to process next
+	 * packet */
+	st_gdata->rx_state = ST_W4_PACKET_TYPE;
+	st_gdata->rx_skb = NULL;
+	st_gdata->rx_count = 0;
+
+	return 0;
+}
+
+/* internal function for action when wake-up ack
+ * received
+ */
+static inline void st_wakeup_ack(unsigned char cmd)
+{
+	register struct sk_buff *waiting_skb;
+	spin_lock(&st_gdata->lock);
+	/* de-Q from waitQ and Q in txQ now that the
+	 * chip is awake
+	 */
+	while ((waiting_skb = skb_dequeue(&st_gdata->tx_waitq)))
+		skb_queue_tail(&st_gdata->txq, waiting_skb);
+
+	/* state forwarded to ST LL */
+	st_ll_sleep_state((unsigned long)cmd);
+	spin_unlock(&st_gdata->lock);
+
+	/* wake up to send the recently copied skbs from waitQ */
+	st_tx_wakeup(st_gdata);
+}
+
+/* Decodes received RAW data and forwards to corresponding
+ * client drivers (Bluetooth,FM,GPS..etc).
+ *
+ */
+void st_int_recv(const unsigned char *data, long count)
+{
+	register char *ptr;
+	struct hci_event_hdr *eh;
+	struct hci_acl_hdr *ah;
+	struct hci_sco_hdr *sh;
+	struct fm_event_hdr *fm;
+	struct gps_event_hdr *gps;
+	register int len = 0, type = 0, dlen = 0;
+	static enum proto_type protoid = ST_MAX;
+
+	ST_DRV_DBG("count %ld rx_state %ld"
+		   "rx_count %ld", count, st_gdata->rx_state,
+		   st_gdata->rx_count);
+
+	ptr = (char *)data;
+	/* tty_receive sent null ? */
+	if (unlikely(ptr == NULL)) {
+		ST_DRV_ERR(" received null from TTY ");
+		return;
+	}
+
+	/* Decode received bytes here */
+	while (count) {
+		if (st_gdata->rx_count) {
+			len = min_t(unsigned int, st_gdata->rx_count, count);
+			memcpy(skb_put(st_gdata->rx_skb, len), ptr, len);
+			st_gdata->rx_count -= len;
+			count -= len;
+			ptr += len;
+
+			if (st_gdata->rx_count)
+				continue;
+
+			/* Check ST RX state machine , where are we? */
+			switch (st_gdata->rx_state) {
+
+				/* Waiting for complete packet ? */
+			case ST_BT_W4_DATA:
+				ST_DRV_DBG("Complete pkt received");
+
+				/* Ask ST CORE to forward
+				 * the packet to protocol driver */
+				st_send_frame(protoid, st_gdata->rx_skb);
+
+				st_gdata->rx_state = ST_W4_PACKET_TYPE;
+				st_gdata->rx_skb = NULL;
+				protoid = ST_MAX;	/* is this required ? */
+				continue;
+
+				/* Waiting for Bluetooth event header ? */
+			case ST_BT_W4_EVENT_HDR:
+				eh = (struct hci_event_hdr *)st_gdata->rx_skb->
+				    data;
+
+				ST_DRV_DBG("Event header: evt 0x%2.2x"
+					   "plen %d", eh->evt, eh->plen);
+
+				st_check_data_len(protoid, eh->plen);
+				continue;
+
+				/* Waiting for Bluetooth acl header ? */
+			case ST_BT_W4_ACL_HDR:
+				ah = (struct hci_acl_hdr *)st_gdata->rx_skb->
+				    data;
+				dlen = __le16_to_cpu(ah->dlen);
+
+				ST_DRV_DBG("ACL header: dlen %d", dlen);
+
+				st_check_data_len(protoid, dlen);
+				continue;
+
+				/* Waiting for Bluetooth sco header ? */
+			case ST_BT_W4_SCO_HDR:
+				sh = (struct hci_sco_hdr *)st_gdata->rx_skb->
+				    data;
+
+				ST_DRV_DBG("SCO header: dlen %d", sh->dlen);
+
+				st_check_data_len(protoid, sh->dlen);
+				continue;
+			case ST_FM_W4_EVENT_HDR:
+				fm = (struct fm_event_hdr *)st_gdata->rx_skb->
+				    data;
+				ST_DRV_DBG("FM Header: ");
+				st_check_data_len(ST_FM, fm->plen);
+				continue;
+				/* TODO : Add GPS packet machine logic here */
+			case ST_GPS_W4_EVENT_HDR:
+				/* [0x09 pkt hdr][R/W byte][2 byte len] */
+				gps = (struct gps_event_hdr *)st_gdata->rx_skb->
+				     data;
+				ST_DRV_DBG("GPS Header: ");
+				st_check_data_len(ST_GPS, gps->plen);
+				continue;
+			}	/* end of switch rx_state */
+		}
+
+		/* end of if rx_count */
+		/* Check first byte of packet and identify module
+		 * owner (BT/FM/GPS) */
+		switch (*ptr) {
+
+			/* Bluetooth event packet? */
+		case HCI_EVENT_PKT:
+			ST_DRV_DBG("Event packet");
+			st_gdata->rx_state = ST_BT_W4_EVENT_HDR;
+			st_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+			type = HCI_EVENT_PKT;
+			protoid = ST_BT;
+			break;
+
+			/* Bluetooth acl packet? */
+		case HCI_ACLDATA_PKT:
+			ST_DRV_DBG("ACL packet");
+			st_gdata->rx_state = ST_BT_W4_ACL_HDR;
+			st_gdata->rx_count = HCI_ACL_HDR_SIZE;
+			type = HCI_ACLDATA_PKT;
+			protoid = ST_BT;
+			break;
+
+			/* Bluetooth sco packet? */
+		case HCI_SCODATA_PKT:
+			ST_DRV_DBG("SCO packet");
+			st_gdata->rx_state = ST_BT_W4_SCO_HDR;
+			st_gdata->rx_count = HCI_SCO_HDR_SIZE;
+			type = HCI_SCODATA_PKT;
+			protoid = ST_BT;
+			break;
+
+			/* Channel 8(FM) packet? */
+		case ST_FM_CH8_PKT:
+			ST_DRV_DBG("FM CH8 packet");
+			type = ST_FM_CH8_PKT;
+			st_gdata->rx_state = ST_FM_W4_EVENT_HDR;
+			st_gdata->rx_count = FM_EVENT_HDR_SIZE;
+			protoid = ST_FM;
+			break;
+
+			/* Channel 9(GPS) packet? */
+		case 0x9:	/*ST_LL_GPS_CH9_PKT */
+			ST_DRV_DBG("GPS CH9 packet");
+			type = 0x9;	/* ST_LL_GPS_CH9_PKT; */
+			protoid = ST_GPS;
+			st_gdata->rx_state = ST_GPS_W4_EVENT_HDR;
+			st_gdata->rx_count = 3;	/* GPS_EVENT_HDR_SIZE -1*/
+			break;
+		case LL_SLEEP_IND:
+		case LL_SLEEP_ACK:
+		case LL_WAKE_UP_IND:
+			/* this takes appropriate action based on
+			 * sleep state received --
+			 */
+			st_ll_sleep_state(*ptr);
+			ptr++;
+			count--;
+			continue;
+		case LL_WAKE_UP_ACK:
+			/* wake up ack received */
+			st_wakeup_ack(*ptr);
+			ptr++;
+			count--;
+			continue;
+			/* Unknow packet? */
+		default:
+			ST_DRV_ERR("Unknown packet type %2.2x", (__u8) *ptr);
+			ptr++;
+			count--;
+			continue;
+		};
+		ptr++;
+		count--;
+
+		switch (protoid) {
+		case ST_BT:
+			/* Allocate new packet to hold received data */
+			st_gdata->rx_skb =
+			    bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+			if (!st_gdata->rx_skb) {
+				ST_DRV_ERR("Can't allocate mem for new packet");
+				st_gdata->rx_state = ST_W4_PACKET_TYPE;
+				st_gdata->rx_count = 0;
+				return;
+			}
+			bt_cb(st_gdata->rx_skb)->pkt_type = type;
+			break;
+		case ST_FM:	/* for FM */
+			st_gdata->rx_skb =
+			    alloc_skb(FM_MAX_FRAME_SIZE, GFP_ATOMIC);
+			if (!st_gdata->rx_skb) {
+				ST_DRV_ERR("Can't allocate mem for new packet");
+				st_gdata->rx_state = ST_W4_PACKET_TYPE;
+				st_gdata->rx_count = 0;
+				return;
+			}
+			/* place holder 0x08 */
+			skb_reserve(st_gdata->rx_skb, 1);
+			st_gdata->rx_skb->cb[0] = ST_FM_CH8_PKT;
+			break;
+		case ST_GPS:
+			/* for GPS */
+			st_gdata->rx_skb =
+			    alloc_skb(100 /*GPS_MAX_FRAME_SIZE */ , GFP_ATOMIC);
+			if (!st_gdata->rx_skb) {
+				ST_DRV_ERR("Can't allocate mem for new packet");
+				st_gdata->rx_state = ST_W4_PACKET_TYPE;
+				st_gdata->rx_count = 0;
+				return;
+			}
+			/* place holder 0x09 */
+			skb_reserve(st_gdata->rx_skb, 1);
+			st_gdata->rx_skb->cb[0] = 0x09;	/*ST_GPS_CH9_PKT; */
+			break;
+		case ST_MAX:
+			break;
+		}
+	}
+	ST_DRV_DBG("done %s", __func__);
+	return;
+}
+
+/* internal de-Q function
+ * -- return previous in-completely written skb
+ *  or return the skb in the txQ
+ */
+struct sk_buff *st_int_dequeue(struct st_data_s *st_data)
+{
+	struct sk_buff *returning_skb;
+
+	ST_DRV_VER("%s", __func__);
+	/* if the previous skb wasn't written completely
+	 */
+	if (st_gdata->tx_skb != NULL) {
+		returning_skb = st_gdata->tx_skb;
+		st_gdata->tx_skb = NULL;
+		return returning_skb;
+	}
+
+	/* de-Q from the txQ always if previous write is complete */
+	return skb_dequeue(&st_gdata->txq);
+}
+
+/* internal Q-ing function
+ * will either Q the skb to txq or the tx_waitq
+ * depending on the ST LL state
+ *
+ * lock the whole func - since ll_getstate and Q-ing should happen
+ * in one-shot
+ */
+void st_int_enqueue(struct sk_buff *skb)
+{
+	unsigned long flags = 0;
+
+	ST_DRV_VER("%s", __func__);
+	/* this function can be invoked in more then one context.
+	 * so have a lock */
+	spin_lock_irqsave(&st_gdata->lock, flags);
+
+	switch (st_ll_getstate()) {
+	case ST_LL_AWAKE:
+		ST_DRV_DBG("ST LL is AWAKE, sending normally");
+		skb_queue_tail(&st_gdata->txq, skb);
+		break;
+	case ST_LL_ASLEEP_TO_AWAKE:
+		skb_queue_tail(&st_gdata->tx_waitq, skb);
+		break;
+	case ST_LL_AWAKE_TO_ASLEEP:	/* host cannot be in this state */
+		ST_DRV_ERR("ST LL is illegal state(%ld),"
+			   "purging received skb.", st_ll_getstate());
+		kfree_skb(skb);
+		break;
+
+	case ST_LL_ASLEEP:
+		/* call a function of ST LL to put data
+		 * in tx_waitQ and wake_ind in txQ
+		 */
+		skb_queue_tail(&st_gdata->tx_waitq, skb);
+		st_ll_wakeup();
+		break;
+	default:
+		ST_DRV_ERR("ST LL is illegal state(%ld),"
+			   "purging received skb.", st_ll_getstate());
+		kfree_skb(skb);
+		break;
+	}
+	spin_unlock_irqrestore(&st_gdata->lock, flags);
+	ST_DRV_VER("done %s", __func__);
+	return;
+}
+
+/*
+ * internal wakeup function
+ * called from either
+ * - TTY layer when write's finished
+ * - st_write (in context of the protocol stack)
+ */
+void st_tx_wakeup(struct st_data_s *st_data)
+{
+	struct sk_buff *skb;
+	unsigned long flags;	/* for irq save flags */
+	ST_DRV_VER("%s", __func__);
+	/* check for sending & set flag sending here */
+	if (test_and_set_bit(ST_TX_SENDING, &st_data->tx_state)) {
+		ST_DRV_DBG("ST already sending");
+		/* keep sending */
+		set_bit(ST_TX_WAKEUP, &st_data->tx_state);
+		return;
+		/* TX_WAKEUP will be checked in another
+		 * context
+		 */
+	}
+	do {			/* come back if st_tx_wakeup is set */
+		/* woke-up to write */
+		clear_bit(ST_TX_WAKEUP, &st_data->tx_state);
+		while ((skb = st_int_dequeue(st_data))) {
+			int len;
+			spin_lock_irqsave(&st_data->lock, flags);
+			/* enable wake-up from TTY */
+			set_bit(TTY_DO_WRITE_WAKEUP, &st_data->tty->flags);
+			len = st_int_write(skb->data, skb->len);
+			skb_pull(skb, len);
+			/* if skb->len = len as expected, skb->len=0 */
+			if (skb->len) {
+				/* would be the next skb to be sent */
+				st_data->tx_skb = skb;
+				spin_unlock_irqrestore(&st_gdata->lock, flags);
+				break;
+			}
+			kfree_skb(skb);
+			spin_unlock_irqrestore(&st_gdata->lock, flags);
+		}
+		/* if wake-up is set in another context- restart sending */
+	} while (test_bit(ST_TX_WAKEUP, &st_data->tx_state));
+
+	/* clear flag sending */
+	clear_bit(ST_TX_SENDING, &st_data->tx_state);
+}
+
+/********************************************************************/
+/* functions called from ST KIM
+*/
+void kim_st_list_protocols(char *buf)
+{
+#ifdef DEBUG
+	unsigned char i = ST_MAX;
+#endif
+	spin_lock(&st_gdata->lock);
+#ifdef DEBUG			/* more detailed log */
+	for (i = 0; i < ST_MAX; i++) {
+		if (i == 0) {
+			sprintf(buf, "%s is %s", protocol_strngs[i],
+				st_gdata->list[i] !=
+				NULL ? "Registered" : "Unregistered");
+		} else {
+			sprintf(buf, "%s\n%s is %s", buf, protocol_strngs[i],
+				st_gdata->list[i] !=
+				NULL ? "Registered" : "Unregistered");
+		}
+	}
+	sprintf(buf, "%s\n", buf);
+#else /* limited info */
+	sprintf(buf, "BT=%c\nFM=%c\nGPS=%c\n",
+		st_gdata->list[ST_BT] != NULL ? 'R' : 'U',
+		st_gdata->list[ST_FM] != NULL ? 'R' : 'U',
+		st_gdata->list[ST_GPS] != NULL ? 'R' : 'U');
+#endif
+	spin_unlock(&st_gdata->lock);
+}
+
+/********************************************************************/
+/*
+ * functions called from protocol stack drivers
+ * to be EXPORT-ed
+ */
+long st_register(struct st_proto_s *new_proto)
+{
+	long err = ST_SUCCESS;
+	ST_DRV_DBG("%s(%d) ", __func__, new_proto->type);
+	if (st_gdata == NULL || new_proto == NULL || new_proto->recv == NULL
+	    || new_proto->reg_complete_cb == NULL) {
+		ST_DRV_ERR("gdata/new_proto/recv or reg_complete_cb not ready");
+		return ST_ERR_FAILURE;
+	}
+
+	if (new_proto->type < ST_BT || new_proto->type >= ST_MAX) {
+		ST_DRV_ERR("protocol %d not supported", new_proto->type);
+		return ST_ERR_NOPROTO;
+	}
+
+	if (st_gdata->list[new_proto->type] != NULL) {
+		ST_DRV_ERR("protocol %d already registered", new_proto->type);
+		return ST_ERR_ALREADY;
+	}
+
+	/* can be from process context only */
+	spin_lock(&st_gdata->lock);
+
+	if (test_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state)) {
+		ST_DRV_DBG(" ST_REG_IN_PROGRESS:%d ", new_proto->type);
+		/* fw download in progress */
+		st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
+
+		st_gdata->list[new_proto->type] = new_proto;
+		new_proto->write = st_write;
+
+		set_bit(ST_REG_PENDING, &st_gdata->st_state);
+		spin_unlock(&st_gdata->lock);
+		return ST_ERR_PENDING;
+	} else if (is_protocol_list_empty() == ST_EMPTY) {
+		ST_DRV_DBG(" protocol list empty :%d ", new_proto->type);
+		set_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+		st_recv = st_kim_recv;
+
+		/* release lock previously held - re-locked below */
+		spin_unlock(&st_gdata->lock);
+
+		/* enable the ST LL - to set default chip state */
+		st_ll_enable();
+		/* this may take a while to complete
+		 * since it involves BT fw download
+		 */
+		err = st_kim_start();
+		if (err != ST_SUCCESS) {
+			clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+			if ((is_protocol_list_empty() != ST_EMPTY) &&
+			    (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
+				ST_DRV_ERR(" KIM failure complete callback ");
+				st_reg_complete(ST_ERR_FAILURE);
+			}
+
+			return ST_ERR_FAILURE;
+		}
+
+		/* the protocol might require other gpios to be toggled
+		 */
+		st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
+
+		clear_bit(ST_REG_IN_PROGRESS, &st_gdata->st_state);
+		st_recv = st_int_recv;
+
+		/* this is where all pending registration
+		 * are signalled to be complete by calling callback functions
+		 */
+		if ((is_protocol_list_empty() != ST_EMPTY) &&
+		    (test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
+			ST_DRV_VER(" call reg complete callback ");
+			st_reg_complete(ST_SUCCESS);
+		}
+		clear_bit(ST_REG_PENDING, &st_gdata->st_state);
+
+		/* check for already registered once more,
+		 * since the above check is old
+		 */
+		if (st_gdata->list[new_proto->type] != NULL) {
+			ST_DRV_ERR(" proto %d already registered ",
+				   new_proto->type);
+			return ST_ERR_ALREADY;
+		}
+
+		spin_lock(&st_gdata->lock);
+		st_gdata->list[new_proto->type] = new_proto;
+		new_proto->write = st_write;
+		spin_unlock(&st_gdata->lock);
+		return err;
+	}
+	/* if fw is already downloaded & new stack registers protocol */
+	else {
+		switch (new_proto->type) {
+		case ST_BT:
+			/* do nothing */
+			break;
+		case ST_FM:
+		case ST_GPS:
+			st_kim_chip_toggle(new_proto->type, KIM_GPIO_ACTIVE);
+			break;
+		case ST_MAX:
+		default:
+			ST_DRV_ERR("%d protocol not supported",
+				   new_proto->type);
+			err = ST_ERR_NOPROTO;
+			/* something wrong */
+			break;
+		}
+		st_gdata->list[new_proto->type] = new_proto;
+		new_proto->write = st_write;
+
+		/* lock already held before entering else */
+		spin_unlock(&st_gdata->lock);
+		return err;
+	}
+	ST_DRV_DBG("done %s(%d) ", __func__, new_proto->type);
+}
+EXPORT_SYMBOL_GPL(st_register);
+
+/* to unregister a protocol -
+ * to be called from protocol stack driver
+ */
+long st_unregister(enum proto_type type)
+{
+	long err = ST_SUCCESS;
+	ST_DRV_DBG("%s: %d ", __func__, type);
+
+	if (type < ST_BT || type >= ST_MAX) {
+		ST_DRV_ERR(" protocol %d not supported", type);
+		return ST_ERR_NOPROTO;
+	}
+
+	spin_lock(&st_gdata->lock);
+
+	if (st_gdata->list[type] == NULL) {
+		ST_DRV_ERR(" protocol %d not registered", type);
+		spin_unlock(&st_gdata->lock);
+		return ST_ERR_NOPROTO;
+	}
+
+	st_gdata->list[type] = NULL;
+
+	/* kim ignores BT in the below function
+	 * and handles the rest, BT is toggled
+	 * only in kim_start and kim_stop
+	 */
+	st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
+	spin_unlock(&st_gdata->lock);
+
+	if ((is_protocol_list_empty() == ST_EMPTY) &&
+	    (!test_bit(ST_REG_PENDING, &st_gdata->st_state))) {
+		ST_DRV_DBG(" all protocols unregistered ");
+
+		/* stop traffic on tty */
+		if (st_gdata->tty) {
+			tty_ldisc_flush(st_gdata->tty);
+			stop_tty(st_gdata->tty);
+		}
+
+		/* all protocols now unregistered */
+		st_kim_stop();
+		/* disable ST LL */
+		st_ll_disable();
+	}
+	return err;
+}
+
+/*
+ * called in protocol stack drivers
+ * via the write function pointer
+ */
+long st_write(struct sk_buff *skb)
+{
+#ifdef DEBUG
+	enum proto_type protoid = ST_MAX;
+#endif
+	long len;
+	struct st_data_s *st_data = st_gdata;
+
+	if (unlikely(skb == NULL || st_gdata == NULL
+		|| st_gdata->tty == NULL)) {
+		ST_DRV_ERR("data/tty unavailable to perform write");
+		return ST_ERR_FAILURE;
+	}
+#ifdef DEBUG			/* open-up skb to read the 1st byte */
+	switch (skb->data[0]) {
+	case HCI_COMMAND_PKT:
+	case HCI_ACLDATA_PKT:
+	case HCI_SCODATA_PKT:
+		protoid = ST_BT;
+		break;
+	case ST_FM_CH8_PKT:
+		protoid = ST_FM;
+		break;
+	case 0x09:
+		protoid = ST_GPS;
+		break;
+	}
+	if (unlikely(st_gdata->list[protoid] == NULL)) {
+		ST_DRV_ERR(" protocol %d not registered, and writing? ",
+			   protoid);
+		return ST_ERR_FAILURE;
+	}
+#endif
+	ST_DRV_DBG("%d to be written", skb->len);
+	len = skb->len;
+
+	/* st_ll to decide where to enqueue the skb */
+	st_int_enqueue(skb);
+	/* wake up */
+	st_tx_wakeup(st_data);
+
+	/* return number of bytes written */
+	return len;
+}
+
+/* for protocols making use of shared transport */
+EXPORT_SYMBOL_GPL(st_unregister);
+
+/********************************************************************/
+/*
+ * functions called from TTY layer
+ */
+static int st_tty_open(struct tty_struct *tty)
+{
+	int err = ST_SUCCESS;
+	ST_DRV_DBG("%s ", __func__);
+
+	st_gdata->tty = tty;
+
+	/* don't do an wakeup for now */
+	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
+	/* mem already allocated
+	 */
+	tty->receive_room = 65536;
+	/* Flush any pending characters in the driver and discipline. */
+	tty_ldisc_flush(tty);
+	tty_driver_flush_buffer(tty);
+	/*
+	 * signal to UIM via KIM that -
+	 * installation of N_SHARED ldisc is complete
+	 */
+	st_kim_complete();
+	ST_DRV_DBG("done %s", __func__);
+	return err;
+}
+
+static void st_tty_close(struct tty_struct *tty)
+{
+	unsigned char i = ST_MAX;
+	ST_DRV_DBG("%s ", __func__);
+
+	/* TODO:
+	 * if a protocol has been registered & line discipline
+	 * un-installed for some reason - what should be done ?
+	 */
+	spin_lock(&st_gdata->lock);
+	for (i = ST_BT; i < ST_MAX; i++) {
+		if (st_gdata->list[i] != NULL)
+			ST_DRV_ERR("%d not un-registered", i);
+		st_gdata->list[i] = NULL;
+	}
+	spin_unlock(&st_gdata->lock);
+	/*
+	 * signal to UIM via KIM that -
+	 * N_SHARED ldisc is un-installed
+	 */
+	st_kim_complete();
+	st_gdata->tty = NULL;
+	/* Flush any pending characters in the driver and discipline. */
+	tty_ldisc_flush(tty);
+	tty_driver_flush_buffer(tty);
+
+	spin_lock(&st_gdata->lock);
+	/* empty out txq and tx_waitq */
+	skb_queue_purge(&st_gdata->txq);
+	skb_queue_purge(&st_gdata->tx_waitq);
+	/* reset the TTY Rx states of ST */
+	st_gdata->rx_count = 0;
+	st_gdata->rx_state = ST_W4_PACKET_TYPE;
+	kfree_skb(st_gdata->rx_skb);
+	st_gdata->rx_skb = NULL;
+	spin_unlock(&st_gdata->lock);
+
+	ST_DRV_DBG("%s: done ", __func__);
+}
+
+static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
+			   char *flags, int count)
+{
+#ifdef VERBOSE
+	long i;
+	printk(KERN_ERR "incoming data...\n");
+	for (i = 0; i < count; i++)
+		printk(" %x", data[i]);
+	printk(KERN_ERR "\n.. data end\n");
+#endif
+
+	/*
+	 * if fw download is in progress then route incoming data
+	 * to KIM for validation
+	 */
+	spin_lock(&st_gdata->lock);
+	st_recv(data, count);
+	spin_unlock(&st_gdata->lock);
+
+	ST_DRV_VER("done %s", __func__);
+}
+
+/* wake-up function called in from the TTY layer
+ * inside the internal wakeup function will be called
+ */
+static void st_tty_wakeup(struct tty_struct *tty)
+{
+	ST_DRV_DBG("%s ", __func__);
+	/* don't do an wakeup for now */
+	clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+
+	/* call our internal wakeup */
+	st_tx_wakeup((void *)st_gdata);
+}
+
+static void st_tty_flush_buffer(struct tty_struct *tty)
+{
+	ST_DRV_DBG("%s ", __func__);
+
+	kfree_skb(st_gdata->tx_skb);
+	st_gdata->tx_skb = NULL;
+
+	tty->ops->flush_buffer(tty);
+	return;
+}
+
+/********************************************************************/
+static int __init st_core_init(void)
+{
+	long err;
+	static struct tty_ldisc_ops *st_ldisc_ops;
+
+	/* populate and register to TTY line discipline */
+	st_ldisc_ops = kzalloc(sizeof(*st_ldisc_ops), GFP_KERNEL);
+	if (!st_ldisc_ops) {
+		ST_DRV_ERR("no mem to allocate");
+		return -ENOMEM;
+	}
+
+	st_ldisc_ops->magic = TTY_LDISC_MAGIC;
+	st_ldisc_ops->name = "n_st";	/*"n_hci"; */
+	st_ldisc_ops->open = st_tty_open;
+	st_ldisc_ops->close = st_tty_close;
+	st_ldisc_ops->receive_buf = st_tty_receive;
+	st_ldisc_ops->write_wakeup = st_tty_wakeup;
+	st_ldisc_ops->flush_buffer = st_tty_flush_buffer;
+	st_ldisc_ops->owner = THIS_MODULE;
+
+	err = tty_register_ldisc(N_SHARED, st_ldisc_ops);
+	if (err) {
+		ST_DRV_ERR("error registering %d line discipline %ld",
+			   N_SHARED, err);
+		kfree(st_ldisc_ops);
+		return err;
+	}
+	ST_DRV_DBG("registered n_shared line discipline");
+
+	st_gdata = kzalloc(sizeof(struct st_data_s), GFP_KERNEL);
+	if (!st_gdata) {
+		ST_DRV_ERR("memory allocation failed");
+		err = tty_unregister_ldisc(N_SHARED);
+		if (err)
+			ST_DRV_ERR("unable to un-register ldisc %ld", err);
+		kfree(st_ldisc_ops);
+		err = -ENOMEM;
+		return err;
+	}
+
+	/* Initialize ST TxQ and Tx waitQ queue head. All BT/FM/GPS module skb's
+	 * will be pushed in this queue for actual transmission.
+	 */
+	skb_queue_head_init(&st_gdata->txq);
+	skb_queue_head_init(&st_gdata->tx_waitq);
+
+	/* Locking used in st_int_enqueue() to avoid multiple execution */
+	spin_lock_init(&st_gdata->lock);
+
+	/* ldisc_ops ref to be only used in __exit of module */
+	st_gdata->ldisc_ops = st_ldisc_ops;
+
+	err = st_kim_init();
+	if (err) {
+		ST_DRV_ERR("error during kim initialization(%ld)", err);
+		kfree(st_gdata);
+		err = tty_unregister_ldisc(N_SHARED);
+		if (err)
+			ST_DRV_ERR("unable to un-register ldisc");
+		kfree(st_ldisc_ops);
+		return -1;
+	}
+
+	err = st_ll_init();
+	if (err) {
+		ST_DRV_ERR("error during st_ll initialization(%ld)", err);
+		err = st_kim_deinit();
+		kfree(st_gdata);
+		err = tty_unregister_ldisc(N_SHARED);
+		if (err)
+			ST_DRV_ERR("unable to un-register ldisc");
+		kfree(st_ldisc_ops);
+		return -1;
+	}
+	return 0;
+}
+
+static void __exit st_core_exit(void)
+{
+	long err;
+	/* internal module cleanup */
+	err = st_ll_deinit();
+	if (err)
+		ST_DRV_ERR("error during deinit of ST LL %ld", err);
+	err = st_kim_deinit();
+	if (err)
+		ST_DRV_ERR("error during deinit of ST KIM %ld", err);
+
+	if (st_gdata != NULL) {
+		/* Free ST Tx Qs and skbs */
+		skb_queue_purge(&st_gdata->txq);
+		skb_queue_purge(&st_gdata->tx_waitq);
+		kfree_skb(st_gdata->rx_skb);
+		kfree_skb(st_gdata->tx_skb);
+		/* TTY ldisc cleanup */
+		err = tty_unregister_ldisc(N_SHARED);
+		if (err)
+			ST_DRV_ERR("unable to un-register ldisc %ld", err);
+		kfree(st_gdata->ldisc_ops);
+		/* free the global data pointer */
+		kfree(st_gdata);
+	}
+}
+
+module_init(st_core_init);
+module_exit(st_core_exit);
+MODULE_AUTHOR("Pavan Savoy <pavan_savoy@ti.com>");
+MODULE_DESCRIPTION("Shared Transport Driver for TI BT/FM/GPS combo chips ");
+MODULE_LICENSE("GPL");
diff --git a/drivers/misc/ti-st/st_core.h b/drivers/misc/ti-st/st_core.h
new file mode 100644
index 0000000..b88d1e7
--- /dev/null
+++ b/drivers/misc/ti-st/st_core.h
@@ -0,0 +1,92 @@
+/*
+ *  Shared Transport Core header file
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ST_CORE_H
+#define ST_CORE_H
+
+#include <linux/skbuff.h>
+#include "st.h"
+
+/* states of protocol list */
+#define ST_NOTEMPTY 	1
+#define ST_EMPTY	0
+
+/*
+ * possible st_states
+ */
+#define ST_INITIALIZING 	1
+#define ST_REG_IN_PROGRESS 	2
+#define ST_REG_PENDING	 	3
+#define ST_WAITING_FOR_RESP 	4
+
+/*
+ * local data required for ST/KIM/ST-HCI-LL
+ */
+struct st_data_s {
+	unsigned long st_state;
+/*
+ * an instance of tty_struct & ldisc ops to move around
+ */
+	struct tty_struct *tty;
+	struct tty_ldisc_ops *ldisc_ops;
+/*
+ * the tx skb -
+ * if the skb is already dequeued and the tty failed to write the same
+ * maintain the skb to write in the next transaction
+ */
+	struct sk_buff *tx_skb;
+#define ST_TX_SENDING	1
+#define ST_TX_WAKEUP	2
+	unsigned long tx_state;
+/*
+ * list of protocol registered
+ */
+	struct st_proto_s *list[ST_MAX];
+/*
+ * lock
+ */
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+	struct sk_buff_head txq, tx_waitq;
+	spinlock_t lock;	/* ST LL state lock  */
+};
+
+/* point this to tty->driver->write or tty->ops->write
+ * depending upon the kernel version
+ */
+int st_int_write(const unsigned char *, int);
+/* internal write function, passed onto protocol drivers
+ * via the write function ptr of protocol struct
+ */
+long st_write(struct sk_buff *);
+/* function to be called from ST-LL
+ */
+void st_ll_send_frame(enum proto_type, struct sk_buff *);
+/* internal wake up function */
+void st_tx_wakeup(struct st_data_s *st_data);
+
+#define GPS_STUB_TEST
+#ifdef GPS_STUB_TEST
+int gps_chrdrv_stub_write(const unsigned char*, int);
+void gps_chrdrv_stub_init(void);
+#endif
+
+#endif /*ST_CORE_H */
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
new file mode 100644
index 0000000..971e0b3
--- /dev/null
+++ b/drivers/misc/ti-st/st_kim.c
@@ -0,0 +1,722 @@
+/*
+ *  Shared Transport Line discipline driver Core
+ *	Init Manager module responsible for GPIO control
+ *	and firmware download
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include <linux/platform_device.h>
+#include <linux/jiffies.h>
+#include <linux/firmware.h>
+#include <linux/delay.h>
+#include <linux/wait.h>
+#include <linux/gpio.h>
+
+#include <linux/sched.h>
+
+#include "st_kim.h"
+/* understand BT events for fw response */
+#include <net/bluetooth/bluetooth.h>
+#include <net/bluetooth/hci_core.h>
+#include <net/bluetooth/hci.h>
+
+/* all debug macros go in here */
+#define ST_KIM_ERR(fmt, arg...)  printk(KERN_ERR "(stk):"fmt"\n" , ## arg)
+#if defined(DEBUG)		/* limited debug messages */
+#define ST_KIM_DBG(fmt, arg...)  printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#define ST_KIM_VER(fmt, arg...)
+#elif defined(VERBOSE)		/* very verbose */
+#define ST_KIM_DBG(fmt, arg...)  printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#define ST_KIM_VER(fmt, arg...)  printk(KERN_INFO "(stk):"fmt"\n" , ## arg)
+#else /* error msgs only */
+#define ST_KIM_DBG(fmt, arg...)
+#define ST_KIM_VER(fmt, arg...)
+#endif
+
+static int kim_probe(struct platform_device *pdev);
+static int kim_remove(struct platform_device *pdev);
+static ssize_t show_pid(struct device *dev, struct device_attribute
+			*attr, char *buf);
+static ssize_t store_pid(struct device *dev, struct device_attribute
+			 *devattr, char *buf, size_t count);
+static ssize_t show_list(struct device *dev, struct device_attribute
+			 *attr, char *buf);
+/* KIM platform device driver structure */
+static struct platform_driver kim_platform_driver = {
+	.probe = kim_probe,
+	.remove = kim_remove,
+	/* TODO: ST driver power management during suspend/resume ?
+	 */
+#if 0
+	.suspend = kim_suspend,
+	.resume = kim_resume,
+#endif
+	.driver = {
+		   .name = "kim",
+		   .owner = THIS_MODULE,
+		   },
+};
+
+/* structures specific for sysfs entries */
+static struct kobj_attribute pid_attr =
+__ATTR(pid, 0644, (void *)show_pid, (void *)store_pid);
+
+static struct kobj_attribute list_protocols =
+__ATTR(protocols, 0444, (void *)show_list, NULL);
+
+static struct attribute *uim_attrs[] = {
+	&pid_attr.attr,
+	/* add more debug sysfs entries */
+	&list_protocols.attr,
+	NULL,
+};
+
+static struct attribute_group uim_attr_grp = {
+	.attrs = uim_attrs,
+};
+
+/* strings to be used for rfkill entries and by
+ * ST Core to be used for sysfs debug entry
+ */
+#define PROTO_ENTRY(type, name)	name
+const unsigned char *protocol_names[] = {
+	PROTO_ENTRY(ST_BT, "Bluetooth"),
+	PROTO_ENTRY(ST_FM, "FM"),
+	PROTO_ENTRY(ST_GPS, "GPS"),
+};
+
+static struct kim_data_s *kim_gdata;
+
+/**********************************************************************/
+/* internal functions */
+
+/*
+ * function to return whether the firmware response was proper
+ * in case of error don't complete so that waiting for proper
+ * response times out
+ */
+void validate_firmware_response(struct sk_buff *skb)
+{
+	if (unlikely(skb->data[5] != 0)) {
+		ST_KIM_ERR("no proper response during fw download");
+		ST_KIM_ERR("data6 %x", skb->data[5]);
+		return;		/* keep waiting for the proper response */
+	}
+	/* becos of all the script being downloaded */
+	complete_all(&kim_gdata->kim_rcvd);
+	kfree_skb(skb);
+}
+
+/* check for data len received inside kim_int_recv
+ * most often hit the last case to update state to waiting for data
+ */
+static inline int kim_check_data_len(int len)
+{
+	register int room = skb_tailroom(kim_gdata->rx_skb);
+
+	ST_KIM_DBG("len %d room %d", len, room);
+
+	if (!len) {
+		validate_firmware_response(kim_gdata->rx_skb);
+	} else if (len > room) {
+		/* Received packet's payload length is larger.
+		 * We can't accommodate it in created skb.
+		 */
+		ST_KIM_ERR("Data length is too large len %d room %d", len,
+			   room);
+		kfree_skb(kim_gdata->rx_skb);
+	} else {
+		/* Packet header has non-zero payload length and
+		 * we have enough space in created skb. Lets read
+		 * payload data */
+		kim_gdata->rx_state = ST_BT_W4_DATA;
+		kim_gdata->rx_count = len;
+		return len;
+	}
+
+	/* Change ST LL state to continue to process next
+	 * packet */
+	kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+	kim_gdata->rx_skb = NULL;
+	kim_gdata->rx_count = 0;
+
+	return 0;
+}
+
+/* receive function called during firmware download
+ * - firmware download responses on different UART drivers
+ *   have been observed to come in bursts of different
+ *   tty_receive and hence the logic
+ */
+void kim_int_recv(const unsigned char *data, long count)
+{
+	register char *ptr;
+	struct hci_event_hdr *eh;
+	register int len = 0, type = 0;
+
+	ST_KIM_DBG("%s", __func__);
+	/* Decode received bytes here */
+	ptr = (char *)data;
+	if (unlikely(ptr == NULL)) {
+		ST_KIM_ERR(" received null from TTY ");
+		return;
+	}
+	while (count) {
+		if (kim_gdata->rx_count) {
+			len = min_t(unsigned int, kim_gdata->rx_count, count);
+			memcpy(skb_put(kim_gdata->rx_skb, len), ptr, len);
+			kim_gdata->rx_count -= len;
+			count -= len;
+			ptr += len;
+
+			if (kim_gdata->rx_count)
+				continue;
+
+			/* Check ST RX state machine , where are we? */
+			switch (kim_gdata->rx_state) {
+				/* Waiting for complete packet ? */
+			case ST_BT_W4_DATA:
+				ST_KIM_DBG("Complete pkt received");
+				validate_firmware_response(kim_gdata->rx_skb);
+				kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+				kim_gdata->rx_skb = NULL;
+				continue;
+				/* Waiting for Bluetooth event header ? */
+			case ST_BT_W4_EVENT_HDR:
+				eh = (struct hci_event_hdr *)kim_gdata->
+				    rx_skb->data;
+				ST_KIM_DBG("Event header: evt 0x%2.2x"
+					   "plen %d", eh->evt, eh->plen);
+				kim_check_data_len(eh->plen);
+				continue;
+			}	/* end of switch */
+		}		/* end of if rx_state */
+		switch (*ptr) {
+			/* Bluetooth event packet? */
+		case HCI_EVENT_PKT:
+			ST_KIM_DBG("Event packet");
+			kim_gdata->rx_state = ST_BT_W4_EVENT_HDR;
+			kim_gdata->rx_count = HCI_EVENT_HDR_SIZE;
+			type = HCI_EVENT_PKT;
+			break;
+		default:
+			ST_KIM_DBG("unknown packet");
+			ptr++;
+			count--;
+			continue;
+		}		/* end of switch *ptr */
+		ptr++;
+		count--;
+		kim_gdata->rx_skb =
+		    bt_skb_alloc(HCI_MAX_FRAME_SIZE, GFP_ATOMIC);
+		if (!kim_gdata->rx_skb) {
+			ST_KIM_ERR("can't allocate mem for new packet");
+			kim_gdata->rx_state = ST_W4_PACKET_TYPE;
+			kim_gdata->rx_count = 0;
+			return;
+		} /* not necessary in this case */
+		bt_cb(kim_gdata->rx_skb)->pkt_type = type;
+	}			/* end of while count */
+	ST_KIM_DBG("done %s", __func__);
+	return;
+}
+
+static long read_local_version(char *bts_scr_name)
+{
+	unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0;
+	char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 };
+
+	ST_KIM_DBG("%s", __func__);
+
+	INIT_COMPLETION(kim_gdata->kim_rcvd);
+	if (4 != st_int_write(read_ver_cmd, 4)) {
+		ST_KIM_ERR("kim: couldn't write 4 bytes");
+		return ST_ERR_FAILURE;
+	}
+
+	if (!wait_for_completion_timeout
+	    (&kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
+		ST_KIM_ERR(" waiting for ver info- timed out ");
+		return ST_ERR_FAILURE;
+	}
+
+	version =
+	    MAKEWORD(kim_gdata->resp_buffer[13], kim_gdata->resp_buffer[14]);
+	chip = (version & 0x7C00) >> 10;
+	min_ver = (version & 0x007F);
+	maj_ver = (version & 0x0380) >> 7;
+
+	if (version & 0x8000)
+		maj_ver |= 0x0008;
+
+	sprintf(bts_scr_name, "TIInit_%d.%d.%d.bts", chip, maj_ver, min_ver);
+	ST_KIM_DBG("%s", bts_scr_name);
+	return ST_SUCCESS;
+}
+
+/* internal function which parses through the .bts firmware script file
+ * intreprets SEND, DELAY actions only as of now
+ */
+static long download_firmware(void)
+{
+	long err = ST_SUCCESS;
+	long len = 0;
+	register unsigned char *ptr = NULL;
+	register unsigned char *action_ptr = NULL;
+	unsigned char bts_scr_name[30] = { 0 };	/* 30 char long bts scr name? */
+
+	ST_KIM_VER("%s", __func__);
+
+	err = read_local_version(bts_scr_name);
+	if (err != ST_SUCCESS) {
+		ST_KIM_ERR("kim: failed to read local ver");
+		return err;
+	}
+	err =
+	    request_firmware(&kim_gdata->fw_entry, bts_scr_name,
+			     &kim_gdata->kim_pdev->dev);
+	if (unlikely((err != 0) || (kim_gdata->fw_entry->data == NULL) ||
+		     (kim_gdata->fw_entry->size == 0))) {
+		ST_KIM_ERR(" request_firmware failed(errno %ld) for %s", err,
+			   bts_scr_name);
+		return ST_ERR_FAILURE;
+	}
+	ptr = (void *)kim_gdata->fw_entry->data;
+	len = kim_gdata->fw_entry->size;
+	/* bts_header to remove out magic number and
+	 * version
+	 */
+	ptr += sizeof(struct bts_header);
+	len -= sizeof(struct bts_header);
+
+	while (len > 0 && ptr) {
+		ST_KIM_VER(" action size %d, type %d ",
+			   ((struct bts_action *)ptr)->size,
+			   ((struct bts_action *)ptr)->type);
+
+		switch (((struct bts_action *)ptr)->type) {
+		case ACTION_SEND_COMMAND:	/* action send */
+			action_ptr = &(((struct bts_action *)ptr)->data[0]);
+			if (unlikely
+			    (((struct hci_command *)action_ptr)->opcode ==
+			     0xFF36)) {
+				/* ignore remote change
+				 * baud rate HCI VS command */
+				ST_KIM_ERR
+				    (" change remote baud\
+				    rate command in firmware");
+				break;
+			}
+
+			INIT_COMPLETION(kim_gdata->kim_rcvd);
+			err = st_int_write(((struct bts_action_send *)
+					    action_ptr)->data,
+					   ((struct bts_action *)ptr)->size);
+			if (unlikely(err < 0)) {
+				release_firmware(kim_gdata->fw_entry);
+				return ST_ERR_FAILURE;
+			}
+			if (!wait_for_completion_timeout
+			    (&kim_gdata->kim_rcvd,
+			     msecs_to_jiffies(CMD_RESP_TIME))) {
+				ST_KIM_ERR
+				    (" response timeout during fw download ");
+				/* timed out */
+				release_firmware(kim_gdata->fw_entry);
+				return ST_ERR_FAILURE;
+			}
+			break;
+		case ACTION_DELAY:	/* sleep */
+			ST_KIM_DBG("sleep command in scr");
+			action_ptr = &(((struct bts_action *)ptr)->data[0]);
+			mdelay(((struct bts_action_delay *)action_ptr)->msec);
+			break;
+		}
+		len =
+		    len - (sizeof(struct bts_action) +
+			   ((struct bts_action *)ptr)->size);
+		ptr =
+		    ptr + sizeof(struct bts_action) +
+		    ((struct bts_action *)ptr)->size;
+	}
+	/* fw download complete */
+	release_firmware(kim_gdata->fw_entry);
+	return ST_SUCCESS;
+}
+
+/**********************************************************************/
+/* functions called from ST core */
+
+/* function to toggle the GPIO
+ * needs to know whether the GPIO is active high or active low
+ */
+void st_kim_chip_toggle(enum proto_type type, enum kim_gpio_state state)
+{
+	ST_KIM_DBG(" %s ", __func__);
+
+	if (kim_gdata->gpios[type] == -1) {
+		ST_KIM_DBG(" gpio not requested for protocol %s",
+			   protocol_names[type]);
+		return;
+	}
+	switch (type) {
+	case ST_BT:
+		/*Do Nothing */
+		break;
+
+	case ST_FM:
+		if (state == KIM_GPIO_ACTIVE)
+			gpio_set_value(kim_gdata->gpios[ST_FM], GPIO_LOW);
+		else
+			gpio_set_value(kim_gdata->gpios[ST_FM], GPIO_HIGH);
+		break;
+
+	case ST_GPS:
+		if (state == KIM_GPIO_ACTIVE)
+			gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_HIGH);
+		else
+			gpio_set_value(kim_gdata->gpios[ST_GPS], GPIO_LOW);
+		break;
+
+	case ST_MAX:
+	default:
+		break;
+	}
+
+	return;
+}
+
+/* called from ST Core, when REG_IN_PROGRESS (registration in progress)
+ * can be because of
+ * 1. response to read local version
+ * 2. during send/recv's of firmware download
+ */
+void st_kim_recv(const unsigned char *data, long count)
+{
+	ST_KIM_DBG(" %s ", __func__);
+	/* copy to local buffer */
+	if (unlikely(data[4] == 0x01 && data[5] == 0x10 && data[0] == 0x04)) {
+		/* must be the read_ver_cmd */
+		memcpy(kim_gdata->resp_buffer, data, count);
+		complete_all(&kim_gdata->kim_rcvd);
+		return;
+	} else {
+		kim_int_recv(data, count);
+		/* either completes or times out */
+	}
+	return;
+}
+
+/* to signal completion of line discipline installation
+ * called from ST Core, upon tty_open
+ */
+void st_kim_complete(void)
+{
+	complete(&kim_gdata->ldisc_installed);
+}
+
+/* called from ST Core upon 1st registration
+*/
+long st_kim_start(void)
+{
+	long err = ST_SUCCESS;
+	long retry = POR_RETRY_COUNT;
+	ST_KIM_DBG(" %s", __func__);
+
+	do {
+		/* Configure BT nShutdown to HIGH state */
+		gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+		mdelay(5);	/* FIXME: a proper toggle */
+		gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH);
+		mdelay(100);
+
+		/* re-initialize the completion */
+		INIT_COMPLETION(kim_gdata->ldisc_installed);
+		/* send signal to UIM */
+		err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 0);
+		if (err != 0) {
+			ST_KIM_VER(" sending SIGUSR2 to uim failed %ld", err);
+			err = ST_ERR_FAILURE;
+			continue;
+		}
+		/* wait for ldisc to be installed */
+		err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
+				msecs_to_jiffies(LDISC_TIME));
+		if (!err) {	/* timeout */
+			ST_KIM_ERR("line disc installation timed out ");
+			err = ST_ERR_FAILURE;
+			continue;
+		} else {
+			/* ldisc installed now */
+			ST_KIM_DBG(" line discipline installed ");
+			err = download_firmware();
+			if (err != ST_SUCCESS) {
+				ST_KIM_ERR("download firmware failed");
+				continue;
+			} else {	/* on success don't retry */
+				break;
+			}
+		}
+	} while (retry--);
+	return err;
+}
+
+/* called from ST Core, on the last un-registration
+*/
+long st_kim_stop(void)
+{
+	long err = ST_SUCCESS;
+
+	INIT_COMPLETION(kim_gdata->ldisc_installed);
+	/* send signal to UIM */
+	err = kill_pid(find_get_pid(kim_gdata->uim_pid), SIGUSR2, 1);
+	if (err != 0) {
+		ST_KIM_ERR("sending SIGUSR2 to uim failed %ld", err);
+		return ST_ERR_FAILURE;
+	}
+
+	/* wait for ldisc to be un-installed */
+	err = wait_for_completion_timeout(&kim_gdata->ldisc_installed,
+			msecs_to_jiffies(LDISC_TIME));
+	if (!err) {		/* timeout */
+		ST_KIM_ERR(" timed out waiting for ldisc to be un-installed");
+		return ST_ERR_FAILURE;
+	}
+
+	/* By default configure BT nShutdown to LOW state */
+	gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+	mdelay(1);
+	gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH);
+	mdelay(1);
+	gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+	return err;
+}
+
+/**********************************************************************/
+/* functions called from subsystems */
+
+/* called when sysfs entry is written to */
+static ssize_t store_pid(struct device *dev, struct device_attribute
+			 *devattr, char *buf, size_t count)
+{
+	ST_KIM_DBG("%s: pid %s ", __func__, buf);
+	sscanf(buf, "%ld", &kim_gdata->uim_pid);
+	/* to be made use by kim_start to signal SIGUSR2
+	 */
+	return strlen(buf);
+}
+
+/* called when sysfs entry is read from */
+static ssize_t show_pid(struct device *dev, struct device_attribute
+			*attr, char *buf)
+{
+	sprintf(buf, "%ld", kim_gdata->uim_pid);
+	return strlen(buf);
+}
+
+/* called when sysfs entry is read from */
+static ssize_t show_list(struct device *dev, struct device_attribute
+			 *attr, char *buf)
+{
+	kim_st_list_protocols(buf);
+	return strlen(buf);
+}
+
+#ifdef LEGACY_RFKILL_SUPPORT
+/* function called from rfkill subsystem, when someone from
+ * user space would write 0/1 on the sysfs entry
+ * /sys/class/rfkill/rfkill0,1,3/state
+ */
+static int kim_toggle_radio(void *data, enum rfkill_state state)
+{
+	enum proto_type type = (enum proto_type)data;
+	ST_KIM_DBG(" %s ", __func__);
+	if (type == ST_BT) {
+		/* Configure BT nShutdown to HIGH state */
+		gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+		mdelay(1);	/* FIXME: a proper toggle */
+		gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_HIGH);
+
+		if (state == RFKILL_STATE_SOFT_BLOCKED)
+			gpio_set_value(kim_gdata->gpios[ST_BT], GPIO_LOW);
+	}
+
+	switch (state) {
+	case RFKILL_STATE_UNBLOCKED:
+		st_kim_chip_toggle(type, KIM_GPIO_ACTIVE);
+		break;
+	case RFKILL_STATE_SOFT_BLOCKED:
+		st_kim_chip_toggle(type, KIM_GPIO_INACTIVE);
+		break;
+	default:
+		printk(KERN_ERR "invalid rfkill state %d", state);
+	}
+	return ST_SUCCESS;
+}
+#endif
+
+/**********************************************************************/
+/* functions called from platform device driver subsystem
+ * need to have a relevant platform device entry in the platform's
+ * board-*.c file
+ */
+
+static int kim_probe(struct platform_device *pdev)
+{
+	long status;
+	long proto;
+	long *gpios = pdev->dev.platform_data;
+
+	for (proto = 0; proto < ST_MAX; proto++) {
+		kim_gdata->gpios[proto] = gpios[proto];
+		ST_KIM_VER(" %ld gpio to be requested", gpios[proto]);
+	}
+
+	for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
+		/* Claim the Bluetooth/FM/GPIO
+		 * nShutdown gpio from the system
+		 */
+		status = gpio_request(gpios[proto], "kim");
+		if (unlikely(status)) {
+			ST_KIM_ERR(" gpio %ld request failed ", gpios[proto]);
+			proto -= 1;
+			while (proto >= 0) {
+				if (gpios[proto] != -1)
+					gpio_free(gpios[proto]);
+			}
+			return status;
+		}
+
+		/* Configure nShutdown GPIO as output=0 */
+		status =
+		    gpio_direction_output(gpios[proto], 0);
+		if (unlikely(status)) {
+			ST_KIM_ERR(" unable to configure gpio %ld",
+				   gpios[proto]);
+			proto -= 1;
+			while (proto >= 0) {
+				if (gpios[proto] != -1)
+					gpio_free(gpios[proto]);
+			}
+			return status;
+		}
+	}
+	/* pdev to contain BT, FM and GPS enable/N-Shutdown GPIOs
+	 * execute request_gpio, set output direction
+	 */
+	kim_gdata->kim_kobj = kobject_create_and_add("uim", NULL);
+	/* create the sysfs entry for UIM to put in pid */
+	if (sysfs_create_group(kim_gdata->kim_kobj, &uim_attr_grp)) {
+		ST_KIM_ERR(" sysfs entry creation failed");
+		kobject_put(kim_gdata->kim_kobj);
+		/* free requested GPIOs and fail probe */
+		for (proto = ST_BT; proto < ST_MAX; proto++) {
+			if (gpios[proto] != -1)
+				gpio_free(gpios[proto]);
+		}
+		return -1;	/* fail insmod */
+	}
+
+	ST_KIM_DBG(" sysfs entry created ");
+
+	/* get reference of pdev for request_firmware
+	 */
+	kim_gdata->kim_pdev = pdev;
+	init_completion(&kim_gdata->kim_rcvd);
+	init_completion(&kim_gdata->ldisc_installed);
+#ifdef LEGACY_RFKILL_SUPPORT
+	for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
+		/* TODO: should all types be rfkill_type_bt ? */
+		kim_gdata->rfkill[proto] = rfkill_allocate(&pdev->dev,
+					   RFKILL_TYPE_BLUETOOTH);
+		if (kim_gdata->rfkill[proto] == NULL) {
+			ST_KIM_ERR("cannot create rfkill entry for gpio %ld",
+				   gpios[proto]);
+			continue;
+		}
+		kim_gdata->rfkill[proto]->name = protocol_names[proto];
+		kim_gdata->rfkill[proto]->state = RFKILL_STATE_SOFT_BLOCKED;
+		kim_gdata->rfkill[proto]->user_claim_unsupported = 1;
+		kim_gdata->rfkill[proto]->user_claim = 0;
+		/* sending protocol id instead of gpio */
+		kim_gdata->rfkill[proto]->data = (void *)proto;
+		kim_gdata->rfkill[proto]->toggle_radio = kim_toggle_radio;
+		status = rfkill_register(kim_gdata->rfkill[proto]);
+		if (unlikely(status)) {
+			ST_KIM_ERR("rfkill registration failed for gpio %ld",
+				   gpios[proto]);
+			rfkill_free(kim_gdata->rfkill[proto]);
+			continue;
+		}
+		ST_KIM_DBG("rfkill entry created for %ld", gpios[proto]);
+	}
+#endif
+	return ST_SUCCESS;
+}
+
+static int kim_remove(struct platform_device *pdev)
+{
+	/* free the GPIOs requested
+	 */
+	long *gpios = pdev->dev.platform_data;
+	long proto;
+
+	for (proto = 0; (proto < ST_MAX) && (gpios[proto] != -1); proto++) {
+		/* Claim the Bluetooth/FM/GPIO
+		 * nShutdown gpio from the system
+		 */
+		gpio_free(gpios[proto]);
+#ifdef LEGACY_RFKILL_SUPPORT
+		rfkill_unregister(kim_gdata->rfkill[proto]);
+		kim_gdata->rfkill[proto] = NULL;
+#endif
+	}
+	ST_KIM_DBG("kim: GPIO Freed");
+	/* delete the sysfs entries */
+	sysfs_remove_group(kim_gdata->kim_kobj, &uim_attr_grp);
+	kobject_put(kim_gdata->kim_kobj);
+	kim_gdata->kim_pdev = NULL;
+	return ST_SUCCESS;
+}
+
+/**********************************************************************/
+/* entry point for ST KIM module, called in from ST Core */
+
+long st_kim_init(void)
+{
+	long ret = ST_SUCCESS;
+	kim_gdata = kzalloc(sizeof(struct kim_data_s), GFP_ATOMIC);
+	if (!kim_gdata) {
+		ST_KIM_ERR("no mem to allocate");
+		return -ENOMEM;
+	}
+	ret = platform_driver_register(&kim_platform_driver);
+	if (ret != 0) {
+		ST_KIM_ERR("platform drv registration failed");
+		return ST_ERR_FAILURE;
+	}
+	return ST_SUCCESS;
+}
+
+long st_kim_deinit(void)
+{
+	/* the following returns void */
+	platform_driver_unregister(&kim_platform_driver);
+	kfree(kim_gdata);
+	kim_gdata = NULL;
+	return ST_SUCCESS;
+}
diff --git a/drivers/misc/ti-st/st_kim.h b/drivers/misc/ti-st/st_kim.h
new file mode 100644
index 0000000..8953290
--- /dev/null
+++ b/drivers/misc/ti-st/st_kim.h
@@ -0,0 +1,151 @@
+/*
+ *  Shared Transport Line discipline driver Core
+ *  	Init Manager Module header file
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ST_KIM_H
+#define ST_KIM_H
+
+#include <linux/types.h>
+#include "st.h"
+#include "st_core.h"
+#include "st_ll.h"
+#include <linux/rfkill.h>
+
+/* time in msec to wait for
+ * line discipline to be installed
+ */
+#define LDISC_TIME	500
+#define CMD_RESP_TIME	500
+#define MAKEWORD(a, b)  ((unsigned short)(((unsigned char)(a)) \
+	| ((unsigned short)((unsigned char)(b))) << 8))
+
+#define GPIO_HIGH 1
+#define GPIO_LOW  0
+
+/* the Power-On-Reset logic, requires to attempt
+ * to download firmware onto chip more than once
+ * since the self-test for chip takes a while
+ */
+#define POR_RETRY_COUNT 5
+/*
+ * legacy rfkill support where-in 3 rfkill
+ * devices are created for the 3 gpios
+ * that ST has requested
+#define LEGACY_RFKILL_SUPPORT
+ */
+/*
+ * header file for ST provided by KIM
+ */
+struct kim_data_s {
+	long uim_pid;
+	struct platform_device *kim_pdev;
+	struct completion kim_rcvd, ldisc_installed;
+	/* MAX len of the .bts firmware script name */
+	char resp_buffer[30];
+	const struct firmware *fw_entry;
+	long gpios[ST_MAX];
+	struct kobject *kim_kobj;
+/* used by kim_int_recv to validate fw response */
+	unsigned long rx_state;
+	unsigned long rx_count;
+	struct sk_buff *rx_skb;
+#ifdef LEGACY_RFKILL_SUPPORT
+	struct rfkill *rfkill[ST_MAX];
+#endif
+};
+
+long st_kim_init(void);
+long st_kim_deinit(void);
+
+long st_kim_start(void);
+long st_kim_stop(void);
+/*
+ * called from st_tty_receive to authenticate fw_download
+ */
+void st_kim_recv(const unsigned char *, long count);
+
+void st_kim_chip_toggle(enum proto_type, enum kim_gpio_state);
+
+void st_kim_complete(void);
+
+/* function called from ST KIM to ST Core, to
+ * list out the protocols registered
+ */
+void kim_st_list_protocols(char *);
+
+/*
+ * BTS headers
+ */
+#define ACTION_SEND_COMMAND     1
+#define ACTION_WAIT_EVENT       2
+#define ACTION_SERIAL           3
+#define ACTION_DELAY            4
+#define ACTION_RUN_SCRIPT       5
+#define ACTION_REMARKS          6
+
+/*
+ *  * BRF Firmware header
+ *   */
+struct bts_header {
+	uint32_t magic;
+	uint32_t version;
+	uint8_t future[24];
+	uint8_t actions[0];
+} __attribute__ ((packed));
+
+/*
+ *  * BRF Actions structure
+ *   */
+struct bts_action {
+	uint16_t type;
+	uint16_t size;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+struct bts_action_send {
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+struct bts_action_wait {
+	uint32_t msec;
+	uint32_t size;
+	uint8_t data[0];
+} __attribute__ ((packed));
+
+struct bts_action_delay {
+	uint32_t msec;
+} __attribute__ ((packed));
+
+struct bts_action_serial {
+	uint32_t baud;
+	uint32_t flow_control;
+} __attribute__ ((packed));
+
+/* for identifying the change speed HCI VS
+ * command
+ */
+struct hci_command {
+	uint8_t prefix;
+	uint16_t opcode;
+	uint8_t plen;
+	uint32_t speed;
+} __attribute__ ((packed));
+
+
+#endif /* ST_KIM_H */
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c
new file mode 100644
index 0000000..c6c605c
--- /dev/null
+++ b/drivers/misc/ti-st/st_ll.c
@@ -0,0 +1,174 @@
+/*
+ *  Shared Transport driver
+ *  	HCI-LL module responsible for TI proprietary HCI_LL protocol
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#include "st_ll.h"
+
+/* all debug macros go in here */
+#define ST_LL_ERR(fmt, arg...)  printk(KERN_ERR "(stll):"fmt"\n" , ## arg)
+#if defined(DEBUG)		/* limited debug messages */
+#define ST_LL_DBG(fmt, arg...)  printk(KERN_INFO "(stll):"fmt"\n" , ## arg)
+#define ST_LL_VER(fmt, arg...)
+#elif defined(VERBOSE)		/* very verbose */
+#define ST_LL_DBG(fmt, arg...)  printk(KERN_INFO "(stll):"fmt"\n" , ## arg)
+#define ST_LL_VER(fmt, arg...)  printk(KERN_INFO "(stll):"fmt"\n" , ## arg)
+#else /* error msgs only */
+#define ST_LL_DBG(fmt, arg...)
+#define ST_LL_VER(fmt, arg...)
+#endif
+
+static struct ll_struct_s *ll;
+
+/**********************************************************************/
+/* internal functions */
+static void send_ll_cmd(unsigned char cmd)
+{
+
+	ST_LL_DBG("%s: writing %x", __func__, cmd);
+	st_int_write(&cmd, 1);
+	return;
+}
+
+static void ll_device_want_to_sleep(void)
+{
+	ST_LL_DBG("%s", __func__);
+	/* sanity check */
+	if (ll->ll_state != ST_LL_AWAKE)
+		ST_LL_ERR("ERR hcill: ST_LL_GO_TO_SLEEP_IND"
+			  "in state %ld", ll->ll_state);
+
+	spin_lock(&ll->lock);
+	send_ll_cmd(LL_SLEEP_ACK);
+	/* update state */
+	ll->ll_state = ST_LL_ASLEEP;
+	spin_unlock(&ll->lock);
+}
+
+static void ll_device_want_to_wakeup(void)
+{
+	spin_lock(&ll->lock);
+	/* diff actions in diff states */
+	switch (ll->ll_state) {
+	case ST_LL_ASLEEP:
+		send_ll_cmd(LL_WAKE_UP_ACK);	/* send wake_ack */
+		break;
+	case ST_LL_ASLEEP_TO_AWAKE:
+		/* duplicate wake_ind */
+		ST_LL_ERR("duplicate wake_ind while waiting for Wake ack");
+		break;
+	case ST_LL_AWAKE:
+		/* duplicate wake_ind */
+		ST_LL_ERR("duplicate wake_ind already AWAKE");
+		break;
+	case ST_LL_AWAKE_TO_ASLEEP:
+		/* duplicate wake_ind */
+		ST_LL_ERR("duplicate wake_ind");
+		break;
+	}
+	/* update state */
+	ll->ll_state = ST_LL_AWAKE;
+	spin_unlock(&ll->lock);
+}
+
+/**********************************************************************/
+/* functions invoked by ST Core */
+
+/* called when ST Core wants to
+ * enable ST LL */
+void st_ll_enable(void)
+{
+	ll->ll_state = ST_LL_AWAKE;
+}
+
+/* called when ST Core /local module wants to
+ * disable ST LL */
+void st_ll_disable(void)
+{
+	ll->ll_state = ST_LL_INVALID;
+}
+
+/* called when ST Core wants to update the state */
+void st_ll_wakeup(void)
+{
+	if (likely(ll->ll_state != ST_LL_AWAKE)) {
+		send_ll_cmd(LL_WAKE_UP_IND);	/* WAKE_IND */
+		ll->ll_state = ST_LL_ASLEEP_TO_AWAKE;
+	} else {
+		/* don't send the duplicate wake_indication */
+		ST_LL_ERR(" Chip already AWAKE ");
+	}
+}
+
+/* called when ST Core wants the state */
+unsigned long st_ll_getstate(void)
+{
+	ST_LL_DBG(" returning state %ld", ll->ll_state);
+	return ll->ll_state;
+}
+
+/* called from ST Core, when a PM related packet arrives */
+unsigned long st_ll_sleep_state(unsigned char cmd)
+{
+	switch (cmd) {
+	case LL_SLEEP_IND:	/* sleep ind */
+		ST_LL_DBG("sleep indication recvd");
+		ll_device_want_to_sleep();
+		break;
+	case LL_SLEEP_ACK:	/* sleep ack */
+		ST_LL_ERR("sleep ack rcvd: host shouldn't");
+		break;
+	case LL_WAKE_UP_IND:	/* wake ind */
+		ST_LL_DBG("wake indication recvd");
+		ll_device_want_to_wakeup();
+		break;
+	case LL_WAKE_UP_ACK:	/* wake ack */
+		ST_LL_DBG("wake ack rcvd");
+		ll->ll_state = ST_LL_AWAKE;
+		break;
+	default:
+		ST_LL_ERR(" unknown input/state ");
+		return ST_ERR_FAILURE;
+	}
+	return ST_SUCCESS;
+}
+
+/* Called from ST CORE to initialize ST LL */
+long st_ll_init(void)
+{
+	long err = ST_SUCCESS;
+
+	/* Allocate memory for ST LL private structure */
+	ll = kzalloc(sizeof(*ll), GFP_ATOMIC);
+	if (!ll) {
+		ST_LL_ERR("kzalloc failed to alloc memory for ST LL");
+		err = -ENOMEM;
+		return err;
+	}
+	spin_lock_init(&ll->lock);
+	/* set state to invalid */
+	ll->ll_state = ST_LL_INVALID;
+	return err;
+}
+
+/* Called from ST CORE to de-initialize ST LL */
+long st_ll_deinit(void)
+{
+	kfree(ll);
+	return 0;
+}
diff --git a/drivers/misc/ti-st/st_ll.h b/drivers/misc/ti-st/st_ll.h
new file mode 100644
index 0000000..4cb0d03
--- /dev/null
+++ b/drivers/misc/ti-st/st_ll.h
@@ -0,0 +1,68 @@
+/*
+ *  Shared Transport Low Level (ST LL)
+ *
+ *  Copyright (C) 2009 Texas Instruments
+ *
+ *  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, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+#ifndef ST_LL_H
+#define ST_LL_H
+
+#include <linux/skbuff.h>
+#include "st.h"
+#include "st_core.h"
+
+/* ST LL receiver states */
+#define ST_W4_PACKET_TYPE       0
+#define ST_BT_W4_EVENT_HDR      1
+#define ST_BT_W4_ACL_HDR        2
+#define ST_BT_W4_SCO_HDR        3
+#define ST_BT_W4_DATA           4
+#define ST_FM_W4_EVENT_HDR      5
+#define ST_GPS_W4_EVENT_HDR    	6
+
+/* ST LL state machines */
+#define ST_LL_ASLEEP               0
+#define ST_LL_ASLEEP_TO_AWAKE      1
+#define ST_LL_AWAKE                2
+#define ST_LL_AWAKE_TO_ASLEEP      3
+#define ST_LL_INVALID		   4
+
+#define LL_SLEEP_IND	0x30
+#define LL_SLEEP_ACK	0x31
+#define LL_WAKE_UP_IND	0x32
+#define LL_WAKE_UP_ACK	0x33
+
+/* ST LL private information */
+struct ll_struct_s {
+	unsigned long ll_state;	/* ST LL power state */
+	spinlock_t lock;
+};
+
+/* initialize and de-init ST LL */
+long st_ll_init(void);
+long st_ll_deinit(void);
+
+/* enable/disable ST LL along with KIM start/stop
+ * called by ST Core
+ */
+void st_ll_enable(void);
+void st_ll_disable(void);
+
+unsigned long st_ll_getstate(void);
+unsigned long st_ll_sleep_state(unsigned char);
+void st_ll_wakeup(void);
+#endif /* ST_LL_H */
diff --git a/drivers/misc/wl127x-rfkill.c b/drivers/misc/wl127x-rfkill.c
index aa8d462..7e35012 100644
--- a/drivers/misc/wl127x-rfkill.c
+++ b/drivers/misc/wl127x-rfkill.c
@@ -26,10 +26,12 @@
 #include <linux/gpio.h>
 #include <linux/rfkill.h>
 #include <linux/platform_device.h>
+#include <linux/device.h>
 #include <linux/wl127x-rfkill.h>
 
 static int wl127x_rfkill_set_power(void *data, enum rfkill_state state)
 {
+#ifndef CONFIG_BUILD_TI_ST
 	int nshutdown_gpio = (int)data;
 
 	switch (state) {
@@ -42,6 +44,7 @@
 	default:
 		printk(KERN_ERR "invalid rfkill state %d\n", state);
 	}
+#endif
 	return 0;
 }
 
@@ -52,6 +55,7 @@
 	enum rfkill_state default_state = RFKILL_STATE_SOFT_BLOCKED;  /* off */
 
 	if (pdata->bt_nshutdown_gpio >= 0) {
+#ifndef CONFIG_BUILD_TI_ST
 		rc = gpio_request(pdata->bt_nshutdown_gpio,
 				  "wl127x_bt_nshutdown_gpio");
 		if (unlikely(rc))
@@ -60,7 +64,7 @@
 		rc = gpio_direction_output(pdata->bt_nshutdown_gpio, 0);
 		if (unlikely(rc))
 			return rc;
-
+#endif
 		rfkill_set_default(RFKILL_TYPE_BLUETOOTH, default_state);
 		wl127x_rfkill_set_power((void *)pdata->bt_nshutdown_gpio,
 					default_state);
@@ -86,7 +90,7 @@
 			return rc;
 		}
 	}
-
+#ifndef CONFIG_BUILD_TI_ST
 	if (pdata->fm_enable_gpio >= 0) {
 		rc = gpio_request(pdata->fm_enable_gpio,
 				  "wl127x_fm_enable_gpio");
@@ -121,7 +125,7 @@
 			return rc;
 		}
 	}
-
+#endif
 	return 0;
 }
 
@@ -132,15 +136,17 @@
 	if (pdata->bt_nshutdown_gpio >= 0) {
 		rfkill_unregister(pdata->rfkill[WL127X_BLUETOOTH]);
 		rfkill_free(pdata->rfkill[WL127X_BLUETOOTH]);
+#ifndef CONFIG_BUILD_TI_ST
 		gpio_free(pdata->bt_nshutdown_gpio);
+#endif
 	}
-
+#ifndef CONFIG_BUILD_TI_ST
 	if (pdata->fm_enable_gpio >= 0) {
 		rfkill_unregister(pdata->rfkill[WL127X_FM]);
 		rfkill_free(pdata->rfkill[WL127X_FM]);
 		gpio_free(pdata->fm_enable_gpio);
 	}
-
+#endif
 	return 0;
 }
 
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 92e2862..c3d8481 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -378,6 +378,8 @@
 				continue;
 			}
 			status = get_card_status(card, req);
+		} else if (disable_multi == 1) {
+			disable_multi = 0;
 		}
 
 		if (brq.cmd.error) {
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index c232d11..8f9186b 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -216,6 +216,24 @@
 		goto out;
 	}
 
+#ifdef CONFIG_HC_Broken_eMMC_ZOOM2
+	/*
+	 * Hack: eMMC on Zoom2 seems to have a lower EXT_CSD Rev.
+	 * This is incorrect as it is an HC card. The card becomes
+	 * unusable if not set to blockaddr mode.
+	 * The low level driver sets up the unused bit for MMC2 on Zoom2.
+	 * Revert this hack once it is fixed in the card.
+	 */
+	if (card->host->unused) {
+		card->ext_csd.sectors =
+			ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
+			ext_csd[EXT_CSD_SEC_CNT + 1] << 8 |
+			ext_csd[EXT_CSD_SEC_CNT + 2] << 16 |
+			ext_csd[EXT_CSD_SEC_CNT + 3] << 24;
+		if (card->ext_csd.sectors)
+			mmc_card_set_blockaddr(card);
+	} else
+#endif
 	if (ext_csd_struct >= 2) {
 		card->ext_csd.sectors =
 			ext_csd[EXT_CSD_SEC_CNT + 0] << 0 |
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 992b7fa..ad0a1e9 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -109,6 +109,17 @@
 
           If unsure, say N.
 
+config HC_Broken_eMMC_ZOOM2
+        bool "HC_Broken_eMMC support for Zoom2"
+	depends on OMAP_HS_MMC2 && MACH_OMAP_ZOOM2 || MACH_OMAP_ZOOM3
+	default y
+	help
+	  This selects High capacity eMMC support for Zoom2.
+	  If you have a Zoom2 board with a broken high capacity eMMC device,
+	  say Y here.
+
+	  If unsure, say N.
+
 config MMC_WBSD
 	tristate "Winbond W83L51xD SD/MMC Card Interface support"
 	depends on ISA_DMA_API
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index ce9ec83..a879136 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -77,6 +77,7 @@
 #define MSBS			(1 << 5)
 #define BCE			(1 << 1)
 #define FOUR_BIT		(1 << 1)
+#define DW8			(1 << 5)
 #define CC			0x1
 #define TC			0x02
 #define OD			0x1
@@ -84,7 +85,10 @@
 #define CMD_TIMEOUT		(1 << 16)
 #define DATA_TIMEOUT		(1 << 20)
 #define CMD_CRC			(1 << 17)
+#define CMD_CEB			(1 << 18)
+#define CMD_CIE			(1 << 19)
 #define DATA_CRC		(1 << 21)
+#define DATA_DEB		(1 << 22)
 #define CARD_ERR		(1 << 28)
 #define STAT_CLEAR		0xFFFFFFFF
 #define INIT_STREAM_CMD		0x00000000
@@ -135,6 +139,7 @@
 	struct	clk		*dbclk;
 	struct	semaphore	sem;
 	struct	work_struct	mmc_carddetect_work;
+	struct  work_struct	mmc_opp_set_work;
 	void	__iomem		*base;
 	resource_size_t		mapbase;
 	unsigned int		id;
@@ -152,6 +157,9 @@
 	int			slot_id;
 	int			dbclk_enabled;
 	int 			clks_enabled;
+	int			inactive;
+	unsigned long		max_vdd1_opp;
+	unsigned long		min_vdd1_opp;
 	unsigned		off_counter;
 	spinlock_t		clk_lock;
 	struct timer_list	inact_timer;
@@ -382,6 +390,18 @@
 			resptype = 2;
 	}
 
+#ifdef CONFIG_HC_Broken_eMMC_ZOOM2
+	if (host->id == OMAP_MMC2_DEVID) {
+		/*
+		 * HACK:
+		 * eMMC on Zoom2 seems fail init sequence without this
+		 * delay on SWITCH CMD.
+		 */
+		if (cmd->opcode == 6)
+			msleep(200);
+	}
+#endif
+
 	/*
 	 * Unlike OMAP1 controller, the cmdtype does not seem to be based on
 	 * ac, bc, adtc, bcr. Only commands ending an open ended transfer need
@@ -468,6 +488,7 @@
 	struct mmc_omap_host *host = (struct mmc_omap_host *) data;
 
 	omap_hsmmc_disable_clks(host);
+	schedule_work(&host->mmc_opp_set_work);
 }
 
 /*
@@ -571,7 +592,9 @@
 		mmc_omap_report_irq(host, status);
 #endif
 		if ((status & CMD_TIMEOUT) ||
-			(status & CMD_CRC)) {
+			(status & CMD_CRC) ||
+			(status & CMD_CEB) ||
+			(status & CMD_CIE)) {
 			if (host->cmd) {
 				if (status & CMD_TIMEOUT) {
 					mmc_omap_reset_controller_fsm(host, SRC);
@@ -587,7 +610,8 @@
 			}
 		}
 		if ((status & DATA_TIMEOUT) ||
-			(status & DATA_CRC)) {
+			(status & DATA_CRC) ||
+			(status & DATA_DEB)) {
 			if (host->data) {
 				if (status & DATA_TIMEOUT)
 					mmc_dma_cleanup(host);
@@ -691,6 +715,9 @@
 						mmc_carddetect_work);
 	struct omap_mmc_slot_data *slot = &mmc_slot(host);
 
+	if (host->suspended)
+		return;
+
 	omap_hsmmc_enable_clks(host);
 
 	host->carddetect = slot->card_detect(slot->card_detect_irq);
@@ -704,6 +731,17 @@
 	}
 }
 
+static void mmc_omap_opp_setup(struct work_struct *work)
+{
+	struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
+		mmc_opp_set_work);
+
+	if (host->pdata->set_vdd1_opp) {
+		host->pdata->set_vdd1_opp(host->dev, host->min_vdd1_opp);
+		host->inactive = 1;
+	}
+}
+
 /*
  * ISR for handling card insertion and removal
  */
@@ -711,6 +749,9 @@
 {
 	struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
 
+	if (host->suspended)
+		return IRQ_HANDLED;
+
 	schedule_work(&host->mmc_carddetect_work);
 
 	return IRQ_HANDLED;
@@ -925,10 +966,16 @@
 	WARN_ON(host->mrq != NULL);
 	host->mrq = req;
 
+	if (host->inactive)
+		if (host->pdata->set_vdd1_opp)
+			host->pdata->set_vdd1_opp(host->dev,
+				host->max_vdd1_opp);
+
+	del_timer_sync(&host->inact_timer);
+	host->inactive = 0;
 	omap_hsmmc_enable_clks(host);
 
 	mmc_omap_prepare_data(host, req);
-	del_timer_sync(&host->inact_timer);
 	mmc_omap_start_command(host, req->cmd, req->data);
 }
 
@@ -940,6 +987,7 @@
 	u16 dsor = 0;
 	unsigned long regval;
 	unsigned long timeout;
+	u32 con;
 
 	del_timer_sync(&host->inact_timer);
 	omap_hsmmc_enable_clks(host);
@@ -968,11 +1016,19 @@
 	}
 
 	switch (mmc->ios.bus_width) {
+	case MMC_BUS_WIDTH_8:
+		OMAP_HSMMC_WRITE(host->base, CON,
+			OMAP_HSMMC_READ(host->base, CON) | DW8);
+		break;
 	case MMC_BUS_WIDTH_4:
+		OMAP_HSMMC_WRITE(host->base, CON,
+			OMAP_HSMMC_READ(host->base, CON) & ~DW8);
 		OMAP_HSMMC_WRITE(host->base, HCTL,
 			OMAP_HSMMC_READ(host->base, HCTL) | FOUR_BIT);
 		break;
 	case MMC_BUS_WIDTH_1:
+		OMAP_HSMMC_WRITE(host->base, CON,
+			OMAP_HSMMC_READ(host->base, CON) & ~DW8);
 		OMAP_HSMMC_WRITE(host->base, HCTL,
 			OMAP_HSMMC_READ(host->base, HCTL) & ~FOUR_BIT);
 		break;
@@ -1027,9 +1083,11 @@
 	if (ios->power_mode == MMC_POWER_ON)
 		send_init_stream(host);
 
+	con = OMAP_HSMMC_READ(host->base, CON);
 	if (ios->bus_mode == MMC_BUSMODE_OPENDRAIN)
-		OMAP_HSMMC_WRITE(host->base, CON,
-				OMAP_HSMMC_READ(host->base, CON) | OD);
+		OMAP_HSMMC_WRITE(host->base, CON, con | OD);
+	else
+		OMAP_HSMMC_WRITE(host->base, CON, con & ~OD);
 
 	omap_hsmmc_disable_clks(host);
 }
@@ -1131,6 +1189,24 @@
 	host->mapbase	= res->start;
 	host->base	= ioremap(host->mapbase, SZ_4K);
 
+	host->max_vdd1_opp = pdata->max_vdd1_opp;
+	host->min_vdd1_opp = pdata->min_vdd1_opp;
+
+#ifdef CONFIG_HC_Broken_eMMC_ZOOM2
+	/*
+	 * HACK:
+	 * The HC eMMC card on Zoom2 is broken. It reports wrong ext_csd
+	 * version. This is a hack to make the eMMC card useble on Zoom2.
+	 * Without this hack the MMC core fails to detect the correct size
+	 * of the card and hence accesses beyond the detected boundary results
+	 * in DATA CRC errors.
+	 * Make use of the unused bit to indicate the host controller ID to
+	 * the MMC core.
+	 */
+	if (host->id == OMAP_MMC2_DEVID)
+		host->mmc->unused = 1;
+#endif
+
 #ifdef CONFIG_MMC_EMBEDDED_SDIO
 	if (pdata->slots[0].embedded_sdio)
 		mmc_set_embedded_sdio_data(mmc,
@@ -1141,6 +1217,7 @@
 #endif
 	platform_set_drvdata(pdev, host);
 	INIT_WORK(&host->mmc_carddetect_work, mmc_omap_detect);
+	INIT_WORK(&host->mmc_opp_set_work, mmc_omap_opp_setup);
 
 	mmc->ops	= &mmc_omap_ops;
 	mmc->f_min	= 400000;
@@ -1155,8 +1232,8 @@
 
 	host->clks_enabled = 0;
 	host->off_counter = 0;
+	host->inactive = 0;
 
-	host->clks_enabled = 0;
 	host->iclk = clk_get(&pdev->dev, "mmchs_ick");
 	if (IS_ERR(host->iclk)) {
 		ret = PTR_ERR(host->iclk);
@@ -1193,7 +1270,9 @@
 
 	mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED;
 
-	if (pdata->slots[host->slot_id].wires >= 4)
+	if (mmc_slot(host).wires >= 8)
+		mmc->caps |= MMC_CAP_8_BIT_DATA;
+	else if (pdata->slots[host->slot_id].wires >= 4)
 		mmc->caps |= MMC_CAP_4_BIT_DATA;
 
 	/* Only MMC1 supports 3.0V */
@@ -1344,24 +1423,27 @@
 		return 0;
 
 	if (host) {
+		host->suspended = 1;
+		if (host->pdata->suspend) {
+			ret = host->pdata->suspend(&pdev->dev,
+						host->slot_id);
+			if (ret) {
+				dev_dbg(mmc_dev(host->mmc),
+					"Unable to handle MMC board"
+					" level suspend\n");
+				host->suspended = 0;
+				return ret;
+			}
+		}
+		cancel_work_sync(&host->mmc_carddetect_work);
+
 		ret = mmc_suspend_host(host->mmc, state);
 		if (ret == 0) {
-			host->suspended = 1;
-
 			omap_hsmmc_enable_clks(host);
 
 			OMAP_HSMMC_WRITE(host->base, ISE, 0);
 			OMAP_HSMMC_WRITE(host->base, IE, 0);
 
-			if (host->pdata->suspend) {
-				ret = host->pdata->suspend(&pdev->dev,
-								host->slot_id);
-				if (ret)
-					dev_dbg(mmc_dev(host->mmc),
-						"Unable to handle MMC board"
-						" level suspend\n");
-			}
-
 			if (host->id == OMAP_MMC1_DEVID
 					&& !(OMAP_HSMMC_READ(host->base, HCTL)
 							& SDVSDET)) {
@@ -1377,6 +1459,15 @@
 			}
 
 			omap_hsmmc_disable_clks(host);
+		} else {
+			host->suspended = 0;
+			if (host->pdata->resume) {
+				ret = host->pdata->resume(&pdev->dev,
+					host->slot_id);
+				if (ret)
+					dev_dbg(mmc_dev(host->mmc),
+						"Unmask interrupt failed\n");
+			}
 		}
 
 	}
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index a0e8e0e..c46a59d 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -80,13 +80,22 @@
 	help
           Support for NAND flash on Texas Instruments OMAP2 and OMAP3 platforms.
 
-config MTD_NAND_OMAP_HWECC
-        bool "OMAP enable hardware ECC"
-        depends on MTD_NAND && MTD_NAND_OMAP2
-        default n
-        help
-          The ECC compuatation for the data to be written/read can be either by
-          software or omap has Hw ecc engine which calculates it.
+config MTD_NAND_OMAP_PREFETCH
+	bool "GPMC prefetch support for NAND Flash device"
+	depends on MTD_NAND && MTD_NAND_OMAP2
+	default y
+	help
+	  The NAND device can be accessed for Read/Write using GPMC PREFETCH engine
+	  to improve the performance.
+
+config MTD_NAND_OMAP_PREFETCH_DMA
+	depends on MTD_NAND_OMAP_PREFETCH
+	bool "DMA mode"
+	default n
+	help
+	  The GPMC PREFETCH engine can be configured eigther in MPU interrupt mode
+	  or in DMA interrupt mode.
+	  Say y for DMA mode or MPU mode will be used
 
 config MTD_NAND_OMAP
 	tristate "NAND Flash device on OMAP H3/H2/P2 boards"
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 8ba3e3e..8d6d033 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -2524,11 +2524,13 @@
 	struct nand_chip *chip = mtd->priv;
 	int i;
 
-	for (i = 0; i < 2000; i++) {
-		if (chip->dev_ready(mtd))
-			break;
-		mdelay(10);
-	}
+	if (chip->state != FL_READY)
+		for (i = 0; i < 40; i++) {
+			if (chip->dev_ready(mtd))
+				break;
+			mdelay(10);
+		}
+	chip->state = FL_READY;
 }
 
 static int nand_panic_write(struct mtd_info *mtd, loff_t to, size_t len,
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 9d0acda..d296d40 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -19,7 +19,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/io.h>
 
-#include <asm/dma.h>
+#include <mach/dma.h>
 
 #include <mach/gpmc.h>
 #include <mach/nand.h>
@@ -112,6 +112,26 @@
 static const char *part_probes[] = { "cmdlinepart", NULL };
 #endif
 
+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH
+static int use_prefetch = 1;
+
+/* "modprobe ... use_prefetch=0" etc */
+module_param(use_prefetch, bool, 0);
+MODULE_PARM_DESC(use_prefetch, "enable/disable use of PREFETCH");
+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+static int use_dma = 1;
+
+/* "modprobe ... use_dma=0" etc */
+module_param(use_dma, bool, 0);
+MODULE_PARM_DESC(use_dma, "enable/disable use of DMA");
+#else
+const int use_dma;
+#endif
+#else
+const int use_prefetch;
+const int use_dma;
+#endif
+
 struct omap_nand_info {
 	struct nand_hw_control		controller;
 	struct omap_nand_platform_data	*pdata;
@@ -119,11 +139,48 @@
 	struct mtd_partition		*parts;
 	struct nand_chip		nand;
 	struct platform_device		*pdev;
+	struct device			*dev;
 
 	int				gpmc_cs;
 	unsigned long			phys_base;
 	void __iomem			*gpmc_cs_baseaddr;
 	void __iomem			*gpmc_baseaddr;
+	void __iomem			*nand_pref_fifo_add;
+	struct completion		comp;
+	int				dma_ch;
+};
+
+static struct nand_ecclayout nand_x8_hw_romcode_oob_64 = {
+	.eccbytes = 12,
+	.eccpos = {
+		1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12
+	},
+	.oobfree = {
+		{.offset = 13,
+			.length = 51}
+		}
+};
+
+/* Define some generic bad / good block scan pattern which are used
+ * while scanning a device for factory marked good / bad blocks
+ */
+static uint8_t scan_ff_pattern[] = { 0xff };
+static struct nand_bbt_descr bb_descrip_flashbased = {
+	.options = NAND_BBT_SCANEMPTY | NAND_BBT_SCANALLPAGES,
+	.offs = 0,
+	.len = 1,
+	.pattern = scan_ff_pattern,
+};
+
+static struct nand_ecclayout nand_x16_hw_romcode_oob_64 = {
+	.eccbytes = 12,
+	.eccpos = {
+		2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13
+	},
+	.oobfree = {
+			{.offset = 14,
+			.length = 50}
+	}
 };
 
 /*
@@ -160,6 +217,14 @@
 {
 	struct omap_nand_info *info = container_of(mtd,
 					struct omap_nand_info, mtd);
+	struct omap_nand_platform_data  *pdata;
+
+	pdata = info->pdev->dev.platform_data;
+	if (cmd == NAND_CMD_ERASE1) {
+		if (pdata->board_unlock)
+			pdata->board_unlock(mtd, info->dev);
+	}
+
 	switch (ctrl) {
 	case NAND_CTRL_CHANGE | NAND_CTRL_CLE:
 		info->nand.IO_ADDR_W = info->gpmc_cs_baseaddr +
@@ -188,6 +253,44 @@
 }
 
 /*
+ * omap_read_buf8 - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf8(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct nand_chip *nand = mtd->priv;
+
+	ioread8_rep(nand->IO_ADDR_R, buf, len);
+}
+
+/**
+ * omap_write_buf8 - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf8(struct mtd_info *mtd, const u_char *buf, int len)
+{
+	struct omap_nand_info *info = container_of(mtd,
+						struct omap_nand_info, mtd);
+	struct omap_nand_platform_data  *pdata;
+
+	pdata = info->pdev->dev.platform_data;
+	u_char *p = (u_char *)buf;
+
+	if (pdata->board_unlock)
+		pdata->board_unlock(mtd, info->dev);
+
+	while (len--) {
+		iowrite8(*p++, info->nand.IO_ADDR_W);
+		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
+					GPMC_STATUS) & GPMC_BUF_FULL));
+	}
+}
+
+/*
  * omap_read_buf16 - read data from NAND controller into buffer
  * @mtd: MTD device structure
  * @buf: buffer to store date
@@ -197,7 +300,7 @@
 {
 	struct nand_chip *nand = mtd->priv;
 
-	__raw_readsw(nand->IO_ADDR_R, buf, len / 2);
+	ioread16_rep(nand->IO_ADDR_R, buf, len / 2);
 }
 
 /*
@@ -210,18 +313,274 @@
 {
 	struct omap_nand_info *info = container_of(mtd,
 						struct omap_nand_info, mtd);
+	struct omap_nand_platform_data  *pdata;
+
+	pdata = info->pdev->dev.platform_data;
 	u16 *p = (u16 *) buf;
 
+	if (pdata->board_unlock)
+		pdata->board_unlock(mtd, info->dev);
+
 	/* FIXME try bursts of writesw() or DMA ... */
 	len >>= 1;
 
 	while (len--) {
-		writew(*p++, info->nand.IO_ADDR_W);
+		iowrite16(*p++, info->nand.IO_ADDR_W);
 
 		while (GPMC_BUF_EMPTY == (readl(info->gpmc_baseaddr +
 						GPMC_STATUS) & GPMC_BUF_FULL));
 	}
 }
+
+/**
+ * omap_read_buf_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+	struct omap_nand_info *info = container_of(mtd,
+						struct omap_nand_info, mtd);
+	uint32_t pfpw_status = 0, r_count = 0;
+	int ret = 0;
+	u32 *p = (u32 *)buf;
+
+	/* take care of subpage reads */
+	for (; len % 4 != 0; ) {
+		*buf++ = __raw_readb(info->nand.IO_ADDR_R);
+		len--;
+	}
+	p = (u32 *) buf;
+
+	/* configure and start prefetch transfer */
+	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x0);
+	if (ret) {
+		/* PFPW engine is busy, use cpu copy method */
+		if (info->nand.options & NAND_BUSWIDTH_16)
+			omap_read_buf16(mtd, buf, len);
+		else
+			omap_read_buf8(mtd, buf, len);
+	} else {
+		do {
+			pfpw_status = gpmc_prefetch_status();
+			r_count = ((pfpw_status >> 24) & 0x7F) >> 2;
+			ioread32_rep(info->nand_pref_fifo_add, p, r_count);
+			p += r_count;
+			len -= r_count << 2;
+		} while (len);
+
+		/* disable and stop the PFPW engine */
+		gpmc_prefetch_reset();
+	}
+}
+
+/**
+ * omap_write_buf_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_pref(struct mtd_info *mtd,
+					const u_char *buf, int len)
+{
+	struct omap_nand_info *info = container_of(mtd,
+						struct omap_nand_info, mtd);
+	struct omap_nand_platform_data  *pdata;
+	uint32_t pfpw_status = 0, w_count = 0;
+	int i = 0, ret = 0;
+
+	pdata = info->pdev->dev.platform_data;
+
+	if (pdata->board_unlock)
+		pdata->board_unlock(mtd, info->dev);
+
+	u16 *p = (u16 *) buf;
+
+	/* take care of subpage writes */
+	if (len % 2 != 0) {
+		writeb(*buf, info->nand.IO_ADDR_R);
+		p = (u16 *)(buf + 1);
+		len--;
+	}
+
+	/*  configure and start prefetch transfer */
+	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x0, len, 0x1);
+	if (ret) {
+		/* PFPW engine is busy, use cpu copy method */
+		if (info->nand.options & NAND_BUSWIDTH_16)
+			omap_write_buf16(mtd, buf, len);
+		else
+			omap_write_buf8(mtd, buf, len);
+	} else {
+		pfpw_status = gpmc_prefetch_status();
+		while (pfpw_status & 0x3FFF) {
+			w_count = ((pfpw_status >> 24) & 0x7F) >> 1;
+			for (i = 0; (i < w_count) && len; i++, len -= 2)
+				iowrite16(*p++, info->nand_pref_fifo_add);
+			pfpw_status = gpmc_prefetch_status();
+		}
+
+		/* disable and stop the PFPW engine */
+		gpmc_prefetch_reset();
+	}
+}
+
+#ifdef CONFIG_MTD_NAND_OMAP_PREFETCH_DMA
+/*
+ * omap_nand_dma_cb: callback on the completion of dma transfer
+ * @lch: logical channel
+ * @ch_satuts: channel status
+ * @data: pointer to completion data structure
+ */
+static void omap_nand_dma_cb(int lch, u16 ch_status, void *data)
+{
+	complete((struct completion *) data);
+}
+
+/*
+ * omap_nand_dma_transfer: configer and start dma transfer
+ * @mtd: MTD device structure
+ * @addr: virtual address in RAM of source/destination
+ * @len: number of data bytes to be transferred
+ * @is_write: flag for read/write operation
+ */
+static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+					unsigned int len, int is_write)
+{
+	struct omap_nand_info *info = container_of(mtd,
+					struct omap_nand_info, mtd);
+	uint32_t prefetch_status = 0;
+	enum dma_data_direction dir = is_write ? DMA_TO_DEVICE :
+							DMA_FROM_DEVICE;
+	dma_addr_t dma_addr;
+	int ret;
+
+	/* The fifo depth is 64 bytes. We have a sync at each frame and frame
+	 * length is 64 bytes.
+	 */
+	int buf_len = len >> 6;
+
+	if (addr >= high_memory) {
+		struct page *p1;
+
+		if (((size_t)addr & PAGE_MASK) !=
+			((size_t)(addr + len - 1) & PAGE_MASK))
+			goto out_copy;
+		p1 = vmalloc_to_page(addr);
+		if (!p1)
+			goto out_copy;
+		addr = page_address(p1) + ((size_t)addr & ~PAGE_MASK);
+	}
+
+	dma_addr = dma_map_single(&info->pdev->dev, addr, len, dir);
+	if (dma_mapping_error(&info->pdev->dev, dma_addr)) {
+		dev_err(&info->pdev->dev,
+			"Couldn't DMA map a %d byte buffer\n", len);
+		goto out_copy;
+	}
+
+	if (is_write) {
+		omap_set_dma_dest_params(info->dma_ch, 0,
+					OMAP_DMA_AMODE_CONSTANT,
+					info->phys_base, 0, 0);
+		omap_set_dma_src_params(info->dma_ch, 0,
+					OMAP_DMA_AMODE_POST_INC,
+					dma_addr, 0, 0);
+		omap_set_dma_transfer_params(info->dma_ch,
+					OMAP_DMA_DATA_TYPE_S32,
+					0x10, buf_len, OMAP_DMA_SYNC_FRAME,
+					OMAP24XX_DMA_GPMC, OMAP_DMA_DST_SYNC);
+	} else {
+		omap_set_dma_src_params(info->dma_ch, 0,
+						OMAP_DMA_AMODE_CONSTANT,
+						info->phys_base, 0, 0);
+		omap_set_dma_dest_params(info->dma_ch, 0,
+						OMAP_DMA_AMODE_POST_INC,
+						dma_addr, 0, 0);
+		omap_set_dma_transfer_params(info->dma_ch,
+					OMAP_DMA_DATA_TYPE_S32,
+					0x10, buf_len, OMAP_DMA_SYNC_FRAME,
+					OMAP24XX_DMA_GPMC, OMAP_DMA_SRC_SYNC);
+	}
+	/*  configure and start prefetch transfer */
+	ret = gpmc_prefetch_enable(info->gpmc_cs, 0x1, len, is_write);
+	if (ret)
+		/* PFPW engine is busy, use cpu copy methode */
+		goto out_copy;
+
+	init_completion(&info->comp);
+
+	omap_start_dma(info->dma_ch);
+
+	/* setup and start DMA using dma_addr */
+	wait_for_completion(&info->comp);
+
+	while (0x3fff & (prefetch_status = gpmc_prefetch_status()))
+		;
+	/* disable and stop the PFPW engine */
+	gpmc_prefetch_reset();
+
+	dma_unmap_single(&info->pdev->dev, dma_addr, len, dir);
+	return 0;
+
+out_copy:
+	if (info->nand.options & NAND_BUSWIDTH_16)
+		is_write == 0 ? omap_read_buf16(mtd, (u_char *) addr, len)
+			: omap_write_buf16(mtd, (u_char *) addr, len);
+	else
+		is_write == 0 ? omap_read_buf8(mtd, (u_char *) addr, len)
+			: omap_write_buf8(mtd, (u_char *) addr, len);
+	return 0;
+}
+#else
+static void omap_nand_dma_cb(int lch, u16 ch_status, void *data) {}
+static inline int omap_nand_dma_transfer(struct mtd_info *mtd, void *addr,
+					unsigned int len, int is_write)
+{
+	return 0;
+}
+#endif
+
+/**
+ * omap_read_buf_dma_pref - read data from NAND controller into buffer
+ * @mtd: MTD device structure
+ * @buf: buffer to store date
+ * @len: number of bytes to read
+ */
+static void omap_read_buf_dma_pref(struct mtd_info *mtd, u_char *buf, int len)
+{
+	if (len <= mtd->oobsize)
+		omap_read_buf_pref(mtd, buf, len);
+	else
+		/* start transfer in DMA mode */
+		omap_nand_dma_transfer(mtd, buf, len, 0x0);
+}
+
+/**
+ * omap_write_buf_dma_pref - write buffer to NAND controller
+ * @mtd: MTD device structure
+ * @buf: data buffer
+ * @len: number of bytes to write
+ */
+static void omap_write_buf_dma_pref(struct mtd_info *mtd,
+					const u_char *buf, int len)
+{
+	struct omap_nand_platform_data  *pdata;
+	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+									mtd);
+
+	pdata = info->pdev->dev.platform_data;
+	if (pdata->board_unlock)
+		pdata->board_unlock(mtd, info->dev);
+
+	if (len <= mtd->oobsize)
+		omap_write_buf_pref(mtd, buf, len);
+	else
+		/* start transfer in DMA mode */
+		omap_nand_dma_transfer(mtd, buf, len, 0x1);
+}
+
 /*
  * omap_verify_buf - Verify chip data against buffer
  * @mtd: MTD device structure
@@ -245,7 +604,6 @@
 	return 0;
 }
 
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
 /*
  * omap_hwecc_init-Initialize the Hardware ECC for NAND flash in GPMC controller
  * @mtd: MTD device structure
@@ -322,7 +680,6 @@
 	/* P2048o, P1024o, P512o, P256o, P2048e, P1024e, P512e, P256e */
 	*ecc_code++ = ((val >> 8) & 0x0f) | ((val >> 20) & 0xf0);
 	reg += 4;
-	gen_true_ecc(ecc_code-3);
 
 	return 0;
 }
@@ -364,7 +721,6 @@
 
 	__raw_writel(val, info->gpmc_baseaddr + GPMC_ECC_CONFIG);
 }
-#endif
 
 /*
  * omap_wait - Wait function is called during Program and erase
@@ -392,6 +748,169 @@
 	return status;
 }
 
+/**
+ * omap_compare_ecc - Detect (2 bits) and correct (1 bit) error in data
+ * @ecc_data1:  ecc code from nand spare area
+ * @ecc_data2:  ecc code from hardware register obtained from hardware ecc
+ * @page_data:  page data
+ *
+ * This function compares two ECC's and indicates if there is an error.
+ * If the error can be corrected it will be corrected to the buffer.
+ */
+static int omap_compare_ecc(u8 *ecc_data1,	/* read from NAND memory */
+				u8 *ecc_data2,	/* read from register */
+				u8 *page_data)
+{
+	uint	i;
+	u8	tmp0_bit[8], tmp1_bit[8], tmp2_bit[8];
+	u8	comp0_bit[8], comp1_bit[8], comp2_bit[8];
+	u8	ecc_bit[24];
+	u8	ecc_sum = 0;
+	u8	find_bit = 0;
+	uint	find_byte = 0;
+	int	isEccFF;
+
+	isEccFF = ((*(u32 *)ecc_data1 & 0xFFFFFF) == 0xFFFFFF);
+
+	gen_true_ecc(ecc_data1);
+	gen_true_ecc(ecc_data2);
+
+	for (i = 0; i <= 2; i++) {
+		*(ecc_data1 + i) = ~(*(ecc_data1 + i));
+		*(ecc_data2 + i) = ~(*(ecc_data2 + i));
+	}
+
+	for (i = 0; i < 8; i++) {
+		tmp0_bit[i]     = *ecc_data1 % 2;
+		*ecc_data1	= *ecc_data1 / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		tmp1_bit[i]	 = *(ecc_data1 + 1) % 2;
+		*(ecc_data1 + 1) = *(ecc_data1 + 1) / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		tmp2_bit[i]	 = *(ecc_data1 + 2) % 2;
+		*(ecc_data1 + 2) = *(ecc_data1 + 2) / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		comp0_bit[i]     = *ecc_data2 % 2;
+		*ecc_data2       = *ecc_data2 / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		comp1_bit[i]     = *(ecc_data2 + 1) % 2;
+		*(ecc_data2 + 1) = *(ecc_data2 + 1) / 2;
+	}
+
+	for (i = 0; i < 8; i++) {
+		comp2_bit[i]     = *(ecc_data2 + 2) % 2;
+		*(ecc_data2 + 2) = *(ecc_data2 + 2) / 2;
+	}
+
+	for (i = 0; i < 6; i++)
+		ecc_bit[i] = tmp2_bit[i + 2] ^ comp2_bit[i + 2];
+
+	for (i = 0; i < 8; i++)
+		ecc_bit[i + 6] = tmp0_bit[i] ^ comp0_bit[i];
+
+	for (i = 0; i < 8; i++)
+		ecc_bit[i + 14] = tmp1_bit[i] ^ comp1_bit[i];
+
+	ecc_bit[22] = tmp2_bit[0] ^ comp2_bit[0];
+	ecc_bit[23] = tmp2_bit[1] ^ comp2_bit[1];
+
+	for (i = 0; i < 24; i++)
+		ecc_sum += ecc_bit[i];
+
+	switch (ecc_sum) {
+	case 0:
+		/* Not reached because this function is not called if
+		 *  ECC values are equal
+		 */
+		return 0;
+
+	case 1:
+		/* Uncorrectable error */
+		DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR 1\n");
+		return -1;
+
+	case 11:
+		/* UN-Correctable error */
+		DEBUG(MTD_DEBUG_LEVEL0, "ECC UNCORRECTED_ERROR B\n");
+		return -1;
+
+	case 12:
+		/* Correctable error */
+		find_byte = (ecc_bit[23] << 8) +
+			    (ecc_bit[21] << 7) +
+			    (ecc_bit[19] << 6) +
+			    (ecc_bit[17] << 5) +
+			    (ecc_bit[15] << 4) +
+			    (ecc_bit[13] << 3) +
+			    (ecc_bit[11] << 2) +
+			    (ecc_bit[9]  << 1) +
+			    ecc_bit[7];
+
+		find_bit = (ecc_bit[5] << 2) + (ecc_bit[3] << 1) + ecc_bit[1];
+
+		DEBUG(MTD_DEBUG_LEVEL0, "Correcting single bit ECC error at "
+				"offset: %d, bit: %d\n", find_byte, find_bit);
+
+		page_data[find_byte] ^= (1 << find_bit);
+
+		return 0;
+	default:
+		if (isEccFF) {
+			if (ecc_data2[0] == 0 &&
+			    ecc_data2[1] == 0 &&
+			    ecc_data2[2] == 0)
+				return 0;
+		}
+		DEBUG(MTD_DEBUG_LEVEL0, "UNCORRECTED_ERROR default\n");
+		return -1;
+	}
+}
+/**
+ * omap_correct_data - Compares the ECC read with HW generated ECC
+ * @mtd: MTD device structure
+ * @dat: page data
+ * @read_ecc: ecc read from nand flash
+ * @calc_ecc: ecc read from HW ECC registers
+ *
+ * Compares the ecc read from nand spare area with ECC registers values
+ * and if ECC's mismached, it will call 'omap_compare_ecc' for error detection
+ * and correction.
+ */
+static int omap_correct_data(struct mtd_info *mtd, u_char *dat,
+				u_char *read_ecc, u_char *calc_ecc)
+{
+	struct omap_nand_info *info = container_of(mtd, struct omap_nand_info,
+							mtd);
+	int blockCnt = 0, i = 0, ret = 0;
+
+	/* Ex NAND_ECC_HW12_2048 */
+	if ((info->nand.ecc.mode == NAND_ECC_HW) &&
+		(info->nand.ecc.size  == 2048))
+		blockCnt = 4;
+	else
+		blockCnt = 1;
+
+	for (i = 0; i < blockCnt; i++) {
+		if (memcmp(read_ecc, calc_ecc, 3) != 0) {
+			ret = omap_compare_ecc(read_ecc, calc_ecc, dat);
+			if (ret < 0)
+				return ret;
+		}
+		read_ecc += 3;
+		calc_ecc += 3;
+		dat      += 512;
+	}
+	return 0;
+}
+
 /*
  * omap_dev_ready - calls the platform specific dev_ready function
  * @mtd: MTD device structure
@@ -443,6 +962,7 @@
 	init_waitqueue_head(&info->controller.wq);
 
 	info->pdev = pdev;
+	info->dev		= &pdev->dev;
 
 	info->gpmc_cs		= pdata->cs;
 	info->gpmc_baseaddr	= pdata->gpmc_baseaddr;
@@ -489,12 +1009,6 @@
 	info->nand.IO_ADDR_W = info->nand.IO_ADDR_R;
 	info->nand.cmd_ctrl  = omap_hwcontrol;
 
-	/* REVISIT:  only supports 16-bit NAND flash */
-
-	info->nand.read_buf   = omap_read_buf16;
-	info->nand.write_buf  = omap_write_buf16;
-	info->nand.verify_buf = omap_verify_buf;
-
 	/*
 	* If RDY/BSY line is connected to OMAP then use the omap ready funcrtion
 	* and the generic nand_wait function which reads the status register
@@ -515,20 +1029,58 @@
 								== 0x1000)
 		info->nand.options  |= NAND_BUSWIDTH_16;
 
-#ifdef CONFIG_MTD_NAND_OMAP_HWECC
-	info->nand.ecc.bytes		= 3;
-	info->nand.ecc.size		= 512;
-	info->nand.ecc.calculate	= omap_calculate_ecc;
-	info->nand.ecc.hwctl		= omap_enable_hwecc;
-	info->nand.ecc.correct		= nand_correct_data;
-	info->nand.ecc.mode		= NAND_ECC_HW;
+	if (use_prefetch) {
+		/* copy the virtual address of nand base for fifo access */
+		info->nand_pref_fifo_add = info->nand.IO_ADDR_R;
 
-	/* init HW ECC */
-	omap_hwecc_init(&info->mtd);
-#else
-	info->nand.ecc.mode = NAND_ECC_SOFT;
-	info->nand.ecc.size		= 512;
-#endif
+		info->nand.read_buf   = omap_read_buf_pref;
+		info->nand.write_buf  = omap_write_buf_pref;
+		if (use_dma) {
+			err = omap_request_dma(OMAP24XX_DMA_GPMC, "NAND",
+				omap_nand_dma_cb, &info->comp, &info->dma_ch);
+			if (err < 0) {
+				info->dma_ch = -1;
+				printk(KERN_WARNING "DMA request failed."
+					" Non-dma data transfer mode\n");
+			} else {
+				omap_set_dma_dest_burst_mode(info->dma_ch,
+					OMAP_DMA_DATA_BURST_16);
+				omap_set_dma_src_burst_mode(info->dma_ch,
+					OMAP_DMA_DATA_BURST_16);
+
+				info->nand.read_buf   = omap_read_buf_dma_pref;
+				info->nand.write_buf  = omap_write_buf_dma_pref;
+			}
+		}
+	} else {
+		if (info->nand.options & NAND_BUSWIDTH_16) {
+			info->nand.read_buf   = omap_read_buf16;
+			info->nand.write_buf  = omap_write_buf16;
+		} else {
+			info->nand.read_buf   = omap_read_buf8;
+			info->nand.write_buf  = omap_write_buf8;
+		}
+	}
+	info->nand.verify_buf = omap_verify_buf;
+
+	if (pdata->ecc_opt == 0x1) {
+		info->nand.ecc.bytes            = 3;
+		info->nand.ecc.size             = 512;
+		if (info->nand.options & NAND_BUSWIDTH_16) {
+			info->nand.ecc.layout   = &nand_x16_hw_romcode_oob_64;
+		} else {
+			info->nand.ecc.layout   = &nand_x8_hw_romcode_oob_64;
+			info->nand.badblock_pattern = &bb_descrip_flashbased;
+		}
+		info->nand.ecc.calculate        = omap_calculate_ecc;
+		info->nand.ecc.hwctl            = omap_enable_hwecc;
+		info->nand.ecc.correct          = omap_correct_data;
+		info->nand.ecc.mode             = NAND_ECC_HW;
+		/* init HW ECC */
+		omap_hwecc_init(&info->mtd);
+	} else {
+		info->nand.ecc.mode = NAND_ECC_SOFT;
+	}
 
 	/* DIP switches on some boards change between 8 and 16 bit
 	 * bus widths for flash.  Try the other width if the first try fails.
@@ -540,6 +1092,9 @@
 			goto out_release_mem_region;
 		}
 	}
+	/* If the board has an unlock function, use it */
+	if (pdata->unlock != NULL)
+	info->mtd.unlock	= pdata->unlock;
 
 #ifdef CONFIG_MTD_PARTITIONS
 	err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0);
@@ -571,9 +1126,12 @@
 	struct omap_nand_info *info = mtd->priv;
 
 	platform_set_drvdata(pdev, NULL);
+	if (use_dma)
+		omap_free_dma(info->dma_ch);
+
 	/* Release NAND device, its internal structures and partitions */
 	nand_release(&info->mtd);
-	iounmap(info->nand.IO_ADDR_R);
+	iounmap(info->nand_pref_fifo_add);
 	kfree(&info->mtd);
 	return 0;
 }
@@ -620,6 +1178,15 @@
 static int __init omap_nand_init(void)
 {
 	printk(KERN_INFO "%s driver initializing\n", DRIVER_NAME);
+
+	/* This check is required if driver is being
+	 * loaded run time as a module
+	 */
+	if ((1 == use_dma) && (0 == use_prefetch)) {
+		printk(KERN_INFO"Wrong parameters: 'use_dma' can not be 1 "
+			"without use_prefetch'. Prefetch will not be"
+			" used in either mode (mpu or dma)\n");
+	}
 	return platform_driver_register(&omap_nand_driver);
 }
 
diff --git a/drivers/net/pppolac.c b/drivers/net/pppolac.c
index b4d879d..af3202a 100644
--- a/drivers/net/pppolac.c
+++ b/drivers/net/pppolac.c
@@ -3,7 +3,6 @@
  * Driver for PPP on L2TP Access Concentrator / PPPoLAC Socket (RFC 2661)
  *
  * Copyright (C) 2009 Google, Inc.
- * Author: Chia-chi Yeh <chiachi@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
@@ -22,8 +21,10 @@
  * only works on IPv4 due to the lack of UDP encapsulation support in IPv6. */
 
 #include <linux/module.h>
+#include <linux/workqueue.h>
 #include <linux/skbuff.h>
 #include <linux/file.h>
+#include <linux/netdevice.h>
 #include <linux/net.h>
 #include <linux/udp.h>
 #include <linux/ppp_defs.h>
@@ -31,6 +32,7 @@
 #include <linux/if_pppox.h>
 #include <linux/ppp_channel.h>
 #include <net/tcp_states.h>
+#include <asm/uaccess.h>
 
 #define L2TP_CONTROL_BIT	0x80
 #define L2TP_LENGTH_BIT		0x40
@@ -51,10 +53,10 @@
 	return (union unaligned *)ptr;
 }
 
-static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb)
+static int pppolac_recv_core(struct sock *sk_udp, struct sk_buff *skb)
 {
-	struct sock *sk;
-	struct pppolac_opt *opt;
+	struct sock *sk = (struct sock *)sk_udp->sk_user_data;
+	struct pppolac_opt *opt = &pppox_sk(sk)->proto.lac;
 	__u8 bits;
 	__u8 *ptr;
 
@@ -64,9 +66,9 @@
 
 	/* Put it back if it is a control packet. */
 	if (skb->data[sizeof(struct udphdr)] & L2TP_CONTROL_BIT)
-		return 1;
+		return opt->backlog_rcv(sk_udp, skb);
 
-	/* Now the packet is ours. Skip UDP header. */
+	/* Skip UDP header. */
 	skb_pull(skb, sizeof(struct udphdr));
 
 	/* Check the version. */
@@ -93,26 +95,12 @@
 			!skb_pull(skb, skb->data[-2] << 8 | skb->data[-1]))
 		goto drop;
 
-	/* Now ptr is pointing to the tunnel and skb is pointing to the payload.
-	 * We have to lock sk_udp to prevent sk from being closed. */
-	lock_sock(sk_udp);
-	sk = sk_udp->sk_user_data;
-	if (!sk) {
-		release_sock(sk_udp);
-		goto drop;
-	}
-	sock_hold(sk);
-	release_sock(sk_udp);
-	opt = &pppox_sk(sk)->proto.lac;
-
 	/* Check the tunnel and the session. */
-	if (unaligned(ptr)->u32 != opt->local) {
-		sock_put(sk);
+	if (unaligned(ptr)->u32 != opt->local)
 		goto drop;
-	}
 
-	/* Check the sequence if it is present. According to RFC 2661 page 10
-	 * and 43, the only thing to do is updating opt->sequencing. */
+	/* Check the sequence if it is present. According to RFC 2661 section
+	 * 5.4, the only thing to do is to update opt->sequencing. */
 	opt->sequencing = bits & L2TP_SEQUENCE_BIT;
 
 	/* Skip PPP address and control if they are present. */
@@ -124,26 +112,50 @@
 	if (skb->len >= 1 && skb->data[0] & 1)
 		skb_push(skb, 1)[0] = 0;
 
-	/* Finally, deliver the packet to PPP channel. We have to lock sk to
-	 * prevent another thread from calling pppox_unbind_sock(). */
+	/* Finally, deliver the packet to PPP channel. */
 	skb_orphan(skb);
-	lock_sock(sk);
 	ppp_input(&pppox_sk(sk)->chan, skb);
-	release_sock(sk);
-	sock_put(sk);
-	return 0;
-
+	return NET_RX_SUCCESS;
 drop:
 	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static int pppolac_recv(struct sock *sk_udp, struct sk_buff *skb)
+{
+	sock_hold(sk_udp);
+	sk_receive_skb(sk_udp, skb, 0);
 	return 0;
 }
 
+static struct sk_buff_head delivery_queue;
+
+static void pppolac_xmit_core(struct work_struct *delivery_work)
+{
+	mm_segment_t old_fs = get_fs();
+	struct sk_buff *skb;
+
+	set_fs(KERNEL_DS);
+	while ((skb = skb_dequeue(&delivery_queue))) {
+		struct sock *sk_udp = skb->sk;
+		struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
+		struct msghdr msg = {
+			.msg_iov = (struct iovec *)&iov,
+			.msg_iovlen = 1,
+			.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
+		};
+		sk_udp->sk_prot->sendmsg(NULL, sk_udp, &msg, skb->len);
+		kfree_skb(skb);
+	}
+	set_fs(old_fs);
+}
+
+static DECLARE_WORK(delivery_work, pppolac_xmit_core);
+
 static int pppolac_xmit(struct ppp_channel *chan, struct sk_buff *skb)
 {
 	struct sock *sk_udp = (struct sock *)chan->private;
 	struct pppolac_opt *opt = &pppox_sk(sk_udp->sk_user_data)->proto.lac;
-	struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
-	struct kvec iov;
 
 	/* Install PPP address and control. */
 	skb_push(skb, 2);
@@ -166,11 +178,10 @@
 	skb->data[1] = L2TP_VERSION;
 	unaligned(&skb->data[2])->u32 = opt->remote;
 
-	/* Now send the packet via UDP socket. */
-	iov.iov_base = skb->data;
-	iov.iov_len = skb->len;
-	kernel_sendmsg(sk_udp->sk_socket, &msg, &iov, 1, skb->len);
-	kfree_skb(skb);
+	/* Now send the packet via the delivery queue. */
+	skb_set_owner_w(skb, sk_udp);
+	skb_queue_tail(&delivery_queue, skb);
+	schedule_work(&delivery_work);
 	return 1;
 }
 
@@ -235,6 +246,7 @@
 	po->chan.mtu = PPP_MTU - 80;
 	po->proto.lac.local = unaligned(&addr->local)->u32;
 	po->proto.lac.remote = unaligned(&addr->remote)->u32;
+	po->proto.lac.backlog_rcv = sk_udp->sk_backlog_rcv;
 
 	error = ppp_register_channel(&po->chan);
 	if (error)
@@ -243,8 +255,8 @@
 	sk->sk_state = PPPOX_CONNECTED;
 	udp_sk(sk_udp)->encap_type = UDP_ENCAP_L2TPINUDP;
 	udp_sk(sk_udp)->encap_rcv = pppolac_recv;
+	sk_udp->sk_backlog_rcv = pppolac_recv_core;
 	sk_udp->sk_user_data = sk;
-
 out:
 	if (sock_udp) {
 		release_sock(sk_udp);
@@ -270,12 +282,12 @@
 
 	if (sk->sk_state != PPPOX_NONE) {
 		struct sock *sk_udp = (struct sock *)pppox_sk(sk)->chan.private;
-		pppox_unbind_sock(sk);
-
 		lock_sock(sk_udp);
-		sk_udp->sk_user_data = NULL;
+		pppox_unbind_sock(sk);
 		udp_sk(sk_udp)->encap_type = 0;
 		udp_sk(sk_udp)->encap_rcv = NULL;
+		sk_udp->sk_backlog_rcv = pppox_sk(sk)->proto.lac.backlog_rcv;
+		sk_udp->sk_user_data = NULL;
 		release_sock(sk_udp);
 		sockfd_put(sk_udp->sk_socket);
 	}
@@ -349,6 +361,8 @@
 	error = register_pppox_proto(PX_PROTO_OLAC, &pppolac_pppox_proto);
 	if (error)
 		proto_unregister(&pppolac_proto);
+	else
+		skb_queue_head_init(&delivery_queue);
 	return error;
 }
 
diff --git a/drivers/net/pppopns.c b/drivers/net/pppopns.c
index eae4bda..29809712 100644
--- a/drivers/net/pppopns.c
+++ b/drivers/net/pppopns.c
@@ -3,7 +3,6 @@
  * Driver for PPP on PPTP Network Server / PPPoPNS Socket (RFC 2637)
  *
  * Copyright (C) 2009 Google, Inc.
- * Author: Chia-chi Yeh <chiachi@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
@@ -22,14 +21,17 @@
  * and IPv6. */
 
 #include <linux/module.h>
+#include <linux/workqueue.h>
 #include <linux/skbuff.h>
 #include <linux/file.h>
+#include <linux/netdevice.h>
 #include <linux/net.h>
 #include <linux/ppp_defs.h>
 #include <linux/if.h>
 #include <linux/if_ppp.h>
 #include <linux/if_pppox.h>
 #include <linux/ppp_channel.h>
+#include <asm/uaccess.h>
 
 #define GRE_HEADER_SIZE		8
 
@@ -50,76 +52,90 @@
 	__u32	sequence;
 } __attribute__((packed));
 
-static void pppopns_recv(struct sock *sk_raw, int length)
+static int pppopns_recv_core(struct sock *sk_raw, struct sk_buff *skb)
 {
-	struct sock *sk;
-	struct pppopns_opt *opt;
-	struct sk_buff *skb;
+	struct sock *sk = (struct sock *)sk_raw->sk_user_data;
+	struct pppopns_opt *opt = &pppox_sk(sk)->proto.pns;
 	struct header *hdr;
 
-	/* Lock sk_raw to prevent sk from being closed. */
-	lock_sock(sk_raw);
-	sk = (struct sock *)sk_raw->sk_user_data;
-	if (!sk) {
-		release_sock(sk_raw);
-		return;
-	}
-	sock_hold(sk);
-	release_sock(sk_raw);
-	opt = &pppox_sk(sk)->proto.pns;
+	/* Skip transport header */
+	skb_pull(skb, skb_transport_header(skb) - skb->data);
 
-	/* Process packets from the receive queue. */
-	while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) {
-		skb_pull(skb, skb_transport_header(skb) - skb->data);
+	/* Drop the packet if it is too short. */
+	if (skb->len < GRE_HEADER_SIZE)
+		goto drop;
 
-		/* Drop the packet if it is too short. */
-		if (skb->len < GRE_HEADER_SIZE)
-			goto drop;
-
-		/* Check the header. */
-		hdr = (struct header *)skb->data;
-		if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local ||
+	/* Check the header. */
+	hdr = (struct header *)skb->data;
+	if (hdr->type != PPTP_GRE_TYPE || hdr->call != opt->local ||
 			(hdr->bits & PPTP_GRE_BITS_MASK) != PPTP_GRE_BITS)
-			goto drop;
+		goto drop;
 
-		/* Skip all fields including optional ones. */
-		if (!skb_pull(skb, GRE_HEADER_SIZE +
-				(hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) +
-				(hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0)))
-			goto drop;
+	/* Skip all fields including optional ones. */
+	if (!skb_pull(skb, GRE_HEADER_SIZE +
+			(hdr->bits & PPTP_GRE_SEQ_BIT ? 4 : 0) +
+			(hdr->bits & PPTP_GRE_ACK_BIT ? 4 : 0)))
+		goto drop;
 
-		/* Check the length. */
-		if (skb->len != ntohs(hdr->length))
-			goto drop;
+	/* Check the length. */
+	if (skb->len != ntohs(hdr->length))
+		goto drop;
 
-		/* Skip PPP address and control if they are present. */
-		if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
-				skb->data[1] == PPP_CTRL)
-			skb_pull(skb, 2);
+	/* Skip PPP address and control if they are present. */
+	if (skb->len >= 2 && skb->data[0] == PPP_ADDR &&
+			skb->data[1] == PPP_CTRL)
+		skb_pull(skb, 2);
 
-		/* Fix PPP protocol if it is compressed. */
-		if (skb->len >= 1 && skb->data[0] & 1)
-			skb_push(skb, 1)[0] = 0;
+	/* Fix PPP protocol if it is compressed. */
+	if (skb->len >= 1 && skb->data[0] & 1)
+		skb_push(skb, 1)[0] = 0;
 
-		/* Deliver the packet to PPP channel. We have to lock sk to
-		 * prevent another thread from calling pppox_unbind_sock(). */
-		skb_orphan(skb);
-		lock_sock(sk);
-		ppp_input(&pppox_sk(sk)->chan, skb);
-		release_sock(sk);
-		continue;
+	/* Finally, deliver the packet to PPP channel. */
+	skb_orphan(skb);
+	ppp_input(&pppox_sk(sk)->chan, skb);
+	return NET_RX_SUCCESS;
 drop:
+	kfree_skb(skb);
+	return NET_RX_DROP;
+}
+
+static void pppopns_recv(struct sock *sk_raw, int length)
+{
+	struct sk_buff *skb;
+	while ((skb = skb_dequeue(&sk_raw->sk_receive_queue))) {
+		sock_hold(sk_raw);
+		sk_receive_skb(sk_raw, skb, 0);
+	}
+}
+
+static struct sk_buff_head delivery_queue;
+
+static void pppopns_xmit_core(struct work_struct *delivery_work)
+{
+	mm_segment_t old_fs = get_fs();
+	struct sk_buff *skb;
+
+	set_fs(KERNEL_DS);
+	while ((skb = skb_dequeue(&delivery_queue))) {
+		struct sock *sk_raw = skb->sk;
+		struct kvec iov = {.iov_base = skb->data, .iov_len = skb->len};
+		struct msghdr msg = {
+			.msg_iov = (struct iovec *)&iov,
+			.msg_iovlen = 1,
+			.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT,
+		};
+		sk_raw->sk_prot->sendmsg(NULL, sk_raw, &msg, skb->len);
 		kfree_skb(skb);
 	}
-	sock_put(sk);
+	set_fs(old_fs);
 }
 
+static DECLARE_WORK(delivery_work, pppopns_xmit_core);
+
 static int pppopns_xmit(struct ppp_channel *chan, struct sk_buff *skb)
 {
 	struct sock *sk_raw = (struct sock *)chan->private;
 	struct pppopns_opt *opt = &pppox_sk(sk_raw->sk_user_data)->proto.pns;
-	struct msghdr msg = {.msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT};
-	struct kvec iov;
 	struct header *hdr;
 	__u16 length;
 
@@ -138,11 +154,10 @@
 	hdr->sequence = htonl(opt->sequence);
 	opt->sequence++;
 
-	/* Now send the packet via RAW socket. */
-	iov.iov_base = skb->data;
-	iov.iov_len = skb->len;
-	kernel_sendmsg(sk_raw->sk_socket, &msg, &iov, 1, skb->len);
-	kfree_skb(skb);
+	/* Now send the packet via the delivery queue. */
+	skb_set_owner_w(skb, sk_raw);
+	skb_queue_tail(&delivery_queue, skb);
+	schedule_work(&delivery_work);
 	return 1;
 }
 
@@ -208,15 +223,19 @@
 	po->chan.mtu = PPP_MTU - 80;
 	po->proto.pns.local = addr->local;
 	po->proto.pns.remote = addr->remote;
+	po->proto.pns.data_ready = sk_raw->sk_data_ready;
+	po->proto.pns.backlog_rcv = sk_raw->sk_backlog_rcv;
 
 	error = ppp_register_channel(&po->chan);
 	if (error)
 		goto out;
 
 	sk->sk_state = PPPOX_CONNECTED;
-	sk_raw->sk_user_data = sk;
+	lock_sock(sk_raw);
 	sk_raw->sk_data_ready = pppopns_recv;
-
+	sk_raw->sk_backlog_rcv = pppopns_recv_core;
+	sk_raw->sk_user_data = sk;
+	release_sock(sk_raw);
 out:
 	if (sock_tcp)
 		sockfd_put(sock_tcp);
@@ -241,8 +260,10 @@
 
 	if (sk->sk_state != PPPOX_NONE) {
 		struct sock *sk_raw = (struct sock *)pppox_sk(sk)->chan.private;
-		pppox_unbind_sock(sk);
 		lock_sock(sk_raw);
+		pppox_unbind_sock(sk);
+		sk_raw->sk_data_ready = pppox_sk(sk)->proto.pns.data_ready;
+		sk_raw->sk_backlog_rcv = pppox_sk(sk)->proto.pns.backlog_rcv;
 		sk_raw->sk_user_data = NULL;
 		release_sock(sk_raw);
 		sock_release(sk_raw->sk_socket);
@@ -317,6 +338,8 @@
 	error = register_pppox_proto(PX_PROTO_OPNS, &pppopns_pppox_proto);
 	if (error)
 		proto_unregister(&pppopns_proto);
+	else
+		skb_queue_head_init(&delivery_queue);
 	return error;
 }
 
diff --git a/drivers/net/smc911x.c b/drivers/net/smc911x.c
index 15376b3..62cf939 100644
--- a/drivers/net/smc911x.c
+++ b/drivers/net/smc911x.c
@@ -269,7 +269,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	unsigned mask, cfg, cr;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
@@ -326,7 +326,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	unsigned cr;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", CARDNAME, __func__);
 
@@ -516,7 +516,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	unsigned int free;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	DBG(SMC_DEBUG_FUNC | SMC_DEBUG_TX, "%s: --> %s\n",
 		dev->name, __func__);
@@ -790,7 +790,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	int timeout;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 	unsigned int reg;
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
@@ -890,7 +890,7 @@
 	int my_phy_caps; /* My PHY capabilities */
 	int my_ad_caps; /* My Advertised capabilities */
 	int status;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s()\n", dev->name, __func__);
 
@@ -1011,7 +1011,7 @@
 	struct smc911x_local *lp = netdev_priv(dev);
 	unsigned int status, mask, timeout;
 	unsigned int rx_overrun=0, cr, pkts;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
@@ -1267,7 +1267,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	int status, mask;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
@@ -1305,7 +1305,7 @@
 	struct smc911x_local *lp = netdev_priv(dev);
 	unsigned int multicast_table[2];
 	unsigned int mcr, update_multicast = 0;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 
@@ -1478,7 +1478,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	int ret, status;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	DBG(SMC_DEBUG_FUNC, "%s: --> %s\n", dev->name, __func__);
 	cmd->maxtxpkt = 1;
@@ -1519,7 +1519,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	int ret;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	if (lp->phy_type != 0) {
 		spin_lock_irqsave(&lp->lock, flags);
@@ -1552,7 +1552,7 @@
 {
 	struct smc911x_local *lp = netdev_priv(dev);
 	int ret = -EINVAL;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 
 	if (lp->phy_type != 0) {
 		spin_lock_irqsave(&lp->lock, flags);
@@ -1586,7 +1586,7 @@
 										 struct ethtool_regs* regs, void *buf)
 {
 	struct smc911x_local *lp = netdev_priv(dev);
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 	u32 reg,i,j=0;
 	u32 *data = (u32*)buf;
 
diff --git a/drivers/net/smc911x.h b/drivers/net/smc911x.h
index 50fcf11..31eae34 100644
--- a/drivers/net/smc911x.h
+++ b/drivers/net/smc911x.h
@@ -740,7 +740,7 @@
 #define SMC_SET_FIFO_INT(lp, x)		SMC_outl( x, lp, FIFO_INT )
 #define SMC_SET_FIFO_TDA(lp, x)					\
 	do {							\
-		unsigned long __flags;				\
+		unsigned long uninitialized_var(__flags);	\
 		int __mask;					\
 		local_irq_save(__flags);			\
 		__mask = SMC_GET_FIFO_INT((lp)) & ~(0xFF<<24);	\
diff --git a/drivers/net/smsc911x.c b/drivers/net/smsc911x.c
index d1590ac..d603c4e 100644
--- a/drivers/net/smsc911x.c
+++ b/drivers/net/smsc911x.c
@@ -318,7 +318,7 @@
 			goto out;
 		}
 
-	SMSC_WARNING(HW, "Timed out waiting for MII write to finish");
+	SMSC_WARNING(HW, "Timed out waiting for MII read to finish");
 	reg = -EIO;
 
 out:
@@ -730,8 +730,8 @@
 			 * usage is 10/100 indicator */
 			pdata->gpio_setting = smsc911x_reg_read(pdata,
 				GPIO_CFG);
-			if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_)
-			    && (!pdata->using_extphy)) {
+			if ((pdata->gpio_setting & GPIO_CFG_LED1_EN_) &&
+			    (!pdata->using_extphy)) {
 				/* Force 10/100 LED off, after saving
 				 * orginal GPIO configuration */
 				pdata->gpio_orig_setting = pdata->gpio_setting;
@@ -769,7 +769,7 @@
 		return -ENODEV;
 	}
 
-	phydev = phy_connect(dev, phydev->dev.bus_id,
+	phydev = phy_connect(dev, dev_name(&phydev->dev),
 		&smsc911x_phy_adjust_link, 0, pdata->config.phy_interface);
 
 	if (IS_ERR(phydev)) {
@@ -778,7 +778,8 @@
 	}
 
 	pr_info("%s: attached PHY driver [%s] (mii_bus:phy_addr=%s, irq=%d)\n",
-		dev->name, phydev->drv->name, phydev->dev.bus_id, phydev->irq);
+		dev->name, phydev->drv->name,
+		dev_name(&phydev->dev), phydev->irq);
 
 	/* mask with MAC supported features */
 	phydev->supported &= (PHY_BASIC_FEATURES | SUPPORTED_Pause |
@@ -797,7 +798,7 @@
 	SMSC_TRACE(HW, "Passed Loop Back Test");
 #endif				/* USE_PHY_WORK_AROUND */
 
-	SMSC_TRACE(HW, "phy initialised succesfully");
+	SMSC_TRACE(HW, "phy initialised successfully");
 	return 0;
 }
 
@@ -893,22 +894,22 @@
 			SMSC_WARNING(HW,
 				"Packet tag reserved bit is high");
 		} else {
-			if (unlikely(tx_stat & 0x00008000)) {
+			if (unlikely(tx_stat & TX_STS_ES_)) {
 				dev->stats.tx_errors++;
 			} else {
 				dev->stats.tx_packets++;
 				dev->stats.tx_bytes += (tx_stat >> 16);
 			}
-			if (unlikely(tx_stat & 0x00000100)) {
+			if (unlikely(tx_stat & TX_STS_EXCESS_COL_)) {
 				dev->stats.collisions += 16;
 				dev->stats.tx_aborted_errors += 1;
 			} else {
 				dev->stats.collisions +=
 				    ((tx_stat >> 3) & 0xF);
 			}
-			if (unlikely(tx_stat & 0x00000800))
+			if (unlikely(tx_stat & TX_STS_LOST_CARRIER_))
 				dev->stats.tx_carrier_errors += 1;
-			if (unlikely(tx_stat & 0x00000200)) {
+			if (unlikely(tx_stat & TX_STS_LATE_COL_)) {
 				dev->stats.collisions++;
 				dev->stats.tx_aborted_errors++;
 			}
@@ -922,19 +923,17 @@
 {
 	int crc_err = 0;
 
-	if (unlikely(rxstat & 0x00008000)) {
+	if (unlikely(rxstat & RX_STS_ES_)) {
 		dev->stats.rx_errors++;
-		if (unlikely(rxstat & 0x00000002)) {
+		if (unlikely(rxstat & RX_STS_CRC_ERR_)) {
 			dev->stats.rx_crc_errors++;
 			crc_err = 1;
 		}
 	}
 	if (likely(!crc_err)) {
-		if (unlikely((rxstat & 0x00001020) == 0x00001020)) {
-			/* Frame type indicates length,
-			 * and length error is set */
+		if (unlikely((rxstat & RX_STS_FRAME_TYPE_) &&
+			     (rxstat & RX_STS_LENGTH_ERR_)))
 			dev->stats.rx_length_errors++;
-		}
 		if (rxstat & RX_STS_MCAST_)
 			dev->stats.multicast++;
 	}
@@ -953,7 +952,7 @@
 		do {
 			udelay(1);
 			val = smsc911x_reg_read(pdata, RX_DP_CTRL);
-		} while (--timeout && (val & RX_DP_CTRL_RX_FFWD_));
+		} while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout);
 
 		if (unlikely(timeout == 0))
 			SMSC_WARNING(HW, "Timed out waiting for "
@@ -1160,8 +1159,8 @@
 
 	/* Make sure EEPROM has finished loading before setting GPIO_CFG */
 	timeout = 50;
-	while ((timeout--) &&
-	       (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_)) {
+	while ((smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) &&
+	       --timeout) {
 		udelay(10);
 	}
 
@@ -1250,7 +1249,7 @@
 	napi_enable(&pdata->napi);
 
 	temp = smsc911x_reg_read(pdata, INT_EN);
-	temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_);
+	temp |= (INT_EN_TDFA_EN_ | INT_EN_RSFL_EN_ | INT_EN_RXSTOP_INT_EN_);
 	smsc911x_reg_write(pdata, INT_EN, temp);
 
 	spin_lock_irq(&pdata->mac_lock);
@@ -1422,11 +1421,6 @@
 
 			/* Request the hardware to stop, then perform the
 			 * update when we get an RX_STOP interrupt */
-			smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
-			temp = smsc911x_reg_read(pdata, INT_EN);
-			temp |= INT_EN_RXSTOP_INT_EN_;
-			smsc911x_reg_write(pdata, INT_EN, temp);
-
 			temp = smsc911x_mac_read(pdata, MAC_CR);
 			temp &= ~(MAC_CR_RXEN_);
 			smsc911x_mac_write(pdata, MAC_CR, temp);
@@ -1465,9 +1459,6 @@
 		/* Called when there is a multicast update scheduled and
 		 * it is now safe to complete the update */
 		SMSC_TRACE(INTR, "RX Stop interrupt");
-		temp = smsc911x_reg_read(pdata, INT_EN);
-		temp &= (~INT_EN_RXSTOP_INT_EN_);
-		smsc911x_reg_write(pdata, INT_EN, temp);
 		smsc911x_reg_write(pdata, INT_STS, INT_STS_RXSTOP_INT_);
 		smsc911x_rx_multicast_update_workaround(pdata);
 		serviced = IRQ_HANDLED;
@@ -1662,6 +1653,7 @@
 					  u8 address, u8 data)
 {
 	u32 op = E2P_CMD_EPC_CMD_ERASE_ | address;
+	u32 temp;
 	int ret;
 
 	SMSC_TRACE(DRV, "address 0x%x, data 0x%x", address, data);
@@ -1670,6 +1662,10 @@
 	if (!ret) {
 		op = E2P_CMD_EPC_CMD_WRITE_ | address;
 		smsc911x_reg_write(pdata, E2P_DATA, (u32)data);
+
+		/* Workaround for hardware read-after-write restriction */
+		temp = smsc911x_reg_read(pdata, BYTE_TEST);
+
 		ret = smsc911x_eeprom_send_cmd(pdata, op);
 	}
 
@@ -1746,6 +1742,7 @@
 	.ndo_do_ioctl		= smsc911x_do_ioctl,
 	.ndo_validate_addr	= eth_validate_addr,
 	.ndo_set_mac_address 	= eth_mac_addr,
+	.ndo_change_mtu		= eth_change_mtu,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 	.ndo_poll_controller	= smsc911x_poll_controller,
 #endif
@@ -1882,7 +1879,7 @@
 	if (!res)
 		res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 
-	release_mem_region(res->start, res->end - res->start);
+	release_mem_region(res->start, resource_size(res));
 
 	iounmap(pdata->ioaddr);
 
@@ -1896,9 +1893,9 @@
 	struct net_device *dev;
 	struct smsc911x_data *pdata;
 	struct smsc911x_platform_config *config = pdev->dev.platform_data;
-	struct resource *res;
+	struct resource *res, *irq_res;
 	unsigned int intcfg = 0;
-	int res_size;
+	int res_size, irq_flags;
 	int retval;
 	DECLARE_MAC_BUF(mac);
 
@@ -1921,7 +1918,15 @@
 		retval = -ENODEV;
 		goto out_0;
 	}
-	res_size = res->end - res->start;
+	res_size = resource_size(res);
+
+	irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+	if (!irq_res) {
+		pr_warning("%s: Could not allocate irq resource.\n",
+			SMSC_CHIPNAME);
+		retval = -ENODEV;
+		goto out_0;
+	}
 
 	if (!request_mem_region(res->start, res_size, SMSC_CHIPNAME)) {
 		retval = -EBUSY;
@@ -1939,7 +1944,8 @@
 
 	pdata = netdev_priv(dev);
 
-	dev->irq = platform_get_irq(pdev, 0);
+	dev->irq = irq_res->start;
+	irq_flags = irq_res->flags & IRQF_TRIGGER_MASK;
 	pdata->ioaddr = ioremap_nocache(res->start, res_size);
 
 	/* copy config parameters across to pdata */
@@ -1972,8 +1978,8 @@
 	smsc911x_reg_write(pdata, INT_EN, 0);
 	smsc911x_reg_write(pdata, INT_STS, 0xFFFFFFFF);
 
-	retval = request_irq(dev->irq, smsc911x_irqhandler, IRQF_DISABLED,
-			     dev->name, dev);
+	retval = request_irq(dev->irq, smsc911x_irqhandler,
+			     irq_flags | IRQF_SHARED, dev->name, dev);
 	if (retval) {
 		SMSC_WARNING(PROBE,
 			"Unable to claim requested irq: %d", dev->irq);
@@ -2033,8 +2039,7 @@
 
 	spin_unlock_irq(&pdata->mac_lock);
 
-	dev_info(&dev->dev, "MAC Address: %s\n",
-		 print_mac(mac, dev->dev_addr));
+	dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
 
 	return 0;
 
@@ -2048,7 +2053,7 @@
 out_free_netdev_2:
 	free_netdev(dev);
 out_release_io_1:
-	release_mem_region(res->start, res->end - res->start);
+	release_mem_region(res->start, resource_size(res));
 out_0:
 	return retval;
 }
diff --git a/drivers/net/smsc911x.h b/drivers/net/smsc911x.h
index 2b76654..016360c 100644
--- a/drivers/net/smsc911x.h
+++ b/drivers/net/smsc911x.h
@@ -30,7 +30,7 @@
 #define SMSC_NAPI_WEIGHT	16
 
 /* implements a PHY loopback test at initialisation time, to ensure a packet
- * can be succesfully looped back */
+ * can be successfully looped back */
 #define USE_PHY_WORK_AROUND
 
 #define DPRINTK(nlevel, klevel, fmt, args...) \
@@ -81,12 +81,19 @@
 
 #define RX_STATUS_FIFO			0x40
 #define RX_STS_ES_			0x00008000
+#define RX_STS_LENGTH_ERR_		0x00001000
 #define RX_STS_MCAST_			0x00000400
+#define RX_STS_FRAME_TYPE_		0x00000020
+#define RX_STS_CRC_ERR_			0x00000002
 
 #define RX_STATUS_FIFO_PEEK		0x44
 
 #define TX_STATUS_FIFO			0x48
 #define TX_STS_ES_			0x00008000
+#define TX_STS_LOST_CARRIER_		0x00000800
+#define TX_STS_NO_CARRIER_		0x00000400
+#define TX_STS_LATE_COL_		0x00000200
+#define TX_STS_EXCESS_COL_		0x00000100
 
 #define TX_STATUS_FIFO_PEEK		0x4C
 
diff --git a/drivers/power/twl4030_bci_battery.c b/drivers/power/twl4030_bci_battery.c
index c716e09..a76b3a8 100644
--- a/drivers/power/twl4030_bci_battery.c
+++ b/drivers/power/twl4030_bci_battery.c
@@ -164,6 +164,7 @@
 
 	struct power_supply	bat;
 	struct power_supply	bk_bat;
+	struct power_supply     usb_bat;
 	struct delayed_work	twl4030_bci_monitor_work;
 	struct delayed_work	twl4030_bk_bci_monitor_work;
 };
@@ -182,7 +183,7 @@
 static inline int twl4030charger_presence_evt(void)
 {
 	int ret;
-	u8 chg_sts, set = 0, clear = 0;
+	u8 uninitialized_var(chg_sts), set = 0, clear = 0;
 
 	/* read charger power supply status */
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &chg_sts,
@@ -237,7 +238,7 @@
 static int twl4030battery_presence_evt(void)
 {
 	int ret;
-	u8 batstsmchg, batstspchg;
+	u8 uninitialized_var(batstsmchg), uninitialized_var(batstspchg);
 
 	/* check for the battery presence in main charge*/
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
@@ -278,7 +279,7 @@
 static int twl4030battery_level_evt(void)
 {
 	int ret;
-	u8 mfst;
+	u8 uninitialized_var(mfst);
 
 	/* checking for threshold event */
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
@@ -322,7 +323,8 @@
  */
 static irqreturn_t twl4030battery_interrupt(int irq, void *_di)
 {
-	u8 isr1a_val, isr2a_val, clear_2a, clear_1a;
+	u8 uninitialized_var(isr1a_val), uninitialized_var(isr2a_val);
+	u8 clear_2a, clear_1a;
 	int ret;
 
 #ifdef CONFIG_LOCKDEP
@@ -621,7 +623,7 @@
  */
 static int twl4030battery_temperature(void)
 {
-	u8 val;
+	u8 uninitialized_var(val);
 	int temp, curr, volt, res, ret;
 
 	/* Getting and calculating the thermistor voltage */
@@ -680,7 +682,7 @@
 static int twl4030battery_current(void)
 {
 	int ret, curr = read_bci_val(T2_BATTERY_CUR);
-	u8 val;
+	u8 uninitialized_var(val);
 
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
 		REG_BCICTL1);
@@ -725,7 +727,7 @@
 static int twl4030charger_presence(void)
 {
 	int ret;
-	u8 hwsts;
+	u8 uninitialized_var(hwsts);
 
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_MASTER, &hwsts,
 		REG_STS_HW_CONDITIONS);
@@ -753,7 +755,7 @@
 static int twl4030bci_status(void)
 {
 	int ret;
-	u8 status;
+	u8 uninitialized_var(status);
 
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE,
 		&status, REG_BCIMSTATEC);
@@ -768,7 +770,7 @@
 static int read_bci_val(u8 reg)
 {
 	int ret, temp;
-	u8 val;
+	u8 uninitialized_var(val);
 
 	/* reading MSB */
 	ret = twl4030_i2c_read_u8(TWL4030_MODULE_MAIN_CHARGE, &val,
@@ -861,6 +863,10 @@
 	POWER_SUPPLY_PROP_VOLTAGE_NOW,
 };
 
+static enum power_supply_property twl4030_usb_battery_props[] = {
+	POWER_SUPPLY_PROP_ONLINE,
+};
+
 static void
 twl4030_bk_bci_battery_read_status(struct twl4030_bci_device_info *di)
 {
@@ -887,13 +893,25 @@
 static void
 twl4030_bci_battery_update_status(struct twl4030_bci_device_info *di)
 {
+	int old_charge_source = di->charge_rsoc;
+
 	twl4030_bci_battery_read_status(di);
 	di->charge_status = POWER_SUPPLY_STATUS_UNKNOWN;
-
 	if (power_supply_am_i_supplied(&di->bat))
 		di->charge_status = POWER_SUPPLY_STATUS_CHARGING;
 	else
 		di->charge_status = POWER_SUPPLY_STATUS_DISCHARGING;
+
+	/*
+	 * Since Charger interrupt only happens for AC plug-in
+	 * and not for usb plug-in, we use the next update
+	 * cycle to update the status of the power_supply
+	 * change to user space.
+	 */
+	di->charge_rsoc = usb_charger_flag;
+	if (old_charge_source !=  di->charge_rsoc)
+		power_supply_changed(&di->usb_bat);
+
 }
 
 static void twl4030_bci_battery_work(struct work_struct *work)
@@ -937,6 +955,21 @@
 	return 0;
 }
 
+static int twl4030_usb_battery_get_property(struct power_supply *psy,
+					enum power_supply_property psp,
+					union power_supply_propval *val)
+{
+	switch (psp) {
+	case POWER_SUPPLY_PROP_ONLINE:
+		val->intval = usb_charger_flag;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
 static int twl4030_bci_battery_get_property(struct power_supply *psy,
 					enum power_supply_property psp,
 					union power_supply_propval *val)
@@ -1040,6 +1073,20 @@
 	di->bk_bat.get_property = twl4030_bk_bci_battery_get_property;
 	di->bk_bat.external_power_changed = NULL;
 
+	/*
+	 * Android expects a battery type POWER_SUPPLY_TYPE_USB
+	 * as a usb charger battery. This battery
+	 * and its "online" property are used to determine if the
+	 * usb cable is plugged in or not.
+	 */
+	di->usb_bat.name = "twl4030_bci_usb_src";
+	di->usb_bat.supplied_to = twl4030_bci_supplied_to;
+	di->usb_bat.type = POWER_SUPPLY_TYPE_USB;
+	di->usb_bat.properties = twl4030_usb_battery_props;
+	di->usb_bat.num_properties = ARRAY_SIZE(twl4030_usb_battery_props);
+	di->usb_bat.get_property = twl4030_usb_battery_get_property;
+	di->usb_bat.external_power_changed = NULL;
+
 	twl4030charger_ac_en(ENABLE);
 	twl4030charger_usb_en(ENABLE);
 	twl4030battery_hw_level_en(ENABLE);
@@ -1100,8 +1147,16 @@
 				twl4030_bk_bci_battery_work);
 	schedule_delayed_work(&di->twl4030_bk_bci_monitor_work, 500);
 
+	ret = power_supply_register(&pdev->dev, &di->usb_bat);
+	if (ret) {
+		dev_dbg(&pdev->dev, "failed to register usb battery\n");
+		goto usb_batt_failed;
+	}
+
 	return 0;
 
+usb_batt_failed:
+	power_supply_unregister(&di->bk_bat);
 bk_batt_failed:
 	power_supply_unregister(&di->bat);
 batt_failed:
diff --git a/drivers/rtc/rtc-twl4030.c b/drivers/rtc/rtc-twl4030.c
index ad35f76..4926d24 100644
--- a/drivers/rtc/rtc-twl4030.c
+++ b/drivers/rtc/rtc-twl4030.c
@@ -189,7 +189,9 @@
 {
 	unsigned char rtc_data[ALL_TIME_REGS + 1];
 	int ret;
-	u8 save_control;
+	u8 uninitialized_var(save_control);
+
+	memset(rtc_data, 0, (ALL_TIME_REGS + 1));
 
 	ret = twl4030_rtc_read_u8(&save_control, REG_RTC_CTRL_REG);
 	if (ret < 0)
@@ -221,10 +223,12 @@
 
 static int twl4030_rtc_set_time(struct device *dev, struct rtc_time *tm)
 {
-	unsigned char save_control;
+	unsigned char uninitialized_var(save_control);
 	unsigned char rtc_data[ALL_TIME_REGS + 1];
 	int ret;
 
+	memset(rtc_data, 0, (ALL_TIME_REGS + 1));
+
 	rtc_data[1] = bin2bcd(tm->tm_sec);
 	rtc_data[2] = bin2bcd(tm->tm_min);
 	rtc_data[3] = bin2bcd(tm->tm_hour);
@@ -323,7 +327,7 @@
 	unsigned long events = 0;
 	int ret = IRQ_NONE;
 	int res;
-	u8 rd_reg;
+	u8 uninitialized_var(rd_reg);
 
 #ifdef CONFIG_LOCKDEP
 	/* WORKAROUND for lockdep forcing IRQF_DISABLED on us, which
@@ -392,7 +396,7 @@
 	struct rtc_device *rtc;
 	int ret = 0;
 	int irq = platform_get_irq(pdev, 0);
-	u8 rd_reg;
+	u8 uninitialized_var(rd_reg);
 
 	if (irq <= 0)
 		return -EINVAL;
@@ -495,9 +499,7 @@
 {
 	irqstat = rtc_irq_bits;
 
-	/* REVISIT alarm may need to wake us from sleep */
-	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M |
-			 BIT_RTC_INTERRUPTS_REG_IT_ALARM_M);
+	mask_rtc_irq_bit(BIT_RTC_INTERRUPTS_REG_IT_TIMER_M);
 	return 0;
 }
 
diff --git a/drivers/serial/omap-serial.c b/drivers/serial/omap-serial.c
index 1a0e74d..ddc6ac6 100644
--- a/drivers/serial/omap-serial.c
+++ b/drivers/serial/omap-serial.c
@@ -32,28 +32,26 @@
 #include <linux/serial_core.h>
 #include <linux/io.h>
 #include <linux/dma-mapping.h>
+#include <mach/mux.h>
+#include <mach/control.h>
+#include <linux/wakelock.h>
 
 #include <asm/irq.h>
-#include <asm/dma.h>
 
 #include <mach/dmtimer.h>
 #include <mach/omap-serial.h>
 #include <mach/gpio.h>
 #include <mach/dma.h>
 #include <mach/io.h>
-#ifdef CONFIG_OMAP3_PM
-#include <../arch/arm/mach-omap2/ti-compat.h>
-#include <../arch/arm/mach-omap2/prcm-regs.h>
-#endif
 
 unsigned long isr8250_activity;
 
 #define CONSOLE_NAME	"console="
 
 #ifdef CONFIG_ARCH_OMAP34XX
-#define OMAP_MDR1_DISABLE 0x07
-#define OMAP_MDR1_MODE13X 0x03
-#define OMAP_MDR1_MODE16X 0x00
+#define OMAP_MDR1_DISABLE 	0x07
+#define OMAP_MDR1_MODE13X 	0x03
+#define OMAP_MDR1_MODE16X 	0x00
 #define OMAP_MODE13X_SPEED	230400
 #endif
 
@@ -69,16 +67,16 @@
 
 /*
  * We default to IRQ0 for the "no irq" hack.   Some
- * machine types want others as well - they're free
+ * machine types want  others as well - they're free
  * to redefine this in their header file.
  */
 #define is_real_interrupt(irq)  ((irq) != 0)
 
-// TBD: move this to header file
+/* TBD: move this to header file */
 static u8 uart_dma_tx[MAX_UARTS + 1] =
-    { OMAP24XX_DMA_UART1_TX, OMAP24XX_DMA_UART2_TX, OMAP24XX_DMA_UART3_TX };
+	{OMAP24XX_DMA_UART1_TX, OMAP24XX_DMA_UART2_TX, OMAP24XX_DMA_UART3_TX};
 static u8 uart_dma_rx[MAX_UARTS + 1] =
-    { OMAP24XX_DMA_UART1_RX, OMAP24XX_DMA_UART2_RX, OMAP24XX_DMA_UART3_RX };
+	{OMAP24XX_DMA_UART1_RX, OMAP24XX_DMA_UART2_RX, OMAP24XX_DMA_UART3_RX};
 
 
 struct uart_omap_dma {
@@ -110,6 +108,7 @@
 	unsigned char		ier;
 	unsigned char		lcr;
 	unsigned char		mcr;
+	unsigned char		efr;
 	int			use_dma;
 	int			is_buf_dma_alloced;
 	/*
@@ -120,22 +119,26 @@
 	unsigned int		lsr_break_flag;
 #define MSR_SAVE_FLAGS UART_MSR_ANY_DELTA
 	unsigned char		msr_saved_flags;
-	char			name[12];
+	char			name[20];
 	int			use_console;
 	spinlock_t		uart_lock;
-	char			dev_name[50];
 };
 
 static struct uart_omap_port *ui[MAX_UARTS + 1];
 unsigned int fcr[MAX_UARTS];
+static struct wake_lock omap_serial_wakelock;
 
 /* Forward declaration of dma callback functions */
 static void uart_tx_dma_callback(int lch, u16 ch_status, void *data);
-static void serial_omap_display_reg(struct uart_port *port);
 static void serial_omap_rx_timeout(unsigned long uart_no);
 static void serial_omap_start_rxdma(struct uart_omap_port *up);
 
-int console_detect(char *str){
+#ifdef DEBUG
+static void serial_omap_display_reg(struct uart_port *port);
+#endif
+
+int console_detect(char *str)
+{
 	extern char *saved_command_line;
 	char *next, *start = NULL;
 	int i;
@@ -150,7 +153,6 @@
 		} else {
 			next++;
 		}
-
 	}
 	if (!start)
 		return -EPERM;
@@ -158,8 +160,8 @@
 	start = strchr(start, '=') + 1;
 	while (*start != ',') {
 		str[i++] = *start++;
-		if (i > 6){
-			printk("Invalid Console Name\n");
+		if (i > 6) {
+			printk(KERN_INFO "Invalid Console Name\n");
 			return -EPERM;
 		}
 	}
@@ -212,7 +214,7 @@
 static void serial_omap_stop_rxdma(struct uart_omap_port *up)
 {
 	if (up->uart_dma.rx_dma_state) {
-		del_timer(&up->uart_dma.rx_timer);
+		del_timer_sync(&up->uart_dma.rx_timer);
 		omap_stop_dma(up->uart_dma.rx_dma_channel);
 		omap_free_dma(up->uart_dma.rx_dma_channel);
 		up->uart_dma.rx_dma_channel = 0xFF;
@@ -224,7 +226,7 @@
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 
-	DPRINTK("serial_omap_enable_ms+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_enable_ms+%d\n", up->pdev->id);
 	up->ier |= UART_IER_MSI;
 	serial_out(up, UART_IER, up->ier);
 }
@@ -234,11 +236,12 @@
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 	if (up->use_dma) {
 		if (up->uart_dma.tx_dma_channel != 0xFF) {
-		/*
-		 * Check if dma is still active . If yes do nothing , return.
-		 * Else stop dma
-		 */
-			int status = omap_readl(OMAP34XX_DMA4_BASE + OMAP_DMA4_CCR(up->uart_dma.tx_dma_channel));
+			/*
+			 * Check if dma is still active . If yes do nothing,
+			 * return. Else stop dma
+			 */
+			int status = omap_readl(OMAP34XX_DMA4_BASE +
+				    OMAP_DMA4_CCR(up->uart_dma.tx_dma_channel));
 			if (status & (1 << 7))
 				return;
 			omap_stop_dma(up->uart_dma.tx_dma_channel);
@@ -251,13 +254,6 @@
 		up->ier &= ~UART_IER_THRI;
 		serial_out(up, UART_IER, up->ier);
 	}
-#ifdef CONFIG_OMAP3_PM
-	if (!up->uart_dma.rx_dma_state) {
-		unsigned int tmp;
-		tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7) | (2 << 3);
-		serial_out(up, UART_OMAP_SYSC, tmp); /* smart-idle */
-	}
-#endif
 }
 
 static void serial_omap_stop_rx(struct uart_port *port)
@@ -267,6 +263,10 @@
 	up->ier &= ~UART_IER_RLSI;
 	up->port.read_status_mask &= ~UART_LSR_DR;
 	serial_out(up, UART_IER, up->ier);
+	/*Disable the UART CTS wakeup for UART1,UART2*/
+	if ((!port->suspended && (((up->pdev->id - 1) == UART1) ||
+			((up->pdev->id  - 1) == UART2))))
+		omap_uart_cts_wakeup((up->pdev->id - 1), 0);
 
 }
 
@@ -354,7 +354,6 @@
 	}
 
 	count = up->port.fifosize / 4;
-
 	do {
 		serial_out(up, UART_TX, xmit->buf[xmit->tail]);
 		xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
@@ -373,23 +372,13 @@
 static void serial_omap_start_tx(struct uart_port *port)
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
-#ifdef CONFIG_OMAP3_PM
-		/* Disallow OCP bus idle. UART TX irqs are not seen during
-		 * bus idle. Alternative is to set kernel timer at fifo
-		 * drain rate.
-		 */
-		unsigned int tmp;
-		tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7) | (1 << 3);
-		serial_out(up, UART_OMAP_SYSC, tmp); /* no-idle */
-#endif
-
 	if (up->use_dma && !(up->port.x_char)) {
 
 		struct circ_buf *xmit = &up->port.info->xmit;
-		unsigned int start = up->uart_dma.tx_buf_dma_phys + (xmit->tail & (UART_XMIT_SIZE - 1));
-		if (uart_circ_empty(xmit) || up->uart_dma.tx_dma_state) {
+		unsigned int start = up->uart_dma.tx_buf_dma_phys +
+				     (xmit->tail & (UART_XMIT_SIZE - 1));
+		if (uart_circ_empty(xmit) || up->uart_dma.tx_dma_state)
 			return;
-		}
 		spin_lock(&(up->uart_dma.tx_lock));
 		up->uart_dma.tx_dma_state = 1;
 		spin_unlock(&(up->uart_dma.tx_lock));
@@ -398,21 +387,26 @@
 		/* It is a circular buffer. See if the buffer has wounded back.
 		 * If yes it will have to be transferred in two separate dma
 		 * transfers */
-		if (start + up->uart_dma.tx_buf_size >= up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
-			up->uart_dma.tx_buf_size = (up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
+		if (start + up->uart_dma.tx_buf_size >=
+				up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE)
+			up->uart_dma.tx_buf_size =
+				(up->uart_dma.tx_buf_dma_phys +
+				UART_XMIT_SIZE) - start;
 
-		if (up->uart_dma.tx_dma_channel == 0xFF) {
-			omap_request_dma(uart_dma_tx[up->pdev->id-1],"UART Tx DMA",
-			(void *)uart_tx_dma_callback,up,
-			&(up->uart_dma.tx_dma_channel));
-		}
+		if (up->uart_dma.tx_dma_channel == 0xFF)
+			omap_request_dma(uart_dma_tx[up->pdev->id-1],
+					"UART Tx DMA",
+					(void *)uart_tx_dma_callback, up,
+					&(up->uart_dma.tx_dma_channel));
 		omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
-					 OMAP_DMA_AMODE_CONSTANT, UART_BASE(up->pdev->id - 1), 0,0);
+					 OMAP_DMA_AMODE_CONSTANT,
+					 UART_BASE(up->pdev->id - 1), 0, 0);
 		omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
-			OMAP_DMA_AMODE_POST_INC, start, 0,0);
+					OMAP_DMA_AMODE_POST_INC, start, 0, 0);
 
 		omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
-					     OMAP_DMA_DATA_TYPE_S8, up->uart_dma.tx_buf_size, 1,
+					     OMAP_DMA_DATA_TYPE_S8,
+					     up->uart_dma.tx_buf_size, 1,
 					     OMAP_DMA_SYNC_ELEMENT,
 					     uart_dma_tx[(up->pdev->id)-1], 0);
 
@@ -468,16 +462,13 @@
 		up->ier &= ~UART_IER_RDI;
 		serial_out(up, UART_IER, up->ier);
 		serial_omap_start_rxdma(up);
-	}
-	else if (lsr & UART_LSR_DR) {
+	} else if (lsr & UART_LSR_DR) {
 		receive_chars(up, &lsr);
 	}
 	check_modem_status(up);
-	if ((lsr & UART_LSR_THRE) && (iir & 0x2)) {
+	if ((lsr & UART_LSR_THRE) && (iir & 0x2))
 		transmit_chars(up);
-	}
 	isr8250_activity = jiffies;
-
 	return IRQ_HANDLED;
 }
 
@@ -487,7 +478,7 @@
 	unsigned long flags;
 	unsigned int ret;
 
-	DPRINTK("serial_omap_tx_empty+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_tx_empty+%d\n", up->pdev->id);
 	spin_lock_irqsave(&up->port.lock, flags);
 	ret = serial_in(up, UART_LSR) & UART_LSR_TEMT ? TIOCSER_TEMT : 0;
 	spin_unlock_irqrestore(&up->port.lock, flags);
@@ -502,7 +493,7 @@
 	unsigned int ret;
 
 	status = check_modem_status(up);
-	DPRINTK("serial_omap_get_mctrl+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_get_mctrl+%d\n", up->pdev->id);
 
 	ret = 0;
 	if (status & UART_MSR_DCD)
@@ -520,8 +511,10 @@
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 	unsigned char mcr = 0;
+	u16 efr = 0;
+	u16 lcr = 0;
 
-	DPRINTK("serial_omap_set_mctrl+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_set_mctrl+%d\n", up->pdev->id);
 	if (mctrl & TIOCM_RTS)
 		mcr |= UART_MCR_RTS;
 	if (mctrl & TIOCM_DTR)
@@ -533,8 +526,25 @@
 	if (mctrl & TIOCM_LOOP)
 		mcr |= UART_MCR_LOOP;
 
+	lcr = serial_in(up, UART_LCR);
+	/* Set the CONFIG B Mode to read the EFR */
+	serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+	efr = serial_in(up, UART_EFR);
+	/* The EFR[4] bit to enable the MCR write */
+	serial_out(up, UART_EFR, UART_EFR_ECB);
+	serial_out(up, UART_LCR, 0x0); /* Operational mode */
+
 	mcr |= up->mcr;
 	serial_out(up, UART_MCR, mcr);
+
+	/* Set the CONFIG B Mode to read the EFR */
+	serial_out(up, UART_LCR, 0xBF); /* Config B mode */
+	serial_out(up, UART_EFR, efr);
+
+	/* Restore the LCR Value */
+	serial_out(up, UART_LCR, lcr);
+
+	return;
 }
 
 static void serial_omap_break_ctl(struct uart_port *port, int break_state)
@@ -542,7 +552,7 @@
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 	unsigned long flags;
 
-	DPRINTK("serial_omap_break_ctl+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_break_ctl+%d\n", up->pdev->id);
 	spin_lock_irqsave(&up->port.lock, flags);
 	if (break_state == -1)
 		up->lcr |= UART_LCR_SBC;
@@ -559,9 +569,14 @@
 	int irq_flags = 0;
 	int retval;
 
+	/*Enable the UART CTS wakeup for UART1,UART2*/
+	if (((up->pdev->id - 1) == UART1) || ((up->pdev->id  - 1) == UART2))
+		omap_uart_cts_wakeup((up->pdev->id - 1), 1);
+
+
 	/* Zoom2 has GPIO_102 connected to Serial device:
-	* Active High
-	*/
+	 * Active High
+	 */
 	if (up->port.flags & UPF_TRIGGER_HIGH)
 		irq_flags |= IRQF_TRIGGER_HIGH;
 
@@ -571,27 +586,17 @@
 	/*
 	 * Allocate the IRQ
 	 */
-	retval = request_irq(up->port.irq, serial_omap_irq, irq_flags, up->name, up);
-	if (retval) {
+	retval = request_irq(up->port.irq, serial_omap_irq, irq_flags,
+				up->name, up);
+	if (retval)
 		return retval;
-	}
-
-	/*
-	 * Stop the baud clock and disable the UART. UART will be enabled
-	 * back in set_termios. This is essential for DMA mode operations.
-	 */
-	serial_out(up, UART_LCR, UART_LCR_DLAB);
-	serial_out(up, UART_DLL, 0);
-	serial_out(up, UART_DLM, 0);
-	serial_out(up, UART_LCR, 0);
-	serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
+	DPRINTK("serial_omap_startup+%d\n", up->pdev->id);
 
 	/*
 	 * Clear the FIFO buffers and disable them.
 	 * (they will be reenabled in set_termios())
 	 */
 	serial_omap_clear_fifos(up);
-	serial_out(up, UART_SCR, 0x00);
 	/* For Hardware flow control */
 	serial_out(up, UART_MCR, 0x2);
 
@@ -599,7 +604,8 @@
 	 * Clear the interrupt registers.
 	 */
 	(void) serial_in(up, UART_LSR);
-	(void) serial_in(up, UART_RX);
+	if (serial_in(up, UART_LSR) & UART_LSR_DR)
+		(void)serial_in(up, UART_RX);
 	(void) serial_in(up, UART_IIR);
 	(void) serial_in(up, UART_MSR);
 	/*
@@ -622,8 +628,6 @@
 
 	up->msr_saved_flags = 0;
 
-
-
 	if (up->port.flags & UPF_FOURPORT) {
 		unsigned int icp;
 		/*
@@ -638,8 +642,9 @@
 			free_page((unsigned long)up->port.info->xmit.buf);
 			up->port.info->xmit.buf = NULL;
 			up->port.info->xmit.buf = dma_alloc_coherent(NULL,
-                                               UART_XMIT_SIZE,
-                                               (dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys), 0);
+				UART_XMIT_SIZE,
+				(dma_addr_t *)&(up->uart_dma.tx_buf_dma_phys),
+				0);
 			up->is_buf_dma_alloced = 1;
 		}
 		init_timer(&(up->uart_dma.rx_timer));
@@ -647,19 +652,18 @@
 		up->uart_dma.rx_timer.data = up->pdev->id;
 		/* Currently the buffer size is 4KB. Can increase it later*/
 		up->uart_dma.rx_buf = dma_alloc_coherent(NULL,
-					up->uart_dma.rx_buf_size,
-					(dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
-		serial_omap_start_rxdma(up);
-	} else {
-		/*
-		* Finally, enable interrupts.  Note: Modem status interrupts
-		* are set via set_termios(), which will be occurring imminently
-		* anyway, so we don't enable them here.
-		*/
-		up->ier = UART_IER_RLSI | UART_IER_RDI; //| UART_IER_RTOIE |UART_IER_THRI;
-		serial_out(up, UART_IER, up->ier);
+			up->uart_dma.rx_buf_size,
+			(dma_addr_t *)&(up->uart_dma.rx_buf_dma_phys), 0);
 	}
+	/*
+	* Finally, enable interrupts.  Note: Modem status interrupts
+	* are set via set_termios(), which will be occurring imminently
+	* anyway, so we don't enable them here.
+	*/
+	up->ier = UART_IER_RLSI | UART_IER_RDI;
+	serial_out(up, UART_IER, up->ier);
 
+	isr8250_activity = jiffies;
 	return 0;
 }
 
@@ -668,7 +672,7 @@
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 	unsigned long flags;
 
-	DPRINTK("serial_omap_shutdown+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_shutdown+%d\n", up->pdev->id);
 	/*
 	 * Disable interrupts from this port
 	 */
@@ -694,13 +698,15 @@
 	/*
 	 * Read data port to reset things, and then free the irq
 	 */
-	(void) serial_in(up, UART_RX);
-	if (up->use_dma ) {
+	if (serial_in(up, UART_LSR) & UART_LSR_DR)
+		(void)serial_in(up, UART_RX);
+	if (up->use_dma) {
 		int tmp;
 		if (up->is_buf_dma_alloced) {
 			dma_free_coherent(up->port.dev,
 				  UART_XMIT_SIZE,
-				  up->port.info->xmit.buf, up->uart_dma.tx_buf_dma_phys);
+				  up->port.info->xmit.buf,
+				  up->uart_dma.tx_buf_dma_phys);
 			up->port.info->xmit.buf = NULL;
 			up->is_buf_dma_alloced = 0;
 		}
@@ -708,7 +714,8 @@
 		serial_omap_stop_rx(port);
 		dma_free_coherent(up->port.dev,
 				  up->uart_dma.rx_buf_size,
-				  up->uart_dma.rx_buf, up->uart_dma.rx_buf_dma_phys);
+				  up->uart_dma.rx_buf,
+				  up->uart_dma.rx_buf_dma_phys);
 		up->uart_dma.rx_buf = NULL;
 		tmp = serial_in(up, UART_OMAP_SYSC) & 0x7;
 		serial_out(up, UART_OMAP_SYSC, tmp); /* force-idle */
@@ -717,6 +724,65 @@
 	free_irq(up->port.irq, up);
 }
 
+static inline void
+serial_omap_configure_xonxoff
+		(struct uart_omap_port *up, struct ktermios *termios)
+{
+	unsigned char efr = 0;
+
+	up->lcr = serial_in(up, UART_LCR);
+	serial_out(up, UART_LCR, 0xbf);
+	up->efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, up->efr & ~UART_EFR_ECB);
+
+	serial_out(up, UART_XON1, termios->c_cc[VSTART]);
+	serial_out(up, UART_XOFF1, termios->c_cc[VSTOP]);
+
+	/* clear SW control mode bits */
+	efr = up->efr & 0xf0;
+
+	/* IXON Flag:
+	 * Enable XON/XOFF flow control on output.
+	 * Transmit XON1, XOFF1
+	 */
+	if (termios->c_iflag & IXON)
+		efr |= 0x01 << 3;
+
+	/* IXOFF Flag:
+	 * Enable XON/XOFF flow control on input.
+	 * Receiver compares XON1, XOFF1.
+	 */
+	if (termios->c_iflag & IXOFF)
+		efr |= 0x01 << 1;
+
+	serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+	serial_out(up, UART_LCR, 0x80);
+
+	up->mcr = serial_in(up, UART_MCR);
+
+	/* IXANY Flag:
+	 * Enable any character to restart output.
+	 * Operation resumes after receiving any
+	 * character after recognition of the XOFF character
+	 */
+	if (termios->c_iflag & IXANY)
+		up->mcr |= 1<<5;
+
+	serial_out(up, UART_MCR, up->mcr | 1<<6);
+
+	serial_out(up, UART_LCR, 0xbf);
+	serial_out(up, UART_TI752_TCR, 0x0f);
+	/* Enable special char function UARTi.EFR_REG[5] and
+	 * load the new software flow control mode IXON or IXOFF
+	 * and restore the UARTi.EFR_REG[4] ENHANCED_EN value.
+	 */
+	serial_out(up, UART_EFR, efr | 1<<5);
+	serial_out(up, UART_LCR, 0x80);
+
+	serial_out(up, UART_MCR, up->mcr & ~(1<<6));
+	serial_out(up, UART_LCR, up->lcr);
+}
+
 static void
 serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
 			struct ktermios *old)
@@ -727,11 +793,6 @@
 	unsigned long flags;
 	unsigned int baud, quot;
 
-	serial_out(up, UART_LCR, UART_LCR_DLAB);
-	serial_out(up, UART_DLL, 0);
-	serial_out(up, UART_DLM, 0);
-	serial_out(up, UART_LCR, 0);
-	serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
 	switch (termios->c_cflag & CSIZE) {
 	case CS5:
 		cval = UART_LCR_WLEN5;
@@ -763,9 +824,12 @@
 	quot = serial_omap_get_divisor(port, baud);
 
 	if (up->use_dma)
-		fcr[up->pdev->id - 1] = UART_FCR_ENABLE_FIFO | 0x1 << 6 | 0x1 << 4 | UART_FCR_DMA_SELECT;
+		fcr[up->pdev->id - 1] = UART_FCR_ENABLE_FIFO
+					| 0x1 << 6 | 0x1 << 4
+					| UART_FCR_DMA_SELECT;
 	else
-		fcr[up->pdev->id - 1] = UART_FCR_ENABLE_FIFO | 0x1 << 6 | 0x1 << 4;
+		fcr[up->pdev->id - 1] = UART_FCR_ENABLE_FIFO
+					| 0x1 << 6 | 0x1 << 4;
 
 	/*
 	 * Ok, we're now changing the port state.  Do it with
@@ -814,44 +878,103 @@
 		up->ier |= UART_IER_MSI;
 	serial_out(up, UART_IER, up->ier);
 
-	if (termios->c_cflag & CRTSCTS)
-		efr |= (UART_EFR_CTS | UART_EFR_RTS);
-
-	serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */
-	serial_out(up, UART_DLL, quot & 0xff);		/* LS of divisor */
-	serial_out(up, UART_DLM, quot >> 8);		/* MS of divisor */
-
 	serial_out(up, UART_LCR, cval);		/* reset DLAB */
-	up->lcr = cval;				/* Save LCR */
-	if (up->use_dma)
-		serial_out(up, UART_OMAP_SCR  , ((1 << 6) | (1 << 7)));
 
-	serial_out(up, UART_LCR, 0xbf);	/* Access EFR */
-	serial_out(up, UART_EFR, UART_EFR_ECB);
-	serial_out(up, UART_LCR, 0x0);		/* Access FCR */
-	serial_out(up, UART_FCR, fcr[up->pdev->id - 1]);
-	serial_out(up, UART_LCR, 0xbf);	/* Access EFR */
-	serial_out(up, UART_EFR, efr);
-	serial_out(up, UART_LCR, cval);	/* Access FCR */
+	/*-----------FIFOs and DMA Settings -----------*/
+	serial_out(up, UART_LCR, UART_LCR_DLAB);
+	serial_out(up, UART_DLL, 0);
+	serial_out(up, UART_DLM, 0);
+	serial_out(up, UART_LCR, 0);
 
-	serial_omap_set_mctrl(&up->port, up->port.mctrl);
+ 	serial_out(up, UART_LCR, 0xbf);		/* Access EFR */
+
+	up->efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+	serial_out(up, UART_LCR, 0x0);			/* Access FCR */
+
 	/*
-	 * Clear all the status registers and RX register before
-	 * enabling UART
+	 * old is NULL only if its coming out of Sleep Mode. The up-mcr
+	 * would have a stored value in it, use the value itself. If
+	 * coming up in a normal working state, the MCR register would
+	 * have a valid value, hence read it and then use it.
 	 */
-	(void) serial_in(up, UART_LSR);
-	(void) serial_in(up, UART_RX);
-	(void) serial_in(up, UART_IIR);
-	(void) serial_in(up, UART_MSR);
+	if (NULL != old)
+		up->mcr = serial_in(up, UART_MCR);
+
+	serial_out(up, UART_MCR, up->mcr | 0x40);        /* Access TLR*/
+	/* FIFO ENABLE, DMA MODE */
+	serial_out(up, UART_FCR, fcr[up->pdev->id - 1]);
+	serial_out(up, UART_LCR, 0xbf);			/* Access EFR */
+
+	if (up->use_dma) {
+		serial_out(up, UART_TI752_TLR, 0x00);
+		serial_out(up, UART_OMAP_SCR, ((1 << 6) | (1 << 7)));
+	}
+
+	serial_out(up, UART_EFR, up->efr);
+	serial_out(up, UART_LCR, 0x80);
+	serial_out(up, UART_MCR, up->mcr);        /* Restore TLR */
+
+	/*-----Protocol, Baud Rate, and Interrupt Settings -- */
+
+	serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_DISABLE);
+
+	serial_out(up, UART_LCR, 0xbf); /* Access EFR */
+
+	up->efr = serial_in(up, UART_EFR);
+	serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+	serial_out(up, UART_LCR, 0);
+	serial_out(up, UART_IER, 0);
+	serial_out(up, UART_LCR, 0xbf);
+
+	serial_out(up, UART_DLL, quot & 0xff);          /* LS of divisor */
+	serial_out(up, UART_DLM, quot >> 8);            /* MS of divisor */
+
+	serial_out(up, UART_LCR, 0);
+	serial_out(up, UART_IER, up->ier);
+	serial_out(up, UART_LCR, 0xbf); /* Access EFR */
+
+	serial_out(up, UART_EFR, up->efr);
+	serial_out(up, UART_LCR, cval);
 
 	if (baud > 230400 && baud != 3000000)
 		serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE13X);
 	else
 		serial_out(up, UART_OMAP_MDR1, OMAP_MDR1_MODE16X);
-	spin_unlock_irqrestore(&up->port.lock, flags);
 
-	DPRINTK("serial_omap_set_termios+%d\n",up->pdev->id);
+	/* Hardware Flow Control Configuration */
+
+	if (termios->c_cflag & CRTSCTS) {
+		efr |= (UART_EFR_CTS | UART_EFR_RTS);
+		serial_out(up, UART_LCR, 0x80);
+
+		up->mcr = serial_in(up, UART_MCR);
+		serial_out(up, UART_MCR, up->mcr | 0x40);
+
+		serial_out(up, UART_LCR, 0xbf); /* Access EFR */
+
+		up->efr = serial_in(up, UART_EFR);
+		serial_out(up, UART_EFR, up->efr | UART_EFR_ECB);
+
+		serial_out(up, UART_TI752_TCR, 0x0f);
+		serial_out(up, UART_EFR, efr); /* Enable AUTORTS and AUTOCTS */
+		serial_out(up, UART_LCR, 0x80);
+		serial_out(up, UART_MCR, up->mcr | 0x02);
+		serial_out(up, UART_LCR, cval);
+	}
+
+	serial_omap_set_mctrl(&up->port, up->port.mctrl);
+	/* ----Software Flow Control Configuration----- */
+	if (termios->c_iflag & (IXON | IXOFF))
+		serial_omap_configure_xonxoff(up, termios);
+
+	spin_unlock_irqrestore(&up->port.lock, flags);
+	DPRINTK("serial_omap_set_termios+%d\n", up->pdev->id);
+
+#ifdef DEBUG
 	serial_omap_display_reg(port);
+#endif
 }
 
 static void
@@ -860,16 +983,22 @@
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 	unsigned char efr;
-	DPRINTK("serial_omap_pm+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_pm+%d\n", up->pdev->id);
+	DPRINTK(" PM STATE = %d \n", state);
 	efr = serial_in(up, UART_EFR);
 	serial_out(up, UART_LCR, 0xBF);
 	serial_out(up, UART_EFR, efr | UART_EFR_ECB);
 	serial_out(up, UART_LCR, 0);
 
-	serial_out(up, UART_IER, (state!=0) ? UART_IERX_SLEEP: 0);
+	serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
 	serial_out(up, UART_LCR, 0xBF);
 	serial_out(up, UART_EFR, efr);
 	serial_out(up, UART_LCR, 0);
+	/* Enable module level wake up */
+	serial_out(up, UART_OMAP_WER, 0x7f);
+	/*Holding wakelock for UART*/
+	if (oldstate == 3)
+		wake_lock_timeout(&omap_serial_wakelock, 10*HZ);
 }
 
 static void serial_omap_release_port(struct uart_port *port)
@@ -887,7 +1016,7 @@
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 
-	DPRINTK("serial_omap_config_port+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_config_port+%d\n", up->pdev->id);
 	up->port.type = PORT_OMAP;
 }
 
@@ -904,7 +1033,7 @@
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 
-	DPRINTK("serial_omap_type+%d\n",up->pdev->id);
+	DPRINTK("serial_omap_type+%d\n", up->pdev->id);
 	return up->name;
 }
 
@@ -1074,23 +1203,13 @@
 };
 
 static int serial_omap_remove(struct platform_device *dev);
-static int serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
+
+static
+int serial_omap_suspend(struct platform_device *pdev, pm_message_t state)
 {
 	struct uart_omap_port *up = platform_get_drvdata(pdev);
-	unsigned int tmp;
-
 	if (up)
 		uart_suspend_port(&serial_omap_reg, &up->port);
-	if (up->use_dma) {
-		/*
-		 * Silicon Errata i291 workaround.
-		 * UART Module has to be put in force idle if it is
-		 * configured in DMA mode and when there is no activity
-		 * expected.
-		 */
-		tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7);
-		serial_out(up, UART_OMAP_SYSC, tmp); /* force-idle */
-	}
 	return 0;
 }
 
@@ -1107,37 +1226,45 @@
 {
 	struct uart_omap_port *up = ui[uart_no - 1];
 	unsigned int curr_dma_pos;
-	curr_dma_pos = omap_readl(OMAP34XX_DMA4_BASE + OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel));
-	if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) || (curr_dma_pos == 0)) {
+	curr_dma_pos = omap_readl(OMAP34XX_DMA4_BASE +
+				  OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel));
+	if ((curr_dma_pos == up->uart_dma.prev_rx_dma_pos) ||
+			     (curr_dma_pos == 0)) {
 		/*
-		 * If there is no transfer rx happening for 10sec then stop the dma
-		 * else just restart the timer. See if 10 sec can be improved.
+		 * If there is no transfer rx happening for 3sec
+		 * then stop the dma else just restart the timer.
+		 * See if 3 sec can be improved.
 		 */
-		if (jiffies_to_msecs(jiffies - isr8250_activity) < 10000)
+		if (jiffies_to_msecs(jiffies - isr8250_activity) < 3000)
 			mod_timer(&up->uart_dma.rx_timer, jiffies +
 				usecs_to_jiffies(up->uart_dma.rx_timeout));
 		else {
-			del_timer(&up->uart_dma.rx_timer);
 			serial_omap_stop_rxdma(up);
 			up->ier |= UART_IER_RDI;
 			serial_out(up, UART_IER, up->ier);
 		}
 
 		return;
-	}
-	else {
-		unsigned int curr_transmitted_size = curr_dma_pos - up->uart_dma.prev_rx_dma_pos;
+	} else {
+		unsigned int curr_transmitted_size = curr_dma_pos -
+						up->uart_dma.prev_rx_dma_pos;
 		up->port.icount.rx += curr_transmitted_size;
-		tty_insert_flip_string(up->port.info->port.tty, up->uart_dma.rx_buf + (up->uart_dma.prev_rx_dma_pos - up->uart_dma.rx_buf_dma_phys), curr_transmitted_size);
+		tty_insert_flip_string(up->port.info->port.tty,
+				up->uart_dma.rx_buf +
+				(up->uart_dma.prev_rx_dma_pos -
+				up->uart_dma.rx_buf_dma_phys),
+				curr_transmitted_size);
 		tty_flip_buffer_push(up->port.info->port.tty);
 		up->uart_dma.prev_rx_dma_pos = curr_dma_pos;
-		if (up->uart_dma.rx_buf_size + up->uart_dma.rx_buf_dma_phys == curr_dma_pos) {
+
+		if (up->uart_dma.rx_buf_size +
+				up->uart_dma.rx_buf_dma_phys == curr_dma_pos)
 			serial_omap_start_rxdma(up);
-		}
 		else
-		mod_timer(&up->uart_dma.rx_timer, jiffies +
-				usecs_to_jiffies(up->uart_dma.rx_timeout));
+			mod_timer(&up->uart_dma.rx_timer, jiffies +
+					usecs_to_jiffies(up->uart_dma.rx_timeout));
 		isr8250_activity = jiffies;
+
 	}
 }
 
@@ -1148,47 +1275,40 @@
 
 static void serial_omap_start_rxdma(struct uart_omap_port *up)
 {
-#ifdef CONFIG_OMAP3_PM
-	/* Disallow OCP bus idle. UART TX irqs are not seen during
-	 * bus idle. Alternative is to set kernel timer at fifo
-	 * drain rate.
-	 */
-	unsigned int tmp;
-	tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7) | (1 << 3);
-	serial_out(up, UART_OMAP_SYSC, tmp); /* no-idle */
-#endif
 	if (up->uart_dma.rx_dma_channel == 0xFF) {
-		omap_request_dma(uart_dma_rx[up->pdev->id-1],"UART Rx DMA",
-				(void *)uart_rx_dma_callback,up,
+		omap_request_dma(uart_dma_rx[up->pdev->id-1], "UART Rx DMA",
+			(void *)uart_rx_dma_callback, up,
 				&(up->uart_dma.rx_dma_channel));
+
 		omap_set_dma_src_params(up->uart_dma.rx_dma_channel, 0,
-					OMAP_DMA_AMODE_CONSTANT,
-					UART_BASE(up->pdev->id - 1), 0, 0);
+				OMAP_DMA_AMODE_CONSTANT,
+				UART_BASE(up->pdev->id - 1), 0, 0);
 		omap_set_dma_dest_params(up->uart_dma.rx_dma_channel, 0,
-					OMAP_DMA_AMODE_POST_INC,
-					up->uart_dma.rx_buf_dma_phys, 0, 0);
+				OMAP_DMA_AMODE_POST_INC,
+				up->uart_dma.rx_buf_dma_phys, 0, 0);
 		omap_set_dma_transfer_params(up->uart_dma.rx_dma_channel,
-					OMAP_DMA_DATA_TYPE_S8,
-					up->uart_dma.rx_buf_size, 1,
-					OMAP_DMA_SYNC_ELEMENT,
-					uart_dma_rx[up->pdev->id-1], 0);
+				OMAP_DMA_DATA_TYPE_S8,
+				up->uart_dma.rx_buf_size, 1,
+				OMAP_DMA_SYNC_ELEMENT,
+				uart_dma_rx[up->pdev->id-1], 0);
 	}
 	up->uart_dma.prev_rx_dma_pos = up->uart_dma.rx_buf_dma_phys;
-	omap_writel(0, OMAP34XX_DMA4_BASE +
-		OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel));
+	omap_writel(0, OMAP34XX_DMA4_BASE
+			+ OMAP_DMA4_CDAC(up->uart_dma.rx_dma_channel));
 	omap_start_dma(up->uart_dma.rx_dma_channel);
 	mod_timer(&up->uart_dma.rx_timer, jiffies +
-			usecs_to_jiffies(up->uart_dma.rx_timeout));
+				usecs_to_jiffies(up->uart_dma.rx_timeout));
 	up->uart_dma.rx_dma_state = 1;
+
 }
 
 static void serial_omap_continue_tx(struct uart_omap_port *up)
 {
 	struct circ_buf *xmit = &up->port.info->xmit;
-	int start = up->uart_dma.tx_buf_dma_phys + (xmit->tail & (UART_XMIT_SIZE - 1));
-	if (uart_circ_empty(xmit))  {
-			return;
-	}
+	int start = up->uart_dma.tx_buf_dma_phys
+			+ (xmit->tail & (UART_XMIT_SIZE - 1));
+	if (uart_circ_empty(xmit))
+		return;
 
 	up->uart_dma.tx_buf_size = uart_circ_chars_pending(xmit);
 	/* It is a circular buffer. See if the buffer has wounded back.
@@ -1200,12 +1320,14 @@
 		up->uart_dma.tx_buf_size =
 			(up->uart_dma.tx_buf_dma_phys + UART_XMIT_SIZE) - start;
 	omap_set_dma_dest_params(up->uart_dma.tx_dma_channel, 0,
-				 OMAP_DMA_AMODE_CONSTANT, UART_BASE(up->pdev->id - 1), 0,0);
+				 OMAP_DMA_AMODE_CONSTANT,
+				 UART_BASE(up->pdev->id - 1), 0, 0);
 	omap_set_dma_src_params(up->uart_dma.tx_dma_channel, 0,
-		OMAP_DMA_AMODE_POST_INC, start, 0,0);
+		OMAP_DMA_AMODE_POST_INC, start, 0, 0);
 
 	omap_set_dma_transfer_params(up->uart_dma.tx_dma_channel,
-				     OMAP_DMA_DATA_TYPE_S8, up->uart_dma.tx_buf_size, 1,
+				     OMAP_DMA_DATA_TYPE_S8,
+				     up->uart_dma.tx_buf_size, 1,
 				     OMAP_DMA_SYNC_ELEMENT,
 				     uart_dma_tx[(up->pdev->id)-1], 0);
 
@@ -1216,12 +1338,13 @@
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)data;
 	struct circ_buf *xmit = &up->port.info->xmit;
-	xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & (UART_XMIT_SIZE - 1);
+	xmit->tail = (xmit->tail + up->uart_dma.tx_buf_size) & \
+			(UART_XMIT_SIZE - 1);
 	up->port.icount.tx += up->uart_dma.tx_buf_size;
 
 	/* Revisit: Not sure about the below two steps. Seen some instabilities
-	* with them. might not be needed in the DMA path
-	*/
+	 * with them. might not be needed in the DMA path
+	 */
 	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
 		uart_write_wakeup(&up->port);
 
@@ -1235,8 +1358,8 @@
 		omap_stop_dma(up->uart_dma.tx_dma_channel);
 		serial_omap_continue_tx(up);
 	}
-	isr8250_activity = jiffies;
 
+	isr8250_activity = jiffies;
 	return;
 }
 
@@ -1284,7 +1407,7 @@
 	if (pdev->id == 4) {
 		up->port.membase = ioremap_nocache(mem->start, 0x16 << 1);
 		up->port.flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP |
-			UPF_SHARE_IRQ | UPF_TRIGGER_HIGH;
+					UPF_SHARE_IRQ | UPF_TRIGGER_HIGH;
 		up->port.uartclk = QUART_CLK;
 		up->port.regshift = 1;
 	} else {
@@ -1297,7 +1420,6 @@
 		up->port.regshift = 2;
 	}
 
-
 	if (pdev->id == (UART1+1)) {
 #ifdef CONFIG_SERIAL_OMAP_DMA_UART1
 		up->use_dma = 1;
@@ -1330,10 +1452,9 @@
 		up->uart_dma.tx_dma_channel = 0xFF;
 		up->uart_dma.rx_dma_channel = 0xFF;
 	}
-        if (console_detect(str)){
-                printk("Invalid console paramter. UART Library Init Failed!\n");
-                return -EPERM;
-	}
+	if (console_detect(str))
+		printk(KERN_INFO "Invalid console paramter....\n");
+
 	up->use_console = 0;
 	fcr[pdev->id - 1] = 0;
 	if (!strcmp(str, "ttyS0"))
@@ -1346,15 +1467,15 @@
 		up->use_console = 1;
 	else
 		printk(KERN_INFO
-		       "!!!!!!!! Unable to recongnize Console UART........\n");
+		       "!!!!!!!!! Unable to recongnize Console UART........\n");
 	ui[pdev->id - 1] = up;
 	serial_omap_add_console_port(up);
 
 	ret = uart_add_one_port(&serial_omap_reg, &up->port);
 	if (ret != 0)
 		goto do_release_region;
-	platform_set_drvdata(pdev, up);
 
+	platform_set_drvdata(pdev, up);
 	return 0;
 do_release_region:
 	release_mem_region(mem->start, (mem->end - mem->start) + 1);
@@ -1366,6 +1487,7 @@
 	struct uart_omap_port *up = platform_get_drvdata(dev);
 
 	platform_set_drvdata(dev, NULL);
+
 	if (up) {
 		uart_remove_one_port(&serial_omap_reg, &up->port);
 		kfree(up);
@@ -1387,6 +1509,8 @@
 int __init serial_omap_init(void)
 {
 	int ret;
+	wake_lock_init(&omap_serial_wakelock, WAKE_LOCK_SUSPEND,
+			"omap-serial");
 
 	ret = uart_register_driver(&serial_omap_reg);
 	if (ret != 0)
@@ -1399,16 +1523,17 @@
 
 void __exit serial_omap_exit(void)
 {
+	wake_lock_destroy(&omap_serial_wakelock);
 	platform_driver_unregister(&serial_omap_driver);
 	uart_unregister_driver(&serial_omap_reg);
 }
 
-#if defined(CONFIG_OMAP3_PM)
-int omap24xx_uart_cts_wakeup(int uart_no, int state)
+int omap_uart_cts_wakeup(int uart_no, int state)
 {
-	u32 *ptr;
 	unsigned char lcr, efr;
 	struct uart_omap_port *up = ui[uart_no];
+	u32 padconf_cts;
+	u16 v;
 
 	if (unlikely(uart_no < 0 || uart_no > MAX_UARTS)) {
 		printk(KERN_INFO "Bad uart id %d \n", uart_no);
@@ -1421,21 +1546,28 @@
 		 */
 		switch (uart_no) {
 		case UART1:
-			ptr = (u32 *) (&CONTROL_PADCONF_UART1_CTS);
+			printk(KERN_INFO "Enabling CTS wakeup for UART1");
+			padconf_cts = 0x180;
+			v = omap_ctrl_readw(padconf_cts);
 			break;
 		case UART2:
-			ptr = (u32 *) (&CONTROL_PADCONF_UART2_CTS);
+			printk(KERN_INFO "Enabling CTS wakeup for UART2");
+			padconf_cts = 0x174;
+			v = omap_ctrl_readw(padconf_cts);
 			break;
 		default:
 			printk(KERN_ERR
 			"Wakeup on Uart%d is not supported\n", uart_no);
 			return -EPERM;
 		}
-		*ptr |= (u32)((IO_PAD_WAKEUPENABLE | IO_PAD_OFFPULLUDENABLE |
-				IO_PAD_OFFOUTENABLE | IO_PAD_OFFENABLE |
-				IO_PAD_INPUTENABLE | IO_PAD_PULLUDENABLE|
-				IO_PAD_MUXMODE0)
-				);
+
+		v |= ((OMAP3_WAKEUP_EN | OMAP3_OFF_PULL_EN |
+			OMAP3_OFFOUT_VAL | OMAP3_OFFIN_EN |
+			OMAP3_OFF_EN | OMAP2_PULL_UP |
+			OMAP34XX_MUX_MODE0));
+
+		omap_ctrl_writew(v, padconf_cts);
+
 		/*
 		 * Enable the CTS for module level wakeup
 		 */
@@ -1444,8 +1576,6 @@
 		efr = serial_in(up, UART_EFR);
 		serial_out(up, UART_EFR, efr | UART_EFR_ECB);
 		serial_out(up, UART_LCR, lcr);
-		up->ier	|= (1 << 7);
-		serial_out(up, UART_IER, up->ier);
 		serial_out(up, UART_OMAP_WER,
 				serial_in(up, UART_OMAP_WER) | 0x1);
 		serial_out(up, UART_LCR, 0xbf);
@@ -1458,20 +1588,23 @@
 		 */
 		switch (uart_no) {
 		case UART1:
-			ptr = (u32 *) (&CONTROL_PADCONF_UART1_CTS);
+			padconf_cts = 0x180;
+			v = omap_ctrl_readw(padconf_cts);
 			break;
 		case UART2:
-			ptr = (u32 *) (&CONTROL_PADCONF_UART2_CTS);
+			padconf_cts = 0x174;
+			v = omap_ctrl_readw(padconf_cts);
 			break;
 		default:
 			printk(KERN_ERR
 			"Wakeup on Uart%d is not supported\n", uart_no);
 			return -EPERM;
 		}
-		*ptr &= (u32) (~(IO_PAD_WAKEUPENABLE | IO_PAD_OFFPULLUDENABLE |
-				IO_PAD_OFFOUTENABLE | IO_PAD_OFFENABLE |
-				IO_PAD_INPUTENABLE | IO_PAD_PULLUDENABLE));
-		*ptr |= IO_PAD_MUXMODE7;
+
+		v &= (u32)(~(OMAP3_WAKEUP_EN | OMAP3_OFF_PULL_EN |
+				OMAP3_OFF_EN | OMAP3_OFFIN_EN));
+
+		omap_ctrl_writew(v, padconf_cts);
 
 		/*
 		 * Disable the CTS for module level wakeup
@@ -1481,111 +1614,97 @@
 		efr = serial_in(up, UART_EFR);
 		serial_out(up, UART_EFR, efr | UART_EFR_ECB);
 		serial_out(up, UART_LCR, lcr);
-		up->ier	&= ~(1 << 7);
-		serial_out(up, UART_IER, up->ier);
-		/* TBD:Do we really want to disable module wake up for this in WER*/
+
+		/* TBD:Do we really want to disable
+		 * module wake up for this in WER
+		 */
 		serial_out(up, UART_LCR, 0xbf);
 		serial_out(up, UART_EFR, efr);
 		serial_out(up, UART_LCR, lcr);
 	}
 	return 0;
 }
-EXPORT_SYMBOL(omap24xx_uart_cts_wakeup);
+EXPORT_SYMBOL(omap_uart_cts_wakeup);
+
 /**
- * are_driver8250_uarts_active() - Check if any ports managed by this
- * driver are currently busy.  This should be called with interrupts
- * disabled.
+ * omap_uart_active() - Check if any ports managed by this
+ * driver are currently busy.
+ * Basically used for DMA mode check before putting it to
+ * force idle mode for errata 2.15 implementation.
  */
-int are_driveromap_uarts_active(int *driver8250_managed)
+
+int omap_uart_active(int num)
 {
+	struct uart_omap_port *up = ui[num];
 	struct circ_buf *xmit;
 	unsigned int status;
-	int j;
-	*driver8250_managed = 0x7; /* OMAP has 3 UART instances */
-	for (j = 0; j < 3; j++) {
-		struct uart_omap_port *up = ui[j];
 
-		/* check ownership of port */
-		/* Check only ports managed by this driver and open */
-		if((up->port.dev == NULL) || (up->port.type == PORT_UNKNOWN)){
-			*driver8250_managed &= ~(1 << j);
-			continue;
-		}
-
-		/* driver owns this port but its closed */
-		if (up->port.info == NULL)
-			continue;
-
-		/* check for recent driver activity */
-		/* if from now to last activty < 5 second keep clocks on */
-		if ((jiffies_to_msecs(jiffies - isr8250_activity) < 5000))
-			return 1;
-
-		/* check for any current pending activity */
-		/* Any queued work in ring buffer which can be handled still? */
-		xmit = &up->port.info->xmit;
-		if (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port)))
-			return 1;
-		status = serial_in(up, UART_LSR);
-
-		/* TX hardware not empty/ */
-		if (!(status & (UART_LSR_TEMT | UART_LSR_THRE)))
-			return 1;
-
-		/* Any rx activity? */
-		if (status & UART_LSR_DR)
-			return 1;
-
-		/* Any modem activity */
-		status = serial_in(up, UART_MSR);
-		if (!((status & UART_MSR_ANY_DELTA) == 0))
-			return 1;
-		if (up->use_dma) {
-			/*
-			 * Silicon Errata i291 workaround.
-			 * UART Module has to be put in force idle if it is
-			 * configured in DMA mode and when there is no activity
-			 * expected.
-			 */
-			unsigned int tmp;
-			tmp = (serial_in(up, UART_OMAP_SYSC) & 0x7);
-			serial_out(up, UART_OMAP_SYSC, tmp); /* force-idle */
-		}
-       }
-	if(*driver8250_managed) {
+	/* for DMA mode status of DMA channel
+	 * will decide whether uart port can enter sleep
+	 * or should we block sleep state.
+	 */
+	if (up->use_dma &&
+		(up->uart_dma.tx_dma_channel != 0xFF ||
+		up->uart_dma.rx_dma_channel != 0xFF))
+		return 1;
+	else
 		return 0;
-	}
-	return 1;
+
+	/* check for recent driver activity */
+	/* if from now to last activty < 5 second keep clocks on */
+	if ((jiffies_to_msecs(jiffies - isr8250_activity) < 5000))
+		return 1;
+
+	xmit = &up->port.info->xmit;
+	if (!(uart_circ_empty(xmit) || uart_tx_stopped(&up->port)))
+		return 1;
+
+	status = serial_in(up, UART_LSR);
+	/* TX hardware not empty */
+	if (!(status & (UART_LSR_TEMT | UART_LSR_THRE)))
+		return 1;
+
+	/* Any rx activity? */
+	if (status & UART_LSR_DR)
+		return 1;
+
+	/* Any modem activity */
+	status = serial_in(up, UART_MSR);
+	if (!((status & UART_MSR_ANY_DELTA) == 0))
+		return 1;
+
+	return 0;
 }
-EXPORT_SYMBOL(are_driveromap_uarts_active);
+EXPORT_SYMBOL(omap_uart_active);
 
-#endif
+#ifdef DEBUG
 
+#define UART_OMAP_SPR           0x07    /* Scratchpad register */
 static void serial_omap_display_reg(struct uart_port *port)
 {
 	struct uart_omap_port *up = (struct uart_omap_port *)port;
 	unsigned int lcr, efr, mcr, dll, dlh, xon1, xon2, xoff1, xoff2;
 	unsigned int tcr, tlr, uasr;
-	DPRINTK("Register dump for UART%d\n",up->pdev->id);
-	DPRINTK("IER_REG=0x%x\n",serial_in(up, UART_IER));
-	DPRINTK("IIR_REG=0x%x\n",serial_in(up, UART_IIR));
+	DPRINTK("Register dump for UART%d\n", up->pdev->id);
+	DPRINTK("IER_REG = 0x%x\n", serial_in(up, UART_IER));
+	DPRINTK("IIR_REG = 0x%x\n", serial_in(up, UART_IIR));
 	lcr = serial_in(up, UART_LCR);
-	DPRINTK("LCR_REG=0x%x\n", lcr);
+	DPRINTK("LCR_REG = 0x%x\n", lcr);
 	mcr = serial_in(up, UART_MCR);
-	DPRINTK("MCR_REG=0x%x\n", mcr);
-	DPRINTK("LSR_REG=0x%x\n", serial_in(up, UART_LSR));
-	DPRINTK("MSR_REG=0x%x\n", serial_in(up, UART_MSR));
-	DPRINTK("SPR_REG=0x%x\n", serial_in(up, UART_OMAP_SPR));
-	DPRINTK("MDR1_REG=0x%x\n", serial_in(up, UART_OMAP_MDR1));
-	DPRINTK("MDR2_REG=0x%x\n", serial_in(up, UART_OMAP_MDR2));
-	DPRINTK("SCR_REG=0x%x\n", serial_in(up, UART_OMAP_SCR));
-	DPRINTK("SSR_REG=0x%x\n", serial_in(up, UART_OMAP_SSR));
-	DPRINTK("MVR_REG=0x%x\n", serial_in(up, UART_OMAP_MVER));
-	DPRINTK("SYSC_REG=0x%x\n", serial_in(up, UART_OMAP_SYSC));
-	DPRINTK("SYSS_REG=0x%x\n", serial_in(up, UART_OMAP_SYSS));
-	DPRINTK("WER_REG=0x%x\n", serial_in(up, UART_OMAP_WER));
+	DPRINTK("MCR_REG = 0x%x\n", mcr);
+	DPRINTK("LSR_REG = 0x%x\n", serial_in(up, UART_LSR));
+	DPRINTK("MSR_REG = 0x%x\n", serial_in(up, UART_MSR));
+	DPRINTK("SPR_REG = 0x%x\n", serial_in(up, UART_OMAP_SPR));
+	DPRINTK("MDR1_REG = 0x%x\n", serial_in(up, UART_OMAP_MDR1));
+	DPRINTK("MDR2_REG = 0x%x\n", serial_in(up, UART_OMAP_MDR2));
+	DPRINTK("SCR_REG = 0x%x\n", serial_in(up, UART_OMAP_SCR));
+	DPRINTK("SSR_REG = 0x%x\n", serial_in(up, UART_OMAP_SSR));
+	DPRINTK("MVR_REG = 0x%x\n", serial_in(up, UART_OMAP_MVER));
+	DPRINTK("SYSC_REG = 0x%x\n", serial_in(up, UART_OMAP_SYSC));
+	DPRINTK("SYSS_REG = 0x%x\n", serial_in(up, UART_OMAP_SYSS));
+	DPRINTK("WER_REG = 0x%x\n", serial_in(up, UART_OMAP_WER));
 
-	serial_out(up,UART_LCR, 0xBF);
+	serial_out(up, UART_LCR, 0xBF);
 	dll = serial_in(up, UART_DLL);
 	dlh = serial_in(up, UART_DLM);
 	efr = serial_in(up, UART_EFR);
@@ -1595,14 +1714,14 @@
 	serial_out(up, UART_EFR, efr | UART_EFR_ECB);
 	serial_out(up, UART_LCR, lcr);
 	serial_out(up, UART_MCR, mcr | UART_MCR_TCRTLR);
-	serial_out(up,UART_LCR, 0xBF);
+	serial_out(up, UART_LCR, 0xBF);
 
 	tcr = serial_in(up, UART_TI752_TCR);
 	tlr = serial_in(up, UART_TI752_TLR);
 
 	serial_out(up, UART_LCR, lcr);
 	serial_out(up, UART_MCR, mcr);
-	serial_out(up,UART_LCR, 0xBF);
+	serial_out(up, UART_LCR, 0xBF);
 
 	xoff1 = serial_in(up, UART_XOFF1);
 	xoff2 = serial_in(up, UART_XOFF2);
@@ -1612,21 +1731,22 @@
 	serial_out(up, UART_LCR, lcr);
 
 
-	DPRINTK("DLL_REG=0x%x\n", dll);
-	DPRINTK("DLH_REG=0x%x\n", dlh);
-	DPRINTK("EFR_REG=0x%x\n",efr);
+	DPRINTK("DLL_REG = 0x%x\n", dll);
+	DPRINTK("DLH_REG = 0x%x\n", dlh);
+	DPRINTK("EFR_REG = 0x%x\n", efr);
 
-	DPRINTK("XON1_ADDR_REG=0x%x\n",xon1);
-	DPRINTK("XON2_ADDR_REG=0x%x\n",xon2);
-	DPRINTK("TCR_REG=0x%x\n",tcr);
-	DPRINTK("TLR_REG=0x%x\n",tlr);
+	DPRINTK("XON1_ADDR_REG = 0x%x\n", xon1);
+	DPRINTK("XON2_ADDR_REG = 0x%x\n", xon2);
+	DPRINTK("TCR_REG = 0x%x\n", tcr);
+	DPRINTK("TLR_REG = 0x%x\n", tlr);
 
 
-	DPRINTK("XOFF1_REG=0x%x\n", xoff1);
-	DPRINTK("XOFF2_REG=0x%x\n", xoff2);
-	DPRINTK("UASR_REG=0x%x\n", uasr);
+	DPRINTK("XOFF1_REG = 0x%x\n", xoff1);
+	DPRINTK("XOFF2_REG = 0x%x\n", xoff2);
+	DPRINTK("UASR_REG = 0x%x\n", uasr);
 
 }
+#endif
 
 subsys_initcall(serial_omap_init);
 module_exit(serial_omap_exit);
diff --git a/drivers/spi/omap2_mcspi.c b/drivers/spi/omap2_mcspi.c
index 3da8825..ad86587 100644
--- a/drivers/spi/omap2_mcspi.c
+++ b/drivers/spi/omap2_mcspi.c
@@ -779,7 +779,6 @@
 		spi = m->spi;
 		cs = spi->controller_state;
 
-		omap2_mcspi_set_enable(spi, 1);
 		list_for_each_entry(t, &m->transfers, transfer_list) {
 			if (t->tx_buf == NULL && t->rx_buf == NULL && t->len) {
 				status = -EINVAL;
@@ -807,6 +806,10 @@
 				chconf |= OMAP2_MCSPI_CHCONF_TRM_TX_ONLY;
 			mcspi_write_chconf0(spi, chconf);
 
+			omap2_mcspi_set_master_mode(mcspi->master);
+
+			omap2_mcspi_set_enable(spi, 1);
+
 			if (t->len) {
 				unsigned	count;
 
@@ -835,6 +838,9 @@
 				omap2_mcspi_force_cs(spi, 0);
 				cs_active = 0;
 			}
+			chconf = mcspi_read_cs_reg(spi, OMAP2_MCSPI_CHCONF0);
+			if (chconf & OMAP2_MCSPI_CHCONF_FORCE)
+				omap2_mcspi_set_enable(spi, 0);
 		}
 
 		/* Restore defaults if they were overriden */
@@ -863,8 +869,8 @@
 static int omap2_mcspi_transfer(struct spi_device *spi, struct spi_message *m)
 {
 	struct omap2_mcspi	*mcspi;
-	unsigned long		flags;
-	struct spi_transfer	*t;
+	unsigned long		uninitialized_var(flags);
+	struct spi_transfer 	*uninitialized_var(t);
 
 	m->actual_length = 0;
 	m->status = 0;
diff --git a/drivers/staging/android/ram_console.c b/drivers/staging/android/ram_console.c
index 3375c1c..0ee25bd 100644
--- a/drivers/staging/android/ram_console.c
+++ b/drivers/staging/android/ram_console.c
@@ -146,6 +146,14 @@
 	.index	= -1,
 };
 
+void ram_console_enable_console(int enabled)
+{
+	if (enabled)
+		ram_console.flags |= CON_ENABLED;
+	else
+		ram_console.flags &= ~CON_ENABLED;
+}
+
 static void __init
 ram_console_save_old(struct ram_console_buffer *buffer, char *dest)
 {
diff --git a/drivers/switch/switch_gpio.c b/drivers/switch/switch_gpio.c
index b5f98ca..d585663 100644
--- a/drivers/switch/switch_gpio.c
+++ b/drivers/switch/switch_gpio.c
@@ -111,7 +111,8 @@
 	}
 
 	ret = request_irq(switch_data->irq, gpio_irq_handler,
-			  IRQF_TRIGGER_LOW, pdev->name, switch_data);
+			IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+			pdev->name, switch_data);
 	if (ret < 0)
 		goto err_request_irq;
 
@@ -163,7 +164,11 @@
 	platform_driver_unregister(&gpio_switch_driver);
 }
 
+#ifndef MODULE
+late_initcall(gpio_switch_init);
+#else
 module_init(gpio_switch_init);
+#endif
 module_exit(gpio_switch_exit);
 
 MODULE_AUTHOR("Mike Lockwood <lockwood@android.com>");
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index b3d5a23..7f2909a 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -546,10 +546,6 @@
 	tty->driver_data = acm;
 	acm->tty = tty;
 
-	/* force low_latency on so that our tty_push actually forces the data through,
-	   otherwise it is scheduled, and with high data rates data can get lost. */
-	tty->low_latency = 1;
-
 	if (usb_autopm_get_interface(acm->control) < 0)
 		goto early_bail;
 	else
diff --git a/drivers/usb/gadget/android.c b/drivers/usb/gadget/android.c
index 07fae55..e01b146 100644
--- a/drivers/usb/gadget/android.c
+++ b/drivers/usb/gadget/android.c
@@ -134,14 +134,35 @@
 	return adb_function_add(dev->cdev, c);
 }
 
+static int android_setup_config(struct usb_configuration *c,
+		const struct usb_ctrlrequest *ctrl);
+
 static struct usb_configuration android_config_driver = {
 	.label		= "android",
 	.bind		= android_bind_config,
+	.setup		= android_setup_config,
 	.bConfigurationValue = 1,
 	.bmAttributes	= USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER,
 	.bMaxPower	= CONFIG_USB_GADGET_VBUS_DRAW / 2,
 };
 
+static int android_setup_config(struct usb_configuration *c,
+		const struct usb_ctrlrequest *ctrl)
+{
+	int i;
+	int ret = -EOPNOTSUPP;
+
+	for (i = 0; i < android_config_driver.next_interface_id; i++) {
+		if (android_config_driver.interface[i]->setup) {
+			ret = android_config_driver.interface[i]->setup(
+				android_config_driver.interface[i], ctrl);
+			if (ret >= 0)
+				return ret;
+		}
+	}
+	return ret;
+}
+
 static int __init android_bind(struct usb_composite_dev *cdev)
 {
 	struct android_dev *dev = _android_dev;
@@ -173,6 +194,9 @@
 	strings_dev[STRING_SERIAL_IDX].id = id;
 	device_desc.iSerialNumber = id;
 
+	if (gadget->ops->wakeup)
+		android_config_driver.bmAttributes |= USB_CONFIG_ATT_WAKEUP;
+
 	/* register our configuration */
 	ret = usb_add_config(cdev, &android_config_driver);
 	if (ret) {
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 6995a10..5cd5f8c 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -266,7 +266,7 @@
 			descriptors = f->hs_descriptors;
 		else
 			descriptors = f->descriptors;
-		if (!descriptors || descriptors[0] == NULL) {
+		if (f->hidden || !descriptors || descriptors[0] == NULL) {
 			for (; f != config->interface[interfaceCount];) {
 				interfaceCount++;
 				c->bNumInterfaces--;
@@ -835,6 +835,25 @@
 				value = c->setup(c, ctrl);
 		}
 
+		/* If the vendor request is not processed (value < 0),
+		 * call all device registered configure setup callbacks
+		 * to process it.
+		 * This is used to handle the following cases:
+		 * - vendor request is for the device and arrives before
+		 * setconfiguration.
+		 * - Some devices are required to handle vendor request before
+		 * setconfiguration such as MTP, USBNET.
+		 */
+
+		if (value < 0) {
+			struct usb_configuration        *cfg;
+
+			list_for_each_entry(cfg, &cdev->configs, list) {
+			if (cfg && cfg->setup)
+				value = cfg->setup(cfg, ctrl);
+			}
+		}
+
 		goto done;
 	}
 
diff --git a/drivers/usb/gadget/f_mass_storage.c b/drivers/usb/gadget/f_mass_storage.c
index d81ce9e..f63f572 100644
--- a/drivers/usb/gadget/f_mass_storage.c
+++ b/drivers/usb/gadget/f_mass_storage.c
@@ -251,7 +251,6 @@
 
 /* Big enough to hold our biggest descriptor */
 #define EP0_BUFSIZE	256
-#define DELAYED_STATUS	(EP0_BUFSIZE + 999)	/* An impossibly large value */
 
 /* Number of buffers we will use.  2 is enough for double-buffering */
 #define NUM_BUFFERS	2
@@ -662,7 +661,7 @@
 			 * and reinitialize our state. */
 			DBG(fsg, "bulk reset request\n");
 			raise_exception(fsg, FSG_STATE_RESET);
-			value = DELAYED_STATUS;
+			value = 0;
 			break;
 
 		case USB_BULK_GET_MAX_LUN_REQUEST:
@@ -680,6 +679,16 @@
 		}
 	}
 
+		/* respond with data transfer or status phase? */
+		if (value >= 0) {
+			int rc;
+			cdev->req->zero = value < w_length;
+			cdev->req->length = value;
+			rc = usb_ep_queue(cdev->gadget->ep0, cdev->req, GFP_ATOMIC);
+			if (rc < 0)
+				printk("%s setup response queue error\n", __func__);
+		}
+
 	if (value == -EOPNOTSUPP)
 		VDBG(fsg,
 			"unknown class-specific control req "
@@ -2063,8 +2072,12 @@
 	bh = fsg->next_buffhd_to_fill;
 	while (bh->state != BUF_STATE_EMPTY) {
 		rc = sleep_thread(fsg);
-		if (rc)
+		if (rc) {
+			usb_ep_dequeue(fsg->bulk_out, bh->outreq);
+			bh->outreq_busy = 0;
+			bh->state = BUF_STATE_EMPTY;
 			return rc;
+		}
 	}
 
 	/* Queue a request to read a Bulk-only CBW */
@@ -2135,16 +2148,16 @@
 		DBG(fsg, "reset interface\n");
 reset:
 	 /* Disable the endpoints */
-        if (fsg->bulk_in_enabled) {
-                DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_in->name);
-                usb_ep_disable(fsg->bulk_in);
-                fsg->bulk_in_enabled = 0;
-        }
-        if (fsg->bulk_out_enabled) {
-                DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_out->name);
-                usb_ep_disable(fsg->bulk_out);
-                fsg->bulk_out_enabled = 0;
-        }
+	if (fsg->bulk_in_enabled) {
+		DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_in->name);
+		usb_ep_disable(fsg->bulk_in);
+		fsg->bulk_in_enabled = 0;
+	}
+	if (fsg->bulk_out_enabled) {
+		DBG(fsg, "usb_ep_disable %s\n", fsg->bulk_out->name);
+		usb_ep_disable(fsg->bulk_out);
+		fsg->bulk_out_enabled = 0;
+	}
 
 	/* Deallocate the requests */
 	for (i = 0; i < NUM_BUFFERS; ++i) {
@@ -2281,12 +2294,18 @@
 		}
 	}
 
-	/* Clear out the controller's fifos */
-	if (fsg->bulk_in_enabled)
-		usb_ep_fifo_flush(fsg->bulk_in);
-	if (fsg->bulk_out_enabled)
-		usb_ep_fifo_flush(fsg->bulk_out);
-
+	/*
+	* Do NOT flush the fifo after set_interface()
+	* Otherwise, it results in some data being lost
+	*/
+	if ((fsg->state != FSG_STATE_CONFIG_CHANGE) ||
+		(fsg->new_config != 1))   {
+		/* Clear out the controller's fifos */
+		if (fsg->bulk_in_enabled)
+			usb_ep_fifo_flush(fsg->bulk_in);
+		if (fsg->bulk_out_enabled)
+			usb_ep_fifo_flush(fsg->bulk_out);
+	}
 	/* Reset the I/O buffer states and pointers, the SCSI
 	 * state, and the exception.  Then invoke the handler. */
 	spin_lock_irq(&fsg->lock);
@@ -2924,7 +2943,7 @@
 		goto err_platform_driver_register;
 
 	wake_lock_init(&the_fsg->wake_lock, WAKE_LOCK_SUSPEND,
-		       "usb_mass_storage");
+			   "usb_mass_storage");
 
 	fsg->cdev = cdev;
 	fsg->function.name = shortname;
@@ -2943,6 +2962,7 @@
 	return 0;
 
 err_usb_add_function:
+	wake_lock_destroy(&the_fsg->wake_lock);
 	platform_driver_unregister(&fsg_platform_driver);
 err_platform_driver_register:
 	switch_dev_unregister(&the_fsg->sdev);
diff --git a/drivers/usb/gadget/u_ether.c b/drivers/usb/gadget/u_ether.c
index 96d65ca..334f7d1 100644
--- a/drivers/usb/gadget/u_ether.c
+++ b/drivers/usb/gadget/u_ether.c
@@ -54,6 +54,15 @@
 
 #define UETH__VERSION	"29-May-2008"
 
+/*
+ * Override the NET_IP_ALIGN macro to 0 bytes to have destination buffer
+ * aligned at 4 bytes thereby getting alligned adress for DMA access
+ */
+#if defined(CONFIG_ARCH_OMAP3) || defined(CONFIG_ARCH_OMAP4)
+#undef NET_IP_ALIGN
+#define NET_IP_ALIGN  0
+#endif
+
 struct eth_dev {
 	/* lock is held while accessing port_usb
 	 * or updating its backlink port_usb->ioport
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index 02df795..c8779f8 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -159,6 +159,7 @@
 	tristate "OHCI HCD support"
 	depends on USB && USB_ARCH_HAS_OHCI
 	select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+	select ISP1301_HOST if MACH_OMAP_3430SDP
 	select USB_OTG_UTILS if ARCH_OMAP
 	---help---
 	  The Open Host Controller Interface (OHCI) is a standard for accessing
@@ -173,6 +174,107 @@
 	  To compile this driver as a module, choose M here: the
 	  module will be called ohci-hcd.
 
+choice
+	prompt "PHY/TLL mode"
+	depends on USB_OHCI_HCD && ARCH_OMAP34XX
+	---help---
+	Choose PHY or TLL mode of operation for expansion board 750-2099-001(C)
+	The expansion board has been designed as:
+	Port1 connected to ISP1504
+	Port2 connected to ISP1504
+	Port3 connected to ISP1301
+
+config OMAP_OHCI_PHY_MODE
+	bool "OHCI PHY mode"
+	depends on USB_OHCI_HCD && ARCH_OMAP34XX
+	---help---
+	  OHCI PHY mode or TLL mode of operation to be chosen
+
+config OMAP_OHCI_PHY_MODE_PINS
+	bool "OHCI PHY mode Pins"
+	depends on OMAP_OHCI_PHY_MODE && USB_OHCI_HCD
+	default y
+	---help---
+	  OHCI PHY mode Number of pins
+
+config OMAP_OHCI_PHY_MODE_3PIN
+	bool "phy 3-pin"
+	depends on OMAP_OHCI_PHY_MODE_PINS
+	default y
+	---help---
+	  OHCI PHY 3-pin
+
+config OMAP_OHCI_PHY_MODE_4PIN
+	bool "phy 4-pin"
+	depends on OMAP_OHCI_PHY_MODE_PINS
+	---help---
+	  OHCI PHY 4-pin
+	  This is not implemented yet.
+
+config OMAP_OHCI_PHY_MODE_6PIN_DAT_SE0
+	bool "phy 6-pin dat/se0"
+	depends on OMAP_OHCI_PHY_MODE_PINS
+	---help---
+	  OHCI PHY 6-pin dat/se0
+	  This is not implemented yet.
+
+config OMAP_OHCI_PHY_MODE_6PIN_DP_DM
+	bool "phy 6-pin dp/dm"
+	depends on OMAP_OHCI_PHY_MODE_PINS
+	---help---
+	  OHCI PHY 6-pin dp/dm
+	  This is not implemented yet.
+
+config OMAP_OHCI_TLL_MODE
+	bool "OHCI TLL mode"
+	depends on USB_OHCI_HCD && ARCH_OMAP34XX
+	---help---
+	  OHCI PHY mode or TLL mode of operation to be chosen
+
+config OMAP_OHCI_TLL_MODE_PINS
+	bool "OHCI TLL mode Pins (NOT-IMPLEMENTED)"
+	depends on OMAP_OHCI_TLL_MODE
+	---help---
+	  OHCI TLL mode Number of pins
+
+config OMAP_OHCI_TLL_MODE_2PIN_DAT_SE0
+	bool "phy 2-pin DAT/SE0"
+	depends on OMAP_OHCI_TLL_MODE_PINS
+	---help---
+	  OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_2PIN_DP_DM
+	bool "phy 2-pin DP/DM"
+	depends on OMAP_OHCI_TLL_MODE_PINS
+	---help---
+	  OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_4PIN
+	bool "phy 4-pin"
+	depends on OMAP_OHCI_TLL_MODE_PINS
+	---help---
+	  OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_3PIN
+	bool "phy 3-pin"
+	depends on OMAP_OHCI_TLL_MODE_PINS
+	---help---
+	  OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_6PIN_DAT_SE0
+	bool "phy 6-pin DAT/SE0"
+	depends on OMAP_OHCI_TLL_MODE_PINS
+	---help---
+	  OHCI TLL
+
+config OMAP_OHCI_TLL_MODE_6PIN_DP_DM
+	bool "phy 6-pin DAT/SE0"
+	depends on OMAP_OHCI_TLL_MODE_PINS
+	---help---
+	  OHCI TLL
+endchoice
+
+
 config USB_OHCI_HCD_PPC_SOC
 	bool "OHCI support for on-chip PPC USB controller"
 	depends on USB_OHCI_HCD && (STB03xxx || PPC_MPC52xx)
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 97a53a4..ec082b7 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -567,6 +567,7 @@
 	unsigned long	flags;
 	int		retval = 0;
 	unsigned	selector;
+	u32		runstop;
 
 	/*
 	 * FIXME:  support SetPortFeatures USB_PORT_FEAT_INDICATOR.
@@ -708,6 +709,19 @@
 				set_bit(wIndex, &ehci->port_c_suspend);
 				ehci->reset_done[wIndex] = 0;
 
+				/* Workaround for OMAP errata:
+				 * The errata affects suspend-resume and
+				 * remote-wakeup. We need to halt the
+				 * controller before clearing the resume bit
+				 */
+				runstop = ehci_readl(ehci,
+							&ehci->regs->command);
+				ehci_writel(ehci, (runstop & ~1),
+							&ehci->regs->command);
+				(void) ehci_readl(ehci, &ehci->regs->command);
+				handshake(ehci, &ehci->regs->status,
+						STS_HALT, STS_HALT, 2000);
+
 				/* stop resume signaling */
 				temp = ehci_readl(ehci, status_reg);
 				ehci_writel(ehci,
@@ -715,6 +729,11 @@
 					status_reg);
 				retval = handshake(ehci, status_reg,
 					   PORT_RESUME, 0, 2000 /* 2msec */);
+
+				ehci_writel(ehci, runstop,
+							&ehci->regs->command);
+				(void) ehci_readl(ehci, &ehci->regs->command);
+
 				if (retval != 0) {
 					ehci_err(ehci,
 						"port %d resume error %d\n",
diff --git a/drivers/usb/host/ehci-omap.c b/drivers/usb/host/ehci-omap.c
index c6b1d02..1933c48 100644
--- a/drivers/usb/host/ehci-omap.c
+++ b/drivers/usb/host/ehci-omap.c
@@ -54,8 +54,16 @@
  *	Release the reset after a delay -
  *		to get the PHY state machine in working state
  */
-
+/* Setting:
+ *	Additional switch settings SW4.8=off, S5=1-2, S6=2-3
+ *	USB1HS EHCI PHY mode tested on SDP3630-V0-1-0 board using
+ *	750-2099-003(A) daughter card.
+ */
+#ifdef CONFIG_MACH_OMAP_3630SDP
+#define	EXT_PHY_RESET_GPIO_PORT1	(126)
+#else
 #define	EXT_PHY_RESET_GPIO_PORT1	(57)
+#endif
 #define	EXT_PHY_RESET_GPIO_PORT2	(61)
 
 static int default_usb_port_startup(struct platform_device *dev, int port)
@@ -82,6 +90,7 @@
 		return r;
 	}
 	gpio_direction_output(gpio, 0);
+	gpio_set_value(gpio, 1);
 	return 0;
 }
 
@@ -140,16 +149,18 @@
 
 static struct omap_usb_port_data default_usb_port_data[] = {
 	[0] = {
-		.flags = OMAP_USB_PORT_FLAG_ENABLED,
-		.mode = OMAP_USB_PORT_MODE_UTMI_PHY_6PIN,
+		.flags = (OMAP_USB_PORT_FLAG_ENABLED | \
+			OMAP_USB_PORT_FLAG_AUTOIDLE| \
+			OMAP_USB_PORT_FLAG_NOBITSTUFF),
+		.mode = OMAP_USB_PORT_MODE_ULPI_TLL_SDR,
 	},
 	[1] = {
-		.flags = OMAP_USB_PORT_FLAG_ENABLED,
-		.mode = OMAP_USB_PORT_MODE_ULPI_PHY,
+		.flags = OMAP_USB_PORT_FLAG_AUTOIDLE,
+		.mode = OMAP_USB_PORT_MODE_ULPI_TLL_SDR,
 	},
 	[2] = {
-		.flags = OMAP_USB_PORT_FLAG_ENABLED,
-		.mode = OMAP_USB_PORT_MODE_ULPI_PHY,
+		.flags = OMAP_USB_PORT_FLAG_AUTOIDLE,
+		.mode = OMAP_USB_PORT_MODE_ULPI_TLL_SDR,
 	},
 };
 
@@ -371,45 +382,6 @@
 				((char *)hcd_to_ehci(hcd)) +
 					sizeof(struct ehci_hcd));
 
-	/* Start DPLL5 Programming:
-	 * Clock Framework is not doing this now:
-	 * This will be done in clock framework later
-	 */
-	/* Enable DPLL 5 : Based on Input of 13Mhz*/
-	cm_write_mod_reg((12 << OMAP3430ES2_PERIPH2_DPLL_DIV_SHIFT)|
-			(120 << OMAP3430ES2_PERIPH2_DPLL_MULT_SHIFT),
-			PLL_MOD, OMAP3430ES2_CM_CLKSEL4);
-
-	cm_write_mod_reg(1 << OMAP3430ES2_DIV_120M_SHIFT,
-			PLL_MOD, OMAP3430ES2_CM_CLKSEL5);
-
-	cm_write_mod_reg((7 << OMAP3430ES2_PERIPH2_DPLL_FREQSEL_SHIFT) |
-			(7 << OMAP3430ES2_EN_PERIPH2_DPLL_SHIFT),
-			PLL_MOD, OMAP3430ES2_CM_CLKEN2);
-
-	while (!(cm_read_mod_reg(PLL_MOD, CM_IDLEST2) &
-				OMAP3430ES2_ST_PERIPH2_CLK_MASK))
-		dev_dbg(hcd->self.controller,
-			"idlest2 = 0x%x\n",
-			cm_read_mod_reg(PLL_MOD, CM_IDLEST2));
-	/* End DPLL5 programming */
-
-
-	/* PRCM settings for USBHOST:
-	 * Interface clk un-related to domain transition
-	 */
-	cm_write_mod_reg(0 << OMAP3430ES2_AUTO_USBHOST_SHIFT,
-				OMAP3430ES2_USBHOST_MOD, CM_AUTOIDLE);
-
-	/* Disable sleep dependency with MPU and IVA */
-	cm_write_mod_reg((0 << OMAP3430ES2_EN_MPU_SHIFT) |
-				(0 << OMAP3430ES2_EN_IVA2_SHIFT),
-				OMAP3430ES2_USBHOST_MOD, OMAP3430_CM_SLEEPDEP);
-
-	/* Disable Automatic transition of clock */
-	cm_write_mod_reg(0 << OMAP3430ES2_CLKTRCTRL_USBHOST_SHIFT,
-				OMAP3430ES2_USBHOST_MOD, CM_CLKSTCTRL);
-
 	/* Enable Clocks for USBHOST */
 	ehci_clocks->usbhost_ick_clk = clk_get(&dev->dev,
 						USBHOST_ICKL);
diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
index 5cf5f1e..bf75a84 100644
--- a/drivers/usb/host/ohci-hcd.c
+++ b/drivers/usb/host/ohci-hcd.c
@@ -1002,7 +1002,10 @@
 #define PLATFORM_DRIVER		ohci_hcd_s3c2410_driver
 #endif
 
-#ifdef CONFIG_ARCH_OMAP
+#ifdef CONFIG_ARCH_OMAP3
+#include "ohci-omap3.c"
+#define PLATFORM_DRIVER		ohci_hcd_omap_driver
+#elif defined(CONFIG_ARCH_OMAP)
 #include "ohci-omap.c"
 #define PLATFORM_DRIVER		ohci_hcd_omap_driver
 #endif
diff --git a/drivers/usb/host/ohci-omap3.c b/drivers/usb/host/ohci-omap3.c
new file mode 100644
index 0000000..7489c4e
--- /dev/null
+++ b/drivers/usb/host/ohci-omap3.c
@@ -0,0 +1,845 @@
+/*
+ * OHCI HCD (Host Controller Driver) for USB.
+ *
+ * (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
+ * (C) Copyright 2000-2005 David Brownell
+ * (C) Copyright 2002 Hewlett-Packard Company
+ * (C) Copyright 2007-2009 Texas Instruments
+ * (C) Copyright 2007 Vikram Pandita <vikram.pandita@ti.com>
+ * (C) Copyright 2008 Romit Dasgupta <romit@ti.com>
+ * (C) Copyright 2008-2009 Anand Gadiyar <gadiyar@ti.com>
+ *
+ * OMAP Bus Glue
+ *
+ * Modified for OMAP by Tony Lindgren <tony@atomide.com>
+ * Based on the 2.4 OMAP OHCI driver originally done by MontaVista Software Inc.
+ * and on ohci-sa1111.c by Christopher Hoover <ch@hpl.hp.com>
+ *
+ * This file is licenced under the GPL.
+ */
+
+#include <linux/signal.h>	/* IRQF_DISABLED */
+#include <linux/jiffies.h>
+#include <linux/platform_device.h>
+#include <linux/clk.h>
+
+#include <asm/io.h>
+#include <asm/mach-types.h>
+
+#include <mach/irqs.h>
+#include <mach/usb.h>
+
+#include "ehci-omap.h"
+
+#ifndef CONFIG_ARCH_OMAP
+#error "This file is OMAP bus glue.  CONFIG_OMAP must be defined."
+#endif
+
+extern int usb_disabled(void);
+extern int ocpi_enable(void);
+
+/* Define USBHOST clocks for clock management */
+struct ohci_omap_clock_defs {
+	struct clk	*usbhost_ick_clk;
+	struct clk	*usbhost2_120m_fck_clk;
+	struct clk	*usbhost1_48m_fck_clk;
+	struct clk	*usbtll_fck_clk;
+	struct clk	*usbtll_ick_clk;
+	unsigned	suspended:1;
+	/*
+	 * TODO:
+	 * host_enabled should be put in separate place.
+	 */
+	unsigned	host_enabled:1;
+};
+
+static struct ohci_context_registers {
+	u32	usbtll_sysconfig;
+	u32	usbtll_irqenable;
+	u32	tll_shared_conf;
+	u32	tll_channel_conf[3];
+	u8	ulpi_function_ctrl[3];
+	u8	ulpi_interface_ctrl[3];
+	u8	ulpi_otg_ctrl[3];
+	u8	ulpi_usb_int_en_rise[3];
+	u8	ulpi_usb_int_en_fall[3];
+	u8	ulpi_usb_int_status[3];
+	u8	ulpi_vendor_int_en[3];
+	u8	ulpi_vendor_int_status[3];
+} ohci_context;
+
+/* Clock names as per clock framework: May change so keep as #defs */
+#define USBHOST_ICLK            "usbhost_ick"
+#define USBHOST_120M_FCLK       "usbhost_120m_fck"
+#define USBHOST_48M_FCLK        "usbhost_48m_fck"
+#define USBHOST_TLL_ICLK        "usbtll_ick"
+#define USBHOST_TLL_FCLK        "usbtll_fck"
+
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_omap_init(struct usb_hcd *hcd)
+{
+	struct ohci_hcd		*ohci = hcd_to_ohci(hcd);
+	int			ret;
+
+	dev_dbg(hcd->self.controller, "starting USB Controller\n");
+
+	if ((ret = ohci_init(ohci)) < 0)
+		return ret;
+
+	/* board init will have already handled HMC and mux setup.
+	 * any external transceiver should already be initialized
+	 * too, so all configured ports use the right signaling now.
+	 */
+
+	return 0;
+}
+
+static void ohci_omap_stop(struct usb_hcd *hcd)
+{
+	dev_dbg(hcd->self.controller, "stopping USB Controller\n");
+}
+
+
+/*-------------------------------------------------------------------------*/
+/**
+ * usb_hcd_omap_probe - initialize OMAP-based HCDs
+ * Context: !in_interrupt()
+ *
+ * Allocates basic resources for this USB host controller, and
+ * then invokes the start() method for the HCD associated with it
+ * through the hotplug entry's driver_data.
+ */
+static int usb_hcd_omap_probe(const struct hc_driver *driver,
+			  struct platform_device *pdev)
+{
+	int retval;
+	int i;
+	u32 uhh_hostconfig_value;
+	u8 ohci_port_enable_mask = 0;
+	struct usb_hcd *hcd = 0;
+	struct ohci_hcd *ohci;
+	struct ohci_omap_clock_defs *ohci_clocks;
+
+	if (pdev->num_resources != 2) {
+		printk(KERN_ERR "hcd probe: invalid num_resources: %i\n",
+		       pdev->num_resources);
+		return -ENODEV;
+	}
+
+	if (pdev->resource[0].flags != IORESOURCE_MEM
+			|| pdev->resource[1].flags != IORESOURCE_IRQ) {
+		printk(KERN_ERR "hcd probe: invalid resource type\n");
+		return -ENODEV;
+	}
+
+	hcd = usb_create_hcd(driver, &pdev->dev, pdev->dev.bus_id);
+	if (!hcd) {
+		retval = -ENOMEM;
+		goto err0;
+	}
+
+	ohci_clocks = (struct ohci_omap_clock_defs *)
+			(((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+	/* Enable Clocks for USBHOST */
+	ohci_clocks->usbhost_ick_clk = clk_get(&pdev->dev,
+						USBHOST_ICLK);
+	if (IS_ERR(ohci_clocks->usbhost_ick_clk))
+		return PTR_ERR(ohci_clocks->usbhost_ick_clk);
+	clk_enable(ohci_clocks->usbhost_ick_clk);
+
+	ohci_clocks->usbhost2_120m_fck_clk = clk_get(&pdev->dev,
+						USBHOST_120M_FCLK);
+	if (IS_ERR(ohci_clocks->usbhost2_120m_fck_clk)) {
+		clk_disable(ohci_clocks->usbhost_ick_clk);
+		clk_put(ohci_clocks->usbhost_ick_clk);
+		return PTR_ERR(ohci_clocks->usbhost2_120m_fck_clk);
+	}
+	clk_enable(ohci_clocks->usbhost2_120m_fck_clk);
+
+	ohci_clocks->usbhost1_48m_fck_clk = clk_get(&pdev->dev,
+						USBHOST_48M_FCLK);
+	if (IS_ERR(ohci_clocks->usbhost1_48m_fck_clk)) {
+		clk_disable(ohci_clocks->usbhost_ick_clk);
+		clk_put(ohci_clocks->usbhost_ick_clk);
+		clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+		clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+		return PTR_ERR(ohci_clocks->usbhost1_48m_fck_clk);
+	}
+	clk_enable(ohci_clocks->usbhost1_48m_fck_clk);
+
+	/* Configure TLL for 60Mhz clk for ULPI */
+	ohci_clocks->usbtll_fck_clk = clk_get(&pdev->dev,
+						USBHOST_TLL_FCLK);
+	if (IS_ERR(ohci_clocks->usbtll_fck_clk)) {
+		clk_disable(ohci_clocks->usbhost_ick_clk);
+		clk_put(ohci_clocks->usbhost_ick_clk);
+		clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+		clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+		clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+		clk_put(ohci_clocks->usbhost1_48m_fck_clk);
+		return PTR_ERR(ohci_clocks->usbtll_fck_clk);
+	}
+	clk_enable(ohci_clocks->usbtll_fck_clk);
+
+	ohci_clocks->usbtll_ick_clk = clk_get(&pdev->dev,
+						USBHOST_TLL_ICLK);
+	if (IS_ERR(ohci_clocks->usbtll_ick_clk)) {
+		clk_disable(ohci_clocks->usbhost_ick_clk);
+		clk_put(ohci_clocks->usbhost_ick_clk);
+		clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+		clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+		clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+		clk_put(ohci_clocks->usbhost1_48m_fck_clk);
+		clk_disable(ohci_clocks->usbtll_fck_clk);
+		clk_put(ohci_clocks->usbtll_fck_clk);
+		return PTR_ERR(ohci_clocks->usbtll_ick_clk);
+	}
+
+	clk_enable(ohci_clocks->usbtll_ick_clk);
+
+	ohci_clocks->suspended = 0;
+
+	/* Disable Auto Idle of USBTLL */
+	cm_write_mod_reg((0 << OMAP3430ES2_AUTO_USBTLL_SHIFT),
+				CORE_MOD, CM_AUTOIDLE3);
+
+	/* Wait for TLL to be Active */
+	while ((cm_read_mod_reg(CORE_MOD, OMAP2430_CM_IDLEST3) &
+				(1 << OMAP3430ES2_ST_USBTLL_SHIFT)));
+
+	/* perform TLL soft reset, and wait until reset is complete */
+	omap_writel(1 << OMAP_USBTLL_SYSCONFIG_SOFTRESET_SHIFT,
+				OMAP_USBTLL_SYSCONFIG);
+	/* Wait for TLL reset to complete */
+	while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) &
+			(1 << OMAP_USBTLL_SYSSTATUS_RESETDONE_SHIFT)));
+
+	/* smart idle mode */
+	omap_writel((1 << OMAP_USBTLL_SYSCONFIG_ENAWAKEUP_SHIFT) |
+			(2 << OMAP_USBTLL_SYSCONFIG_SIDLEMODE_SHIFT) |
+			(0 << OMAP_USBTLL_SYSCONFIG_CACTIVITY_SHIFT) |
+			(1 << OMAP_USBTLL_SYSCONFIG_AUTOIDLE_SHIFT),
+						OMAP_USBTLL_SYSCONFIG);
+
+
+	/* Put UHH in NoIdle/NoStandby mode */
+	omap_writel((1 << OMAP_UHH_SYSCONFIG_AUTOIDLE_SHIFT) |
+			(1 << OMAP_UHH_SYSCONFIG_ENAWAKEUP_SHIFT) |
+			(1 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT) |
+			(0 << OMAP_UHH_SYSCONFIG_CACTIVITY_SHIFT) |
+			(1 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT),
+						OMAP_UHH_SYSCONFIG);
+
+#ifdef CONFIG_OMAP_OHCI_PHY_MODE
+	/* TLL in FS-PHY mode operation */
+	uhh_hostconfig_value = (1 << OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN_SHIFT) |
+			(1 << OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN_SHIFT) |
+			(1 << OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN_SHIFT) |
+			(0 << OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN_SHIFT);
+
+	if (omap_rev() >= OMAP3430_REV_ES3_0){
+
+/* For ES 3, we have per-port control for the ULPI Bypass
+ * The ULPI Bypass needs to be set to 0 only if the EHCI PHY Mode
+ * is selected for that port.
+ * Hence it is easier to make it conditional on EHCI_PHY_MODE
+ *
+ * ES 2 does not have per-port control. Hence it is not possible to have
+ * EHCI in PHY Mode and OHCI both working at the same time
+ *
+ * FIXME: This common code should be moved elsewhere
+ *
+ */
+
+#ifndef CONFIG_OMAP_EHCI_PHY_MODE_PORT1
+		uhh_hostconfig_value |=
+			(1 << OMAP_UHH_HOSTCONFIG_P1_ULPI_BYPASS_SHIFT);
+#endif
+
+#ifndef CONFIG_OMAP_EHCI_PHY_MODE_PORT2
+		uhh_hostconfig_value |=
+			(1 << OMAP_UHH_HOSTCONFIG_P2_ULPI_BYPASS_SHIFT);
+#endif
+
+#ifndef CONFIG_OMAP_EHCI_PHY_MODE_PORT3
+		uhh_hostconfig_value |=
+			(1 << OMAP_UHH_HOSTCONFIG_P3_ULPI_BYPASS_SHIFT);
+#endif
+	} else {
+		uhh_hostconfig_value |=
+			(1 << OMAP_UHH_HOSTCONFIG_P1_ULPI_BYPASS_SHIFT);
+	}
+
+	omap_writel(uhh_hostconfig_value, OMAP_UHH_HOSTCONFIG);
+
+#if 0
+	/* Ensure BYPASS bit is not set */
+	while (!(omap_readl(OMAP_UHH_HOSTCONFIG) &
+		(1 << OMAP_UHH_HOSTCONFIG_P3_ULPI_BYPASS_SHIFT)));
+#endif
+
+	pr_debug("Entered UTMI PHY MODE: success");
+
+	/* Program Common TLL register */
+	omap_writel((1 << OMAP_TLL_SHARED_CONF_FCLK_IS_ON_SHIFT) |
+			(1 << OMAP_TLL_SHARED_CONF_USB_DIVRATION_SHIFT) |
+			(0 << OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN_SHIFT) |
+			(0 << OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN_SHFT),
+				OMAP_TLL_SHARED_CONF);
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1)
+		ohci_port_enable_mask |= (1 << 0);
+		pr_debug("\n-> 3/4-PIN-PHY-mode of Port1\n");
+#endif
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2)
+		ohci_port_enable_mask |= (1 << 1);
+#endif
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3)
+		ohci_port_enable_mask |= (1 << 2);
+#endif
+
+	for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) {
+
+		/* Enable only required ports */
+		if (!(ohci_port_enable_mask & (1 << i)))
+			continue;
+
+		/* Disable AutoIdle */
+		omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+			    ~(1 << OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE_SHIFT),
+			    OMAP_TLL_CHANNEL_CONF(i));
+
+		/* Disable BitStuffing */
+		omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+			(1 << OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF_SHIFT),
+			OMAP_TLL_CHANNEL_CONF(i));
+
+		/* SDR Mode */
+		omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) &
+			    ~(1 << OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE_SHIFT),
+			    OMAP_TLL_CHANNEL_CONF(i));
+
+		/* CHANMODE: UTMI-to-serial FS/LS mode */
+		omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+			(1 << OMAP_TLL_CHANNEL_CONF_CHANMODE_SHIFT),
+			    OMAP_TLL_CHANNEL_CONF(i));
+
+#if 0
+		/* Enable port 3 only. Not enabling ports 1 & 2 */
+		if (i != 2)
+			continue;
+#endif
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT1) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT2) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_4PIN_PORT3)
+		pr_debug("\n-> Set:(4-PIN-PHY-mode-Port1)\n");
+		/* FSLSMODE: 4-pin bidirectional PHY */
+		omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+			(3 << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT),
+			    OMAP_TLL_CHANNEL_CONF(i));
+#endif
+
+#if defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT1) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT2) || \
+    defined(CONFIG_OMAP_OHCI_PHY_MODE_3PIN_PORT3)
+
+		/* FSLSMODE: 3-pin bidirectional PHY */
+		omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+			(2 << OMAP_TLL_CHANNEL_CONF_FSLSMODE_SHIFT),
+			    OMAP_TLL_CHANNEL_CONF(i));
+#endif
+
+		omap_writel(omap_readl(OMAP_TLL_CHANNEL_CONF(i)) |
+			    (1<<OMAP_TLL_CHANNEL_CONF_CHANEN_SHIFT),
+			    OMAP_TLL_CHANNEL_CONF(i));
+
+	}
+#else
+#error "FS-TLL Not implemented"
+#endif /* CONFIG_OMAP_OHCI_PHY_MODE */
+
+	hcd->rsrc_start = pdev->resource[0].start;
+	hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1;
+
+	/*
+	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
+		dev_dbg(&pdev->dev, "request_mem_region failed\n");
+		retval = -EBUSY;
+		goto err1;
+	}
+	 */
+
+	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
+	if (!hcd->regs) {
+		dev_err(&pdev->dev, "can't ioremap OHCI HCD\n");
+		retval = -ENOMEM;
+		goto err2;
+	}
+
+	/*
+	pr_debug("\n\n-->VIRT-OHCI-BASE [0x%x], [0x%x] irq[%d]\n\n",
+			hcd->regs, (unsigned int)io_p2v( 0x48064400 ),
+			pdev->resource[1].start);
+	 */
+
+	ohci = hcd_to_ohci(hcd);
+	ohci_hcd_init(ohci);
+
+	ohci_clocks->host_enabled = 1;
+
+	//irq = platform_get_irq(pdev, 0);
+	//if (irq < 0) {
+	//	retval = -ENXIO;
+	//	goto err3;
+	//}
+	retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED);
+	if (retval)
+		goto err3;
+
+	return 0;
+err3:
+	iounmap(hcd->regs);
+err2:
+//	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+//err1:
+	usb_put_hcd(hcd);
+	clk_disable(ohci_clocks->usbhost_ick_clk);
+	clk_put(ohci_clocks->usbhost_ick_clk);
+	clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+	clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+	clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+	clk_put(ohci_clocks->usbhost1_48m_fck_clk);
+	clk_disable(ohci_clocks->usbtll_fck_clk);
+	clk_put(ohci_clocks->usbtll_fck_clk);
+	clk_disable(ohci_clocks->usbtll_ick_clk);
+	clk_put(ohci_clocks->usbtll_ick_clk);
+err0:
+//	clk_put(usb_dc_ck);
+//	clk_put(usb_host_ck);
+	return retval;
+}
+
+/* may be called with controller, bus, and devices active */
+
+/**
+ * usb_hcd_omap_remove - shutdown processing for OMAP-based HCDs
+ * @dev: USB Host Controller being removed
+ * Context: !in_interrupt()
+ *
+ * Reverses the effect of usb_hcd_omap_probe(), first invoking
+ * the HCD's stop() method.  It is always called from a thread
+ * context, normally "rmmod", "apmd", or something similar.
+ */
+static inline void
+usb_hcd_omap_remove(struct usb_hcd *hcd, struct platform_device *pdev)
+{
+	struct ohci_omap_clock_defs *ohci_clocks;
+	struct ohci_hcd		*ohci = hcd_to_ohci (hcd);
+
+	ohci_clocks = (struct ohci_omap_clock_defs *)
+			(((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+	usb_remove_hcd(hcd);
+	if (ohci->transceiver) {
+		(void) otg_set_host(ohci->transceiver, 0);
+		put_device(ohci->transceiver->dev);
+	}
+	iounmap(hcd->regs);
+	//release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
+	usb_put_hcd(hcd);
+
+	/* Reset OMAP modules for insmod/rmmod to work */
+	omap_writel((1 << 1), OMAP_UHH_SYSCONFIG);
+	while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1 << 0)));
+	while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1 << 1)));
+	while (!(omap_readl(OMAP_UHH_SYSSTATUS) & (1 << 2)));
+	pr_debug("UHH RESET DONE OMAP_UHH_SYSSTATUS %x !!\n",
+			omap_readl(OMAP_UHH_SYSSTATUS));
+
+	omap_writel((1<<1), OMAP_USBTLL_SYSCONFIG);
+	while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) & (1<<0)));
+	pr_debug("TLL RESET DONE");
+
+	if (ohci_clocks->usbtll_fck_clk != NULL) {
+		clk_disable(ohci_clocks->usbtll_fck_clk);
+		clk_put(ohci_clocks->usbtll_fck_clk);
+		ohci_clocks->usbtll_fck_clk = NULL;
+	}
+
+	if (ohci_clocks->usbhost_ick_clk != NULL) {
+		clk_disable(ohci_clocks->usbhost_ick_clk);
+		clk_put(ohci_clocks->usbhost_ick_clk);
+		ohci_clocks->usbhost_ick_clk = NULL;
+	}
+
+	if (ohci_clocks->usbhost1_48m_fck_clk != NULL) {
+		clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+		clk_put(ohci_clocks->usbhost1_48m_fck_clk);
+		ohci_clocks->usbhost1_48m_fck_clk = NULL;
+	}
+
+	if (ohci_clocks->usbhost2_120m_fck_clk != NULL) {
+		clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+		clk_put(ohci_clocks->usbhost2_120m_fck_clk);
+		ohci_clocks->usbhost2_120m_fck_clk = NULL;
+	}
+
+	if (ohci_clocks->usbtll_ick_clk != NULL) {
+		clk_disable(ohci_clocks->usbtll_ick_clk);
+		clk_put(ohci_clocks->usbtll_ick_clk);
+		ohci_clocks->usbtll_ick_clk = NULL;
+	}
+}
+/*-------------------------------------------------------------------------*/
+
+static int
+ohci_omap_start(struct usb_hcd *hcd)
+{
+	struct omap_usb_config *config;
+	struct ohci_omap_clock_defs *ohci_clocks;
+	int		ret;
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+
+	ohci_clocks = (struct ohci_omap_clock_defs *)
+		(((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+	if (!ohci_clocks->host_enabled)
+		return 0;
+	config = hcd->self.controller->platform_data;
+#ifdef HACK_OMAP_OHCI /* todo */
+	if (config->otg || config->rwc) {
+		ohci->hc_control = OHCI_CTRL_RWC;
+		writel(OHCI_CTRL_RWC, &ohci->regs->control);
+	}
+#endif
+
+	ohci->hc_control = OHCI_CTRL_RWC;
+	writel(OHCI_CTRL_RWC, &ohci->regs->control);
+	if ((ret = ohci_run(ohci)) < 0) {
+		dev_err(hcd->self.controller, "can't start\n");
+		ohci_stop(hcd);
+		return ret;
+	}
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+#ifdef CONFIG_OMAP34XX_OFFMODE
+static void ohci_context_save(void)
+{
+	int i;
+
+	if (is_sil_rev_less_than(OMAP3430_REV_ES3_1)) {
+		ohci_context.usbtll_sysconfig =
+				omap_readl(OMAP_USBTLL_SYSCONFIG);
+		ohci_context.usbtll_irqenable =
+				omap_readl(OMAP_USBTLL_IRQENABLE);
+		ohci_context.tll_shared_conf =
+				omap_readl(OMAP_TLL_SHARED_CONF);
+
+		for (i = 0; i < 3; i++) {
+			ohci_context.tll_channel_conf[i] =
+				omap_readl(OMAP_TLL_CHANNEL_CONF(i));
+			ohci_context.ulpi_function_ctrl[i] =
+				omap_readb(OMAP_TLL_ULPI_FUNCTION_CTRL(i));
+			ohci_context.ulpi_interface_ctrl[i] =
+				omap_readb(OMAP_TLL_ULPI_INTERFACE_CTRL(i));
+			ohci_context.ulpi_otg_ctrl[i] =
+				omap_readb(OMAP_TLL_ULPI_OTG_CTRL(i));
+			ohci_context.ulpi_usb_int_en_rise[i] =
+				omap_readb(OMAP_TLL_ULPI_INT_EN_RISE(i));
+			ohci_context.ulpi_usb_int_en_fall[i] =
+				omap_readb(OMAP_TLL_ULPI_INT_EN_FALL(i));
+			ohci_context.ulpi_usb_int_status[i] =
+				omap_readb(OMAP_TLL_ULPI_INT_STATUS(i));
+		}
+	}
+}
+
+static void ohci_context_restore(void)
+{
+	int i;
+
+	if (is_sil_rev_less_than(OMAP3430_REV_ES3_1)) {
+
+#if 0
+	/* FIXME: This was reported as not working. Temporarily
+	 * disable this infinite loop pending investigation
+	 */
+
+	/* perform TLL soft reset, and wait until reset is complete */
+	omap_writel(1 << OMAP_USBTLL_SYSCONFIG_SOFTRESET_SHIFT,
+				OMAP_USBTLL_SYSCONFIG);
+
+	/* Wait for TLL reset to complete */
+	while (!(omap_readl(OMAP_USBTLL_SYSSTATUS) &
+			(1 << OMAP_USBTLL_SYSSTATUS_RESETDONE_SHIFT)));
+#endif
+
+		omap_writel(ohci_context.usbtll_sysconfig,
+					OMAP_USBTLL_SYSCONFIG);
+		omap_writel(ohci_context.tll_shared_conf,
+					OMAP_TLL_SHARED_CONF);
+
+		for (i = 0; i < 3; i++) {
+
+			omap_writel(ohci_context.tll_channel_conf[i],
+					OMAP_TLL_CHANNEL_CONF(i));
+			omap_writeb(ohci_context.ulpi_interface_ctrl[i],
+					OMAP_TLL_ULPI_INTERFACE_CTRL(i));
+			omap_writeb(ohci_context.ulpi_function_ctrl[i],
+					OMAP_TLL_ULPI_FUNCTION_CTRL(i));
+			omap_writeb(ohci_context.ulpi_otg_ctrl[i],
+					OMAP_TLL_ULPI_OTG_CTRL(i));
+			omap_writeb(ohci_context.ulpi_usb_int_en_rise[i],
+					OMAP_TLL_ULPI_INT_EN_RISE(i));
+			omap_writeb(ohci_context.ulpi_usb_int_en_fall[i],
+					OMAP_TLL_ULPI_INT_EN_FALL(i));
+			omap_writeb(ohci_context.ulpi_usb_int_status[i],
+					OMAP_TLL_ULPI_INT_STATUS(i));
+		}
+		omap_writel(ohci_context.usbtll_irqenable,
+					OMAP_USBTLL_IRQENABLE);
+	}
+}
+#else
+
+static void ohci_context_save(void)
+{
+}
+
+static void ohci_context_restore(void)
+{
+}
+
+#endif /* CONFIG_OMAP34XX_OFFMODE */
+
+static int omap_ohci_bus_suspend(struct usb_hcd *hcd)
+{
+	struct ohci_omap_clock_defs *ohci_clocks;
+	int ret = 0;
+	u32 uhh_sysconfig;
+
+	ohci_clocks = (struct ohci_omap_clock_defs *)
+			(((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+	if (!ohci_clocks->suspended) {
+		ret = ohci_bus_suspend(hcd);
+		if (ret)
+			return ret;
+		mdelay(8); /* MSTANDBY assertion delayed by ~8ms */
+
+		/* Need to set ForceStandby,ForceIdle here
+		 * else the domain may not be able to transition
+		 * back during clk_enable if there was a pending event.
+		 */
+
+		uhh_sysconfig = omap_readl(OMAP_UHH_SYSCONFIG);
+		uhh_sysconfig &= ~(3 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT);
+		uhh_sysconfig &= ~(3 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT);
+		omap_writel(uhh_sysconfig, OMAP_UHH_SYSCONFIG);
+
+		ohci_context_save();
+		clk_disable(ohci_clocks->usbhost_ick_clk);
+		clk_disable(ohci_clocks->usbhost2_120m_fck_clk);
+		clk_disable(ohci_clocks->usbhost1_48m_fck_clk);
+		clk_disable(ohci_clocks->usbtll_ick_clk);
+		clk_disable(ohci_clocks->usbtll_fck_clk);
+		ohci_clocks->suspended = 1;
+		clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+	}
+
+	return ret;
+}
+
+static int omap_ohci_bus_resume(struct usb_hcd *hcd)
+{
+	struct ohci_omap_clock_defs *ohci_clocks;
+	int ret = 0;
+	u32 uhh_sysconfig;
+
+	ohci_clocks = (struct ohci_omap_clock_defs *)
+			(((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+	if (ohci_clocks->suspended) {
+		clk_enable(ohci_clocks->usbtll_ick_clk);
+		clk_enable(ohci_clocks->usbtll_fck_clk);
+		ohci_context_restore();
+
+		clk_enable(ohci_clocks->usbhost_ick_clk);
+		clk_enable(ohci_clocks->usbhost2_120m_fck_clk);
+		clk_enable(ohci_clocks->usbhost1_48m_fck_clk);
+		ohci_clocks->suspended = 0;
+		set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
+
+		/* Need to set back to NoStandby,Noidle
+		 * FIXME: Maybe SmartIdle, SmartStandby will also work
+		 */
+
+		uhh_sysconfig = omap_readl(OMAP_UHH_SYSCONFIG);
+		uhh_sysconfig &= ~(3 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT);
+		uhh_sysconfig &= ~(3 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT);
+		uhh_sysconfig |= (1 << OMAP_UHH_SYSCONFIG_MIDLEMODE_SHIFT);
+		uhh_sysconfig |= (1 << OMAP_UHH_SYSCONFIG_SIDLEMODE_SHIFT);
+		omap_writel(uhh_sysconfig, OMAP_UHH_SYSCONFIG);
+
+		ret = ohci_bus_resume(hcd);
+	}
+
+	return ret;
+}
+
+static void omap_ohci_shutdown(struct usb_hcd *hcd)
+{
+	struct ohci_omap_clock_defs *ohci_clocks;
+	ohci_clocks = (struct ohci_omap_clock_defs *)
+			(((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+
+	if (ohci_clocks->suspended) {
+		clk_enable(ohci_clocks->usbhost_ick_clk);
+		clk_enable(ohci_clocks->usbtll_ick_clk);
+		clk_enable(ohci_clocks->usbtll_fck_clk);
+		clk_enable(ohci_clocks->usbhost1_48m_fck_clk);
+		clk_enable(ohci_clocks->usbhost2_120m_fck_clk);
+		ohci_clocks->suspended = 0;
+	}
+	ohci_shutdown(hcd);
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+static const struct hc_driver ohci_omap_hc_driver = {
+	.description =		hcd_name,
+	.product_desc =		"OMAP OHCI",
+	.hcd_priv_size =	sizeof(struct ohci_hcd)
+					+ sizeof(struct ohci_omap_clock_defs),
+
+	/*
+	 * generic hardware linkage
+	 */
+	.irq =			ohci_irq,
+	.flags =		HCD_USB11 | HCD_MEMORY,
+
+	/*
+	 * basic lifecycle operations
+	 */
+	.reset =		ohci_omap_init,
+	.start =		ohci_omap_start,
+	.stop =			ohci_omap_stop,
+	.shutdown =		omap_ohci_shutdown,
+
+	/*
+	 * managing i/o requests and associated device resources
+	 */
+	.urb_enqueue =		ohci_urb_enqueue,
+	.urb_dequeue =		ohci_urb_dequeue,
+	.endpoint_disable =	ohci_endpoint_disable,
+
+	/*
+	 * scheduling support
+	 */
+	.get_frame_number =	ohci_get_frame,
+
+	/*
+	 * root hub support
+	 */
+	.hub_status_data =	ohci_hub_status_data,
+	.hub_control =		ohci_hub_control,
+#ifdef	CONFIG_PM
+	.bus_suspend =		omap_ohci_bus_suspend,
+	.bus_resume =		omap_ohci_bus_resume,
+#endif
+	.start_port_reset =	ohci_start_port_reset,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int ohci_hcd_omap_drv_probe(struct platform_device *dev)
+{
+	return usb_hcd_omap_probe(&ohci_omap_hc_driver, dev);
+}
+
+static int ohci_hcd_omap_drv_remove(struct platform_device *dev)
+{
+	struct usb_hcd		*hcd = platform_get_drvdata(dev);
+	struct ohci_omap_clock_defs *ohci_clocks;
+	ohci_clocks = (struct ohci_omap_clock_defs *)
+			(((char *)hcd_to_ohci(hcd)) + sizeof(struct ohci_hcd));
+	if (ohci_clocks->suspended) {
+		clk_enable(ohci_clocks->usbhost_ick_clk);
+		clk_enable(ohci_clocks->usbtll_ick_clk);
+		clk_enable(ohci_clocks->usbtll_fck_clk);
+		clk_enable(ohci_clocks->usbhost1_48m_fck_clk);
+		clk_enable(ohci_clocks->usbhost2_120m_fck_clk);
+		ohci_clocks->suspended = 0;
+	}
+	usb_hcd_omap_remove(hcd, dev);
+//	platform_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+#if 0
+
+static int ohci_omap_suspend(struct platform_device *dev, pm_message_t message)
+{
+	struct ohci_hcd	*ohci = hcd_to_ohci(platform_get_drvdata(dev));
+
+	if (time_before(jiffies, ohci->next_statechange))
+		msleep(5);
+	ohci->next_statechange = jiffies;
+	omap_ohci_bus_suspend(ohci_to_hcd(ohci));
+	ohci_to_hcd(ohci)->state = HC_STATE_SUSPENDED;
+	dev->dev.power.power_state = PMSG_SUSPEND;
+	return 0;
+}
+
+static int ohci_omap_resume(struct platform_device *dev)
+{
+	struct usb_hcd *hcd = platform_get_drvdata(dev);
+	struct ohci_hcd	*ohci = hcd_to_ohci(hcd);
+
+	if (time_before(jiffies, ohci->next_statechange))
+		msleep(5);
+	ohci->next_statechange = jiffies;
+
+	dev->dev.power.power_state = PMSG_ON;
+	ohci_finish_controller_resume(hcd);
+	return 0;
+}
+
+#endif
+
+/*-------------------------------------------------------------------------*/
+
+/*
+ * Driver definition to register with the OMAP bus
+ */
+static struct platform_driver ohci_hcd_omap_driver = {
+	.probe		= ohci_hcd_omap_drv_probe,
+	.remove		= ohci_hcd_omap_drv_remove,
+	.shutdown	= usb_hcd_platform_shutdown,
+#if 0
+	.suspend	= ohci_omap_suspend,
+	.resume		= ohci_omap_resume,
+#endif
+	.driver		= {
+		.owner	= THIS_MODULE,
+		.name	= "ohci-omap",
+	},
+};
+
+MODULE_ALIAS("platform:ohci");
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 5424b7a..1237c32 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1304,8 +1304,7 @@
 #endif
 	u8 reg;
 	char *type;
-	u16 hwvers, rev_major, rev_minor;
-	char aInfo[78], aRevision[32], aDate[12];
+	char aInfo[100], aRevision[32], aDate[12];
 	void __iomem	*mbase = musb->mregs;
 	int		status = 0;
 	int		i;
@@ -1377,11 +1376,10 @@
 	}
 
 	/* log release info */
-	hwvers = musb_read_hwvers(mbase);
-	rev_major = (hwvers >> 10) & 0x1f;
-	rev_minor = hwvers & 0x3ff;
-	snprintf(aRevision, 32, "%d.%d%s", rev_major,
-		rev_minor, (hwvers & 0x8000) ? "RC" : "");
+	musb->hwvers = musb_read_hwvers(mbase);
+	snprintf(aRevision, 32, "%d.%d%s", MUSB_HWVERS_MAJOR(musb->hwvers),
+		MUSB_HWVERS_MINOR(musb->hwvers),
+		(musb->hwvers & MUSB_HWVERS_RC) ? "RC" : "");
 	printk(KERN_DEBUG "%s: %sHDRC RTL version %s %s\n",
 			musb_driver_name, type, aRevision, aDate);
 
@@ -2142,17 +2140,14 @@
 
 #ifdef	CONFIG_PM
 
-static int musb_suspend(struct platform_device *pdev, pm_message_t message)
+static int musb_suspend_late(struct platform_device *pdev, pm_message_t message)
 {
-	unsigned long	flags;
 	struct musb	*musb = dev_to_musb(&pdev->dev);
 
 	if (!musb->clock)
 		return 0;
 
-	spin_lock_irqsave(&musb->lock, flags);
-
-	musb_save_context(musb);
+	musb_platform_save_context(musb);
 
 	if (is_peripheral_active(musb)) {
 		/* FIXME force disconnect unless we know USB will wake
@@ -2168,32 +2163,28 @@
 		musb->set_clock(musb->clock, 0);
 	else
 		clk_disable(musb->clock);
-	spin_unlock_irqrestore(&musb->lock, flags);
+
 	return 0;
 }
 
-static int musb_resume(struct platform_device *pdev)
+static int musb_resume_early(struct platform_device *pdev)
 {
-	unsigned long	flags;
 	struct musb	*musb = dev_to_musb(&pdev->dev);
 
 	if (!musb->clock)
 		return 0;
 
-	spin_lock_irqsave(&musb->lock, flags);
-
 	if (musb->set_clock)
 		musb->set_clock(musb->clock, 1);
 	else
 		clk_enable(musb->clock);
 
-	musb_restore_context(musb);
+	musb_platform_restore_context(musb);
 
 	/* for static cmos like DaVinci, register values were preserved
 	 * unless for some reason the whole soc powered down and we're
 	 * not treating that as a whole-system restart (e.g. swsusp)
 	 */
-	spin_unlock_irqrestore(&musb->lock, flags);
 	return 0;
 }
 
@@ -2210,8 +2201,8 @@
 	},
 	.remove		= __devexit_p(musb_remove),
 	.shutdown	= musb_shutdown,
-	.suspend	= musb_suspend,
-	.resume		= musb_resume,
+	.suspend_late	= musb_suspend_late,
+	.resume_early	= musb_resume_early,
 };
 
 /*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h
index e1d0adc..ef0b9bd 100644
--- a/drivers/usb/musb/musb_core.h
+++ b/drivers/usb/musb/musb_core.h
@@ -309,6 +309,14 @@
 	struct clk		*clock;
 	irqreturn_t		(*isr)(int, void *);
 	struct work_struct	irq_work;
+#define MUSB_HWVERS_MAJOR(x)	((x >> 10) & 0x1f)
+#define MUSB_HWVERS_MINOR(x)	(x & 0x3ff)
+#define MUSB_HWVERS_RC		0x8000
+#define MUSB_HWVERS_1300	0x52C
+#define MUSB_HWVERS_1400	0x590
+#define MUSB_HWVERS_1800	0x720
+#define MUSB_HWVERS_2000	0x800
+	u16			hwvers;
 
 /* this hub status bit is reserved by USB 2.0 and not seen by usbcore */
 #define MUSB_PORT_STAT_RESUME	(1 << 31)
@@ -527,8 +535,8 @@
 
 extern irqreturn_t musb_interrupt(struct musb *);
 
-extern void musb_save_context(struct musb *musb);
-extern void musb_restore_context(struct musb *musb);
+extern void musb_platform_save_context(struct musb *musb);
+extern void musb_platform_restore_context(struct musb *musb);
 
 extern void musb_platform_enable(struct musb *musb);
 extern void musb_platform_disable(struct musb *musb);
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 62e5a3e..e11eee4 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -678,8 +678,16 @@
 							transfer_size);
 				}
 
-				if (use_dma)
+				if (use_dma) {
 					return;
+				} else {
+					/* Need to clear DMAENAB for the
+					 * backup PIO mode transfer to work
+					 */
+					csr &= ~MUSB_RXCSR_DMAENAB;
+					musb_writew(epio, MUSB_RXCSR, csr);
+				}
+
 			}
 #endif	/* Mentor's DMA */
 
@@ -1516,6 +1524,7 @@
 	spin_lock_irqsave(&musb->lock, flags);
 	if (is_on) {
 	    if (!musb->softconnect) {
+			musb_start(musb);
 			musb->softconnect = 1;
 			musb_pullup(musb, is_on);
 		}
diff --git a/drivers/usb/musb/musbhsdma.c b/drivers/usb/musb/musbhsdma.c
index 8662e9e..5c07afb 100644
--- a/drivers/usb/musb/musbhsdma.c
+++ b/drivers/usb/musb/musbhsdma.c
@@ -151,6 +151,11 @@
 				? (1 << MUSB_HSDMA_TRANSMIT_SHIFT)
 				: 0);
 
+	if (musb_channel->transmit)
+		controller->tx_active |= (1 << bchannel);
+	else
+		controller->rx_active |= (1 << bchannel);
+
 	/* address/count */
 	musb_write_hsdma_addr(mbase, bchannel, dma_addr);
 	musb_write_hsdma_count(mbase, bchannel, len);
@@ -166,6 +171,8 @@
 				dma_addr_t dma_addr, u32 len)
 {
 	struct musb_dma_channel *musb_channel = channel->private_data;
+	struct musb_dma_controller *controller = musb_channel->controller;
+	struct musb *musb = controller->private_data;
 
 	DBG(2, "ep%d-%s pkt_sz %d, dma_addr 0x%x length %d, mode %d\n",
 		musb_channel->epnum,
@@ -175,6 +182,26 @@
 	BUG_ON(channel->status == MUSB_DMA_STATUS_UNKNOWN ||
 		channel->status == MUSB_DMA_STATUS_BUSY);
 
+	/*
+	 * make sure the DMA address is 4 byte aligned, if not
+	 * we use the PIO mode for OMAP 3630 and beyond
+	 */
+	if ((dma_addr % 4) && (musb->hwvers >= MUSB_HWVERS_1800))
+		return false;
+
+	/* In version 1.4, if two DMA channels are simultaneously
+	 * enabled in opposite directions, there is a chance that
+	 * the DMA controller will hang. However, it is safe to
+	 * have multiple DMA channels enabled in the same direction
+	 * at the same time.
+	 */
+	if (musb->hwvers == MUSB_HWVERS_1400) {
+		if (musb_channel->transmit && controller->rx_active)
+			return false;
+		else if	(!musb_channel->transmit && controller->tx_active)
+			return false;
+	}
+
 	channel->actual_len = 0;
 	musb_channel->start_addr = dma_addr;
 	musb_channel->len = len;
@@ -227,6 +254,11 @@
 		musb_write_hsdma_addr(mbase, bchannel, 0);
 		musb_write_hsdma_count(mbase, bchannel, 0);
 		channel->status = MUSB_DMA_STATUS_FREE;
+
+		if (musb_channel->transmit)
+			musb_channel->controller->tx_active &= ~(1 << bchannel);
+		else
+			musb_channel->controller->rx_active &= ~(1 << bchannel);
 	}
 
 	return 0;
@@ -249,13 +281,32 @@
 	u8 int_hsdma;
 
 	u32 addr;
-	u16 csr;
+	u16 csr, count;
 
 	spin_lock_irqsave(&musb->lock, flags);
 
 	int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR);
-	if (!int_hsdma)
-		goto done;
+	if (!int_hsdma) {
+		DBG(2, "spurious DMA irq\n");
+
+		for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
+			musb_channel = (struct musb_dma_channel *)
+					&(controller->channel[bchannel]);
+			channel = &musb_channel->channel;
+			if (channel->status == MUSB_DMA_STATUS_BUSY) {
+				count = musb_readw(mbase,
+					MUSB_HSDMA_CHANNEL_OFFSET(bchannel,
+							MUSB_HSDMA_COUNT));
+				if (count == 0)
+					int_hsdma |= (1 << bchannel);
+			}
+		}
+
+		DBG(2, "int_hsdma = 0x%x\n", int_hsdma);
+
+		if (!int_hsdma)
+			goto done;
+	}
 
 	for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) {
 		if (int_hsdma & (1 << bchannel)) {
@@ -290,6 +341,13 @@
 
 				channel->status = MUSB_DMA_STATUS_FREE;
 
+				if (musb_channel->transmit)
+					controller->tx_active &=
+							~(1 << bchannel);
+				else
+					controller->rx_active &=
+							~(1 << bchannel);
+
 				/* completed */
 				if ((devctl & MUSB_DEVCTL_HM)
 					&& (musb_channel->transmit)
diff --git a/drivers/usb/musb/musbhsdma.h b/drivers/usb/musb/musbhsdma.h
index 1299d92..df87863 100644
--- a/drivers/usb/musb/musbhsdma.h
+++ b/drivers/usb/musb/musbhsdma.h
@@ -146,4 +146,6 @@
 	u8				channel_count;
 	u8				used_channels;
 	u8				irq;
+	u8				tx_active;
+	u8				rx_active;
 };
diff --git a/drivers/usb/musb/omap2430.c b/drivers/usb/musb/omap2430.c
index c186043..ec8a448 100644
--- a/drivers/usb/musb/omap2430.c
+++ b/drivers/usb/musb/omap2430.c
@@ -37,10 +37,14 @@
 #include <asm/mach-types.h>
 #include <mach/hardware.h>
 #include <mach/mux.h>
+#include <mach/omap-pm.h>
 
 #include "musb_core.h"
 #include "omap2430.h"
 
+#define VDD1_OPP3_FREQ	500000000
+#define VDD1_OPP1_FREQ	125000000
+
 #ifdef CONFIG_ARCH_OMAP3430
 #define	get_cpu_rev()	2
 #endif
@@ -49,6 +53,10 @@
 
 static struct timer_list musb_idle_timer;
 
+void musb_link_save_context(struct otg_transceiver *xceiv);
+void musb_link_restore_context(struct otg_transceiver *xceiv);
+void musb_link_force_active(int on);
+
 static void musb_do_idle(unsigned long _musb)
 {
 	struct musb	*musb = (void *)_musb;
@@ -152,6 +160,17 @@
 {
 }
 
+/*  Set the MUSB vdd1 opp constraint */
+static void musb_set_opp_constraint(struct musb *musb)
+{
+	struct musb_hdrc_platform_data *pdata =
+			musb->controller->platform_data;
+
+	/* Initialize vdd1 to opp3 constraint  */
+	if (pdata->set_vdd1_opp)
+		pdata->set_vdd1_opp(musb->controller, VDD1_OPP3_FREQ);
+}
+
 static void omap_set_vbus(struct musb *musb, int is_on)
 {
 	u8		devctl;
@@ -247,13 +266,17 @@
 	musb->xceiv = *x;
 	musb_platform_resume(musb);
 
+	/*
+	 * Do Forcestdby here, for the case when kernel boots up
+	 * without cable attached, force_active(0) won't be called.
+	 */
 	l = omap_readl(OTG_SYSCONFIG);
-	l &= ~ENABLEWAKEUP;	/* disable wakeup */
+	l |= ENABLEWAKEUP;	/* Enable wakeup */
 	l &= ~NOSTDBY;		/* remove possible nostdby */
-	l |= SMARTSTDBY;	/* enable smart standby */
+	l |= FORCESTDBY;	/* enable smart standby */
 	l &= ~AUTOIDLE;		/* disable auto idle */
 	l &= ~NOIDLE;		/* remove possible noidle */
-	l |= SMARTIDLE;		/* enable smart idle */
+	l |= FORCEIDLE;		/* enable smart idle */
 	/*
 	 * MUSB AUTOIDLE don't work in 3430.
 	 * Workaround by Richard Woodruff/TI
@@ -280,6 +303,13 @@
 		musb->xceiv.set_power = omap_set_power;
 	musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON;
 
+	x->link_save_context = musb_link_save_context;
+	x->link_restore_context = musb_link_restore_context;
+	x->link_force_active = musb_link_force_active;
+	x->link = musb;
+
+	otg_put_transceiver(x);
+
 	setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb);
 
 	return 0;
@@ -297,6 +327,7 @@
 
 static struct musb_context_registers {
 
+	u32 off_counter;
 	u32 otg_sysconfig, otg_forcestandby;
 
 	u8 faddr, power;
@@ -311,12 +342,16 @@
 
 } musb_context;
 
-void musb_save_context(struct musb *musb)
+void musb_platform_save_context(struct musb *musb)
 {
 	int i;
+	struct musb_hdrc_platform_data *plat = musb->controller->platform_data;
 
 	DBG(4, "Saving musb_registers\n");
 
+	musb_context.off_counter =
+			plat->context_loss_counter(musb->controller);
+
 	musb_context.otg_sysconfig = omap_readl(OTG_SYSCONFIG);
 	musb_context.otg_forcestandby = omap_readl(OTG_FORCESTDBY);
 
@@ -370,7 +405,7 @@
 
 }
 
-void musb_restore_context(struct musb *musb)
+void musb_platform_restore_context(struct musb *musb)
 {
 	int i;
 
@@ -439,10 +474,107 @@
 
 }
 
+void musb_link_save_context(struct otg_transceiver *xceiv)
+{
+	struct musb	*musb = xceiv->link;
+
+	struct musb_hdrc_platform_data *pdata =
+			musb->controller->platform_data;
+
+	musb_platform_save_context(musb);
+
+	/* On cable detach remove restriction on CORE domain:
+	 * Now core domain can go to off
+	 */
+	omap_pm_set_max_mpu_wakeup_lat(musb->controller, -1);
+
+	/* Initialize vdd1 to opp1 constraint  */
+	if (pdata->set_vdd1_opp)
+		pdata->set_vdd1_opp(musb->controller, VDD1_OPP1_FREQ);
+}
+
+void musb_link_restore_context(struct otg_transceiver *xceiv)
+{
+	struct musb	*musb = xceiv->link;
+	struct musb_hdrc_platform_data *plat =
+			musb->controller->platform_data;
+
+	/* MUSB has no h/w SAR: So restrict CORE domain
+	 * from going to OFF mode
+	 * So prevent CPUIdle going to C7, restrict to C6
+	 */
+	omap_pm_set_max_mpu_wakeup_lat(musb->controller, 6250);
+	musb_set_opp_constraint(musb);
+
+	/* No context restore needed in case
+	 * OFF transition has not happened
+	 */
+	if (musb_context.off_counter ==
+		plat->context_loss_counter(musb->controller)) {
+		DBG(4,"No context was lost. Not restoring.\n");
+		return;
+	}
+
+	musb_platform_restore_context(musb);
+}
+
+void musb_link_force_active(int enable)
+{
+	u32 l;
+
+	l = omap_readl(OTG_SYSCONFIG);
+
+	/*
+	 * We have encountered enumeration problems on the omap3
+	 * when power management has been enabled and the device
+	 * is transitioning in and out of CORE retention. To
+	 * workaround this problem, we force the musb controller
+	 * to be always active (no idle/standby) when the usb
+	 * cable is attached and inactive (smart idle/standby)
+	 * when the cable is removed.
+	 */
+	if (enable) {
+		l &= ~SMARTSTDBY;	/* disable smart standby */
+		l |= NOSTDBY;		/* enable nostdby */
+		l &= ~SMARTIDLE;	/* disable smart idle */
+		l |= NOIDLE;		/* enable noidle */
+
+		/* Disable Mstandby */
+		omap_writel((omap_readl(OTG_FORCESTDBY) & ~ENABLEFORCE),
+				 OTG_FORCESTDBY);
+	} else {
+		/*
+		 * When the device is disconnected put the OTG to
+		 * Forceidle and Forcestdby. There where known issues
+		 * on different custom boards, wherein
+		 * the OTG idle ack was broken. May be the OTG senses
+		 * some fake activity on the lines.
+		 * Also, this might be moved to suspend/resume hooks.
+		 * Right now, musb doesn't have suspend/resume hooks
+		 * plugged in to LDM.
+		 */
+		l |= ENABLEWAKEUP;	/* Enable wakeup */
+		l &= ~SMARTSTDBY;	/* enable smart standby */
+		l |= FORCESTDBY;
+		l &= ~NOSTDBY;		/* disable nostdby */
+		l |= FORCEIDLE;
+		l &= ~NOIDLE;		/* disable noidle */
+
+		/* Enable Mstdby */
+		omap_writel((omap_readl(OTG_FORCESTDBY) | ENABLEFORCE),
+				 OTG_FORCESTDBY);
+	}
+
+	omap_writel(l, OTG_SYSCONFIG);
+}
+
 #else
 
-#define musb_save_context	do {} while (0)
-#define musb_restore_context	do {} while (0)
+#define musb_platform_save_context	do {} while (0)
+#define musb_platform_restore_context	do {} while (0)
+#define musb_link_save_context	do {} while (0)
+#define musb_link_restore_context	do {} while (0)
+#define musb_link_force_active	do {} while (0)
 
 #endif
 
@@ -502,6 +634,7 @@
 
 int musb_platform_exit(struct musb *musb)
 {
+	struct otg_transceiver *x = otg_get_transceiver();
 
 	omap_vbus_power(musb, 0 /*off*/, 1);
 
@@ -510,5 +643,11 @@
 	clk_put(musb->clock);
 	musb->clock = 0;
 
+	x->link_save_context = NULL;
+	x->link_restore_context = NULL;
+	x->link = NULL;
+
+	otg_put_transceiver(x);
+
 	return 0;
 }
diff --git a/drivers/usb/otg/Kconfig b/drivers/usb/otg/Kconfig
index ee55b44..ce46e94 100644
--- a/drivers/usb/otg/Kconfig
+++ b/drivers/usb/otg/Kconfig
@@ -43,7 +43,7 @@
 
 config TWL4030_USB
 	tristate "TWL4030 USB Transceiver Driver"
-	depends on TWL4030_CORE
+	depends on TWL4030_CORE && REGULATOR_TWL4030
 	select USB_OTG_UTILS
 	help
 	  Enable this to support the USB OTG transceiver on TWL4030
@@ -51,4 +51,17 @@
 	  This transceiver supports high and full speed devices plus,
 	  in host mode, low speed.
 
+config ISP1301_HOST
+	bool "Philips ISP1301 in Host mode with OMAP3 OHCI"
+	depends on ARCH_OMAP_OTG && (MACH_OMAP_3430SDP || MACH_OMAP_3630SDP)
+	default y
+	help
+	  If you say yes here you get support for the Philips ISP1301
+	  USB-On-The-Go transceiver working with the OMAP3 OHCI controller.
+	  The ISP1301 is used in products including the 3430SDP development
+	  boards for Texas Instruments OMAP3 processors.
+
+	  This driver can also be built as a module.  If so, the module
+	  will be called isp1301_host.
+
 endif # USB || OTG
diff --git a/drivers/usb/otg/Makefile b/drivers/usb/otg/Makefile
index d73c7cf..89c25ad 100644
--- a/drivers/usb/otg/Makefile
+++ b/drivers/usb/otg/Makefile
@@ -9,6 +9,7 @@
 obj-$(CONFIG_USB_GPIO_VBUS)	+= gpio_vbus.o
 obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o
 obj-$(CONFIG_TWL4030_USB)	+= twl4030-usb.o
+obj-$(CONFIG_ISP1301_HOST)	+= isp1301_host.o
 
 ccflags-$(CONFIG_USB_DEBUG)	+= -DDEBUG
 ccflags-$(CONFIG_USB_GADGET_DEBUG) += -DDEBUG
diff --git a/drivers/usb/otg/isp1301_host.c b/drivers/usb/otg/isp1301_host.c
new file mode 100644
index 0000000..578633e
--- /dev/null
+++ b/drivers/usb/otg/isp1301_host.c
@@ -0,0 +1,247 @@
+/*
+ * isp1301_host - ISP 1301 USB transceiver, talking to OMAP OHCI controller
+ *
+ * Copyright (C) 2004 Texas Instruments
+ * Copyright (C) 2004 David Brownell
+ * Copyright (C) 2008 Anand Gadiyar
+ *
+ * Based on isp1301_omap.c
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* The ISP1301 is used with the OHCI controller in the OMAP3430 SDP.
+ * The other isp1301 driver does otg_set_transceiver if CONFIG_OTG is
+ * defined. For the OMAP3, the MUSB controller is the OTG controller
+ * (and therefore CONFIG_OTG would likely be defined) but it very likely
+ * would be used with a different transceiver (TWL4030, ISP1504, ...)
+ *
+ * This driver is a stub driver meant to put the ISP1301 in host mode.
+ * It is based on the original isp1301 driver.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/i2c.h>
+
+
+#define DRIVER_VERSION	"10 February 2009"
+#define DRIVER_NAME	(isp1301_driver.driver.name)
+
+MODULE_DESCRIPTION("ISP1301 USB HOST Transceiver Driver");
+MODULE_LICENSE("GPL");
+
+struct isp1301 {
+	struct i2c_client	*client;
+	void			(*i2c_release)(struct device *dev);
+
+	int			irq_type;
+
+	unsigned		working:1;
+
+};
+
+
+
+/*-------------------------------------------------------------------------*/
+
+static struct i2c_driver isp1301_driver;
+
+/* smbus apis are used for portability */
+
+static inline u8 isp1301_get_u8(struct isp1301 *isp, u8 reg)
+{
+	return i2c_smbus_read_byte_data(isp->client, reg + 0);
+}
+
+static inline int isp1301_get_u16(struct isp1301 *isp, u8 reg)
+{
+	return i2c_smbus_read_word_data(isp->client, reg);
+}
+
+static inline int isp1301_set_bits(struct isp1301 *isp, u8 reg, u8 bits)
+{
+	return i2c_smbus_write_byte_data(isp->client, reg + 0, bits);
+}
+
+static inline int isp1301_clear_bits(struct isp1301 *isp, u8 reg, u8 bits)
+{
+	return i2c_smbus_write_byte_data(isp->client, reg + 1, bits);
+}
+
+/*-------------------------------------------------------------------------*/
+
+/* identification */
+#define	ISP1301_VENDOR_ID		0x00	/* u16 read */
+#define	ISP1301_PRODUCT_ID		0x02	/* u16 read */
+#define	ISP1301_BCD_DEVICE		0x14	/* u16 read */
+
+#define	I2C_VENDOR_ID_PHILIPS		0x04cc
+#define	I2C_PRODUCT_ID_PHILIPS_1301	0x1301
+
+/* operational registers */
+#define	ISP1301_MODE_CONTROL_1		0x04	/* u8 read, set, +1 clear */
+#	define	MC1_SPEED		(1 << 0)
+#	define	MC1_SUSPEND		(1 << 1)
+#	define	MC1_DAT_SE0		(1 << 2)
+#	define	MC1_TRANSPARENT		(1 << 3)
+#	define	MC1_BDIS_ACON_EN	(1 << 4)
+#	define	MC1_OE_INT_EN		(1 << 5)
+#	define	MC1_UART_EN		(1 << 6)
+#	define	MC1_MASK		0x7f
+#define	ISP1301_MODE_CONTROL_2		0x12	/* u8 read, set, +1 clear */
+#	define	MC2_GLOBAL_PWR_DN	(1 << 0)
+#	define	MC2_SPD_SUSP_CTRL	(1 << 1)
+#	define	MC2_BI_DI		(1 << 2)
+#	define	MC2_TRANSP_BDIR0	(1 << 3)
+#	define	MC2_TRANSP_BDIR1	(1 << 4)
+#	define	MC2_AUDIO_EN		(1 << 5)
+#	define	MC2_PSW_EN		(1 << 6)
+#	define	MC2_EN2V7		(1 << 7)
+#define	ISP1301_OTG_CONTROL_1		0x06	/* u8 read, set, +1 clear */
+#	define	OTG1_DP_PULLUP		(1 << 0)
+#	define	OTG1_DM_PULLUP		(1 << 1)
+#	define	OTG1_DP_PULLDOWN	(1 << 2)
+#	define	OTG1_DM_PULLDOWN	(1 << 3)
+#	define	OTG1_ID_PULLDOWN	(1 << 4)
+#	define	OTG1_VBUS_DRV		(1 << 5)
+#	define	OTG1_VBUS_DISCHRG	(1 << 6)
+#	define	OTG1_VBUS_CHRG		(1 << 7)
+
+#define	ISP1301_INTERRUPT_SOURCE	0x08	/* u8 read */
+#define	ISP1301_INTERRUPT_LATCH		0x0A	/* u8 read, set, +1 clear */
+
+#define	ISP1301_INTERRUPT_FALLING	0x0C	/* u8 read, set, +1 clear */
+#define	ISP1301_INTERRUPT_RISING	0x0E	/* u8 read, set, +1 clear */
+
+/*-------------------------------------------------------------------------*/
+
+static void isp1301_release(struct device *dev)
+{
+	struct isp1301	*isp;
+
+	isp = dev_get_drvdata(dev);
+
+	/* ugly -- i2c hijacks our memory hook to wait_for_completion() */
+	if (isp->i2c_release)
+		isp->i2c_release(dev);
+	kfree(isp);
+}
+
+static int __exit isp1301_remove(struct i2c_client *i2c)
+{
+	struct isp1301	*isp;
+
+	isp = i2c_get_clientdata(i2c);
+
+	isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
+	isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
+
+	put_device(&i2c->dev);
+
+	return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __init
+isp1301_probe(struct i2c_client *i2c, const struct i2c_device_id *id)
+{
+	int			status;
+	struct isp1301		*isp;
+
+
+	isp = kzalloc(sizeof *isp, GFP_KERNEL);
+	if (!isp)
+		return 0;
+
+	i2c_set_clientdata(i2c, isp);
+	isp->client = i2c;
+
+	/* verify the chip (shouldn't be necesary) */
+	status = isp1301_get_u16(isp, ISP1301_VENDOR_ID);
+	if (status != I2C_VENDOR_ID_PHILIPS) {
+		dev_dbg(&i2c->dev, "not philips id: %d\n", status);
+		goto fail;
+	}
+	status = isp1301_get_u16(isp, ISP1301_PRODUCT_ID);
+	if (status != I2C_PRODUCT_ID_PHILIPS_1301) {
+		dev_dbg(&i2c->dev, "not isp1301, %d\n", status);
+		goto fail;
+	}
+	isp->i2c_release = i2c->dev.release;
+	i2c->dev.release = isp1301_release;
+
+	/* initial development used chiprev 2.00 */
+	status = i2c_smbus_read_word_data(i2c, ISP1301_BCD_DEVICE);
+	dev_info(&i2c->dev, "chiprev %x.%02x, driver " DRIVER_VERSION "\n",
+		status >> 8, status & 0xff);
+
+	/* make like power-on reset */
+	isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_MASK);
+
+	isp1301_set_bits(isp, ISP1301_MODE_CONTROL_2, MC2_BI_DI);
+	isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_2, ~MC2_BI_DI);
+
+	isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1,
+				OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN);
+	isp1301_clear_bits(isp, ISP1301_OTG_CONTROL_1,
+				~(OTG1_DM_PULLDOWN | OTG1_DP_PULLDOWN));
+
+	isp1301_clear_bits(isp, ISP1301_INTERRUPT_LATCH, ~0);
+	isp1301_clear_bits(isp, ISP1301_INTERRUPT_FALLING, ~0);
+	isp1301_clear_bits(isp, ISP1301_INTERRUPT_RISING, ~0);
+
+	/* ISP1301 is put in host mode by default for OHCI host */
+
+	isp1301_clear_bits(isp, ISP1301_MODE_CONTROL_1, MC1_SUSPEND);
+	isp1301_set_bits(isp, ISP1301_MODE_CONTROL_1, MC1_DAT_SE0);
+	isp1301_set_bits(isp, ISP1301_OTG_CONTROL_1, OTG1_VBUS_DRV);
+	return 0;
+fail:
+	kfree(isp);
+	return -ENODEV;
+}
+
+static const struct i2c_device_id isp1301_id[] = {
+	{ "isp1301_host", 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, isp1301_id);
+
+static struct i2c_driver isp1301_driver = {
+	.driver = {
+		.name	= "isp1301_host",
+	},
+	.probe		= isp1301_probe,
+	.remove		= __exit_p(isp1301_remove),
+	.id_table	= isp1301_id,
+};
+
+/*-------------------------------------------------------------------------*/
+
+static int __init isp_init(void)
+{
+	return i2c_add_driver(&isp1301_driver);
+}
+module_init(isp_init);
+
+static void __exit isp_exit(void)
+{
+	i2c_del_driver(&isp1301_driver);
+}
+module_exit(isp_exit);
+
diff --git a/drivers/usb/otg/twl4030-usb.c b/drivers/usb/otg/twl4030-usb.c
index 416e441..734497d 100644
--- a/drivers/usb/otg/twl4030-usb.c
+++ b/drivers/usb/otg/twl4030-usb.c
@@ -34,6 +34,8 @@
 #include <linux/delay.h>
 #include <linux/usb/otg.h>
 #include <linux/i2c/twl4030.h>
+#include <linux/regulator/consumer.h>
+#include <linux/err.h>
 
 
 /* Register defines */
@@ -110,6 +112,9 @@
 #define CARKIT_PLS_CTRL_RXPLSEN		(1 << 1)
 #define CARKIT_PLS_CTRL_TXPLSEN		(1 << 0)
 
+#define CARKIT_ANA_CTRL			0xBB
+#define SEL_MADC_MCPC			(1 << 3)
+
 #define MCPC_CTRL			0x30
 #define MCPC_CTRL_SET			0x31
 #define MCPC_CTRL_CLR			0x32
@@ -215,6 +220,7 @@
 
 /* In module TWL4030_MODULE_PM_MASTER */
 #define PROTECT_KEY			0x0E
+#define STS_HW_CONDITIONS		0x0F
 
 /* In module TWL4030_MODULE_PM_RECEIVER */
 #define VUSB_DEDICATED1			0x7D
@@ -246,6 +252,11 @@
 	struct otg_transceiver	otg;
 	struct device		*dev;
 
+	/* TWL4030 internal USB regulator supplies */
+	struct regulator	*usb1v5;
+	struct regulator	*usb1v8;
+	struct regulator	*usb3v1;
+
 	/* for vbus reporting with irqs disabled */
 	spinlock_t		lock;
 
@@ -344,15 +355,26 @@
 	int	status;
 	int	linkstat = USB_LINK_UNKNOWN;
 
-	/* STS_HW_CONDITIONS */
-	status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER, 0x0f);
+	/*
+	 * For ID/VBUS sensing, see manual section 15.4.8 ...
+	 * except when using only battery backup power, two
+	 * comparators produce VBUS_PRES and ID_PRES signals,
+	 * which don't match docs elsewhere.  But ... BIT(7)
+	 * and BIT(2) of STS_HW_CONDITIONS, respectively, do
+	 * seem to match up.  If either is true the USB_PRES
+	 * signal is active, the OTG module is activated, and
+	 * its interrupt may be raised (may wake the system).
+	 */
+	status = twl4030_readb(twl, TWL4030_MODULE_PM_MASTER,
+			STS_HW_CONDITIONS);
 	if (status < 0)
 		dev_err(twl->dev, "USB link status err %d\n", status);
-	else if (status & BIT(7))
-		linkstat = USB_LINK_VBUS;
-	else if (status & BIT(2))
-		linkstat = USB_LINK_ID;
-	else
+	else if (status & (BIT(7) | BIT(2))) {
+		if (status & BIT(2))
+			linkstat = USB_LINK_ID;
+		else
+			linkstat = USB_LINK_VBUS;
+	} else
 		linkstat = USB_LINK_NONE;
 
 	dev_dbg(twl->dev, "HW_CONDITIONS 0x%02x/%d; link %d\n",
@@ -434,6 +456,18 @@
 
 	pwr = twl4030_usb_read(twl, PHY_PWR_CTRL);
 	if (on) {
+		regulator_enable(twl->usb3v1);
+		regulator_enable(twl->usb1v8);
+		/*
+		 * Disabling usb3v1 regulator (= writing 0 to VUSB3V1_DEV_GRP
+		 * in twl4030) resets the VUSB_DEDICATED2 register. This reset
+		 * enables VUSB3V1_SLEEP bit that remaps usb3v1 ACTIVE state to
+		 * SLEEP. We work around this by clearing the bit after usv3v1
+		 * is re-activated. This ensures that VUSB3V1 is really active.
+		 */
+		twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
+							VUSB_DEDICATED2);
+		regulator_enable(twl->usb1v5);
 		pwr &= ~PHY_PWR_PHYPWD;
 		WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
 		twl4030_usb_write(twl, PHY_CLK_CTRL,
@@ -443,6 +477,9 @@
 	} else  {
 		pwr |= PHY_PWR_PHYPWD;
 		WARN_ON(twl4030_usb_write_verify(twl, PHY_PWR_CTRL, pwr) < 0);
+		regulator_disable(twl->usb1v5);
+		regulator_disable(twl->usb1v8);
+		regulator_disable(twl->usb3v1);
 	}
 }
 
@@ -451,6 +488,9 @@
 	if (twl->asleep)
 		return;
 
+	if (twl->otg.link_save_context)
+		twl->otg.link_save_context(&twl->otg);
+
 	twl4030_phy_power(twl, 0);
 	twl->asleep = 1;
 }
@@ -466,9 +506,13 @@
 	if (twl->usb_mode == T2_USB_MODE_ULPI)
 		twl4030_i2c_access(twl, 0);
 	twl->asleep = 0;
+
+	if (twl->otg.link_restore_context)
+		twl->otg.link_restore_context(&twl->otg);
+
 }
 
-static void twl4030_usb_ldo_init(struct twl4030_usb *twl)
+static int twl4030_usb_ldo_init(struct twl4030_usb *twl)
 {
 	/* Enable writing to power configuration registers */
 	twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0xC0, PROTECT_KEY);
@@ -480,20 +524,45 @@
 	/* input to VUSB3V1 LDO is from VBAT, not VBUS */
 	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x14, VUSB_DEDICATED1);
 
-	/* turn on 3.1V regulator */
-	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB3V1_DEV_GRP);
+	/* Initialize 3.1V regulator */
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_DEV_GRP);
+
+	twl->usb3v1 = regulator_get(twl->dev, "usb3v1");
+	if (IS_ERR(twl->usb3v1))
+		return -ENODEV;
+
 	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB3V1_TYPE);
 
-	/* turn on 1.5V regulator */
-	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V5_DEV_GRP);
+	/* Initialize 1.5V regulator */
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_DEV_GRP);
+
+	twl->usb1v5 = regulator_get(twl->dev, "usb1v5");
+	if (IS_ERR(twl->usb1v5))
+		goto fail1;
+
 	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V5_TYPE);
 
-	/* turn on 1.8V regulator */
-	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0x20, VUSB1V8_DEV_GRP);
+	/* Initialize 1.8V regulator */
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_DEV_GRP);
+
+	twl->usb1v8 = regulator_get(twl->dev, "usb1v8");
+	if (IS_ERR(twl->usb1v8))
+		goto fail2;
+
 	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0, VUSB1V8_TYPE);
 
 	/* disable access to power configuration registers */
 	twl4030_i2c_write_u8(TWL4030_MODULE_PM_MASTER, 0, PROTECT_KEY);
+
+	return 0;
+
+fail2:
+	regulator_put(twl->usb1v5);
+	twl->usb1v5 = NULL;
+fail1:
+	regulator_put(twl->usb3v1);
+	twl->usb3v1 = NULL;
+	return -ENODEV;
 }
 
 static ssize_t twl4030_usb_vbus_show(struct device *dev,
@@ -515,6 +584,7 @@
 static irqreturn_t twl4030_usb_irq(int irq, void *_twl)
 {
 	struct twl4030_usb *twl = _twl;
+	struct otg_transceiver x = twl->otg;
 	int status;
 
 #ifdef CONFIG_LOCKDEP
@@ -539,12 +609,18 @@
 		 * USB_LINK_VBUS state.  musb_hdrc won't care until it
 		 * starts to handle softconnect right.
 		 */
-		twl4030charger_usb_en(status == USB_LINK_VBUS);
 
-		if (status == USB_LINK_NONE)
+		if (status == USB_LINK_NONE) {
+			if (x.link_force_active)
+				x.link_force_active(0);
 			twl4030_phy_suspend(twl, 0);
-		else
+		} else {
+			if (x.link_force_active)
+				x.link_force_active(1);
 			twl4030_phy_resume(twl);
+		}
+
+		twl4030charger_usb_en(status == USB_LINK_VBUS);
 	}
 	sysfs_notify(&twl->dev->kobj, NULL, "vbus");
 
@@ -598,7 +674,7 @@
 {
 	struct twl4030_usb_data *pdata = pdev->dev.platform_data;
 	struct twl4030_usb	*twl;
-	int			status;
+	int			status, err;
 
 	if (!pdata) {
 		dev_dbg(&pdev->dev, "platform_data not available\n");
@@ -622,13 +698,32 @@
 	/* init spinlock for workqueue */
 	spin_lock_init(&twl->lock);
 
-	twl4030_usb_ldo_init(twl);
+	err = twl4030_usb_ldo_init(twl);
+	if (err) {
+		dev_err(&pdev->dev, "ldo init failed\n");
+		kfree(twl);
+		return err;
+	}
 	otg_set_transceiver(&twl->otg);
 
 	platform_set_drvdata(pdev, twl);
 	if (device_create_file(&pdev->dev, &dev_attr_vbus))
 		dev_warn(&pdev->dev, "could not create sysfs file\n");
 
+	/*
+	 * One time configuration to route MCPC pins to the MADC for
+	 * monitoring */
+	regulator_enable(twl->usb3v1);
+	regulator_enable(twl->usb1v8);
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, 0,
+			VUSB_DEDICATED2);
+	regulator_enable(twl->usb1v5);
+	twl4030_usb_write(twl, CARKIT_ANA_CTRL,
+		twl4030_usb_read(twl, CARKIT_ANA_CTRL) | SEL_MADC_MCPC);
+	regulator_disable(twl->usb1v5);
+	regulator_disable(twl->usb1v8);
+	regulator_disable(twl->usb3v1);
+
 	/* Our job is to use irqs and status from the power module
 	 * to keep the transceiver disabled when nothing's connected.
 	 *
@@ -688,6 +783,9 @@
 	twl4030_usb_clear_bits(twl, POWER_CTRL, POWER_CTRL_OTG_ENAB);
 
 	twl4030_phy_power(twl, 0);
+	regulator_put(twl->usb1v5);
+	regulator_put(twl->usb1v8);
+	regulator_put(twl->usb3v1);
 
 	kfree(twl);
 
diff --git a/drivers/usb/serial/generic.c b/drivers/usb/serial/generic.c
index 814909f..e6bf9b2 100644
--- a/drivers/usb/serial/generic.c
+++ b/drivers/usb/serial/generic.c
@@ -122,12 +122,6 @@
 
 	dbg("%s - port %d", __func__, port->number);
 
-	/* force low_latency on so that our tty_push actually forces the data
-	   through, otherwise it is scheduled, and with high data rates (like
-	   with OHCI) data can get lost. */
-	if (tty)
-		tty->low_latency = 1;
-
 	/* clear the throttle flags */
 	spin_lock_irqsave(&port->lock, flags);
 	port->throttled = 0;
diff --git a/drivers/video/omap/Kconfig b/drivers/video/omap/Kconfig
index 1258741..c0bd726 100644
--- a/drivers/video/omap/Kconfig
+++ b/drivers/video/omap/Kconfig
@@ -14,7 +14,7 @@
 
 config FB_OMAP_LCD_WVGA
         bool "Use LCD in VGA mode"
-	depends on ARCH_OMAP34XX && MACH_OMAP_ZOOM2
+	depends on ARCH_OMAP34XX && (MACH_OMAP_ZOOM2 || MACH_OMAP_ZOOM3)
 
 choice
 	depends on FB_OMAP && MACH_OVERO
diff --git a/drivers/video/omap2/displays/panel-zoom2.c b/drivers/video/omap2/displays/panel-zoom2.c
index 3e17375..67cddf6 100644
--- a/drivers/video/omap2/displays/panel-zoom2.c
+++ b/drivers/video/omap2/displays/panel-zoom2.c
@@ -31,6 +31,9 @@
 
 #include <mach/display.h>
 
+/* Delay between Panel configuration and Panel enabling */
+#define LCD_RST_DELAY		100
+
 #define LCD_XRES		800
 #define LCD_YRES		480
 
@@ -41,6 +44,10 @@
 /* Current Pixel clock */
 #define LCD_PIXEL_CLOCK		LCD_PIXCLOCK_MIN
 
+static int zoom2_spi_resume(struct spi_device *spi);
+static int zoom2_spi_suspend(struct spi_device *spi, pm_message_t mesg);
+
+struct spi_device *zoom2_spi_device;
 
 /*NEC NL8048HL11-01B  Manual
  * defines HFB, HSW, HBP, VFP, VSW, VBP as shown below
@@ -64,6 +71,11 @@
 	dssdev->panel.config = OMAP_DSS_LCD_TFT | OMAP_DSS_LCD_IVS |
 				OMAP_DSS_LCD_IHS;
 	dssdev->panel.timings = zoom2_panel_timings;
+#ifdef CONFIG_FB_OMAP2_32_BPP
+	dssdev->panel.recommended_bpp = 24;
+#else
+	dssdev->panel.recommended_bpp = 16;
+#endif
 
 	return 0;
 }
@@ -91,12 +103,19 @@
 
 static int zoom2_panel_suspend(struct omap_dss_device *dssdev)
 {
+	pm_message_t mesg;
+
+	mesg.event = PM_EVENT_SUSPEND;
 	zoom2_panel_disable(dssdev);
+	zoom2_spi_suspend(zoom2_spi_device, mesg);
+
 	return 0;
 }
 
 static int zoom2_panel_resume(struct omap_dss_device *dssdev)
 {
+	zoom2_spi_resume(zoom2_spi_device);
+	mdelay(LCD_RST_DELAY);
 	return zoom2_panel_enable(dssdev);
 }
 
@@ -227,6 +246,7 @@
 	spi->bits_per_word = 32;
 	spi_setup(spi);
 
+	zoom2_spi_device = spi;
 	init_nec_wvga_lcd(spi);
 
 	omap_dss_register_driver(&zoom2_driver);
diff --git a/drivers/video/omap2/displays/sil9022.c b/drivers/video/omap2/displays/sil9022.c
index 666fec5..5bde029 100644
--- a/drivers/video/omap2/displays/sil9022.c
+++ b/drivers/video/omap2/displays/sil9022.c
@@ -30,18 +30,22 @@
 #include <mach/display.h>
 #include <mach/io.h>
 
+#include <mach/omap-pm.h>
+
+u16 current_descriptor_addrs;
+
 static struct i2c_client *sil9022_client;
 
 static struct omap_video_timings omap_dss_hdmi_timings = {
 	.x_res          = HDMI_XRES,
 	.y_res          = HDMI_YRES,
 	.pixel_clock    = HDMI_PIXCLOCK_MAX,
-	.hfp            = 63,
-	.hsw            = 255,
-	.hbp            = 49,
+	.hfp            = 110,
+	.hbp            = 220,
+	.hsw            = 40,
 	.vfp            = 5,
-	.vsw            = 20,
-	.vbp            = 4,
+	.vbp            = 20,
+	.vsw            = 5,
 };
 
 static struct hdmi_reg_data  hdmi_tpi_audio_config_data[] = {
@@ -135,6 +139,213 @@
 	0x00
 };
 
+void get_horz_vert_timing_info(u8 *edid)
+{
+	/*HORIZONTAL FRONT PORCH */
+	omap_dss_hdmi_timings.hfp = edid[current_descriptor_addrs + 8];
+	/*HORIZONTAL SYNC WIDTH */
+	omap_dss_hdmi_timings.hsw = edid[current_descriptor_addrs + 9];
+	/*HORIZONTAL BACK PORCH */
+	omap_dss_hdmi_timings.hbp = (((edid[current_descriptor_addrs + 4]
+					  & 0x0F) << 8) |
+					edid[current_descriptor_addrs + 3]) -
+		(omap_dss_hdmi_timings.hfp + omap_dss_hdmi_timings.hsw);
+	/*VERTICAL FRONT PORCH */
+	omap_dss_hdmi_timings.vfp = ((edid[current_descriptor_addrs + 10] &
+				       0xF0) >> 4);
+	/*VERTICAL SYNC WIDTH */
+	omap_dss_hdmi_timings.vsw = (edid[current_descriptor_addrs + 10] &
+				      0x0F);
+	/*VERTICAL BACK PORCH */
+	omap_dss_hdmi_timings.vbp = (((edid[current_descriptor_addrs + 7] &
+					0x0F) << 8) |
+				      edid[current_descriptor_addrs + 6]) -
+		(omap_dss_hdmi_timings.vfp + omap_dss_hdmi_timings.vsw);
+
+	dev_dbg(&sil9022_client->dev, "<%s> \n"
+				       "hfp			= %d\n"
+				       "hsw			= %d\n"
+				       "hbp			= %d\n"
+				       "vfp			= %d\n"
+				       "vsw			= %d\n"
+				       "vbp			= %d\n",
+		 __func__,
+		 omap_dss_hdmi_timings.hfp,
+		 omap_dss_hdmi_timings.hsw,
+		 omap_dss_hdmi_timings.hbp,
+		 omap_dss_hdmi_timings.vfp,
+		 omap_dss_hdmi_timings.vsw,
+		 omap_dss_hdmi_timings.vbp
+		 );
+
+}
+
+/*------------------------------------------------------------------------------
+ | Function    : get_edid_timing_data
+ +------------------------------------------------------------------------------
+ | Description : This function gets the resolution information from EDID
+ |
+ | Parameters  : void
+ |
+ | Returns     : void
+ +----------------------------------------------------------------------------*/
+void get_edid_timing_data(u8 *edid, u16 *pixel_clk, u16 *horizontal_res,
+			  u16 *vertical_res)
+{
+	u8 offset, effective_addrs;
+	u8 count;
+	u8 i;
+	u8 flag = false;
+	/*check for 720P timing in block0 */
+	for (count = 0; count < EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR; count++) {
+		current_descriptor_addrs =
+			EDID_DESCRIPTOR_BLOCK0_ADDRESS +
+			count * EDID_TIMING_DESCRIPTOR_SIZE;
+		*horizontal_res =
+			(((edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 4 +
+			   count * EDID_TIMING_DESCRIPTOR_SIZE] & 0xF0) << 4) |
+			 edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 2 +
+			 count * EDID_TIMING_DESCRIPTOR_SIZE]);
+		*vertical_res =
+			(((edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 7 +
+			   count * EDID_TIMING_DESCRIPTOR_SIZE] & 0xF0) << 4) |
+			 edid[EDID_DESCRIPTOR_BLOCK0_ADDRESS + 5 +
+			 count * EDID_TIMING_DESCRIPTOR_SIZE]);
+
+		dev_dbg(&sil9022_client->dev,
+			"<%s> ***Block-0-Timing-descriptor[%d]***\n",
+			__func__, count);
+		for (i = current_descriptor_addrs;
+		      i <
+		      (current_descriptor_addrs+EDID_TIMING_DESCRIPTOR_SIZE);
+		      i++)
+			dev_dbg(&sil9022_client->dev,
+				"%x ==>		%x\n", i, edid[i]);
+
+			dev_dbg(&sil9022_client->dev,
+				 "<%s>\n"
+				 "E-EDID Buffer Index	= %d\n"
+				 "horizontal_res       	= %d\n"
+				 "vertical_res		= %d\n",
+				 __func__,
+				 current_descriptor_addrs,
+				 *horizontal_res,
+				 *vertical_res
+				 );
+
+		if (*horizontal_res == HDMI_XRES &&
+		    *vertical_res == HDMI_YRES) {
+			dev_info(&sil9022_client->dev, "<%s>\nFound EDID Data "
+						       "for %d x %dp\n",
+				 __func__, *horizontal_res, *vertical_res);
+			flag = true;
+			break;
+			}
+	}
+
+	/*check for the Timing in block1 */
+	if (flag != true) {
+		offset = edid[EDID_DESCRIPTOR_BLOCK1_ADDRESS + 2];
+		if (offset != 0) {
+			effective_addrs = EDID_DESCRIPTOR_BLOCK1_ADDRESS
+				+ offset;
+			/*to determine the number of descriptor blocks */
+			for (count = 0;
+			      count < EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR;
+			      count++) {
+				current_descriptor_addrs = effective_addrs +
+					count * EDID_TIMING_DESCRIPTOR_SIZE;
+				*horizontal_res =
+					(((edid[effective_addrs + 4 +
+					   count*EDID_TIMING_DESCRIPTOR_SIZE] &
+					   0xF0) << 4) |
+					 edid[effective_addrs + 2 +
+					 count * EDID_TIMING_DESCRIPTOR_SIZE]);
+				*vertical_res =
+					(((edid[effective_addrs + 7 +
+					   count*EDID_TIMING_DESCRIPTOR_SIZE] &
+					   0xF0) << 4) |
+					 edid[effective_addrs + 5 +
+					 count * EDID_TIMING_DESCRIPTOR_SIZE]);
+
+				dev_dbg(&sil9022_client->dev,
+					 "<%s> Block1-Timing-descriptor[%d]\n",
+					 __func__, count);
+
+				for (i = current_descriptor_addrs;
+				      i < (current_descriptor_addrs+
+					   EDID_TIMING_DESCRIPTOR_SIZE); i++)
+					dev_dbg(&sil9022_client->dev,
+						"%x ==> 	%x\n",
+						   i, edid[i]);
+
+				dev_dbg(&sil9022_client->dev, "<%s>\n"
+						"current_descriptor	= %d\n"
+						"horizontal_res		= %d\n"
+						"vertical_res 		= %d\n",
+					 __func__, current_descriptor_addrs,
+					 *horizontal_res, *vertical_res);
+
+				if (*horizontal_res == HDMI_XRES &&
+				    *vertical_res == HDMI_YRES) {
+					dev_info(&sil9022_client->dev,
+						 "<%s> Found EDID Data for "
+						 "%d x %dp\n",
+						 __func__,
+						 *horizontal_res,
+						 *vertical_res
+						 );
+					flag = true;
+					break;
+					}
+			}
+		}
+	}
+
+	if (flag == true) {
+		*pixel_clk = ((edid[current_descriptor_addrs + 1] << 8) |
+			     edid[current_descriptor_addrs]);
+
+		omap_dss_hdmi_timings.x_res = *horizontal_res;
+		omap_dss_hdmi_timings.y_res = *vertical_res;
+		omap_dss_hdmi_timings.pixel_clock = *pixel_clk*10;
+		dev_dbg(&sil9022_client->dev,
+			 "EDID TIMING DATA supported by zoom2 FOUND\n"
+			 "EDID DTD block address	= %d\n"
+			 "pixel_clk 			= %d\n"
+			 "horizontal res		= %d\n"
+			 "vertical res			= %d\n",
+			 current_descriptor_addrs,
+			 omap_dss_hdmi_timings.pixel_clock,
+			 omap_dss_hdmi_timings.x_res,
+			 omap_dss_hdmi_timings.y_res
+			 );
+
+		get_horz_vert_timing_info(edid);
+	} else {
+
+		dev_info(&sil9022_client->dev,
+			 "<%s>\n"
+			 "EDID TIMING DATA supported by zoom2 NOT FOUND\n"
+			 "setting default timing values for 720p\n"
+			 "pixel_clk 		= %d\n"
+			 "horizontal res	= %d\n"
+			 "vertical res		= %d\n",
+			 __func__,
+			 omap_dss_hdmi_timings.pixel_clock,
+			 omap_dss_hdmi_timings.x_res,
+			 omap_dss_hdmi_timings.y_res
+			 );
+
+		*pixel_clk = omap_dss_hdmi_timings.pixel_clock;
+		*horizontal_res = omap_dss_hdmi_timings.x_res;
+		*vertical_res = omap_dss_hdmi_timings.y_res;
+	}
+
+
+}
+
+
 static int
 sil9022_blockwrite_reg(struct i2c_client *client,
 				  u8 reg, u16 alength, u8 *val, u16 *out_len)
@@ -200,12 +411,12 @@
 
 	/* High byte goes out first */
 	data[0] = reg;
+	err = i2c_transfer(client->adapter, msg, 1);
+	dev_dbg(&client->dev, "<%s> i2c Block Read1 at 0x%x, "
+			       "*val=%d flags=%d err=%d\n",
+		 __func__, data[0], data[1], msg->flags, err);
 
 	for (i = 0; i < alength; i++) {
-		err = i2c_transfer(client->adapter, msg, 1);
-		dev_dbg(&client->dev, "<%s> i2c Block Read1 at 0x%x, "
-				       "*val=%d flags=%d err=%d\n",
-			 __func__, data[0], data[1], msg->flags, err);
 		if (err >= 0) {
 			mdelay(3);
 			msg->flags = I2C_M_RD;
@@ -229,7 +440,7 @@
 	}
 	*out_len = i;
 	dev_info(&client->dev, "<%s> i2c Block Read at 0x%x, bytes read = %d\n",
-		 __func__, reg, *out_len);
+		 __func__, client->addr, *out_len);
 
 	if (err < 0) {
 		dev_err(&client->dev, "<%s> ERROR:  i2c Read at 0x%x, "
@@ -351,12 +562,36 @@
 	int err =  0;
 	u8 val = 0;
 	int retries = 0;
+	int i = 0;
+	int k = 0;
 
 	len = (len < HDMI_EDID_MAX_LENGTH) ? len : HDMI_EDID_MAX_LENGTH;
 
 	/* Request DDC bus access to read EDID info from HDTV */
 	dev_info(&client->dev, "<%s> Reading HDMI EDID\n", __func__);
 
+	/* Bring transmitter to low-Power state */
+	val = TPI_AVI_POWER_STATE_D2;
+	err = sil9022_write_reg(client, HDMI_TPI_DEVICE_POWER_STATE_DATA, val);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"<%s> ERROR: Failed during bring power state - low.\n",
+			 __func__);
+		return err;
+	}
+
+	/* Disable TMDS clock */
+	val = 0x11;
+	err = sil9022_write_reg(client, HDMI_SYS_CTRL_DATA_REG, val);
+	if (err < 0) {
+		dev_err(&client->dev,
+			"<%s> ERROR: Failed during bring power state - low.\n",
+			 __func__);
+		return err;
+	}
+
+	val = 0;
+	/* Read TPI system control register*/
 	err = sil9022_read_reg(client, 1, HDMI_SYS_CTRL_DATA_REG, &val);
 	if (err < 0) {
 		dev_err(&client->dev,
@@ -364,6 +599,9 @@
 		return err;
 	}
 
+	/* The host writes 0x1A[2]=1 to request the
+	 * DDC(Display Data Channel) bus
+	 */
 	val |= TPI_SYS_CTRL_DDC_BUS_REQUEST;
 	err = sil9022_write_reg(client, HDMI_SYS_CTRL_DATA_REG, val);
 	if (err < 0) {
@@ -372,7 +610,7 @@
 		return err;
 	}
 
-	 /*  Poll for bus access granted */
+	 /*  Poll for bus DDC Bus control to be granted */
 	dev_info(&client->dev, "<%s> Poll for DDC bus access\n", __func__);
 	val = 0;
 	do {
@@ -392,10 +630,9 @@
 		return err;
 	}
 
-	/*  Read the EDID structure from the monitor I2C address  */
 	memset(p_buffer, 0, len);
-	/* I2C SetSlaveAddress to HDMI_I2C_MONITOR_ADDRESS */
-
+	/* change I2C SetSlaveAddress to HDMI_I2C_MONITOR_ADDRESS */
+	/*  Read the EDID structure from the monitor I2C address  */
 	client->addr = HDMI_I2C_MONITOR_ADDRESS;
 	err = sil9022_blockread_reg(client, 1, len,
 				    0x00, p_buffer, out_len);
@@ -406,6 +643,21 @@
 		return err;
 	}
 
+	for (i = 0; i < *out_len; i++) {
+		if ((i / 18) < 3) {
+			dev_dbg(&client->dev, "byte->%02x	%x\n",
+				i, p_buffer[i]);
+			continue;
+		}
+		if ((i/18 >= 3 && i/18 <= 6) && (i%18 == 0))
+			dev_dbg(&client->dev, "\n DTD Block %d\n", k++);
+
+		if ((i/18 == 7) && (i%18 == 0))
+			dev_dbg(&client->dev, "\n");
+
+		dev_dbg(&client->dev, "byte->%02x	%x\n", i, p_buffer[i]);
+	}
+
 	/* Release DDC bus access */
 	client->addr = SI9022_I2CSLAVEADDRESS;
 	val &= ~(TPI_SYS_CTRL_DDC_BUS_REQUEST | TPI_SYS_CTRL_DDC_BUS_GRANTED);
@@ -535,20 +787,22 @@
 }
 
 static int
-hdmi_enable(void)
+hdmi_enable(struct omap_dss_device *dssdev)
 {
 	int		err;
 	u8		val, vals[14];
 	int		i;
 	u16		out_len = 0;
 	u8		edid[HDMI_EDID_MAX_LENGTH];
-	HDMI_EDID	*p_edid = (HDMI_EDID *)edid;
-	HDMI_EDID_DTD	*p_video_spec = NULL;
-	HDMI_EDID_DTD	*p_monitor_limits = NULL;
+	u16		horizontal_res;
+	u16		vertical_res;
+	u16		pixel_clk;
+
 
 	memset(edid, 0, HDMI_EDID_MAX_LENGTH);
 	memset(vals, 0, 14);
 
+
 	err = hdmi_read_edid(sil9022_client, HDMI_EDID_MAX_LENGTH,
 			     edid, &out_len);
 	if (err < 0 || out_len == 0) {
@@ -557,29 +811,46 @@
 		return err;
 	}
 
-	/*  Determine DTD info for the attached monitor */
-	for (i = 0; i < HDMI_EDID_MAX_DTDS; i++) {
-		if (p_edid->DTD[i].monitor_limits.block_type ==
-			HDMI_EDID_DTD_TAG_MONITOR_LIMITS)
-			p_monitor_limits = &p_edid->DTD[i];
-
-
-		if (p_edid->DTD[i].video.pixel_clock[0] != 0 &&
-			p_edid->DTD[i].video.pixel_clock[1] != 0)
-			p_video_spec = &p_edid->DTD[i];
-	}
+	get_edid_timing_data(edid,
+			     &pixel_clk,
+			     &horizontal_res,
+			     &vertical_res
+			     );
 
 	/*  Fill the TPI Video Mode Data structure */
-	vals[0] = p_video_spec->video.pixel_clock[0];        /* Pixel clock */
-	vals[1] = p_video_spec->video.pixel_clock[1];
-	vals[2] = 60;                                     /* Vertical freq */
-	vals[3] = 0;
-	vals[4] = p_video_spec->video.horiz_active;      /* Horizontal pixels*/
-	vals[5] = (p_video_spec->video.horiz_high & 0xF0) >> 4;
-	vals[6] = p_video_spec->video.vert_active;       /* Vertical pixels */
-	vals[7] = (p_video_spec->video.vert_high & 0xF0) >> 4;
+	vals[0] = (pixel_clk & 0xFF);                  /* Pixel clock */
+	vals[1] = ((pixel_clk & 0xFF00) >> 8);
+	vals[2] = VERTICAL_FREQ;                    /* Vertical freq */
+	vals[3] = 0x00;
+	vals[4] = (horizontal_res & 0xFF);         /* Horizontal pixels*/
+	vals[5] = ((horizontal_res & 0xFF00) >> 8);
+	vals[6] = (vertical_res & 0xFF);           /* Vertical pixels */
+	vals[7] = ((vertical_res & 0xFF00) >> 8);
 
 
+	dev_info(&sil9022_client->dev, "<%s>\nHDMI Monitor E-EDID Timing Data\n"
+				       "horizontal_res 	= %d\n"
+				       "vertical_res	= %d\n"
+				       "pixel_clk	= %d\n"
+				       "hfp 		= %d\n"
+				       "hsw 		= %d\n"
+				       "hbp 		= %d\n"
+				       "vfp 		= %d\n"
+				       "vsw 		= %d\n"
+				       "vbp 		= %d\n",
+		 __func__,
+		 omap_dss_hdmi_timings.x_res,
+		 omap_dss_hdmi_timings.y_res,
+		 omap_dss_hdmi_timings.pixel_clock,
+		 omap_dss_hdmi_timings.hfp,
+		 omap_dss_hdmi_timings.hsw,
+		 omap_dss_hdmi_timings.hbp,
+		 omap_dss_hdmi_timings.vfp,
+		 omap_dss_hdmi_timings.vsw,
+		 omap_dss_hdmi_timings.vbp
+		 );
+
+	dssdev->panel.timings = omap_dss_hdmi_timings;
 	/*  Write out the TPI Video Mode Data */
 	out_len = 0;
 	err = sil9022_blockwrite_reg(sil9022_client,
@@ -836,6 +1107,14 @@
 {
 	int r = 0;
 
+#ifdef CONFIG_PM
+	struct hdmi_platform_data *pdata = dssdev->dev.platform_data;
+	if (pdata->set_min_bus_tput)
+		pdata->set_min_bus_tput(&sil9022_client->dev,
+					OCP_INITIATOR_AGENT,
+					166 * 1000 * 4);
+#endif
+
 	if (dssdev->platform_enable)
 		r = dssdev->platform_enable(dssdev);
 
@@ -843,7 +1122,7 @@
 	if (r)
 		goto ERROR0;
 
-	r = hdmi_enable();
+	r = hdmi_enable(dssdev);
 	if (r)
 		goto ERROR0;
 	/* wait couple of vsyncs until enabling the LCD */
@@ -856,6 +1135,9 @@
 
 static void hdmi_panel_disable(struct omap_dss_device *dssdev)
 {
+#ifdef CONFIG_PM
+	struct hdmi_platform_data *pdata = dssdev->dev.platform_data;
+#endif
 	hdmi_disable();
 
 	/* wait couple of vsyncs until enabling the hdmi */
@@ -863,6 +1145,12 @@
 
 	if (dssdev->platform_disable)
 		dssdev->platform_disable(dssdev);
+#ifdef CONFIG_PM
+	if (pdata->set_min_bus_tput)
+		pdata->set_min_bus_tput(&sil9022_client->dev,
+					OCP_INITIATOR_AGENT,
+					0);
+#endif
 }
 
 static int hdmi_panel_suspend(struct omap_dss_device *dssdev)
@@ -919,7 +1207,7 @@
 
 	return 0;
 ERROR1:
-	kfree(client);
+	kfree(sil9022_client);
 ERROR0:
 	return err;
 }
diff --git a/drivers/video/omap2/dss/Kconfig b/drivers/video/omap2/dss/Kconfig
index f2ce068..ce82231 100644
--- a/drivers/video/omap2/dss/Kconfig
+++ b/drivers/video/omap2/dss/Kconfig
@@ -47,18 +47,26 @@
 config OMAP2_DSS_DSI
 	bool "DSI support"
 	depends on ARCH_OMAP3
-        default n
+        default y
 	help
 	  MIPI DSI support.
 
 config OMAP2_DSS_USE_DSI_PLL
 	bool "Use DSI PLL for PCLK (EXPERIMENTAL)"
-	default n
+	default y
 	depends on OMAP2_DSS_DSI
 	help
 	  Use DSI PLL to generate pixel clock.  Currently only for DPI output.
 	  DSI PLL can be used to generate higher and more precise pixel clocks.
 
+config OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+	bool "Use DSI PLL for HDMI PCLK (EXPERIMENTAL)"
+	default y
+	depends on OMAP2_DSS_DSI
+	help
+	  Use DSI PLL to generate HDMI pixel clock. Only for HDMI output.
+	  DSI PLL can be used to generate higher and more precise pixel clocks.
+
 config OMAP2_DSS_FAKE_VSYNC
 	bool "Fake VSYNC irq from manual update displays"
 	default n
diff --git a/drivers/video/omap2/dss/core.c b/drivers/video/omap2/dss/core.c
index 347fc44..e6d07bd 100644
--- a/drivers/video/omap2/dss/core.c
+++ b/drivers/video/omap2/dss/core.c
@@ -282,10 +282,10 @@
 
 void dss_clk_enable(enum dss_clock clks)
 {
-	dss_clk_enable_no_ctx(clks);
-
 	if (cpu_is_omap34xx() && dss_need_ctx_restore())
 		restore_all_ctx();
+
+	dss_clk_enable_no_ctx(clks);
 }
 
 static void dss_clk_disable_no_ctx(enum dss_clock clks)
diff --git a/drivers/video/omap2/dss/dispc.c b/drivers/video/omap2/dss/dispc.c
index d061d75..edec707 100644
--- a/drivers/video/omap2/dss/dispc.c
+++ b/drivers/video/omap2/dss/dispc.c
@@ -133,6 +133,14 @@
 
 #define DISPC_MAX_NR_ISRS		8
 
+
+#define LPR_GFX_FIFO_HIGH_THRES		0xB9C
+#define LPR_GFX_FIFO_LOW_THRES		0x7F8
+#define DISPC_VID_ATTRIBUTES_ENABLE	(1 << 0)
+#define DSS_CONTROL_APLL_CLK		1
+static int lpr_enabled;
+static int gfx_in_use;
+
 struct omap_dispc_isr_data {
 	omap_dispc_isr_t	isr;
 	void			*arg;
@@ -161,6 +169,7 @@
 	u32	fifo_size[3];
 
 	spinlock_t irq_lock;
+	spinlock_t lpr_lock;
 	u32 irq_error_mask;
 	struct omap_dispc_isr_data registered_isr[DISPC_MAX_NR_ISRS];
 	u32 error_irqs;
@@ -170,6 +179,7 @@
 } dispc;
 
 static void _omap_dispc_set_irqs(void);
+static int dispc_is_vdma_req(u8 rotation, enum omap_color_mode color_mode);
 
 static inline void dispc_write_reg(const struct dispc_reg idx, u32 val)
 {
@@ -546,158 +556,341 @@
 	dispc_write_reg(DISPC_VID_FIR_COEF_V(plane-1, reg), value);
 }
 
-static void _dispc_set_scale_coef(enum omap_plane plane, int hscaleup,
-		int vscaleup, int five_taps)
+/* New coefficients Begin */
+static void _dispc_set_scale_coef(enum omap_plane plane,
+			u16 orig_width, u16 out_width,
+			u16 orig_height, u16 out_height,
+			int five_taps, bool vdma)
 {
-	/* Coefficients for horizontal up-sampling */
-	static const u32 coef_hup[8] = {
-		0x00800000,
-		0x0D7CF800,
-		0x1E70F5FF,
-		0x335FF5FE,
-		0xF74949F7,
-		0xF55F33FB,
-		0xF5701EFE,
-		0xF87C0DFF,
-	};
+	unsigned long reg, mval, rem_ratio;
+	short int vc_3tap[3][8];
+	short int vc[5][8];
+	short int hc[5][8];
+	int i = 0;
 
-	/* Coefficients for horizontal down-sampling */
-	static const u32 coef_hdown[8] = {
-		0x24382400,
-		0x28371FFE,
-		0x2C361BFB,
-		0x303516F9,
-		0x11343311,
-		0x1635300C,
-		0x1B362C08,
-		0x1F372804,
-	};
+	/* 3-taps vertical filter coefficients */
+	/* Downscaling matrix, if image width > 1024 */
+	const static short int filter_coeff_vc_d[3][8] = {
+		{36,	40,	45,	50,	18, 	23,	27, 	31},
+		{56,	57,	56,	55,	55,	55,	56,	57},
+		{36,	31,	27,	23,	55,	50,	45,	40} };
 
-	/* Coefficients for horizontal and vertical up-sampling */
-	static const u32 coef_hvup[2][8] = {
-		{
-		0x00800000,
-		0x037B02FF,
-		0x0C6F05FE,
-		0x205907FB,
-		0x00404000,
-		0x075920FE,
-		0x056F0CFF,
-		0x027B0300,
-		},
-		{
-		0x00800000,
-		0x0D7CF8FF,
-		0x1E70F5FE,
-		0x335FF5FB,
-		0xF7404000,
-		0xF55F33FE,
-		0xF5701EFF,
-		0xF87C0D00,
-		},
-	};
+	/* Upscaling matrix, if image width > 1024 */
+	const static short int filter_coeff_vc_u[3][8] = {
+		{0,	16,	32,	48,	0,	0,	0,	0 },
+		{128,	112,	96,	80,	64,	80,	96,	112 },
+		{0,	0,	0,	0,	64,	48,	32,	16 } };
 
-	/* Coefficients for horizontal and vertical down-sampling */
-	static const u32 coef_hvdown[2][8] = {
-		{
-		0x24382400,
-		0x28391F04,
-		0x2D381B08,
-		0x3237170C,
-		0x123737F7,
-		0x173732F9,
-		0x1B382DFB,
-		0x1F3928FE,
-		},
-		{
-		0x24382400,
-		0x28371F04,
-		0x2C361B08,
-		0x3035160C,
-		0x113433F7,
-		0x163530F9,
-		0x1B362CFB,
-		0x1F3728FE,
-		},
-	};
+	/* 5-taps horizontal filter coefficients */
+	/* Downscaling matrix, if image width > 1024 */
+	const static short int filter_coeff_hc_d[5][8] = {
+		{0,	4,	8,	12,	-9,	-7,	-5,	-2 },
+		{36,	40,	44,	48,	17,	22,	27,	 31 },
+		{56, 	55,	54,	53,	52,	53,	54,	55 },
+		{36,	31,	27,	22,	51,	48,	44,	40 },
+		{0,	-2,	-5,	-7,	17,	12,	8,	4 } };
 
-	/* Coefficients for vertical up-sampling */
-	static const u32 coef_vup[8] = {
-		0x00000000,
-		0x0000FF00,
-		0x0000FEFF,
-		0x0000FBFE,
-		0x000000F7,
-		0x0000FEFB,
-		0x0000FFFE,
-		0x000000FF,
-	};
+	/* Upscaling matrix, if image width > 1024 */
+	const static short int filter_coeff_hc_u[5][8] = {
+		{0,	0,	0,	0,	0,	0,	0,	0 },
+		{0,	16,	32,	48,	0,	0,	0,	0 },
+		{128,	112,	96,	80,	64,	80,	96,	112 },
+		{0,	0,	0,	0,	64,	48,	32,	16 },
+		{0,	0,	0,	0,	0,	0,	0,	0 } };
 
 
-	/* Coefficients for vertical down-sampling */
-	static const u32 coef_vdown[8] = {
-		0x00000000,
-		0x000004FE,
-		0x000008FB,
-		0x00000CF9,
-		0x0000F711,
-		0x0000F90C,
-		0x0000FB08,
-		0x0000FE04,
-	};
+	/* Filter coefficients designed for various scaling ratios */
+	/* Below Co-effients are defined for 5 taps as
+	* [0] = VCC22
+	* [1] = VC2
+	* [2] = VC1
+	* [3] = VC0
+	* [4] = VC00
+	*/
 
-	const u32 *h_coef;
-	const u32 *hv_coef;
-	const u32 *hv_coef_mod;
-	const u32 *v_coef;
-	int i;
+	const static short int filter_coeff_M8[5][8] = {
+		{17,	14,	5,	-6,	2,	9,	15,	19},
+		{-20,	-4,	17,	47,	-18,	-27,	-30,	-27},
+		{134,	127,	121,	105,	81,	105,	121,	127},
+		{-20,	-27,	-30,	-27,	81,	47,	17,	-4},
+		{17,	18,	15,	9,	-18,	-6,	5,	13 } };
 
-	if (hscaleup)
-		h_coef = coef_hup;
-	else
-		h_coef = coef_hdown;
+	const static short int filter_coeff_M9[5][8] = {
+		{8,	1,	-9,	-18,	14,	17,	17,	14},
+		{-8,	8,	30,	56,	-26,	-30,	-27,	-21},
+		{128,	126,	117,	103,	83,	103,	117,	126},
+		{-8,	-21,	-27,	-30,	83,	56,	30,	8},
+		{8,	14,	17,	17,	-26,	-18,	-9,	1} };
 
-	if (vscaleup) {
-		hv_coef = coef_hvup[five_taps];
-		v_coef = coef_vup;
+	const static short int filter_coeff_M10[5][8] = {
+		{-2,	-10,	-18,	-24,	18,	15,	11,	5},
+		{2,	20,	41,	62,	-28,	-27,	-22,	-12},
+		{128,	125,	116,	102,	83,	102,	116,	125},
+		{2,	-12,	-22,	-27,	83,	62,	41,	20},
+		{-2,	5,	11,	15,	-28,	-24,	-18,	-10} };
 
-		if (hscaleup)
-			hv_coef_mod = NULL;
-		else
-			hv_coef_mod = coef_hvdown[five_taps];
-	} else {
-		hv_coef = coef_hvdown[five_taps];
-		v_coef = coef_vdown;
+	const static short int filter_coeff_M11[5][8] = {
+		{-12,	-19,	-24,	-27,	14,	9,	3,	-4},
+		{12,	30,	49,	67,	-26,	-22,	-15,	-3},
+		{128,	124,	115,	101,	83,	101,	115,	124},
+		{12,	-3,	-15,	-22,	83,	67,	49,	30},
+		{-12,	-4,	3,	9,	-26,	-27,	-24,	-19} };
 
-		if (hscaleup)
-			hv_coef_mod = coef_hvup[five_taps];
-		else
-			hv_coef_mod = NULL;
-	}
+	const static short int filter_coeff_M12[5][8] = {
+		{-19,	-24,	-26,	-25,	6,	1,	-6,	-12},
+		{21,	38,	55,	70,	-21,	-16,	-7,	6},
+		{124,	120,	112,	98,	82,	98,	112,	120},
+		{21,	6,	-7,	-16,	82,	70,	55,	38},
+		{-19,	-12,	-6,	1,	-21,	-25,	-26,	-24} };
 
-	for (i = 0; i < 8; i++) {
-		u32 h, hv;
+	const static short int filter_coeff_M13[5][8] = {
+		{-22,	-25,	-25,	-22,	0,	-6,	-12,	-18 },
+		{27,	43,	58,	71,	-17,	-10,	0,	13 },
+		{118,	115,	107,	95,	81,	95,	107,	115 },
+		{27,	13,	0,	-10,	81,	71,	58,	43 },
+		{-22,	-18,	-12,	-6,	-17,	-22,	-25,	-25} };
 
-		h = h_coef[i];
+	const static short int filter_coeff_M14[5][8] = {
+		{-23,	-24,	-22,	-18,	-6,	-11,	-16,	-20 },
+		{32,	46,	59,	70,	-11,	-4,	6,	18 },
+		{110,	108,	101,	91,	78,	91,	101,	108 },
+		{32,	18,	6,	-4,	78,	70,	59,	46 },
+		{-23,	-20,	-16,	-11,	-11,	-18,	-22,	-24} };
 
-		hv = hv_coef[i];
+	const static short int filter_coeff_M16[5][8] = {
+		{-20,	-18,	-14,	-9,	-14,	-17,	-19,	-21},
+		{37,	48,	58,	66,	-2,	6,	15,	26},
+		{94,	93,	88,	82,	73,	82,	88,	93},
+		{37,	26,	15,	6,	73,	66,	58,	48},
+		{-20,	-21,	-19,	-17,	-2,	-9,	-14,	-18} };
 
-		if (hv_coef_mod) {
-			hv &= 0xffffff00;
-			hv |= (hv_coef_mod[i] & 0xff);
+	const static short int filter_coeff_M19[5][8] = {
+		{-12,	-8,	-4,	1,	-16,	-16,	-16,	-13},
+		{38,	47,	53,	59,	8,	15,	22,	31},
+		{76,	72,	73,	69,	64,	69,	73,	72},
+		{38,	31,	22,	15,	64,	59,	53,	47},
+		{-12,	-14,	-16,	-16,	8,	1,	-4,	-9} };
+
+	const static short int filter_coeff_M22[5][8] = {
+		{-6,	-1,	3,	8,	-14,	-13,	-11,	-7},
+		{37,	44,	48,	53,	13,	19,	25,	32},
+		{66,	61,	63,	61,	58,	61,	63,	61},
+		{37,	32,	25,	19,	58,	53,	48,	44},
+		{-6,	-8,	-11,	-13,	13,	8,	3,	-2} };
+
+	const static short int filter_coeff_M26[5][8] = {
+		{1,	4,	8,	13,	-10,	-8,	-5,	-2},
+		{36,	40,	44,	48,	18,	22,	27,	31},
+		{54,	55,	54,	53,	51,	53,	54,	55},
+		{36,	31,	27,	22,	51,	48,	44,	40},
+		{1,	-2,	-5,	-8,	18,	13,	8,	4 } };
+
+	const static short int filter_coeff_M32[5][8] =	{
+		{7,	10,	14,	17,	-4,	-1,	1,	4},
+		{34,	37,	39,	42,	21,	24,	28,	31},
+		{46,	46,	46,	46,	45,	46,	46,	46},
+		{34,	31,	27,	24,	45,	42,	39,	37},
+		{7,	4,	1,	-1,	21,	17,	14,	10} };
+
+	/* Select the coefficients based on the ratio - height/vertical */
+	if (out_height != 0 && five_taps) {
+		if ((out_height != orig_height) || vdma) {
+			rem_ratio = 0;
+			mval = 8; /* default */
+			rem_ratio =  out_height / orig_height ;
+			if (rem_ratio > 1) {
+				mval = 8;
+				DSSDBG("Coefficient class mval = %lu \n", mval);
+			} else {
+				mval = (8 * orig_height) / out_height;
+			}
+
+			switch (mval) {
+			case 8:
+				memcpy(vc, filter_coeff_M8, sizeof(vc));
+				break;
+			case 9:
+				memcpy(vc, filter_coeff_M9, sizeof(vc));
+				break;
+			case 10:
+				memcpy(vc, filter_coeff_M10, sizeof(vc));
+				break;
+			case 11:
+				memcpy(vc, filter_coeff_M11, sizeof(vc));
+				break;
+			case 12:
+				memcpy(vc, filter_coeff_M12, sizeof(vc));
+				break;
+			case 13:
+				memcpy(vc, filter_coeff_M13, sizeof(vc));
+				break;
+			case 14:
+				memcpy(vc, filter_coeff_M14, sizeof(vc));
+				break;
+			case 15:
+			case 16:
+				memcpy(vc, filter_coeff_M16, sizeof(vc));
+				break;
+			case 17:
+			case 18:
+			case 19:
+				memcpy(vc, filter_coeff_M19, sizeof(vc));
+				break;
+			case 20:
+			case 21:
+			case 22:
+				memcpy(vc, filter_coeff_M22, sizeof(vc));
+				break;
+			case 23:
+			case 24:
+			case 25:
+			case 26:
+				memcpy(vc, filter_coeff_M26, sizeof(vc));
+				break;
+			case 27:
+			case 28:
+			case 29:
+			case 30:
+			case 31:
+			case 32:
+				memcpy(vc, filter_coeff_M32, sizeof(vc));
+				break;
+			default:
+				DSSDBG("Chosing default M val = 8 \n");
+				memcpy(vc, filter_coeff_M8, sizeof(vc));
+				break;
+			};
 		}
-
-		_dispc_write_firh_reg(plane, i, h);
-		_dispc_write_firhv_reg(plane, i, hv);
+	} else if (out_height != 0 && !five_taps) {
+		if (out_height != orig_height) {
+			/* Vertical scaling */
+			if (out_height > orig_height) {
+				DSSDBG("Vertical upscaling \n");
+				memcpy(vc_3tap, filter_coeff_vc_u,
+					sizeof(vc_3tap));
+			} else {
+				DSSDBG("Vertical downscaling \n");
+				memcpy(vc_3tap, filter_coeff_vc_d,
+					sizeof(vc_3tap));
+			}
+		}
 	}
 
-	if (!five_taps)
-		return;
 
+	/* Select the coefficients based on the ratio - width / horizontal */
+	if (out_width != 0 && five_taps) {
+		if ((out_width != orig_width) || vdma) {
+			rem_ratio = 0;
+			mval = 8; /* default */
+			rem_ratio =  out_width / orig_width ;
+			if (rem_ratio > 1)
+				mval = 8;
+			else
+				mval = (8 * orig_width) / out_width;
+
+			switch (mval) {
+			case 8:
+				memcpy(hc, filter_coeff_M8, sizeof(hc));
+				break;
+			case 9:
+				memcpy(hc, filter_coeff_M9, sizeof(hc));
+				break;
+			case 10:
+				memcpy(hc, filter_coeff_M10, sizeof(hc));
+				break;
+			case 11:
+				memcpy(hc, filter_coeff_M11, sizeof(hc));
+				break;
+			case 12:
+				memcpy(hc, filter_coeff_M12, sizeof(hc));
+				break;
+			case 13:
+				memcpy(hc, filter_coeff_M13, sizeof(hc));
+				break;
+			case 14:
+				memcpy(hc, filter_coeff_M14, sizeof(hc));
+				break;
+			case 15:
+			case 16:
+				memcpy(hc, filter_coeff_M16, sizeof(hc));
+				break;
+			case 17:
+			case 18:
+			case 19:
+				memcpy(hc, filter_coeff_M19, sizeof(hc));
+				break;
+			case 20:
+			case 21:
+			case 22:
+				memcpy(hc, filter_coeff_M22, sizeof(hc));
+				break;
+			case 23:
+			case 24:
+			case 25:
+			case 26:
+				memcpy(hc, filter_coeff_M26, sizeof(hc));
+				break;
+			case 27:
+			case 28:
+			case 29:
+			case 30:
+			case 31:
+			case 32:
+				memcpy(hc, filter_coeff_M32, sizeof(hc));
+				break;
+			default:
+				DSSDBG("Chosing default M val = 8 \n");
+				memcpy(hc, filter_coeff_M8, sizeof(hc));
+				break;
+			};
+		}
+	} else if (out_width != 0 && !five_taps) {
+		if (out_width != orig_width) {
+			/* Horizontal scaling */
+			if (out_height > orig_height) {
+				DSSDBG("Horizontal upscaling \n");
+				memcpy(hc, filter_coeff_hc_u, sizeof(hc));
+			} else {
+				DSSDBG("Horizontal downscaling \n");
+				memcpy(hc, filter_coeff_hc_d, sizeof(hc));
+			}
+		}
+	}
+
+	/* Pack the coefficients - use fivetaps for all ratios */
 	for (i = 0; i < 8; i++) {
-		u32 v;
-		v = v_coef[i];
-		_dispc_write_firv_reg(plane, i, v);
+		reg = 0;
+		DSSDBG("Phase i = %d \n", (int)i);
+		reg = ((hc[1][i] & 0xff) << 24)
+			| ((hc[2][i] & 0xff) << 16)
+			| ((hc[3][i] & 0xff) << 8)
+			| (hc[4][i] & 0xff);
+		_dispc_write_firh_reg(plane, i, reg);
+		DSSDBG("H coefficients = 0x%x\n", (int)reg);
+
+		if (!five_taps) {
+			reg = 0;
+			reg = (hc[0][i] & 0xff)
+				| ((vc_3tap[2][i] & 0xff) << 8)
+				| ((vc_3tap[1][i] & 0xff) << 16)
+				| ((vc_3tap[0][i] & 0xff) << 24);
+			_dispc_write_firhv_reg(plane, i, reg);
+			DSSDBG("HV coefficients = 0x%x\n", (int)reg);
+
+		} else {
+			reg = 0;
+			reg = (hc[0][i] & 0xff)
+				| ((vc[3][i] & 0xff) << 8)
+				| ((vc[2][i] & 0xff) << 16)
+				| ((vc[1][i] & 0xff) << 24);
+			_dispc_write_firhv_reg(plane, i, reg);
+			DSSDBG("HV coefficients = 0x%x\n", (int)reg);
+
+			reg = 0;
+			reg =  ((vc[0][i] & 0xff) << 8) | (vc[4][i] & 0xff);
+			_dispc_write_firv_reg(plane, i, reg);
+			DSSDBG("V coefficients = 0x%x\n", (int)reg);
+		}
 	}
 }
 
@@ -1052,12 +1245,16 @@
 	dispc_write_reg(ac1_reg[plane-1], val);
 }
 
+static void _dispc_set_vdma_attrs(enum omap_plane plane, bool enable)
+{
+	REG_FLD_MOD(dispc_reg_att[plane], enable ? 1 : 0, 20, 20);
+}
 
 static void _dispc_set_scaling(enum omap_plane plane,
 		u16 orig_width, u16 orig_height,
 		u16 out_width, u16 out_height,
 		bool ilace, bool five_taps,
-		bool fieldmode)
+		bool fieldmode, bool vdma)
 {
 	int fir_hinc;
 	int fir_vinc;
@@ -1071,14 +1268,16 @@
 	hscaleup = orig_width <= out_width;
 	vscaleup = orig_height <= out_height;
 
-	_dispc_set_scale_coef(plane, hscaleup, vscaleup, five_taps);
+	/* New filter coefficients integration */
+	_dispc_set_scale_coef(plane, orig_width, out_width,
+			orig_height, out_height, five_taps, vdma);
 
-	if (!orig_width || orig_width == out_width)
+	if (!orig_width || (!vdma && (orig_width == out_width)))
 		fir_hinc = 0;
 	else
 		fir_hinc = 1024 * orig_width / out_width;
 
-	if (!orig_height || orig_height == out_height)
+	if (!orig_height || (!vdma && (orig_height == out_height)))
 		fir_vinc = 0;
 	else
 		fir_vinc = 1024 * orig_height / out_height;
@@ -1129,13 +1328,13 @@
 				vidrot = 2;
 				break;
 			case 1:
-				vidrot = 1;
+				vidrot = 3;
 				break;
 			case 2:
 				vidrot = 0;
 				break;
 			case 3:
-				vidrot = 3;
+				vidrot = 1;
 				break;
 			}
 		} else {
@@ -1144,23 +1343,25 @@
 				vidrot = 0;
 				break;
 			case 1:
-				vidrot = 1;
+				vidrot = 3;
 				break;
 			case 2:
 				vidrot = 2;
 				break;
 			case 3:
-				vidrot = 3;
+				vidrot = 1;
 				break;
 			}
 		}
 
 		REG_FLD_MOD(dispc_reg_att[plane], vidrot, 13, 12);
 
-		if (rotation == 1 || rotation == 3)
+		if (!dispc_is_vdma_req(rotation, color_mode) &&
+			(rotation == 1 || rotation == 3))
 			REG_FLD_MOD(dispc_reg_att[plane], 0x1, 18, 18);
 		else
 			REG_FLD_MOD(dispc_reg_att[plane], 0x0, 18, 18);
+
 	} else {
 		REG_FLD_MOD(dispc_reg_att[plane], 0, 13, 12);
 		REG_FLD_MOD(dispc_reg_att[plane], 0, 18, 18);
@@ -1485,6 +1686,17 @@
 	return dispc_pclk_rate() * vf * hf;
 }
 
+static int dispc_is_vdma_req(u8 rotation, enum omap_color_mode color_mode)
+{
+	/* TODO: VDMA support for RGB16 mode */
+	if (cpu_is_omap3630())
+		if ((color_mode == OMAP_DSS_COLOR_YUV2) ||
+			(color_mode == OMAP_DSS_COLOR_UYVY))
+			if ((rotation == 1) || (rotation == 3))
+				return true;
+	return false;
+}
+
 void dispc_set_channel_out(enum omap_plane plane, enum omap_channel channel_out)
 {
 	enable_clocks(1);
@@ -1504,7 +1716,7 @@
 		u8 global_alpha)
 {
 	const int maxdownscale = cpu_is_omap34xx() ? 4 : 2;
-	bool five_taps = 0;
+	bool five_taps = 1;
 	bool fieldmode = 0;
 	int cconv = 0;
 	unsigned offset0, offset1;
@@ -1583,8 +1795,6 @@
 			return -EINVAL;
 		}
 
-		/* Must use 5-tap filter? */
-		five_taps = height > out_height * 2;
 
 		if (!five_taps) {
 			fclk = calc_fclk(width, height,
@@ -1594,10 +1804,12 @@
 			if (cpu_is_omap34xx() && height > out_height &&
 					fclk > dispc_fclk_rate())
 				five_taps = true;
+			if (dispc_is_vdma_req(rotation, color_mode))
+				five_taps = true;
 		}
 
 		if (width > (2048 >> five_taps))
-			return -EINVAL;
+			five_taps = 0;
 
 		if (five_taps)
 			fclk = calc_fclk_five_taps(width, height,
@@ -1658,9 +1870,17 @@
 	_dispc_set_pic_size(plane, width, height);
 
 	if (plane != OMAP_DSS_GFX) {
-		_dispc_set_scaling(plane, width, height,
-				   out_width, out_height,
-				   ilace, five_taps, fieldmode);
+		if (dispc_is_vdma_req(rotation, color_mode)) {
+			_dispc_set_scaling(plane, width, height,
+				out_width, out_height,
+				ilace, five_taps, fieldmode, 1);
+			_dispc_set_vdma_attrs(plane, 1);
+		} else {
+			_dispc_set_scaling(plane, width, height,
+				out_width, out_height,
+				ilace, five_taps, fieldmode, 0);
+			_dispc_set_vdma_attrs(plane, 0);
+		}
 		_dispc_set_vid_size(plane, out_width, out_height);
 		_dispc_set_vid_color_conv(plane, cconv);
 	}
@@ -2373,14 +2593,18 @@
 	DSSDBG("onoff %d rf %d ieo %d ipc %d ihs %d ivs %d acbi %d acb %d\n",
 			onoff, rf, ieo, ipc, ihs, ivs, acbi, acb);
 
-	l |= FLD_VAL(onoff, 17, 17);
-	l |= FLD_VAL(rf, 16, 16);
-	l |= FLD_VAL(ieo, 15, 15);
-	l |= FLD_VAL(ipc, 14, 14);
-	l |= FLD_VAL(ihs, 13, 13);
-	l |= FLD_VAL(ivs, 12, 12);
-	l |= FLD_VAL(acbi, 11, 8);
-	l |= FLD_VAL(acb, 7, 0);
+	if (cpu_is_omap3630()) {
+		l = 0x00033028;
+	} else {
+		l |= FLD_VAL(onoff, 17, 17);
+		l |= FLD_VAL(rf, 16, 16);
+		l |= FLD_VAL(ieo, 15, 15);
+		l |= FLD_VAL(ipc, 14, 14);
+		l |= FLD_VAL(ihs, 13, 13);
+		l |= FLD_VAL(ivs, 12, 12);
+		l |= FLD_VAL(acbi, 11, 8);
+		l |= FLD_VAL(acb, 7, 0);
+	}
 
 	enable_clocks(1);
 	dispc_write_reg(DISPC_POL_FREQ, l);
@@ -2493,8 +2717,16 @@
 
 		goto found;
 	} else if (cpu_is_omap34xx()) {
-		for (cur.fck_div = 16; cur.fck_div > 0; --cur.fck_div) {
-			cur.fck = prate / cur.fck_div * 2;
+		if (cpu_is_omap3630())
+			cur.fck_div = 32;
+		else
+			cur.fck_div = 16;
+
+		for ( ; cur.fck_div > 0; --cur.fck_div) {
+			if (cpu_is_omap3630())
+				cur.fck = prate / cur.fck_div ;
+			else
+				cur.fck = prate / cur.fck_div * 2;
 
 			if (cur.fck > DISPC_MAX_FCK)
 				continue;
@@ -2708,6 +2940,114 @@
 }
 EXPORT_SYMBOL(omap_dispc_unregister_isr);
 
+/* This functions adds the OMAPDSS power saving capability by
+ * FIFO Merge when display is not in use, thus ehancing the DSS for
+ * Screen saver support.
+ */
+int omap_dispc_lpr_enable(void)
+{
+	int rc = 0;
+	unsigned long flags;
+	struct omap_overlay *ovl;
+	int v_attr;
+
+	/* Cannot enable lpr if DSS is inactive */
+	if (!gfx_in_use) {
+		DSSDBG("\nGRX plane in use\n");
+		return -1;
+	}
+
+	spin_lock_irqsave(&dispc.lpr_lock, flags);
+
+	if (lpr_enabled) {
+		DSSDBG("\nLPR is enabled\n");
+		goto lpr_out;
+	}
+
+	/* Check whether LPR can be triggered
+	* - gfx pipeline is routed to LCD
+	* - both video pipelines are disabled (this allows FIFOs merge)
+	*/
+
+	ovl = omap_dss_get_overlay(0);
+
+	if (ovl->manager->id != OMAP_DSS_CHANNEL_LCD) {
+		rc = -1;
+		goto lpr_out;
+	}
+
+	v_attr = dispc_read_reg(DISPC_VID_ATTRIBUTES(0)) |
+			dispc_read_reg(DISPC_VID_ATTRIBUTES(1));
+
+	if (v_attr & DISPC_VID_ATTRIBUTES_ENABLE) {
+		rc = -1;
+		goto lpr_out;
+	}
+
+	dispc_setup_plane_fifo(ovl->id, LPR_GFX_FIFO_LOW_THRES,
+				LPR_GFX_FIFO_HIGH_THRES);
+
+	dispc_enable_fifomerge(1);
+
+	/* Enable LCD */
+
+	dispc_enable_lcd_out(1);
+
+	spin_unlock_irqrestore(&dispc.lpr_lock, flags);
+
+	/*Let LPR settings take an effect */
+
+	dispc_go(ovl->manager->id);
+
+	lpr_enabled = 1;
+
+	return 0;
+
+lpr_out:
+	spin_unlock_irqrestore(&dispc.lpr_lock, flags);
+	return rc;
+
+}
+EXPORT_SYMBOL(omap_dispc_lpr_enable);
+
+int omap_dispc_lpr_disable(void)
+{
+	unsigned long flags;
+	struct omap_overlay *ovl;
+	u32 fifo_low, fifo_high;
+	enum omap_burst_size burst_size;
+
+	if (!gfx_in_use)
+		return -1;
+
+	spin_lock_irqsave(&dispc.lpr_lock, flags);
+
+	ovl = omap_dss_get_overlay(0);
+
+	if (!lpr_enabled) {
+		spin_unlock_irqrestore(&dispc.lpr_lock, flags);
+		return 0;
+	}
+	/* Disable Fifo Merge */
+	dispc_enable_fifomerge(0);
+
+	default_get_overlay_fifo_thresholds(ovl->id, dispc.fifo_size[ovl->id],
+				&burst_size, &fifo_low, &fifo_high);
+
+	/* Restore default fifo size*/
+	dispc_setup_plane_fifo(ovl->id, fifo_low, fifo_high);
+
+	lpr_enabled = 0;
+
+	spin_unlock_irqrestore(&dispc.lpr_lock, flags);
+
+	/* Let DSS take an effect */
+	dispc_go(ovl->manager->id);
+
+	return 0;
+}
+EXPORT_SYMBOL(omap_dispc_lpr_disable);
+
 #ifdef DEBUG
 static void print_irq_status(u32 status)
 {
@@ -3134,6 +3474,14 @@
 
 	enable_clocks(1);
 	_dispc_enable_plane(plane, enable);
+
+	if (plane == OMAP_DSS_GFX) {
+		if (enable)
+			gfx_in_use = 1;
+		else
+			gfx_in_use = 0;
+	}
+
 	enable_clocks(0);
 
 	return 0;
diff --git a/drivers/video/omap2/dss/display.c b/drivers/video/omap2/dss/display.c
index 18fa026..5ca021d 100644
--- a/drivers/video/omap2/dss/display.c
+++ b/drivers/video/omap2/dss/display.c
@@ -277,6 +277,30 @@
 	return size;
 }
 
+unsigned long lpr_enable;
+extern int omap_dispc_lpr_enable(void);
+extern void omap_dispc_lpr_disable(void);
+
+static ssize_t display_lpr_store(struct device *dev,
+		struct device_attribute *attr, const char *buf, size_t size)
+{
+
+	lpr_enable = simple_strtoul(buf, NULL, 0);
+	if (lpr_enable)
+		omap_dispc_lpr_enable();
+	else
+		omap_dispc_lpr_disable();
+
+	return size;
+}
+
+static ssize_t display_lpr_show(struct device *dev,
+		struct device_attribute *attr, char *buf)
+{
+
+	return snprintf(buf, PAGE_SIZE, "%lu\n", lpr_enable);
+}
+
 static DEVICE_ATTR(enabled, S_IRUGO|S_IWUSR,
 		display_enabled_show, display_enabled_store);
 static DEVICE_ATTR(update_mode, S_IRUGO|S_IWUSR,
@@ -291,6 +315,8 @@
 		display_mirror_show, display_mirror_store);
 static DEVICE_ATTR(wss, S_IRUGO|S_IWUSR,
 		display_wss_show, display_wss_store);
+static DEVICE_ATTR(lpr_enable, S_IRUGO|S_IWUSR,
+		display_lpr_show, display_lpr_store);
 
 static struct device_attribute *display_sysfs_attrs[] = {
 	&dev_attr_enabled,
@@ -300,6 +326,7 @@
 	&dev_attr_rotate,
 	&dev_attr_mirror,
 	&dev_attr_wss,
+	&dev_attr_lpr_enable,
 	NULL
 };
 
@@ -370,7 +397,7 @@
 bool dss_use_replication(struct omap_dss_device *dssdev,
 		enum omap_color_mode mode)
 {
-	int bpp;
+	int bpp = 0;
 
 	if (mode != OMAP_DSS_COLOR_RGB12U && mode != OMAP_DSS_COLOR_RGB16)
 		return false;
@@ -381,6 +408,7 @@
 
 	switch (dssdev->type) {
 	case OMAP_DISPLAY_TYPE_DPI:
+	case OMAP_DISPLAY_TYPE_HDMI:
 		bpp = dssdev->phy.dpi.data_lines;
 		break;
 	case OMAP_DISPLAY_TYPE_VENC:
@@ -582,7 +610,7 @@
  * of from-device is decremented. */
 struct omap_dss_device *omap_dss_get_next_device(struct omap_dss_device *from)
 {
-	struct device *dev;
+	struct device *dev = NULL;
 	struct device *dev_start = NULL;
 	struct omap_dss_device *dssdev = NULL;
 
diff --git a/drivers/video/omap2/dss/dpi.c b/drivers/video/omap2/dss/dpi.c
index b6543c8..46ba42e 100644
--- a/drivers/video/omap2/dss/dpi.c
+++ b/drivers/video/omap2/dss/dpi.c
@@ -26,6 +26,7 @@
 #include <linux/clk.h>
 #include <linux/delay.h>
 #include <linux/errno.h>
+#include <linux/i2c/twl4030.h>
 
 #include <mach/board.h>
 #include <mach/display.h>
@@ -33,11 +34,28 @@
 
 #include "dss.h"
 
+/* for enabling VPLL2*/
+#define ENABLE_VPLL2_DEDICATED          0x05
+#define ENABLE_VPLL2_DEV_GRP            0xE0
+#define TWL4030_VPLL2_DEV_GRP           0x33
+#define TWL4030_VPLL2_DEDICATED         0x36
+
 static struct {
 	int update_enabled;
 } dpi;
 
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+static int enable_vpll2_power(int enable)
+{
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				(enable) ? ENABLE_VPLL2_DEDICATED : 0,
+				TWL4030_VPLL2_DEDICATED);
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				(enable) ? ENABLE_VPLL2_DEV_GRP : 0,
+				TWL4030_VPLL2_DEV_GRP);
+	return 0;
+}
+
 static int dpi_set_dsi_clk(bool is_tft, unsigned long pck_req,
 		unsigned long *fck, int *lck_div, int *pck_div)
 {
@@ -166,7 +184,8 @@
 
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
 	dss_clk_enable(DSS_CLK_FCK2);
-	r = dsi_pll_init(0, 1);
+	enable_vpll2_power(1);
+	r = dsi_pll_init(1, 1);
 	if (r)
 		goto err3;
 #endif
@@ -219,6 +238,7 @@
 #ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
 	dss_select_clk_source(0, 0);
 	dsi_pll_uninit();
+	enable_vpll2_power(0);
 	dss_clk_disable(DSS_CLK_FCK2);
 #endif
 
@@ -241,6 +261,13 @@
 
 	dispc_enable_lcd_out(0);
 
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+	dss_select_clk_source(0, 0);
+	dsi_pll_uninit();
+	enable_vpll2_power(0);
+	dss_clk_disable(DSS_CLK_FCK2);
+#endif
+
 	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
 
 	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
@@ -250,6 +277,7 @@
 
 static int dpi_display_resume(struct omap_dss_device *dssdev)
 {
+	int r = 0;
 	if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
 		return -EINVAL;
 
@@ -257,14 +285,44 @@
 
 	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
 
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+	dss_clk_enable(DSS_CLK_FCK2);
+	enable_vpll2_power(1);
+
+	r = dsi_pll_init(1, 1);
+	if (r)
+		goto err0;
+
+	r = dpi_set_mode(dssdev);
+	if (r)
+		goto err0;
+#endif
+
 	dispc_enable_lcd_out(1);
 
-	if (dssdev->driver->resume)
-		dssdev->driver->resume(dssdev);
+	if (dssdev->driver->resume) {
+		r = dssdev->driver->resume(dssdev);
+		if (r)
+			goto err1;
+	}
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
 	return 0;
+
+err1:
+	dispc_enable_lcd_out(0);
+
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+err0:
+	DSSERR("<%s!!> err0: failed to init DSI_PLL = %d\n", __func__, r);
+	dss_select_clk_source(0, 0);
+	dsi_pll_uninit();
+	dss_clk_disable(DSS_CLK_FCK2);
+	enable_vpll2_power(0);
+#endif
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	return r;
 }
 
 static void dpi_set_timings(struct omap_dss_device *dssdev,
diff --git a/drivers/video/omap2/dss/hdmi.c b/drivers/video/omap2/dss/hdmi.c
index e10882d..6e6b88f0 100644
--- a/drivers/video/omap2/dss/hdmi.c
+++ b/drivers/video/omap2/dss/hdmi.c
@@ -1,8 +1,8 @@
 /*
  * linux/drivers/video/omap2/dss/hdmi.c
  *
- * Copyright (C) 2009 Nokia Corporation
- * Author: Tomi Valkeinen <tomi.valkeinen@nokia.com>
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ * Author: srinivas pulukuru <srinivas.pulukuru@ti.com>
  *
  * hdmi settings from TI's DSS driver
  *
@@ -22,21 +22,66 @@
 #define DSS_SUBSYS_NAME "HDMI"
 
 #include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/err.h>
-#include <linux/io.h>
-#include <linux/mutex.h>
+#include <linux/clk.h>
 #include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/platform_device.h>
+#include <linux/errno.h>
 #include <linux/sil9022.h>
+#include <linux/i2c/twl4030.h>
 
+#include <mach/board.h>
 #include <mach/display.h>
+#include <mach/cpu.h>
 
 #include "dss.h"
 
+/* for enabling VPLL2*/
+#define ENABLE_VPLL2_DEDICATED          0x05
+#define ENABLE_VPLL2_DEV_GRP            0xE0
+#define TWL4030_VPLL2_DEV_GRP           0x33
+#define TWL4030_VPLL2_DEDICATED         0x36
+
 struct omap_dss_device *omap_dss_hdmi_device;
 
+static void hdmi_set_timings(struct omap_dss_device *dssdev,
+			struct omap_video_timings *timings);
+
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+static int enable_vpll2_power(int enable)
+{
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				(enable) ? ENABLE_VPLL2_DEDICATED : 0,
+				TWL4030_VPLL2_DEDICATED);
+	twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER,
+				(enable) ? ENABLE_VPLL2_DEV_GRP : 0,
+				TWL4030_VPLL2_DEV_GRP);
+	return 0;
+}
+
+static int hdmi_set_dsi_clk(bool is_tft, unsigned long pck_req,
+		unsigned long *fck, int *lck_div, int *pck_div)
+{
+	struct dsi_clock_info cinfo;
+	int r;
+
+	r = dsi_pll_calc_pck(is_tft, pck_req, &cinfo);
+	if (r)
+		return r;
+
+	r = dsi_pll_program(&cinfo);
+	if (r)
+		return r;
+
+	dss_select_clk_source(0, 1);
+
+	dispc_set_lcd_divisor(cinfo.lck_div, cinfo.pck_div);
+
+	*fck = cinfo.dsi1_pll_fclk;
+	*lck_div = cinfo.lck_div;
+	*pck_div = cinfo.pck_div;
+
+	return 0;
+}
+#else
 static int hdmi_set_dispc_clk(bool is_tft, unsigned long pck_req,
 		unsigned long *fck, int *lck_div, int *pck_div)
 {
@@ -57,6 +102,8 @@
 
 	return 0;
 }
+#endif
+
 static int hdmi_set_mode(struct omap_dss_device *dssdev)
 {
 	struct omap_video_timings *t = &dssdev->panel.timings;
@@ -73,8 +120,13 @@
 
 	is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+	r = hdmi_set_dsi_clk(is_tft, t->pixel_clock * 1000,
+			&fck, &lck_div, &pck_div);
+#else
 	r = hdmi_set_dispc_clk(is_tft, t->pixel_clock * 1000,
 			&fck, &lck_div, &pck_div);
+#endif
 	if (r)
 		goto err0;
 
@@ -113,7 +165,6 @@
 {
 	int r = 0;
 
-	DSSDBG("hdmi_enable_display\n");
 	r = omap_dss_start_device(dssdev);
 	if (r) {
 		DSSERR("failed to start device\n");
@@ -132,9 +183,14 @@
 	if (r)
 		goto err2;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
 	dss_clk_enable(DSS_CLK_FCK2);
-	r = dsi_pll_init(0, 1);
+	/* this needs to be done here in order to
+	 * get the VPLL2 to power up the DSI PLL module
+	 */
+	enable_vpll2_power(1);
+
+	r = dsi_pll_init(1, 1);
 	if (r)
 		goto err3;
 #endif
@@ -152,12 +208,17 @@
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
+	/* Default HDMI panel timings may not work for all monitors */
+	/* Reset HDMI panel timings after enabling HDMI. */
+	DSSINFO("Reset HDMI output timings based on monitor E-EDID timings\n");
+	hdmi_set_timings(dssdev, &dssdev->panel.timings);
+
 	return 0;
 
 err5:
 	dispc_enable_lcd_out(0);
 err4:
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
 	dsi_pll_uninit();
 err3:
 	dss_clk_disable(DSS_CLK_FCK2);
@@ -185,9 +246,10 @@
 
 	dispc_enable_lcd_out(0);
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
 	dss_select_clk_source(0, 0);
 	dsi_pll_uninit();
+	enable_vpll2_power(0);
 	dss_clk_disable(DSS_CLK_FCK2);
 #endif
 
@@ -200,19 +262,23 @@
 
 static int hdmi_display_suspend(struct omap_dss_device *dssdev)
 {
-	int r = 0;
-
-	DSSDBG("hdmi_display_suspend\n");
 	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
 		return -EINVAL;
 
-	DSSDBG("dpi_display_suspend\n");
+	DSSDBG("hdmi_display_suspend\n");
 
 	if (dssdev->driver->suspend)
 		dssdev->driver->suspend(dssdev);
 
 	dispc_enable_lcd_out(0);
 
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+	dss_select_clk_source(0, 0);
+	dsi_pll_uninit();
+	enable_vpll2_power(0);
+	dss_clk_disable(DSS_CLK_FCK2);
+#endif
+
 	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
 
 	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
@@ -223,7 +289,6 @@
 static int hdmi_display_resume(struct omap_dss_device *dssdev)
 {
 	int r = 0;
-
 	if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
 		return -EINVAL;
 
@@ -231,15 +296,44 @@
 
 	dss_clk_enable(DSS_CLK_ICK | DSS_CLK_FCK1);
 
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+	dss_clk_enable(DSS_CLK_FCK2);
+	enable_vpll2_power(1);
+
+	r = dsi_pll_init(1, 1);
+	if (r)
+		goto err0;
+
+	r = hdmi_set_mode(dssdev);
+	if (r)
+		goto err0;
+#endif
+
 	dispc_enable_lcd_out(1);
 
-	if (dssdev->driver->resume)
-		dssdev->driver->resume(dssdev);
+	if (dssdev->driver->resume) {
+		r = dssdev->driver->resume(dssdev);
+		if (r)
+			goto err1;
+	}
 
 	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
 
 	return 0;
 
+err1:
+	dispc_enable_lcd_out(0);
+
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
+err0:
+	DSSERR("<%s!!> err0: failed to init DSI_PLL = %d\n", __func__, r);
+	dss_select_clk_source(0, 0);
+	dsi_pll_uninit();
+	dss_clk_disable(DSS_CLK_FCK2);
+	enable_vpll2_power(0);
+#endif
+	dss_clk_disable(DSS_CLK_ICK | DSS_CLK_FCK1);
+	return r;
 }
 
 static void hdmi_get_timings(struct omap_dss_device *dssdev,
@@ -252,6 +346,7 @@
 			struct omap_video_timings *timings)
 {
 	DSSDBG("hdmi_set_timings\n");
+	dssdev->panel.timings = *timings;
 	if (dssdev->state == OMAP_DSS_DISPLAY_ACTIVE) {
 		hdmi_set_mode(dssdev);
 		dispc_go(OMAP_DSS_CHANNEL_LCD);
@@ -276,7 +371,7 @@
 
 	is_tft = (dssdev->panel.config & OMAP_DSS_LCD_TFT) != 0;
 
-#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL
+#ifdef CONFIG_OMAP2_DSS_USE_DSI_PLL_FOR_HDMI
 	{
 		struct dsi_clock_info cinfo;
 		r = dsi_pll_calc_pck(is_tft, timings->pixel_clock * 1000,
diff --git a/drivers/video/omap2/dss/manager.c b/drivers/video/omap2/dss/manager.c
index d64873a..e1b15d8 100644
--- a/drivers/video/omap2/dss/manager.c
+++ b/drivers/video/omap2/dss/manager.c
@@ -832,7 +832,7 @@
 	DSSDBGF("%d", channel);
 
 	c = &dss_cache.manager_cache[channel];
-
+	dispc_set_default_color(channel, c->default_color);
 	dispc_set_trans_key(channel, c->trans_key_type, c->trans_key);
 	dispc_enable_trans_key(channel, c->trans_enabled);
 	dispc_enable_alpha_blending(channel, c->alpha_enabled);
diff --git a/drivers/video/omap2/dss/rfbi.c b/drivers/video/omap2/dss/rfbi.c
index 9dd2349..69e8a10 100644
--- a/drivers/video/omap2/dss/rfbi.c
+++ b/drivers/video/omap2/dss/rfbi.c
@@ -124,6 +124,7 @@
 	struct kfifo      *cmd_fifo;
 	spinlock_t        cmd_lock;
 	struct completion cmd_done;
+	struct completion update_done;
 	atomic_t          cmd_fifo_full;
 	atomic_t          cmd_pending;
 #ifdef MEASURE_PERF
@@ -419,6 +420,8 @@
 
 	/*callback(rfbi.framedone_callback_data);*/
 
+	complete(&rfbi.update_done);
+
 	atomic_set(&rfbi.cmd_pending, 0);
 
 	process_cmd_fifo();
@@ -1164,6 +1167,7 @@
 		return -ENOMEM;
 
 	init_completion(&rfbi.cmd_done);
+	init_completion(&rfbi.update_done);
 	atomic_set(&rfbi.cmd_fifo_full, 0);
 	atomic_set(&rfbi.cmd_pending, 0);
 
@@ -1208,6 +1212,9 @@
 {
 	int rfbi_module;
 
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+		return 0;
+
 	if (w == 0 || h == 0)
 		return 0;
 
@@ -1233,6 +1240,18 @@
 	return 0;
 }
 
+static enum omap_dss_update_mode rfbi_display_get_update_mode(
+	struct omap_dss_device *dssdev)
+{
+	return OMAP_DSS_UPDATE_MANUAL;
+}
+
+static int rfbi_display_set_update_mode(struct omap_dss_device *dssdev,
+		enum omap_dss_update_mode mode)
+{
+	return 0;
+}
+
 static int rfbi_display_enable_te(struct omap_dss_device *dssdev, bool enable)
 {
 	dssdev->driver->enable_te(dssdev, enable);
@@ -1243,6 +1262,8 @@
 {
 	int r;
 
+	dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
 	r = omap_dss_start_device(dssdev);
 	if (r) {
 		DSSERR("failed to start device\n");
@@ -1294,6 +1315,51 @@
 	omap_dss_stop_device(dssdev);
 }
 
+static int rfbi_display_suspend(struct omap_dss_device *dssdev)
+{
+	DSSDBG("rfbi_display_suspend\n");
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_ACTIVE)
+		return -EINVAL;
+
+	dssdev->state = OMAP_DSS_DISPLAY_SUSPENDED;
+
+	wait_for_completion(&rfbi.update_done);
+
+	rfbi_enable_clocks(1);
+
+	/* Bypass mode must be enabled to allow the RFBI module to idle */
+	REG_FLD_MOD(RFBI_CONTROL, 1, 1, 1);
+
+	rfbi_display_disable(dssdev);
+	rfbi_exit();
+
+	rfbi_enable_clocks(0);
+
+	return 0;
+}
+
+static int rfbi_display_resume(struct omap_dss_device *dssdev)
+{
+
+	DSSDBG("rfbi_display_resume\n");
+
+	if (dssdev->state != OMAP_DSS_DISPLAY_SUSPENDED)
+		return -EINVAL;
+
+	rfbi_enable_clocks(1);
+
+	/* Disable Bypass mode again */
+	REG_FLD_MOD(RFBI_CONTROL, 0, 1, 1);
+
+	rfbi_init();
+	rfbi_display_enable(dssdev);
+
+	rfbi_enable_clocks(0);
+
+	return 0;
+}
+
 int rfbi_init_display(struct omap_dss_device *dssdev)
 {
 	dssdev->enable = rfbi_display_enable;
@@ -1301,6 +1367,10 @@
 	dssdev->update = rfbi_display_update;
 	dssdev->sync = rfbi_display_sync;
 	dssdev->enable_te = rfbi_display_enable_te;
+	dssdev->get_update_mode = rfbi_display_get_update_mode;
+	dssdev->set_update_mode = rfbi_display_set_update_mode;
+	dssdev->suspend = rfbi_display_suspend;
+	dssdev->resume = rfbi_display_resume;
 
 	rfbi.dssdev[dssdev->phy.rfbi.channel] = dssdev;
 
diff --git a/drivers/video/omap2/omapfb/Kconfig b/drivers/video/omap2/omapfb/Kconfig
index 4f66033..c5d44f6 100644
--- a/drivers/video/omap2/omapfb/Kconfig
+++ b/drivers/video/omap2/omapfb/Kconfig
@@ -33,3 +33,10 @@
 	help
 	  Select the number of framebuffers created. OMAP2/3 has 3 overlays
 	  so normally this would be 3.
+
+config FB_OMAP2_32_BPP
+	bool "Support 32 bpp"
+	default n
+	depends on FB_OMAP2
+	help
+	  Supports 32 bpp for zoom2 panel.
diff --git a/drivers/video/omap2/omapfb/omapfb-main.c b/drivers/video/omap2/omapfb/omapfb-main.c
index 41f1615..30cfd76 100644
--- a/drivers/video/omap2/omapfb/omapfb-main.c
+++ b/drivers/video/omap2/omapfb/omapfb-main.c
@@ -412,6 +412,9 @@
 	fix->smem_start = omapfb_get_region_paddr(ofbi);
 	fix->smem_len = rg->size;
 
+	fix->mmio_start = DSS_BASE;
+	fix->mmio_len = DSS_SZ_REGS;
+
 	fix->type = FB_TYPE_PACKED_PIXELS;
 
 	if (var->nonstd)
@@ -1284,6 +1287,9 @@
 		bytespp = 2;
 		break;
 	case 24:
+#ifdef CONFIG_FB_OMAP2_32_BPP
+	case 32:
+#endif
 		bytespp = 4;
 		break;
 	default:
@@ -1565,6 +1571,22 @@
 	return r;
 }
 
+#ifdef CONFIG_HAS_EARLYSUSPEND
+void omapfb_suspend(struct early_suspend *h)
+{
+	struct omapfb_info *fbinfo = container_of(h, struct omapfb_info,
+						early_suspend);
+	omapfb_blank(FB_BLANK_POWERDOWN, fbinfo->fbdev->fbs[fbinfo->id]);
+}
+
+void omapfb_resume(struct early_suspend *h)
+{
+	struct omapfb_info *fbinfo = container_of(h, struct omapfb_info,
+						early_suspend);
+	omapfb_blank(FB_BLANK_UNBLANK, fbinfo->fbdev->fbs[fbinfo->id]);
+}
+#endif
+
 /* initialize fb_info, var, fix to something sane based on the display */
 int omapfb_fb_init(struct omapfb2_device *fbdev, struct fb_info *fbi)
 {
@@ -1637,6 +1659,9 @@
 				var->bits_per_pixel = 16;
 				break;
 			case 24:
+#ifdef CONFIG_FB_OMAP2_32_BPP
+			case 32:
+#endif
 				var->bits_per_pixel = 32;
 				break;
 			default:
@@ -1664,6 +1689,12 @@
 	r = fb_alloc_cmap(&fbi->cmap, 256, 0);
 	if (r)
 		dev_err(fbdev->dev, "unable to allocate color map memory\n");
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	ofbi->early_suspend.suspend = omapfb_suspend;
+	ofbi->early_suspend.resume = omapfb_resume;
+	ofbi->early_suspend.level = EARLY_SUSPEND_LEVEL_DISABLE_FB;
+	register_early_suspend(&ofbi->early_suspend);
+#endif
 
 err:
 	return r;
diff --git a/drivers/video/omap2/omapfb/omapfb.h b/drivers/video/omap2/omapfb/omapfb.h
index 6ca8ba6..c4eb5f8 100644
--- a/drivers/video/omap2/omapfb/omapfb.h
+++ b/drivers/video/omap2/omapfb/omapfb.h
@@ -28,6 +28,7 @@
 #endif
 
 #include <mach/display.h>
+#include <linux/earlysuspend.h>
 
 #ifdef DEBUG
 extern unsigned int omapfb_debug;
@@ -38,6 +39,9 @@
 #define DBG(format, ...)
 #endif
 
+#define DSS_BASE	0x48050000
+#define DSS_SZ_REGS	SZ_512
+
 #define FB2OFB(fb_info) ((struct omapfb_info *)(fb_info->par))
 
 /* max number of overlays to which a framebuffer data can be direct */
@@ -64,6 +68,9 @@
 	enum omap_dss_rotation_type rotation_type;
 	u8 rotation[OMAPFB_MAX_OVL_PER_FB];
 	bool mirror;
+#ifdef CONFIG_HAS_EARLYSUSPEND
+	struct early_suspend early_suspend;
+#endif
 };
 
 struct omapfb2_device {
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 53fd148..660ec78 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -172,7 +172,7 @@
 {
 	int ret;
 	u8 tmp_status;
-	unsigned long irqflags;
+	unsigned long uninitialized_var(irqflags);
 
 	*status = 0;
 
@@ -222,7 +222,7 @@
 static irqreturn_t hdq_isr(int irq, void *_hdq)
 {
 	struct hdq_data *hdq_data = _hdq;
-	unsigned long irqflags;
+	unsigned long uninitialized_var(irqflags);
 
 	spin_lock_irqsave(&hdq_data->hdq_spinlock, irqflags);
 	hdq_data->hdq_irqstatus = hdq_reg_in(hdq_data, OMAP_HDQ_INT_STATUS);
@@ -305,7 +305,7 @@
 {
 	int ret = 0;
 	u8 tmp_status;
-	unsigned long irqflags;
+	unsigned long uninitialized_var(irqflags);
 
 	ret = mutex_lock_interruptible(&hdq_data->hdq_mutex);
 	if (ret < 0) {
diff --git a/fs/partitions/check.c b/fs/partitions/check.c
index 6d72024..7822309 100644
--- a/fs/partitions/check.c
+++ b/fs/partitions/check.c
@@ -304,10 +304,19 @@
 	kfree(p);
 }
 
+static int part_uevent(struct device *dev, struct kobj_uevent_env *env)
+{
+	struct hd_struct *part = dev_to_part(dev);
+
+	add_uevent_var(env, "PARTN=%u", part->partno);
+	return 0;
+}
+
 struct device_type part_type = {
 	.name		= "partition",
 	.groups		= part_attr_groups,
 	.release	= part_release,
+	.uevent		= part_uevent,
 };
 
 static void delete_partition_rcu_cb(struct rcu_head *head)
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 93d926c..54e9cc9 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -258,7 +258,8 @@
 	if (task->mm != mm)
 		goto out;
 	if (task->mm != current->mm &&
-	    __ptrace_may_access(task, PTRACE_MODE_READ) < 0)
+	    __ptrace_may_access(task, PTRACE_MODE_READ) < 0 &&
+	    !capable(CAP_SYS_RESOURCE))
 		goto out;
 	task_unlock(task);
 	return mm;
diff --git a/fs/yaffs2/Kconfig b/fs/yaffs2/Kconfig
index c0e545b..8584450 100644
--- a/fs/yaffs2/Kconfig
+++ b/fs/yaffs2/Kconfig
@@ -154,3 +154,11 @@
 	  but makes look-ups faster.
 
 	  If unsure, say Y.
+
+config YAFFS_EMPTY_LOST_AND_FOUND
+	bool "Empty lost and found on mount"
+	depends on YAFFS_FS
+	default n
+	help
+	  If this is enabled then the contents of lost and found is
+	  automatically dumped at mount.
diff --git a/fs/yaffs2/yaffs_checkptrw.c b/fs/yaffs2/yaffs_checkptrw.c
index 288b550..7b69a64 100644
--- a/fs/yaffs2/yaffs_checkptrw.c
+++ b/fs/yaffs2/yaffs_checkptrw.c
@@ -43,6 +43,9 @@
 		yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, i);
 		if (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT) {
 			T(YAFFS_TRACE_CHECKPOINT, (TSTR("erasing checkpt block %d"TENDSTR), i));
+
+			dev->nBlockErasures++;
+
 			if (dev->eraseBlockInNAND(dev, i - dev->blockOffset /* realign */)) {
 				bi->blockState = YAFFS_BLOCK_STATE_EMPTY;
 				dev->nErasedBlocks++;
@@ -127,6 +130,9 @@
 int yaffs_CheckpointOpen(yaffs_Device *dev, int forWriting)
 {
 
+
+	dev->checkpointOpenForWrite = forWriting;
+
 	/* Got the functions we need? */
 	if (!dev->writeChunkWithTagsToNAND ||
 			!dev->readChunkWithTagsFromNAND ||
@@ -144,9 +150,6 @@
 
 
 	dev->checkpointPageSequence = 0;
-
-	dev->checkpointOpenForWrite = forWriting;
-
 	dev->checkpointByteCount = 0;
 	dev->checkpointSum = 0;
 	dev->checkpointXor = 0;
@@ -168,6 +171,9 @@
 		dev->blocksInCheckpoint = 0;
 		dev->checkpointMaxBlocks = (dev->internalEndBlock - dev->internalStartBlock)/16 + 2;
 		dev->checkpointBlockList = YMALLOC(sizeof(int) * dev->checkpointMaxBlocks);
+		if(!dev->checkpointBlockList)
+			return 0;
+
 		for (i = 0; i < dev->checkpointMaxBlocks; i++)
 			dev->checkpointBlockList[i] = -1;
 	}
@@ -219,6 +225,8 @@
 
 	realignedChunk = chunk - dev->chunkOffset;
 
+	dev->nPageWrites++;
+
 	dev->writeChunkWithTagsToNAND(dev, realignedChunk,
 			dev->checkpointBuffer, &tags);
 	dev->checkpointByteOffset = 0;
@@ -306,6 +314,8 @@
 					dev->checkpointCurrentChunk;
 
 				realignedChunk = chunk - dev->chunkOffset;
+				
+				dev->nPageReads++;
 
 				/* read in the next chunk */
 				/* printf("read checkpoint page %d\n",dev->checkpointPage); */
@@ -348,11 +358,14 @@
 	if (dev->checkpointOpenForWrite) {
 		if (dev->checkpointByteOffset != 0)
 			yaffs_CheckpointFlushBuffer(dev);
-	} else {
+	} else if(dev->checkpointBlockList){
 		int i;
 		for (i = 0; i < dev->blocksInCheckpoint && dev->checkpointBlockList[i] >= 0; i++) {
-			yaffs_BlockInfo *bi = yaffs_GetBlockInfo(dev, dev->checkpointBlockList[i]);
-			if (bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
+			int blk = dev->checkpointBlockList[i];
+			yaffs_BlockInfo *bi = NULL;
+			if( dev->internalStartBlock <= blk && blk <= dev->internalEndBlock)
+				bi = yaffs_GetBlockInfo(dev, blk);
+			if (bi && bi->blockState == YAFFS_BLOCK_STATE_EMPTY)
 				bi->blockState = YAFFS_BLOCK_STATE_CHECKPOINT;
 			else {
 				/* Todo this looks odd... */
@@ -380,15 +393,10 @@
 
 int yaffs_CheckpointInvalidateStream(yaffs_Device *dev)
 {
-	/* Erase the first checksum block */
+	/* Erase the checkpoint data */
 
-	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate"TENDSTR)));
-
-	if (!yaffs_CheckpointSpaceOk(dev))
-		return 0;
+	T(YAFFS_TRACE_CHECKPOINT, (TSTR("checkpoint invalidate of %d blocks"TENDSTR),
+		dev->blocksInCheckpoint));
 
 	return yaffs_CheckpointErase(dev);
 }
-
-
-
diff --git a/fs/yaffs2/yaffs_fs.c b/fs/yaffs2/yaffs_fs.c
index 2288eee..4c155ae 100644
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -163,6 +163,11 @@
 #define yaffs_SuperToDevice(sb)	((yaffs_Device *)sb->u.generic_sbp)
 #endif
 
+
+#define update_dir_time(dir) do {\
+			(dir)->i_ctime = (dir)->i_mtime = CURRENT_TIME; \
+		} while(0)
+		
 static void yaffs_put_super(struct super_block *sb);
 
 static ssize_t yaffs_file_write(struct file *f, const char *buf, size_t n,
@@ -373,6 +378,122 @@
 	up(&dev->grossLock);
 }
 
+
+/*-----------------------------------------------------------------*/
+/* Directory search context allows us to unlock access to yaffs during
+ * filldir without causing problems with the directory being modified.
+ * This is similar to the tried and tested mechanism used in yaffs direct.
+ *
+ * A search context iterates along a doubly linked list of siblings in the
+ * directory. If the iterating object is deleted then this would corrupt
+ * the list iteration, likely causing a crash. The search context avoids
+ * this by using the removeObjectCallback to move the search context to the
+ * next object before the object is deleted.
+ *
+ * Many readdirs (and thus seach conexts) may be alive simulateously so
+ * each yaffs_Device has a list of these.
+ *
+ * A seach context lives for the duration of a readdir.
+ *
+ * All these functions must be called while yaffs is locked.
+ */
+
+struct yaffs_SearchContext {
+	yaffs_Device *dev;
+	yaffs_Object *dirObj;
+	yaffs_Object *nextReturn;
+	struct ylist_head others;
+};
+
+/*
+ * yaffs_NewSearch() creates a new search context, initialises it and
+ * adds it to the device's search context list.
+ *
+ * Called at start of readdir.
+ */
+static struct yaffs_SearchContext * yaffs_NewSearch(yaffs_Object *dir)
+{
+	yaffs_Device *dev = dir->myDev;
+	struct yaffs_SearchContext *sc = YMALLOC(sizeof(struct yaffs_SearchContext));
+	if(sc){
+		sc->dirObj = dir;
+		sc->dev = dev;
+		if( ylist_empty(&sc->dirObj->variant.directoryVariant.children))
+			sc->nextReturn = NULL;
+		else
+			sc->nextReturn = ylist_entry(
+                                dir->variant.directoryVariant.children.next,
+				yaffs_Object,siblings);
+		YINIT_LIST_HEAD(&sc->others);
+		ylist_add(&sc->others,&dev->searchContexts);
+	}
+	return sc;
+}
+
+/*
+ * yaffs_EndSearch() disposes of a search context and cleans up.
+ */
+static void yaffs_EndSearch(struct yaffs_SearchContext * sc)
+{
+	if(sc){
+		ylist_del(&sc->others);
+		YFREE(sc);
+	}
+}
+
+/*
+ * yaffs_SearchAdvance() moves a search context to the next object.
+ * Called when the search iterates or when an object removal causes
+ * the search context to be moved to the next object.
+ */
+static void yaffs_SearchAdvance(struct yaffs_SearchContext *sc)
+{
+        if(!sc)
+                return;
+
+        if( sc->nextReturn == NULL ||
+                ylist_empty(&sc->dirObj->variant.directoryVariant.children))
+                sc->nextReturn = NULL;
+        else {
+                struct ylist_head *next = sc->nextReturn->siblings.next;
+
+                if( next == &sc->dirObj->variant.directoryVariant.children)
+                        sc->nextReturn = NULL; /* end of list */
+                else
+                        sc->nextReturn = ylist_entry(next,yaffs_Object,siblings);
+        }
+}
+
+/*
+ * yaffs_RemoveObjectCallback() is called when an object is unlinked.
+ * We check open search contexts and advance any which are currently
+ * on the object being iterated.
+ */
+static void yaffs_RemoveObjectCallback(yaffs_Object *obj)
+{
+
+        struct ylist_head *i;
+        struct yaffs_SearchContext *sc;
+        struct ylist_head *search_contexts = &obj->myDev->searchContexts;
+
+
+        /* Iterate through the directory search contexts.
+         * If any are currently on the object being removed, then advance
+         * the search context to the next object to prevent a hanging pointer.
+         */
+         ylist_for_each(i, search_contexts) {
+                if (i) {
+                        sc = ylist_entry(i, struct yaffs_SearchContext,others);
+                        if(sc->nextReturn == obj)
+                                yaffs_SearchAdvance(sc);
+                }
+	}
+
+}
+
+
+/*-----------------------------------------------------------------*/
+
 static int yaffs_readlink(struct dentry *dentry, char __user *buffer,
 			int buflen)
 {
@@ -1075,7 +1196,7 @@
 
 	}
 	yaffs_GrossUnlock(dev);
-	return (!nWritten && n) ? -ENOSPC : nWritten;
+	return (nWritten == 0) && (n > 0) ? -ENOSPC : nWritten;
 }
 
 /* Space holding and freeing is done to ensure we have space available for write_begin/end */
@@ -1123,10 +1244,11 @@
 {
 	yaffs_Object *obj;
 	yaffs_Device *dev;
+        struct yaffs_SearchContext *sc;
 	struct inode *inode = f->f_dentry->d_inode;
 	unsigned long offset, curoffs;
-	struct ylist_head *i;
 	yaffs_Object *l;
+        int retVal = 0;
 
 	char name[YAFFS_MAX_NAME_LENGTH + 1];
 
@@ -1137,14 +1259,22 @@
 
 	offset = f->f_pos;
 
+        sc = yaffs_NewSearch(obj);
+        if(!sc){
+                retVal = -ENOMEM;
+                goto unlock_out;
+        }
+
 	T(YAFFS_TRACE_OS, ("yaffs_readdir: starting at %d\n", (int)offset));
 
 	if (offset == 0) {
 		T(YAFFS_TRACE_OS,
 			("yaffs_readdir: entry . ino %d \n",
 			(int)inode->i_ino));
+		yaffs_GrossUnlock(dev);
 		if (filldir(dirent, ".", 1, offset, inode->i_ino, DT_DIR) < 0)
 			goto out;
+		yaffs_GrossLock(dev);
 		offset++;
 		f->f_pos++;
 	}
@@ -1152,9 +1282,11 @@
 		T(YAFFS_TRACE_OS,
 			("yaffs_readdir: entry .. ino %d \n",
 			(int)f->f_dentry->d_parent->d_inode->i_ino));
+		yaffs_GrossUnlock(dev);
 		if (filldir(dirent, "..", 2, offset,
 			f->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
 			goto out;
+		yaffs_GrossLock(dev);
 		offset++;
 		f->f_pos++;
 	}
@@ -1170,10 +1302,12 @@
 		f->f_version = inode->i_version;
 	}
 
-	ylist_for_each(i, &obj->variant.directoryVariant.children) {
+	while(sc->nextReturn){
 		curoffs++;
+                l = sc->nextReturn;
 		if (curoffs >= offset) {
-			l = ylist_entry(i, yaffs_Object, siblings);
+                        int this_inode = yaffs_GetObjectInode(l);
+                        int this_type = yaffs_GetObjectType(l);
 
 			yaffs_GetObjectName(l, name,
 					    YAFFS_MAX_NAME_LENGTH + 1);
@@ -1181,24 +1315,30 @@
 			  ("yaffs_readdir: %s inode %d\n", name,
 			   yaffs_GetObjectInode(l)));
 
+                        yaffs_GrossUnlock(dev);
+
 			if (filldir(dirent,
 					name,
 					strlen(name),
 					offset,
-					yaffs_GetObjectInode(l),
-					yaffs_GetObjectType(l)) < 0)
-				goto up_and_out;
+					this_inode,
+					this_type) < 0)
+				goto out;
+
+                        yaffs_GrossLock(dev);
 
 			offset++;
 			f->f_pos++;
 		}
+                yaffs_SearchAdvance(sc);
 	}
 
-up_and_out:
-out:
+unlock_out:
 	yaffs_GrossUnlock(dev);
+out:
+        yaffs_EndSearch(sc);
 
-	return 0;
+	return retVal;
 }
 
 /*
@@ -1286,6 +1426,7 @@
 	if (obj) {
 		inode = yaffs_get_inode(dir->i_sb, mode, rdev, obj);
 		d_instantiate(dentry, inode);
+		update_dir_time(dir);
 		T(YAFFS_TRACE_OS,
 			("yaffs_mknod created object %d count = %d\n",
 			obj->objectId, atomic_read(&inode->i_count)));
@@ -1339,6 +1480,7 @@
 		dir->i_version++;
 		yaffs_GrossUnlock(dev);
 		mark_inode_dirty(dentry->d_inode);
+		update_dir_time(dir);
 		return 0;
 	}
 	yaffs_GrossUnlock(dev);
@@ -1379,8 +1521,10 @@
 
 	yaffs_GrossUnlock(dev);
 
-	if (link)
+	if (link){
+		update_dir_time(dir);
 		return 0;
+	}
 
 	return -EPERM;
 }
@@ -1406,6 +1550,7 @@
 
 		inode = yaffs_get_inode(dir->i_sb, obj->yst_mode, 0, obj);
 		d_instantiate(dentry, inode);
+		update_dir_time(dir);
 		T(YAFFS_TRACE_OS, ("symlink created OK\n"));
 		return 0;
 	} else {
@@ -1478,7 +1623,10 @@
 			new_dentry->d_inode->i_nlink--;
 			mark_inode_dirty(new_dentry->d_inode);
 		}
-
+		
+		update_dir_time(old_dir);
+		if(old_dir != new_dir)
+			update_dir_time(new_dir);
 		return 0;
 	} else {
 		return -ENOTEMPTY;
@@ -1783,6 +1931,8 @@
 	int skip_checkpoint_read;
 	int skip_checkpoint_write;
 	int no_cache;
+	int empty_lost_and_found_overridden;
+	int empty_lost_and_found;
 } yaffs_options;
 
 #define MAX_OPT_LEN 20
@@ -1798,6 +1948,9 @@
 		memset(cur_opt, 0, MAX_OPT_LEN + 1);
 		p = 0;
 
+		while (*options_str == ',')
+			options_str++;
+
 		while (*options_str && *options_str != ',') {
 			if (p < MAX_OPT_LEN) {
 				cur_opt[p] = *options_str;
@@ -1817,6 +1970,12 @@
 		else if (!strcmp(cur_opt, "no-checkpoint")) {
 			options->skip_checkpoint_read = 1;
 			options->skip_checkpoint_write = 1;
+		} else if (!strcmp(cur_opt, "empty-lost-and-found-disable")) {
+			options->empty_lost_and_found = 0;
+			options->empty_lost_and_found_overridden = 1;
+		} else if (!strcmp(cur_opt, "empty-lost-and-found-enable")) {
+			options->empty_lost_and_found = 1;
+			options->empty_lost_and_found_overridden = 1;
 		} else {
 			printk(KERN_INFO "yaffs: Bad mount option \"%s\"\n",
 					cur_opt);
@@ -1922,6 +2081,13 @@
 	T(YAFFS_TRACE_OS, (" size %lld\n", mtd->size));
 #endif
 
+
+#ifdef CONFIG_YAFFS_EMPTY_LOST_AND_FOUND
+	dev->emptyLostAndFound = 1;
+#endif
+	if(options.empty_lost_and_found_overridden)
+		dev->emptyLostAndFound = options.empty_lost_and_found;
+
 #ifdef CONFIG_YAFFS_AUTO_YAFFS2
 
 	if (yaffsVersion == 1 && WRITE_SIZE(mtd) >= 2048) {
@@ -2084,6 +2250,10 @@
 	/* we assume this is protected by lock_kernel() in mount/umount */
 	ylist_add_tail(&dev->devList, &yaffs_dev_list);
 
+        /* Directory search handling...*/
+        YINIT_LIST_HEAD(&dev->searchContexts);
+        dev->removeObjectCallback = yaffs_RemoveObjectCallback;
+
 	init_MUTEX(&dev->grossLock);
 
 	yaffs_GrossLock(dev);
diff --git a/fs/yaffs2/yaffs_guts.c b/fs/yaffs2/yaffs_guts.c
index 0de2ad3..968223e 100644
--- a/fs/yaffs2/yaffs_guts.c
+++ b/fs/yaffs2/yaffs_guts.c
@@ -49,6 +49,7 @@
 				const yaffs_ExtendedTags *tags);
 
 /* Other local prototypes */
+static void yaffs_UpdateParent(yaffs_Object *obj);
 static int yaffs_UnlinkObject(yaffs_Object *obj);
 static int yaffs_ObjectHasCachedWriteData(yaffs_Object *obj);
 
@@ -112,7 +113,6 @@
 					yaffs_FileStructure *fStruct,
 					__u32 chunkId);
 
-
 /* Function to calculate chunk and offset */
 
 static void yaffs_AddrToChunk(yaffs_Device *dev, loff_t addr, int *chunkOut,
@@ -759,7 +759,7 @@
 	chunkMax = (dev->internalEndBlock+1) * dev->nChunksPerBlock - 1;
 
 	chunkInRange = (((unsigned)(obj->hdrChunk)) >= chunkMin && ((unsigned)(obj->hdrChunk)) <= chunkMax);
-	chunkIdOk = chunkInRange || obj->hdrChunk == 0;
+	chunkIdOk = chunkInRange || (obj->hdrChunk == 0);
 	chunkValid = chunkInRange &&
 			yaffs_CheckChunkBit(dev,
 					obj->hdrChunk / dev->nChunksPerBlock,
@@ -1544,11 +1544,16 @@
 	for (j = 0; theChunk && j < dev->chunkGroupSize; j++) {
 		if (yaffs_CheckChunkBit(dev, theChunk / dev->nChunksPerBlock,
 				theChunk % dev->nChunksPerBlock)) {
-			yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
-							tags);
-			if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
-				/* found it; */
+			
+			if(dev->chunkGroupSize == 1)
 				return theChunk;
+			else {
+				yaffs_ReadChunkWithTagsFromNAND(dev, theChunk, NULL,
+								tags);
+				if (yaffs_TagsMatch(tags, objectId, chunkInInode)) {
+					/* found it; */
+					return theChunk;
+				}
 			}
 		}
 		theChunk++;
@@ -2345,6 +2350,7 @@
 			in = NULL;
 		}
 
+		yaffs_UpdateParent(parent);
 	}
 
 	return in;
@@ -2459,6 +2465,8 @@
 	yaffs_Object *obj = NULL;
 	yaffs_Object *existingTarget = NULL;
 	int force = 0;
+	int result;
+	yaffs_Device *dev;
 
 
 	if (!oldDir || oldDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
@@ -2466,6 +2474,8 @@
 	if (!newDir || newDir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
 		YBUG();
 
+	dev = oldDir->myDev;
+
 #ifdef CONFIG_YAFFS_CASE_INSENSITIVE
 	/* Special case for case insemsitive systems (eg. WinCE).
 	 * While look-up is case insensitive, the name isn't.
@@ -2475,7 +2485,7 @@
 		force = 1;
 #endif
 
-	else if (yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
+	if(yaffs_strlen(newName) > YAFFS_MAX_NAME_LENGTH)
 		/* ENAMETOOLONG */
 		return YAFFS_FAIL;
 
@@ -2493,14 +2503,26 @@
 			return YAFFS_FAIL;	/* EEXIST or ENOTEMPTY */
 		} else if (existingTarget && existingTarget != obj) {
 			/* Nuke the target first, using shadowing,
-			 * but only if it isn't the same object
+			 * but only if it isn't the same object.
+			 *
+			 * Note we must disable gc otherwise it can mess up the shadowing.
+			 *
 			 */
+			dev->isDoingGC=1;
 			yaffs_ChangeObjectName(obj, newDir, newName, force,
 						existingTarget->objectId);
+			existingTarget->isShadowed = 1;
 			yaffs_UnlinkObject(existingTarget);
+			dev->isDoingGC=0;
 		}
 
-		return yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+		result = yaffs_ChangeObjectName(obj, newDir, newName, 1, 0);
+
+		yaffs_UpdateParent(oldDir);
+		if(newDir != oldDir)
+			yaffs_UpdateParent(newDir);
+
+		return result;
 	}
 	return YAFFS_FAIL;
 }
@@ -2964,7 +2986,6 @@
 
 	isCheckpointBlock = (bi->blockState == YAFFS_BLOCK_STATE_CHECKPOINT);
 
-	bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
 
 	T(YAFFS_TRACE_TRACING,
 			(TSTR("Collecting block %d, in use %d, shrink %d, wholeBlock %d" TENDSTR),
@@ -2975,12 +2996,16 @@
 
 	/*yaffs_VerifyFreeChunks(dev); */
 
+	if(bi->blockState == YAFFS_BLOCK_STATE_FULL)
+		bi->blockState = YAFFS_BLOCK_STATE_COLLECTING;
+	
 	bi->hasShrinkHeader = 0;	/* clear the flag so that the block can erase */
 
 	/* Take off the number of soft deleted entries because
 	 * they're going to get really deleted during GC.
 	 */
-	dev->nFreeChunks -= bi->softDeletions;
+	if(dev->gcChunk == 0) /* first time through for this block */
+		dev->nFreeChunks -= bi->softDeletions;
 
 	dev->isDoingGC = 1;
 
@@ -3096,6 +3121,7 @@
 					if (tags.chunkId == 0) {
 						/* It is an object Id,
 						 * We need to nuke the shrinkheader flags first
+						 * Also need to clean up shadowing.
 						 * We no longer want the shrinkHeader flag since its work is done
 						 * and if it is left in place it will mess up scanning.
 						 */
@@ -3104,6 +3130,9 @@
 						oh = (yaffs_ObjectHeader *)buffer;
 						oh->isShrink = 0;
 						tags.extraIsShrinkHeader = 0;
+						oh->shadowsObject = 0;
+						oh->inbandShadowsObject = 0;
+						tags.extraShadows = 0;
 
 						yaffs_VerifyObjectHeader(object, oh, &tags, 1);
 					}
@@ -3624,7 +3653,7 @@
 	newTags.chunkId = chunkInInode;
 	newTags.objectId = in->objectId;
 	newTags.serialNumber =
-	    (prevChunkId >= 0) ? prevTags.serialNumber + 1 : 1;
+	    (prevChunkId > 0) ? prevTags.serialNumber + 1 : 1;
 	newTags.byteCount = nBytes;
 
 	if (nBytes < 1 || nBytes > dev->totalBytesPerChunk) {
@@ -3640,7 +3669,7 @@
 	if (newChunkId >= 0) {
 		yaffs_PutChunkIntoFile(in, chunkInInode, newChunkId, 0);
 
-		if (prevChunkId >= 0)
+		if (prevChunkId > 0)
 			yaffs_DeleteChunk(dev, prevChunkId, 1, __LINE__);
 
 		yaffs_CheckFileSanity(in);
@@ -3726,7 +3755,7 @@
 		if (name && *name) {
 			memset(oh->name, 0, sizeof(oh->name));
 			yaffs_strncpy(oh->name, name, YAFFS_MAX_NAME_LENGTH);
-		} else if (prevChunkId >= 0)
+		} else if (prevChunkId > 0)
 			memcpy(oh->name, oldName, sizeof(oh->name));
 		else
 			memset(oh->name, 0, sizeof(oh->name));
@@ -3784,13 +3813,13 @@
 		/* Create new chunk in NAND */
 		newChunkId =
 		    yaffs_WriteNewChunkWithTagsToNAND(dev, buffer, &newTags,
-						      (prevChunkId >= 0) ? 1 : 0);
+						      (prevChunkId > 0) ? 1 : 0);
 
 		if (newChunkId >= 0) {
 
 			in->hdrChunk = newChunkId;
 
-			if (prevChunkId >= 0) {
+			if (prevChunkId > 0) {
 				yaffs_DeleteChunk(dev, prevChunkId, 1,
 						  __LINE__);
 			}
@@ -5018,11 +5047,13 @@
 	}
 
 
-	/* Write a new object header.
+	/* Write a new object header to reflect the resize.
 	 * show we've shrunk the file, if need be
-	 * Do this only if the file is not in the deleted directories.
+	 * Do this only if the file is not in the deleted directories
+	 * and is not shadowed.
 	 */
 	if (in->parent &&
+	    !in->isShadowed &&
 	    in->parent->objectId != YAFFS_OBJECTID_UNLINKED &&
 	    in->parent->objectId != YAFFS_OBJECTID_DELETED)
 		yaffs_UpdateObjectHeader(in, NULL, 0,
@@ -5164,14 +5195,19 @@
 	}
 }
 
-static int yaffs_DeleteDirectory(yaffs_Object *in)
+static int yaffs_IsNonEmptyDirectory(yaffs_Object *obj)
+{
+	return (obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY) &&
+		!(ylist_empty(&obj->variant.directoryVariant.children));
+}
+
+static int yaffs_DeleteDirectory(yaffs_Object *obj)
 {
 	/* First check that the directory is empty. */
-	if (ylist_empty(&in->variant.directoryVariant.children))
-		return yaffs_DoGenericObjectDeletion(in);
+	if (yaffs_IsNonEmptyDirectory(obj))
+		return YAFFS_FAIL;
 
-	return YAFFS_FAIL;
-
+	return yaffs_DoGenericObjectDeletion(obj);
 }
 
 static int yaffs_DeleteSymLink(yaffs_Object *in)
@@ -5230,6 +5266,9 @@
 		immediateDeletion = 1;
 #endif
 
+	if(obj)
+		yaffs_UpdateParent(obj->parent);
+
 	if (obj->variantType == YAFFS_OBJECT_TYPE_HARDLINK) {
 		return yaffs_DeleteHardLink(obj);
 	} else if (!ylist_empty(&obj->hardLinks)) {
@@ -5284,7 +5323,9 @@
 		default:
 			return YAFFS_FAIL;
 		}
-	} else
+	} else if(yaffs_IsNonEmptyDirectory(obj))
+		return YAFFS_FAIL;
+	else
 		return yaffs_ChangeObjectName(obj, obj->myDev->unlinkedDir,
 					   _Y("unlinked"), 0, 0);
 }
@@ -5323,7 +5364,8 @@
 		/* Handle YAFFS2 case (backward scanning)
 		 * If the shadowed object exists then ignore.
 		 */
-		if (yaffs_FindObjectByNumber(dev, objId))
+		obj = yaffs_FindObjectByNumber(dev, objId);
+		if(obj)
 			return;
 	}
 
@@ -5335,6 +5377,7 @@
 					     YAFFS_OBJECT_TYPE_FILE);
 	if (!obj)
 		return;
+	obj->isShadowed = 1;
 	yaffs_AddObjectToDirectory(dev->unlinkedDir, obj);
 	obj->variant.fileVariant.shrinkSize = 0;
 	obj->valid = 1;		/* So that we don't read any other info for this file */
@@ -5427,6 +5470,125 @@
 
 }
 
+/*
+ * This code iterates through all the objects making sure that they are rooted.
+ * Any unrooted objects are re-rooted in lost+found.
+ * An object needs to be in one of:
+ * - Directly under deleted, unlinked
+ * - Directly or indirectly under root.
+ *
+ * Note:
+ *  This code assumes that we don't ever change the current relationships between
+ *  directories:
+ *   rootDir->parent == unlinkedDir->parent == deletedDir->parent == NULL
+ *   lostNfound->parent == rootDir
+ *
+ * This fixes the problem where directories might have inadvertently been deleted
+ * leaving the object "hanging" without being rooted in the directory tree.
+ */
+
+static int yaffs_HasNULLParent(yaffs_Device *dev, yaffs_Object *obj)
+{
+	return (obj == dev->deletedDir ||
+		obj == dev->unlinkedDir||
+		obj == dev->rootDir);
+}
+
+static void yaffs_FixHangingObjects(yaffs_Device *dev)
+{
+	yaffs_Object *obj;
+	yaffs_Object *parent;
+	int i;
+	struct ylist_head *lh;
+	struct ylist_head *n;
+	int depthLimit;
+	int hanging;
+
+
+	/* Iterate through the objects in each hash entry,
+	 * looking at each object.
+	 * Make sure it is rooted.
+	 */
+
+	for (i = 0; i <  YAFFS_NOBJECT_BUCKETS; i++) {
+		ylist_for_each_safe(lh, n, &dev->objectBucket[i].list) {
+			if (lh) {
+				obj = ylist_entry(lh, yaffs_Object, hashLink);
+				parent= obj->parent;
+
+				if(yaffs_HasNULLParent(dev,obj)){
+					/* These directories are not hanging */
+					hanging = 0;
+				}
+				else if(!parent || parent->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+					hanging = 1;
+				else if(yaffs_HasNULLParent(dev,parent))
+					hanging = 0;
+				else {
+					/*
+					 * Need to follow the parent chain to see if it is hanging.
+					 */
+					hanging = 0;
+					depthLimit=100;
+
+					while(parent != dev->rootDir &&
+						parent->parent &&
+						parent->parent->variantType == YAFFS_OBJECT_TYPE_DIRECTORY &&
+						depthLimit > 0){
+						parent = parent->parent;
+						depthLimit--;
+					}
+					if(parent != dev->rootDir)
+						hanging = 1;
+				}
+				if(hanging){
+					T(YAFFS_TRACE_SCAN,
+					(TSTR("Hanging object %d moved to lost and found" TENDSTR),
+					obj->objectId));
+					yaffs_AddObjectToDirectory(dev->lostNFoundDir,obj);
+				}
+			}
+		}
+	}
+}
+
+
+/*
+ * Delete directory contents for cleaning up lost and found.
+ */
+static void yaffs_DeleteDirectoryContents(yaffs_Object *dir)
+{
+	yaffs_Object *obj;
+	struct ylist_head *lh;
+	struct ylist_head *n;
+
+	if(dir->variantType != YAFFS_OBJECT_TYPE_DIRECTORY)
+		YBUG();
+
+	ylist_for_each_safe(lh, n, &dir->variant.directoryVariant.children) {
+		if (lh) {
+			obj = ylist_entry(lh, yaffs_Object, siblings);
+			if(obj->variantType == YAFFS_OBJECT_TYPE_DIRECTORY)
+				yaffs_DeleteDirectoryContents(obj);
+
+			T(YAFFS_TRACE_SCAN,
+				(TSTR("Deleting lost_found object %d" TENDSTR),
+				obj->objectId));
+
+			/* Need to use UnlinkObject since Delete would not handle
+			 * hardlinked objects correctly.
+			 */
+			yaffs_UnlinkObject(obj);
+		}
+	}
+
+}
+
+static void yaffs_EmptyLostAndFound(yaffs_Device *dev)
+{
+	yaffs_DeleteDirectoryContents(dev->lostNFoundDir);
+}
+
 static int yaffs_Scan(yaffs_Device *dev)
 {
 	yaffs_ExtendedTags tags;
@@ -6666,6 +6828,26 @@
 	}
 }
 
+/*
+ *yaffs_UpdateParent() handles fixing a directories mtime and ctime when a new
+ * link (ie. name) is created or deleted in the directory.
+ *
+ * ie.
+ *   create dir/a : update dir's mtime/ctime
+ *   rm dir/a:   update dir's mtime/ctime
+ *   modify dir/a: don't update dir's mtimme/ctime
+ */
+ 
+static void yaffs_UpdateParent(yaffs_Object *obj)
+{
+	if(!obj)
+		return;
+
+	obj->dirty = 1;
+	obj->yst_mtime = obj->yst_ctime = Y_CURRENT_TIME;
+
+	yaffs_UpdateObjectHeader(obj,NULL,0,0,0);
+}
 
 static void yaffs_RemoveObjectFromDirectory(yaffs_Object *obj)
 {
@@ -6683,11 +6865,10 @@
 
 	ylist_del_init(&obj->siblings);
 	obj->parent = NULL;
-
+	
 	yaffs_VerifyDirectory(parent);
 }
 
-
 static void yaffs_AddObjectToDirectory(yaffs_Object *directory,
 					yaffs_Object *obj)
 {
@@ -6781,7 +6962,7 @@
 				 * Do a real check
 				 */
 				yaffs_GetObjectName(l, buffer,
-						    YAFFS_MAX_NAME_LENGTH);
+						    YAFFS_MAX_NAME_LENGTH + 1);
 				if (yaffs_strncmp(name, buffer, YAFFS_MAX_NAME_LENGTH) == 0)
 					return l;
 			}
@@ -7030,7 +7211,7 @@
 {
 	YCHAR name[257];
 
-	yaffs_GetObjectName(obj, name, 256);
+	yaffs_GetObjectName(obj, name, YAFFS_MAX_NAME_LENGTH + 1);
 
 	T(YAFFS_TRACE_ALWAYS,
 	  (TSTR
@@ -7371,6 +7552,9 @@
 				init_failed = 1;
 
 		yaffs_StripDeletedObjects(dev);
+		yaffs_FixHangingObjects(dev);
+		if(dev->emptyLostAndFound)
+			yaffs_EmptyLostAndFound(dev);
 	}
 
 	if (init_failed) {
@@ -7394,6 +7578,9 @@
 	yaffs_VerifyFreeChunks(dev);
 	yaffs_VerifyBlocks(dev);
 
+	/* Clean up any aborted checkpoint data */
+	if (!dev->isCheckpointed && dev->blocksInCheckpoint > 0)
+		yaffs_InvalidateCheckpoint(dev);
 
 	T(YAFFS_TRACE_TRACING,
 	  (TSTR("yaffs: yaffs_GutsInitialise() done.\n" TENDSTR)));
diff --git a/fs/yaffs2/yaffs_guts.h b/fs/yaffs2/yaffs_guts.h
index a3b1102..1305909 100644
--- a/fs/yaffs2/yaffs_guts.h
+++ b/fs/yaffs2/yaffs_guts.h
@@ -424,6 +424,7 @@
 				 * until the inode is released.
 				 */
 	__u8 beingCreated:1;	/* This object is still being created so skip some checks. */
+	__u8 isShadowed:1;      /* This object is shadowed on the way to being renamed. */
 
 	__u8 serial;		/* serial number of chunk in NAND. Cached here */
 	__u16 sum;		/* sum of the name to speed searching */
@@ -557,6 +558,8 @@
 
 	int useHeaderFileSize;	/* Flag to determine if we should use file sizes from the header */
 
+	int emptyLostAndFound;  /* Flasg to determine if lst+found should be emptied on init */
+
 	int useNANDECC;		/* Flag to decide whether or not to use NANDECC */
 
 	void *genericDevice;	/* Pointer to device context
@@ -592,8 +595,9 @@
 	int isYaffs2;
 
 	/* The removeObjectCallback function must be supplied by OS flavours that
-	 * need it. The Linux kernel does not use this, but yaffs direct does use
-	 * it to implement the faster readdir
+	 * need it.
+         * yaffs direct uses it to implement the faster readdir.
+         * Linux uses it to protect the directory during unlocking.
 	 */
 	void (*removeObjectCallback)(struct yaffs_ObjectStruct *obj);
 
@@ -633,10 +637,14 @@
 
 	struct semaphore sem;	/* Semaphore for waiting on erasure.*/
 	struct semaphore grossLock;	/* Gross locking semaphore */
+	struct rw_semaphore dirLock; /* Lock the directory structure */
 	__u8 *spareBuffer;	/* For mtdif2 use. Don't know the size of the buffer
 				 * at compile time so we have to allocate it.
+
 				 */
 	void (*putSuperFunc) (struct super_block *sb);
+        struct ylist_head searchContexts;
+
 #endif
 
 	int isMounted;
diff --git a/fs/yaffs2/yaffs_mtdif1.c b/fs/yaffs2/yaffs_mtdif1.c
index 1d9311a..bcac470 100644
--- a/fs/yaffs2/yaffs_mtdif1.c
+++ b/fs/yaffs2/yaffs_mtdif1.c
@@ -102,8 +102,6 @@
 	compile_time_assertion(sizeof(yaffs_PackedTags1) == 12);
 	compile_time_assertion(sizeof(yaffs_Tags) == 8);
 
-	dev->nPageWrites++;
-
 	yaffs_PackTags1(&pt1, etags);
 	yaffs_CalcTagsECC((yaffs_Tags *)&pt1);
 
@@ -180,8 +178,6 @@
 	int retval;
 	int deleted;
 
-	dev->nPageReads++;
-
 	memset(&ops, 0, sizeof(ops));
 	ops.mode = MTD_OOB_AUTO;
 	ops.len = (data) ? chunkBytes : 0;
diff --git a/fs/yaffs2/yaffs_mtdif2.c b/fs/yaffs2/yaffs_mtdif2.c
index bd8128c..282a093 100644
--- a/fs/yaffs2/yaffs_mtdif2.c
+++ b/fs/yaffs2/yaffs_mtdif2.c
@@ -52,8 +52,6 @@
 	   ("nandmtd2_WriteChunkWithTagsToNAND chunk %d data %p tags %p"
 	    TENDSTR), chunkInNAND, data, tags));
 
-	dev->nPageWrites++;
-
 	addr  = ((loff_t) chunkInNAND) * dev->totalBytesPerChunk;
 
 	/* For yaffs2 writing there must be both data and tags.
@@ -116,8 +114,6 @@
 	   ("nandmtd2_ReadChunkWithTagsFromNAND chunk %d data %p tags %p"
 	    TENDSTR), chunkInNAND, data, tags));
 
-	dev->nPageReads++;
-
 	if (dev->inbandTags) {
 
 		if (!data) {
diff --git a/fs/yaffs2/yaffs_nand.c b/fs/yaffs2/yaffs_nand.c
index ec32761..f6ba4c79 100644
--- a/fs/yaffs2/yaffs_nand.c
+++ b/fs/yaffs2/yaffs_nand.c
@@ -29,6 +29,8 @@
 
 	int realignedChunkInNAND = chunkInNAND - dev->chunkOffset;
 
+	dev->nPageReads++;
+
 	/* If there are no tags provided, use local tags to get prioritised gc working */
 	if (!tags)
 		tags = &localTags;
@@ -56,6 +58,9 @@
 						   const __u8 *buffer,
 						   yaffs_ExtendedTags *tags)
 {
+
+	dev->nPageWrites++;
+
 	chunkInNAND -= dev->chunkOffset;
 
 
@@ -89,7 +94,7 @@
 {
 	blockNo -= dev->blockOffset;
 
-;
+
 	if (dev->markNANDBlockBad)
 		return dev->markNANDBlockBad(dev, blockNo);
 	else
@@ -119,8 +124,8 @@
 
 	blockInNAND -= dev->blockOffset;
 
-
 	dev->nBlockErasures++;
+
 	result = dev->eraseBlockInNAND(dev, blockInNAND);
 
 	return result;
diff --git a/fs/yaffs2/yaffs_tagscompat.c b/fs/yaffs2/yaffs_tagscompat.c
index 402537fb..e3173cc 100644
--- a/fs/yaffs2/yaffs_tagscompat.c
+++ b/fs/yaffs2/yaffs_tagscompat.c
@@ -170,7 +170,6 @@
 		return YAFFS_FAIL;
 	}
 
-	dev->nPageWrites++;
 	return dev->writeChunkToNAND(dev, chunkInNAND, data, spare);
 }
 
@@ -184,8 +183,6 @@
 	int retVal;
 	yaffs_Spare localSpare;
 
-	dev->nPageReads++;
-
 	if (!spare && data) {
 		/* If we don't have a real spare, then we use a local one. */
 		/* Need this for the calculation of the ecc */
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 1610427..83fcfa7 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -252,6 +252,11 @@
 
 void cpufreq_notify_transition(struct cpufreq_freqs *freqs, unsigned int state);
 
+#ifdef CONFIG_CPU_FREQ_STAT
+extern void cpufreq_exit_idle(int cpu, unsigned long ticks);
+#else
+#define cpufreq_exit_idle(int cpu, unsigned long ticks) do {} while (0)
+#endif
 
 static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, unsigned int min, unsigned int max) 
 {
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index dcf77fa..3650f32 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -17,7 +17,7 @@
 #include <linux/kobject.h>
 #include <linux/completion.h>
 
-#define CPUIDLE_STATE_MAX	8
+#define CPUIDLE_STATE_MAX	16
 #define CPUIDLE_NAME_LEN	16
 #define CPUIDLE_DESC_LEN	32
 
@@ -88,6 +88,7 @@
 
 	int			last_residency;
 	int			state_count;
+	int			max_state;
 	struct cpuidle_state	states[CPUIDLE_STATE_MAX];
 	struct cpuidle_state_kobj *kobjs[CPUIDLE_STATE_MAX];
 	struct cpuidle_state	*last_state;
diff --git a/include/linux/i2c/twl4030.h b/include/linux/i2c/twl4030.h
index 96c1c38..8e906b7 100644
--- a/include/linux/i2c/twl4030.h
+++ b/include/linux/i2c/twl4030.h
@@ -152,6 +152,20 @@
 
 /*----------------------------------------------------------------------*/
 
+/* Iterface Bit Register (INTBR) offsets
+ * (use TWL4030_MODULE_INTBR)
+ */
+
+#define REG_GPPUPDCTR1			0x0F
+
+/* I2C1 and I2C4(SR) SDA/SCL pull-up control bits */
+
+#define I2C_SCL_CTRL_PU 		(1 << 0)
+#define I2C_SDA_CTRL_PU 		(1 << 2)
+#define SR_I2C_SCL_CTRL_PU		(1 << 4)
+#define SR_I2C_SDA_CTRL_PU		(1 << 6)
+/*----------------------------------------------------------------------*/
+
 /*
  * Keypad register offsets (use TWL4030_MODULE_KEYPAD)
  * ... SIH/interrupt only
@@ -387,6 +401,8 @@
 	const struct twl4030_resconfig *resource_config;
 };
 
+extern int twl4030_remove_script(u8 flags);
+
 struct twl4030_platform_data {
 	unsigned				irq_base, irq_end;
 	struct twl4030_bci_platform_data	*bci;
diff --git a/include/linux/if_pppox.h b/include/linux/if_pppox.h
index 179d674..9786aa7 100644
--- a/include/linux/if_pppox.h
+++ b/include/linux/if_pppox.h
@@ -150,12 +150,15 @@
 	__u32	remote;
 	__u16	sequence;
 	__u8	sequencing;
+	int	(*backlog_rcv)(struct sock *sk_udp, struct sk_buff *skb);
 };
 
 struct pppopns_opt {
 	__u16	local;
 	__u16	remote;
 	__u32	sequence;
+	void	(*data_ready)(struct sock *sk_raw, int length);
+	int	(*backlog_rcv)(struct sock *sk_raw, struct sk_buff *skb);
 };
 
 #include <net/sock.h>
diff --git a/include/linux/omap_resizer.h b/include/linux/omap_resizer.h
index 5ac0c88..0ae129c 100644
--- a/include/linux/omap_resizer.h
+++ b/include/linux/omap_resizer.h
@@ -48,6 +48,7 @@
 						 */
 };
 
+typedef void (*rsz_callback) (void *arg1);
 /* Structure Definitions */
 
 /* used to luma enhancement options */
@@ -134,3 +135,11 @@
 };
 
 #endif
+
+int rsz_get_resource(void);
+void rsz_put_resource(void);
+int rsz_configure(struct rsz_params *params, rsz_callback callback,
+		  u32 num_video_buffers, void *arg1);
+int rsz_begin(u32 input_buffer_index,
+			int output_buffer_index, u32 out_off, u32 out_phy_add,
+			u32 in_phy_add, u32 in_off);
diff --git a/include/linux/sil9022.h b/include/linux/sil9022.h
index 439ebee..8543fca 100644
--- a/include/linux/sil9022.h
+++ b/include/linux/sil9022.h
@@ -22,6 +22,7 @@
 #define HDMI_XRES			1280
 #define HDMI_YRES			720
 #define HDMI_PIXCLOCK_MAX		74250
+#define VERTICAL_FREQ 			0x3C
 
 #define I2C_M_WR 			0
 
@@ -104,6 +105,12 @@
 
 
 /* ---------------------------------------------------------------------  */
+#define EDID_TIMING_DESCRIPTOR_SIZE 		0x12
+#define EDID_DESCRIPTOR_BLOCK0_ADDRESS  	0x36
+#define EDID_DESCRIPTOR_BLOCK1_ADDRESS 		0x80
+#define EDID_SIZE_BLOCK0_TIMING_DESCRIPTOR 	4
+#define EDID_SIZE_BLOCK1_TIMING_DESCRIPTOR 	4
+
 /* HDMI Connected States  */
 #define HDMI_STATE_NOMONITOR    0       /* No HDMI monitor connected*/
 #define HDMI_STATE_CONNECTED    1  /* HDMI monitor connected but powered off*/
@@ -698,5 +705,10 @@
 	u8 value;
 } hdmi_reg_data;
 
+struct hdmi_platform_data {
+	void (*set_min_bus_tput)(struct device *dev,
+				 u8 agent_id,
+				 unsigned long r);
+};
 #endif
 
diff --git a/include/linux/tty.h b/include/linux/tty.h
index fc39db9..a52c3d0 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -23,7 +23,7 @@
  */
 #define NR_UNIX98_PTY_DEFAULT	4096      /* Default maximum for Unix98 ptys */
 #define NR_UNIX98_PTY_MAX	(1 << MINORBITS) /* Absolute limit */
-#define NR_LDISCS		19
+#define NR_LDISCS		20
 
 /* line disciplines */
 #define N_TTY		0
@@ -46,6 +46,7 @@
 #define N_GIGASET_M101	16	/* Siemens Gigaset M101 serial DECT adapter */
 #define N_SLCAN		17	/* Serial / USB serial CAN Adaptors */
 #define N_PPS		18	/* Pulse per Second */
+#define N_SHARED	19	/* for TI BT/FM/GPS combo devices*/
 
 /*
  * This character is the same as _POSIX_VDISABLE: it cannot be used as
@@ -187,7 +188,7 @@
 	int (*carrier_raised)(struct tty_port *port);
 	void (*raise_dtr_rts)(struct tty_port *port);
 };
-	
+
 struct tty_port {
 	struct tty_struct	*tty;		/* Back pointer */
 	const struct tty_port_operations *ops;	/* Port operations */
diff --git a/include/linux/usb/composite.h b/include/linux/usb/composite.h
index 935c380..2399007 100644
--- a/include/linux/usb/composite.h
+++ b/include/linux/usb/composite.h
@@ -100,6 +100,7 @@
 	struct usb_descriptor_header	**hs_descriptors;
 
 	struct usb_configuration	*config;
+	int				hidden;
 
 	/* REVISIT:  bind() functions can be marked __init, which
 	 * makes trouble for section mismatch analysis.  See if
diff --git a/include/linux/usb/musb.h b/include/linux/usb/musb.h
index d6aad0e..f94f1d7 100644
--- a/include/linux/usb/musb.h
+++ b/include/linux/usb/musb.h
@@ -81,6 +81,12 @@
 
 	/* MUSB configuration-specific details */
 	struct musb_hdrc_config	*config;
+
+	/* MUSB power domain context lost counter */
+	unsigned (*context_loss_counter) (struct device *dev);
+
+	/* MUSB vdd1 opp constraint */
+	void 		(*set_vdd1_opp) (struct device *dev, unsigned long);
 };
 
 
diff --git a/include/linux/usb/otg.h b/include/linux/usb/otg.h
index 94df4fe..c3d5c26 100644
--- a/include/linux/usb/otg.h
+++ b/include/linux/usb/otg.h
@@ -75,6 +75,18 @@
 	/* start or continue HNP role switch */
 	int	(*start_hnp)(struct otg_transceiver *otg);
 
+	/* ask the link to save internal context */
+	void	(*link_save_context)(struct otg_transceiver *otg);
+
+	/* ask the link to restore internal context */
+	void	(*link_restore_context)(struct otg_transceiver *otg);
+
+	/* ask the link to always be in an active state */
+	void	(*link_force_active)(int enable);
+
+	/* pointer to the link driver */
+	void	*link;
+
 };
 
 
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index a25dc7c..b3a70b0 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -323,6 +323,9 @@
  * xxxxrrrrrrrrrrxxxxgggggggggg xxxxggggggggggxxxxbbbbbbbbbb...
  */
 #define V4L2_PIX_FMT_SGRBG10 v4l2_fourcc('B', 'A', '1', '0')
+#define V4L2_PIX_FMT_SRGGB10 v4l2_fourcc('R', 'G', '1', '0')
+#define V4L2_PIX_FMT_SBGGR10 v4l2_fourcc('B', 'G', '1', '0')
+#define V4L2_PIX_FMT_SGBRG10 v4l2_fourcc('G', 'B', '1', '0')
 /* 10bit raw bayer DPCM compressed to 8 bits */
 #define V4L2_PIX_FMT_SGRBG10DPCM8 v4l2_fourcc('B', 'D', '1', '0')
 #define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B', 'Y', 'R', '2') /* 16  BGBG.. GRGR.. */
@@ -798,6 +801,7 @@
 #define V4L2_CTRL_CLASS_USER 0x00980000	/* Old-style 'user' controls */
 #define V4L2_CTRL_CLASS_MPEG 0x00990000	/* MPEG-compression controls */
 #define V4L2_CTRL_CLASS_CAMERA 0x009a0000	/* Camera class controls */
+#define V4L2_CTRL_CLASS_MODE 0x009b0000		/* Sensor mode information */
 
 #define V4L2_CTRL_ID_MASK      	  (0x0fffffff)
 #define V4L2_CTRL_ID2CLASS(id)    ((id) & 0x0fff0000UL)
@@ -1135,6 +1139,37 @@
 
 #define V4L2_CID_PRIVACY			(V4L2_CID_CAMERA_CLASS_BASE+16)
 
+/* Flash and privacy (indicator) light controls */
+#define V4L2_CID_FLASH_STROBE			(V4L2_CID_CAMERA_CLASS_BASE+13)
+#define V4L2_CID_FLASH_TIMEOUT			(V4L2_CID_CAMERA_CLASS_BASE+14)
+#define V4L2_CID_FLASH_INTENSITY		(V4L2_CID_CAMERA_CLASS_BASE+15)
+#define V4L2_CID_TORCH_INTENSITY		(V4L2_CID_CAMERA_CLASS_BASE+16)
+#define V4L2_CID_INDICATOR_INTENSITY		(V4L2_CID_CAMERA_CLASS_BASE+17)
+
+#define V4L2_CID_TEST_PATTERN			(V4L2_CTRL_CLASS_CAMERA | 0x107e)
+
+/* SMIA-type sensor information */
+#define V4L2_CID_MODE_CLASS_BASE		(V4L2_CTRL_CLASS_MODE | 0x900)
+#define V4L2_CID_MODE_CLASS			(V4L2_CTRL_CLASS_MODE | 1)
+#define V4L2_CID_MODE_FRAME_WIDTH		(V4L2_CID_MODE_CLASS_BASE+1)
+#define V4L2_CID_MODE_FRAME_HEIGHT		(V4L2_CID_MODE_CLASS_BASE+2)
+#define V4L2_CID_MODE_VISIBLE_WIDTH		(V4L2_CID_MODE_CLASS_BASE+3)
+#define V4L2_CID_MODE_VISIBLE_HEIGHT		(V4L2_CID_MODE_CLASS_BASE+4)
+#define V4L2_CID_MODE_PIXELCLOCK		(V4L2_CID_MODE_CLASS_BASE+5)
+#define V4L2_CID_MODE_SENSITIVITY		(V4L2_CID_MODE_CLASS_BASE+6)
+
+/*  Control IDs specific to the AD5820 driver as defined by V4L2 */
+#define V4L2_CID_FOCUS_AD5820_BASE 		(V4L2_CTRL_CLASS_CAMERA | 0x10af)
+#define V4L2_CID_FOCUS_AD5820_RAMP_TIME		(V4L2_CID_FOCUS_AD5820_BASE+0)
+#define V4L2_CID_FOCUS_AD5820_RAMP_MODE		(V4L2_CID_FOCUS_AD5820_BASE+1)
+
+/*  Control IDs specific to the ADP1653 flash driver as defined by V4L2 */
+#define V4L2_CID_FLASH_ADP1653_BASE 		(V4L2_CTRL_CLASS_CAMERA | 0x10f1)
+#define V4L2_CID_FLASH_ADP1653_FAULT_SCP	(V4L2_CID_FLASH_ADP1653_BASE+0)
+#define V4L2_CID_FLASH_ADP1653_FAULT_OT		(V4L2_CID_FLASH_ADP1653_BASE+1)
+#define V4L2_CID_FLASH_ADP1653_FAULT_TMR	(V4L2_CID_FLASH_ADP1653_BASE+2)
+#define V4L2_CID_FLASH_ADP1653_FAULT_OV		(V4L2_CID_FLASH_ADP1653_BASE+3)
+
 /*
  *	T U N I N G
  */
@@ -1377,6 +1412,27 @@
 };
 
 /*
+ *	E V E N T S
+ */
+
+struct v4l2_event {
+	__u32		count;
+	__u32		type;
+	__u32		sequence;
+	struct timespec	timestamp;
+	__u32		reserved[9];
+	__u8		data[64];
+};
+
+struct v4l2_event_subscription {
+	__u32		type;
+	__u32		reserved[7];
+};
+
+#define V4L2_EVENT_ALL				0
+#define V4L2_EVENT_PRIVATE_START		0x08000000
+
+/*
  *	A D V A N C E D   D E B U G G I N G
  *
  *	NOTE: EXPERIMENTAL API, NEVER RELY ON THIS IN APPLICATIONS!
@@ -1502,6 +1558,9 @@
 #endif
 
 #define VIDIOC_S_HW_FREQ_SEEK	 _IOW('V', 82, struct v4l2_hw_freq_seek)
+#define VIDIOC_DQEVENT		 _IOR('V', 83, struct v4l2_event)
+#define VIDIOC_SUBSCRIBE_EVENT	 _IOW('V', 84, struct v4l2_event_subscription)
+#define VIDIOC_UNSUBSCRIBE_EVENT _IOW('V', 85, struct v4l2_event_subscription)
 /* Reminder: when adding new ioctls please add support for them to
    drivers/media/video/v4l2-compat-ioctl32.c as well! */
 
diff --git a/include/linux/wl127x-rfkill.h b/include/linux/wl127x-rfkill.h
index 4fad20a..1edec15 100644
--- a/include/linux/wl127x-rfkill.h
+++ b/include/linux/wl127x-rfkill.h
@@ -26,11 +26,10 @@
 
 #include <linux/rfkill.h>
 
-enum wl127x_devices {
-	WL127X_BLUETOOTH = 0,
-	WL127X_FM,
-	WL127X_MAX_DEV,
-};
+/*  wl127x devices */
+#define WL127X_BLUETOOTH  0
+#define WL127X_FM         1
+#define WL127X_MAX_DEV    2
 
 /* Set bt_nshutdown_gpio or fm_enable_gpio to -1 to disable the corresponding
  * rfkill driver */
diff --git a/include/media/imx046.h b/include/media/imx046.h
index ecca6fb..7565488 100644
--- a/include/media/imx046.h
+++ b/include/media/imx046.h
@@ -28,17 +28,17 @@
  * @priv_data_set: device private data (pointer) access function
  */
 struct imx046_platform_data {
-	int (*power_set)(struct device*, enum v4l2_power power);
+	int (*power_set)(struct v4l2_int_device *s, enum v4l2_power power);
 	int (*ifparm)(struct v4l2_ifparm *p);
-	int (*priv_data_set)(void *);
-	u32 (*set_xclk)(u32 xclk, u8 xclksel);
+	int (*priv_data_set)(struct v4l2_int_device *s, void *);
+	u32 (*set_xclk)(struct v4l2_int_device *s, u32 xclkfreq);
 	int (*cfg_interface_bridge)(u32);
-	int (*csi2_lane_count)(int count);
-	int (*csi2_cfg_vp_out_ctrl)(u8 vp_out_ctrl);
-	int (*csi2_ctrl_update)(bool);
-	int (*csi2_cfg_virtual_id)(u8 ctx, u8 id);
-	int (*csi2_ctx_update)(u8 ctx, bool);
-	int (*csi2_calc_phy_cfg0)(u32, u32, u32);
+	int (*csi2_lane_count)(struct v4l2_int_device *s, int count);
+	int (*csi2_cfg_vp_out_ctrl)(struct v4l2_int_device *s, u8 vp_out_ctrl);
+	int (*csi2_ctrl_update)(struct v4l2_int_device *s, bool);
+	int (*csi2_cfg_virtual_id)(struct v4l2_int_device *s, u8 ctx, u8 id);
+	int (*csi2_ctx_update)(struct v4l2_int_device *s, u8 ctx, bool);
+	int (*csi2_calc_phy_cfg0)(struct v4l2_int_device *s, u32, u32, u32);
 };
 
 #endif /* ifndef IMX046_H */
diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h
index e36faab..325c578 100644
--- a/include/media/v4l2-dev.h
+++ b/include/media/v4l2-dev.h
@@ -16,6 +16,8 @@
 #include <linux/mutex.h>
 #include <linux/videodev2.h>
 
+#include <media/v4l2-fh.h>
+
 #define VIDEO_MAJOR	81
 
 #define VFL_TYPE_GRABBER	0
@@ -75,6 +77,8 @@
 	/* attribute to differentiate multiple indices on one physical device */
 	int index;
 
+	spinlock_t fh_lock;		/* Lock for file handle list */
+	struct list_head fh;		/* File handle list */
 	int debug;			/* Activates debug level*/
 
 	/* Video standard vars */
diff --git a/include/media/v4l2-event.h b/include/media/v4l2-event.h
new file mode 100644
index 0000000..694ffa8
--- /dev/null
+++ b/include/media/v4l2-event.h
@@ -0,0 +1,75 @@
+/*
+ * include/media/v4l2-event.h
+ *
+ * V4L2 events.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus at maxwell.research.nokia.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_EVENT_H
+#define V4L2_EVENT_H
+
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <asm/atomic.h>
+
+#define V4L2_MAX_EVENTS		1024 /* Ought to be enough for everyone. */
+
+struct video_device;
+
+struct _v4l2_event {
+	struct list_head	list;
+	struct v4l2_event	event;
+};
+
+struct v4l2_events {
+	spinlock_t		lock; /* Protect everything here. */
+	struct list_head	available;
+	atomic_t		navailable;
+	u32			sequence;
+	wait_queue_head_t	wait;
+	struct list_head	subscribed; /* Subscribed events. */
+};
+
+struct v4l2_subscribed_event {
+	struct list_head	list;
+	u32			type;
+};
+
+int v4l2_event_init(void);
+void v4l2_event_exit(void);
+
+void v4l2_event_init_fh(struct v4l2_events *events);
+void v4l2_event_del(struct v4l2_events *events);
+
+int v4l2_event_dequeue(struct v4l2_events *events, struct v4l2_event *event);
+
+struct v4l2_subscribed_event *v4l2_event_subscribed(struct v4l2_events *sub,
+						    u32 type);
+
+void v4l2_event_queue(struct video_device *vdev, struct v4l2_event *ev);
+int v4l2_event_pending(struct v4l2_events *events);
+
+int v4l2_event_subscribe(struct v4l2_events *sub,
+			 struct v4l2_event_subscription *s);
+int v4l2_event_unsubscribe(struct v4l2_events *sub,
+			   struct v4l2_event_subscription *s);
+
+#endif /* V4L2_EVENT_H */
diff --git a/include/media/v4l2-fh.h b/include/media/v4l2-fh.h
new file mode 100644
index 0000000..361422b
--- /dev/null
+++ b/include/media/v4l2-fh.h
@@ -0,0 +1,45 @@
+/*
+ * include/media/v4l2-fh.h
+ *
+ * V4L2 file handle.
+ *
+ * Copyright (C) 2009 Nokia Corporation.
+ *
+ * Contact: Sakari Ailus <sakari.ailus at maxwell.research.nokia.com>
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA
+ */
+
+#ifndef V4L2_FH_H
+#define V4L2_FH_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+#include <media/v4l2-event.h>
+
+struct v4l2_fh {
+	struct list_head	list;
+	struct v4l2_events      events; /* events, pending and subscribed */
+};
+
+struct video_device;
+
+int v4l2_fh_add(struct video_device *vdev, struct v4l2_fh *fh);
+void v4l2_fh_del(struct video_device *vdev, struct v4l2_fh *fh);
+int v4l2_fh_init(struct video_device *vdev);
+void v4l2_fh_exit(struct video_device *vdev);
+
+#endif /* V4L2_EVENT_H */
diff --git a/include/media/v4l2-int-device.h b/include/media/v4l2-int-device.h
index 2830ae1..158c07c 100644
--- a/include/media/v4l2-int-device.h
+++ b/include/media/v4l2-int-device.h
@@ -232,6 +232,14 @@
 	 *
 	 */
 	vidioc_int_priv_start_num = 2000,
+	/* VIDIOC_INT_PRIV_G_PIXCLK */
+	vidioc_int_priv_g_pixclk_num,
+	/* VIDIOC_INT_PRIV_G_ACTIVESIZE */
+	vidioc_int_priv_g_activesize_num,
+	/* VIDIOC_INT_PRIV_G_FULLSIZE */
+	vidioc_int_priv_g_fullsize_num,
+	/* VIDIOC_INT_PRIV_G_PIXELSIZE */
+	vidioc_int_priv_g_pixelsize_num,
 };
 
 /*
@@ -310,4 +318,8 @@
 V4L2_INT_WRAPPER_0(init);
 V4L2_INT_WRAPPER_1(g_chip_ident, int, *);
 
+V4L2_INT_WRAPPER_1(priv_g_pixclk, u32, *);
+V4L2_INT_WRAPPER_1(priv_g_activesize, struct v4l2_rect, *);
+V4L2_INT_WRAPPER_1(priv_g_fullsize, struct v4l2_rect, *);
+V4L2_INT_WRAPPER_1(priv_g_pixelsize, struct v4l2_rect, *);
 #endif
diff --git a/include/media/v4l2-ioctl.h b/include/media/v4l2-ioctl.h
index b01c044..df8a7aa 100644
--- a/include/media/v4l2-ioctl.h
+++ b/include/media/v4l2-ioctl.h
@@ -20,6 +20,8 @@
 #include <linux/videodev2.h>
 #endif
 
+struct v4l2_fh;
+
 struct v4l2_ioctl_ops {
 	/* ioctl callbacks */
 
@@ -238,6 +240,13 @@
 	int (*vidioc_enum_frameintervals) (struct file *file, void *fh,
 					   struct v4l2_frmivalenum *fival);
 
+	int (*vidioc_dqevent)	       (struct v4l2_fh *fh,
+					struct v4l2_event *ev);
+	int (*vidioc_subscribe_event)  (struct v4l2_fh *fh,
+					struct v4l2_event_subscription *sub);
+	int (*vidioc_unsubscribe_event) (struct v4l2_fh *fh,
+					 struct v4l2_event_subscription *sub);
+
 	/* For other private ioctls */
 	long (*vidioc_default)	       (struct file *file, void *fh,
 					int cmd, void *arg);
diff --git a/include/net/bluetooth/hci_core.h b/include/net/bluetooth/hci_core.h
index 01f9316..ed16efba 100644
--- a/include/net/bluetooth/hci_core.h
+++ b/include/net/bluetooth/hci_core.h
@@ -180,7 +180,8 @@
 	struct timer_list disc_timer;
 	struct timer_list idle_timer;
 
-	struct work_struct work;
+	struct work_struct work_add;
+	struct work_struct work_del;
 
 	struct device	dev;
 
@@ -350,7 +351,7 @@
 			if (conn->state == BT_CONNECTED) {
 				timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
 				if (!conn->out)
-					timeo *= 5;
+					timeo *= 20;
 			} else
 				timeo = msecs_to_jiffies(10);
 		} else
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index 24247f7..26c7bab 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -30,6 +30,7 @@
 #define SND_SOC_DAIFMT_DSP_A		3 /* L data msb after FRM LRC */
 #define SND_SOC_DAIFMT_DSP_B		4 /* L data msb during FRM LRC */
 #define SND_SOC_DAIFMT_AC97		5 /* AC97 */
+#define SND_SOC_DAIFMT_I2S_1PHASE	6 /* I2S Single phase mode */
 
 /* left and right justified also known as MSB and LSB respectively */
 #define SND_SOC_DAIFMT_MSB		SND_SOC_DAIFMT_LEFT_J
diff --git a/kernel/module.c b/kernel/module.c
index 1196f5d..1278729 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2288,9 +2288,9 @@
 	ftrace_release(mod->module_core, mod->core_size);
  free_unload:
 	module_unload_free(mod);
- free_init:
 #if defined(CONFIG_MODULE_UNLOAD) && defined(CONFIG_SMP)
 	percpu_modfree(mod->refptr);
+ free_init:
 #endif
 	module_free(mod, mod->module_init);
  free_core:
diff --git a/kernel/power/wakelock.c b/kernel/power/wakelock.c
index acbb06d..58548f7 100644
--- a/kernel/power/wakelock.c
+++ b/kernel/power/wakelock.c
@@ -225,7 +225,6 @@
 /* Caller must acquire the list_lock spinlock */
 static void print_active_locks(int type)
 {
-	unsigned long irqflags;
 	struct wake_lock *lock;
 
 	BUG_ON(type >= WAKE_LOCK_TYPE_COUNT);
diff --git a/kernel/printk.c b/kernel/printk.c
index ce492a7..0353ca4 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -44,10 +44,6 @@
 
 #define __LOG_BUF_LEN	(1 << CONFIG_LOG_BUF_SHIFT)
 
-#ifdef CONFIG_DEBUG_LL
-extern void printascii(char *);
-#endif
-
 /* printk's without a loglevel use this.. */
 #define DEFAULT_MESSAGE_LOGLEVEL 4 /* KERN_WARNING */
 
@@ -244,6 +240,14 @@
 }
 
 /*
+ * Clears the ring-buffer
+ */
+void log_buf_clear(void)
+{
+	logged_chars = 0;
+}
+
+/*
  * Copy a range of characters from the log buffer.
  */
 int log_buf_copy(char *dest, int idx, int len)
@@ -710,10 +714,6 @@
 	printed_len += vscnprintf(printk_buf + printed_len,
 				  sizeof(printk_buf) - printed_len, fmt, args);
 
-#ifdef	CONFIG_DEBUG_LL
-	printascii(printk_buf);
-#endif
-
 	/*
 	 * Copy the output into log_buf.  If the caller didn't provide
 	 * appropriate log level tags, we insert them here
diff --git a/kernel/sched.c b/kernel/sched.c
index f1e8560..781cf8b 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -53,6 +53,7 @@
 #include <linux/rcupdate.h>
 #include <linux/cpu.h>
 #include <linux/cpuset.h>
+#include <linux/cpufreq.h>
 #include <linux/percpu.h>
 #include <linux/kthread.h>
 #include <linux/proc_fs.h>
@@ -4362,6 +4363,7 @@
  */
 void account_idle_ticks(unsigned long ticks)
 {
+	cpufreq_exit_idle(smp_processor_id(), ticks);
 	account_idle_time(jiffies_to_cputime(ticks));
 }
 
@@ -5979,7 +5981,7 @@
 	unsigned state;
 
 	state = p->state ? __ffs(p->state) + 1 : 0;
-	printk(KERN_INFO "%-13.13s %c", p->comm,
+	printk(KERN_INFO "%-15.15s %c", p->comm,
 		state < sizeof(stat_nam) - 1 ? stat_nam[state] : '?');
 #if BITS_PER_LONG == 32
 	if (state == TASK_RUNNING)
diff --git a/lib/genalloc.c b/lib/genalloc.c
index f6d276d..eed2bdb 100644
--- a/lib/genalloc.c
+++ b/lib/genalloc.c
@@ -85,7 +85,6 @@
 	int bit, end_bit;
 
 
-	write_lock(&pool->lock);
 	list_for_each_safe(_chunk, _next_chunk, &pool->chunks) {
 		chunk = list_entry(_chunk, struct gen_pool_chunk, next_chunk);
 		list_del(&chunk->next_chunk);
diff --git a/net/bluetooth/hci_conn.c b/net/bluetooth/hci_conn.c
index 1181db0..e082b89 100644
--- a/net/bluetooth/hci_conn.c
+++ b/net/bluetooth/hci_conn.c
@@ -213,6 +213,7 @@
 	conn->type  = type;
 	conn->mode  = HCI_CM_ACTIVE;
 	conn->state = BT_OPEN;
+	conn->auth_type = HCI_AT_GENERAL_BONDING;
 
 	conn->power_save = 1;
 
@@ -371,6 +372,9 @@
 
 	if (acl->state == BT_CONNECTED &&
 			(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
+		acl->power_save = 1;
+		hci_conn_enter_active_mode(acl);
+
 		if (lmp_esco_capable(hdev))
 			hci_setup_sync(sco, acl->handle);
 		else
@@ -424,12 +428,9 @@
 	if (sec_level == BT_SECURITY_SDP)
 		return 1;
 
-	if (sec_level == BT_SECURITY_LOW) {
-		if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0)
-			return hci_conn_auth(conn, sec_level, auth_type);
-		else
-			return 1;
-	}
+	if (sec_level == BT_SECURITY_LOW &&
+				(!conn->ssp_mode || !conn->hdev->ssp_mode))
+		return 1;
 
 	if (conn->link_mode & HCI_LM_ENCRYPT)
 		return hci_conn_auth(conn, sec_level, auth_type);
diff --git a/net/bluetooth/hci_event.c b/net/bluetooth/hci_event.c
index c479592..ffdd6aa 100644
--- a/net/bluetooth/hci_event.c
+++ b/net/bluetooth/hci_event.c
@@ -1647,7 +1647,8 @@
 	}
 
 	if (conn->out && (ev->status == 0x1a || ev->status == 0x1c ||
-			ev->status == 0x1f) && conn->attempt < 2) {
+			ev->status == 0x1f || ev->status == 0x10) &&
+			conn->attempt < 2) {
 		conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
 					(hdev->esco_type & EDR_ESCO_MASK);
 		hci_setup_sync(conn, conn->link->handle);
diff --git a/net/bluetooth/hci_sysfs.c b/net/bluetooth/hci_sysfs.c
index 1a1f916..338686e 100644
--- a/net/bluetooth/hci_sysfs.c
+++ b/net/bluetooth/hci_sysfs.c
@@ -9,8 +9,7 @@
 struct class *bt_class = NULL;
 EXPORT_SYMBOL_GPL(bt_class);
 
-static struct workqueue_struct *btaddconn;
-static struct workqueue_struct *btdelconn;
+static struct workqueue_struct *bluetooth;
 
 static inline char *link_typetostr(int type)
 {
@@ -88,9 +87,10 @@
 
 static void add_conn(struct work_struct *work)
 {
-	struct hci_conn *conn = container_of(work, struct hci_conn, work);
+	struct hci_conn *conn = container_of(work, struct hci_conn, work_add);
 
-	flush_workqueue(btdelconn);
+	/* ensure previous add/del is complete */
+	flush_workqueue(bluetooth);
 
 	if (device_add(&conn->dev) < 0) {
 		BT_ERR("Failed to register connection device");
@@ -114,9 +114,9 @@
 
 	device_initialize(&conn->dev);
 
-	INIT_WORK(&conn->work, add_conn);
+	INIT_WORK(&conn->work_add, add_conn);
 
-	queue_work(btaddconn, &conn->work);
+	queue_work(bluetooth, &conn->work_add);
 }
 
 /*
@@ -131,9 +131,12 @@
 
 static void del_conn(struct work_struct *work)
 {
-	struct hci_conn *conn = container_of(work, struct hci_conn, work);
+	struct hci_conn *conn = container_of(work, struct hci_conn, work_del);
 	struct hci_dev *hdev = conn->hdev;
 
+	/* ensure previous add/del is complete */
+	flush_workqueue(bluetooth);
+
 	while (1) {
 		struct device *dev;
 
@@ -156,9 +159,9 @@
 	if (!device_is_registered(&conn->dev))
 		return;
 
-	INIT_WORK(&conn->work, del_conn);
+	INIT_WORK(&conn->work_del, del_conn);
 
-	queue_work(btdelconn, &conn->work);
+	queue_work(bluetooth, &conn->work_del);
 }
 
 static inline char *host_typetostr(int type)
@@ -435,20 +438,13 @@
 
 int __init bt_sysfs_init(void)
 {
-	btaddconn = create_singlethread_workqueue("btaddconn");
-	if (!btaddconn)
+	bluetooth = create_singlethread_workqueue("bluetooth");
+	if (!bluetooth)
 		return -ENOMEM;
 
-	btdelconn = create_singlethread_workqueue("btdelconn");
-	if (!btdelconn) {
-		destroy_workqueue(btaddconn);
-		return -ENOMEM;
-	}
-
 	bt_class = class_create(THIS_MODULE, "bluetooth");
 	if (IS_ERR(bt_class)) {
-		destroy_workqueue(btdelconn);
-		destroy_workqueue(btaddconn);
+		destroy_workqueue(bluetooth);
 		return PTR_ERR(bt_class);
 	}
 
@@ -457,8 +453,7 @@
 
 void bt_sysfs_cleanup(void)
 {
-	destroy_workqueue(btaddconn);
-	destroy_workqueue(btdelconn);
+	destroy_workqueue(bluetooth);
 
 	class_destroy(bt_class);
 }
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index c109a3a..0b20f99 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -1112,7 +1112,8 @@
 			break;
 
 		case BT_DISCONN:
-			rfcomm_session_put(s);
+			if (s->sock->sk->sk_state != BT_CLOSED)
+				rfcomm_session_put(s);
 			break;
 		}
 	}
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index b04e5ad..9fd7221 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1877,10 +1877,19 @@
 			if (sock_flag(sk, SOCK_DEAD))
 				continue;
 
+			sock_hold(sk);
+			spin_unlock_bh(lock);
+
+			local_bh_disable();
+			bh_lock_sock(sk);
 			sk->sk_err = ETIMEDOUT;
 			sk->sk_error_report(sk);
-			spin_unlock_bh(lock);
+
 			tcp_done(sk);
+			bh_unlock_sock(sk);
+			local_bh_enable();
+			sock_put(sk);
+
 			goto restart;
 		}
 		spin_unlock_bh(lock);
@@ -2496,4 +2505,3 @@
 EXPORT_SYMBOL(tcp_proc_unregister);
 #endif
 EXPORT_SYMBOL(sysctl_tcp_low_latency);
-
diff --git a/scripts/mod/modpost.c b/scripts/mod/modpost.c
index 8892161..9564bb6 100644
--- a/scripts/mod/modpost.c
+++ b/scripts/mod/modpost.c
@@ -1539,7 +1539,8 @@
 			const char *name = strings + sym->st_value;
 			const char *fmt = strchr(name, '\0') + 1;
 			char *line = NULL;
-			asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+			if (asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt) == -1)
+				fatal("asprintf() with %s failed", name);
 			NOFAIL(line);
 			mod->markers[n++] = line;
 		}
@@ -1959,7 +1960,8 @@
 static void add_marker(struct module *mod, const char *name, const char *fmt)
 {
 	char *line = NULL;
-	asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt);
+	if (asprintf(&line, "%s\t%s\t%s\n", name, mod->name, fmt) == -1)
+		fatal("asprintf() with %s failed", name);
 	NOFAIL(line);
 
 	mod->markers = NOFAIL(realloc(mod->markers, ((mod->nmarkers + 1) *
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index 91c250b..97df16a 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -660,6 +660,17 @@
 		/* Wait ramp delay time + 1, so the VMID can settle */
 		mdelay((ramp_base[(hs_pop & TWL4030_RAMP_DELAY) >> 2] /
 			twl4030->sysclk) + 1);
+
+		/* Disable external mute */
+		if (setup && setup->hs_extmute) {
+			if (setup->set_hs_extmute) {
+				setup->set_hs_extmute(0);
+			} else {
+				hs_pop &= ~TWL4030_EXTMUTE;
+				twl4030_write(codec,
+					TWL4030_REG_HS_POPN_SET, hs_pop);
+			}
+		}
 	} else {
 		/* Headset ramp-down _not_ according to
 		 * the TRM, but in a way that it is working */
@@ -676,16 +687,6 @@
 		hs_pop &= ~TWL4030_VMID_EN;
 		twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
 	}
-
-	/* Disable external mute */
-	if (setup && setup->hs_extmute) {
-		if (setup->set_hs_extmute) {
-			setup->set_hs_extmute(0);
-		} else {
-			hs_pop &= ~TWL4030_EXTMUTE;
-			twl4030_write(codec, TWL4030_REG_HS_POPN_SET, hs_pop);
-		}
-	}
 }
 
 static int headsetlpga_event(struct snd_soc_dapm_widget *w,
@@ -1899,12 +1900,16 @@
 	rval = twl4030_set_rate(codec, params);
 	if (rval < 0) {
 		mutex_unlock(&twl4030->mutex);
+		printk(KERN_ERR "twl4030_hw_params: set rate failed, rate = %d\n",
+			params_rate(params));
 		return rval;
 	}
 
 	rval = twl4030_set_format(codec, params);
 	if (rval < 0) {
 		mutex_unlock(&twl4030->mutex);
+		printk(KERN_ERR "twl4030_hw_params: set format failed, format = %d\n",
+			params_format(params));
 		return rval;
 	}
 
@@ -1976,7 +1981,7 @@
 	return 0;
 }
 
-static int twl4030_set_ext_clock(struct snd_soc_codec *codec, int enable)
+int twl4030_set_ext_clock(struct snd_soc_codec *codec, int enable)
 {
 	u8 old_format, format;
 
@@ -2002,6 +2007,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(twl4030_set_ext_clock);
 
 static int twl4030_set_dai_fmt(struct snd_soc_dai *codec_dai,
 			     unsigned int fmt)
@@ -2329,15 +2335,17 @@
 	.name = "twl4030",
 	.playback = {
 		.stream_name = "HiFi Playback",
-		.channels_min = 1,
+		.channels_min = 2,
 		.channels_max = 4,
-		.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000,
+		/*.rates = TWL4030_RATES | SNDRV_PCM_RATE_96000, */
+		.rates = SNDRV_PCM_RATE_44100,
 		.formats = TWL4030_FORMATS,},
 	.capture = {
 		.stream_name = "Capture",
-		.channels_min = 1,
+		.channels_min = 2,
 		.channels_max = 4,
-		.rates = TWL4030_RATES,
+		/*.rates = TWL4030_RATES, */
+		.rates = SNDRV_PCM_RATE_44100,
 		.formats = TWL4030_FORMATS,},
 	.ops = {
 		.startup = twl4030_startup,
diff --git a/sound/soc/codecs/twl4030.h b/sound/soc/codecs/twl4030.h
index bece61c..2d83c19 100644
--- a/sound/soc/codecs/twl4030.h
+++ b/sound/soc/codecs/twl4030.h
@@ -275,6 +275,7 @@
 extern int twl4030_set_rate(struct snd_soc_codec *, struct snd_pcm_hw_params *);
 extern int twl4030_get_clock_divisor(struct snd_soc_codec *,
 				     struct snd_pcm_hw_params *);
+extern int twl4030_set_ext_clock(struct snd_soc_codec *codec, int);
 
 struct twl4030_setup_data {
 	unsigned int ramp_delay_value;
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index 1a0b555..517eaa4 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -74,7 +74,7 @@
 
 config SND_OMAP_SOC_ZOOM2
 	tristate "SoC Audio support for Zoom2"
-	depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP_ZOOM2
+	depends on TWL4030_CORE && SND_OMAP_SOC && (MACH_OMAP_ZOOM2 || MACH_OMAP_ZOOM3)
 	select SND_OMAP_SOC_MCBSP
 	select SND_SOC_TWL4030
 	help
diff --git a/sound/soc/omap/omap-mcbsp.c b/sound/soc/omap/omap-mcbsp.c
index acd1375..a6d4902 100644
--- a/sound/soc/omap/omap-mcbsp.c
+++ b/sound/soc/omap/omap-mcbsp.c
@@ -42,11 +42,11 @@
 	unsigned int			bus_id;
 	struct omap_mcbsp_reg_cfg	regs;
 	unsigned int			fmt;
+	int				clk_id;
 	/*
-	 * Flags indicating is the bus already activated and configured by
+	 * Flags indicating is the bus already onfigured by
 	 * another substream
 	 */
-	int				active;
 	int				configured;
 };
 
@@ -153,12 +153,18 @@
 		 * size in order to avoid underruns in playback startup because
 		 * HW is keeping the DMA request active until FIFO is filled.
 		 */
-		snd_pcm_hw_constraint_minmax(substream->runtime,
+		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+			snd_pcm_hw_constraint_minmax(substream->runtime,
 			SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 4096, UINT_MAX);
+		else
+			snd_pcm_hw_constraint_minmax(substream->runtime,
+			SNDRV_PCM_HW_PARAM_BUFFER_BYTES, 1024, UINT_MAX);
 	}
 
-	if (!cpu_dai->active)
+	if (!cpu_dai->active) {
 		err = omap_mcbsp_request(mcbsp_data->bus_id);
+		cpu_dai->active = 1;
+	}
 
 	return err;
 }
@@ -172,6 +178,7 @@
 
 	if (!cpu_dai->active) {
 		omap_mcbsp_free(mcbsp_data->bus_id);
+		cpu_dai->active = 0;
 		mcbsp_data->configured = 0;
 	}
 }
@@ -182,21 +189,18 @@
 	struct snd_soc_pcm_runtime *rtd = substream->private_data;
 	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
 	struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
-	int err = 0;
+	int err = 0, play = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-	case SNDRV_PCM_TRIGGER_RESUME:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-		if (!mcbsp_data->active++)
-			omap_mcbsp_start(mcbsp_data->bus_id);
+	case SNDRV_PCM_TRIGGER_RESUME:
+		omap_mcbsp_start(mcbsp_data->bus_id, play, !play);
 		break;
-
 	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-		if (!--mcbsp_data->active)
-			omap_mcbsp_stop(mcbsp_data->bus_id);
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		omap_mcbsp_stop(mcbsp_data->bus_id, play, !play);
 		break;
 	default:
 		err = -EINVAL;
@@ -214,9 +218,12 @@
 	struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
 	struct omap_mcbsp_reg_cfg *regs = &mcbsp_data->regs;
 	int dma, bus_id = mcbsp_data->bus_id, id = cpu_dai->id;
-	int wlen, channels, wpf;
-	unsigned long port;
-	unsigned int format;
+	int uninitialized_var(wlen);
+	int uninitialized_var(channels);
+	int uninitialized_var(wpf);
+	unsigned long uninitialized_var(port);
+	unsigned int uninitialized_var(format);
+	int xfer_size = 0;
 
 	if (cpu_class_is_omap1()) {
 		dma = omap1_dma_reqs[bus_id][substream->stream];
@@ -230,6 +237,25 @@
 	} else if (cpu_is_omap343x()) {
 		dma = omap24xx_dma_reqs[bus_id][substream->stream];
 		port = omap34xx_mcbsp_port[bus_id][substream->stream];
+		xfer_size = omap34xx_mcbsp_thresholds[bus_id]
+							[substream->stream];
+		/* reset the xfer_size to the integral multiple of
+		the buffer size. This is for DMA packet mode transfer */
+		if (xfer_size) {
+			/* struct snd_pcm_runtime *runtime = substream->runtime;*/
+			int buffer_size = params_buffer_size(params);
+			if (xfer_size > buffer_size) {
+				printk(KERN_DEBUG "buffer_size is %d \n",
+					buffer_size);
+				xfer_size = 0;
+			} else {
+				int temp =  buffer_size / xfer_size;
+				while (buffer_size % xfer_size) {
+					temp++;
+					xfer_size = buffer_size / (temp);
+				}
+			}
+		}
 	} else {
 		return -ENODEV;
 	}
@@ -237,6 +263,7 @@
 		substream->stream ? "Audio Capture" : "Audio Playback";
 	omap_mcbsp_dai_dma_params[id][substream->stream].dma_req = dma;
 	omap_mcbsp_dai_dma_params[id][substream->stream].port_addr = port;
+	omap_mcbsp_dai_dma_params[id][substream->stream].xfer_size = xfer_size;
 	cpu_dai->dma_data = &omap_mcbsp_dai_dma_params[id][substream->stream];
 
 	if (mcbsp_data->configured) {
@@ -256,6 +283,11 @@
 			wpf--;
 			regs->rcr2	|= RFRLEN2(wpf - 1);
 			regs->xcr2	|= XFRLEN2(wpf - 1);
+		} else if (format == SND_SOC_DAIFMT_I2S_1PHASE) {
+			printk(KERN_DEBUG "Configure McBSP for 1 phase\n");
+			regs->xcr2	&= ~(XPHASE);
+			regs->rcr2	&= ~(RPHASE);
+			wpf--;
 		}
 	case 1:
 	case 4:
@@ -271,11 +303,22 @@
 	switch (params_format(params)) {
 	case SNDRV_PCM_FORMAT_S16_LE:
 		/* Set word lengths */
-		wlen = 16;
-		regs->rcr2	|= RWDLEN2(OMAP_MCBSP_WORD_16);
-		regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_16);
-		regs->xcr2	|= XWDLEN2(OMAP_MCBSP_WORD_16);
-		regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_16);
+		if (format == SND_SOC_DAIFMT_I2S_1PHASE) {
+			regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_32);
+			regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_32);
+			omap_mcbsp_dai_dma_params[id]
+			[SNDRV_PCM_STREAM_PLAYBACK].dma_word_size = 32;
+			omap_mcbsp_dai_dma_params[id]
+			[SNDRV_PCM_STREAM_CAPTURE].dma_word_size = 32;
+		} else {
+			wlen = 16;
+			regs->rcr2	|= RWDLEN2(OMAP_MCBSP_WORD_16);
+			regs->rcr1	|= RWDLEN1(OMAP_MCBSP_WORD_16);
+			regs->xcr2	|= XWDLEN2(OMAP_MCBSP_WORD_16);
+			regs->xcr1	|= XWDLEN1(OMAP_MCBSP_WORD_16);
+			omap_mcbsp_dai_dma_params[id]
+			[substream->stream].dma_word_size = 16;
+		}
 		break;
 	default:
 		/* Unsupported PCM format */
@@ -285,6 +328,7 @@
 	/* Set FS period and length in terms of bit clock periods */
 	switch (format) {
 	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_I2S_1PHASE:
 		regs->srgr2	|= FPER(wlen * channels - 1);
 		regs->srgr1	|= FWID(wlen - 1);
 		break;
@@ -295,7 +339,18 @@
 		break;
 	}
 
+	regs->xccr |= XDMAEN;
+	regs->wken = XRDYEN;
+	regs->rccr |= RDMAEN;
+
 	omap_mcbsp_config(bus_id, &mcbsp_data->regs);
+
+	if ((bus_id == 1) && (xfer_size != 0)) {
+		printk(KERN_DEBUG "Configure McBSP TX FIFO threshold to %d\n",
+			xfer_size);
+		omap_mcbsp_set_tx_threshold(bus_id, xfer_size);
+	}
+
 	mcbsp_data->configured = 1;
 
 	return 0;
@@ -323,12 +378,13 @@
 	regs->rcr2	|= RFIG;
 	regs->xcr2	|= XFIG;
 	if (cpu_is_omap2430() || cpu_is_omap34xx()) {
-		regs->xccr = DXENDLY(1) | XDMAEN;
-		regs->rccr = RFULL_CYCLE | RDMAEN;
+		regs->xccr = DXENDLY(1);
+		regs->rccr = RFULL_CYCLE;
 	}
 
 	switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
 	case SND_SOC_DAIFMT_I2S:
+	case SND_SOC_DAIFMT_I2S_1PHASE:
 		/* 1-bit data delay */
 		regs->rcr2	|= RDATDLY(1);
 		regs->xcr2	|= XDATDLY(1);
@@ -476,6 +532,7 @@
 	case OMAP_MCBSP_SYSCLK_CLKS_FCLK:
 	case OMAP_MCBSP_SYSCLK_CLKS_EXT:
 		err = omap_mcbsp_dai_set_clks_src(mcbsp_data, clk_id);
+		mcbsp_data->clk_id = clk_id;
 		break;
 
 	case OMAP_MCBSP_SYSCLK_CLKX_EXT:
@@ -490,6 +547,31 @@
 	return err;
 }
 
+int omap_mcbsp_dai_suspend(struct snd_soc_dai *cpu_dai)
+{
+	struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+
+	if (cpu_dai->active) {
+		omap_mcbsp_dai_set_clks_src(mcbsp_data, OMAP_MCBSP_SYSCLK_CLKS_FCLK);
+		omap_mcbsp_disable_fclk(mcbsp_data->bus_id);
+	}
+
+	return 0;
+}
+
+int omap_mcbsp_dai_resume(struct snd_soc_dai *cpu_dai)
+{
+	struct omap_mcbsp_data *mcbsp_data = to_mcbsp(cpu_dai->private_data);
+
+	if (cpu_dai->active) {
+		omap_mcbsp_enable_fclk(mcbsp_data->bus_id);
+		omap_mcbsp_config(mcbsp_data->bus_id, &mcbsp_data->regs);
+		omap_mcbsp_dai_set_clks_src(mcbsp_data, mcbsp_data->clk_id);
+	}
+
+	return 0;
+}
+
 #define OMAP_MCBSP_DAI_BUILDER(link_id)				\
 {								\
 	.name = "omap-mcbsp-dai-"#link_id,			\
@@ -506,6 +588,8 @@
 		.rates = OMAP_MCBSP_RATES,			\
 		.formats = SNDRV_PCM_FMTBIT_S16_LE,		\
 	},							\
+	.suspend = omap_mcbsp_dai_suspend,			\
+	.resume = omap_mcbsp_dai_resume,			\
 	.ops = {						\
 		.startup = omap_mcbsp_dai_startup,		\
 		.shutdown = omap_mcbsp_dai_shutdown,		\
diff --git a/sound/soc/omap/omap-pcm.c b/sound/soc/omap/omap-pcm.c
index 5b3dd1f..78ec86f 100644
--- a/sound/soc/omap/omap-pcm.c
+++ b/sound/soc/omap/omap-pcm.c
@@ -155,6 +155,17 @@
 		dma_params.src_start		= runtime->dma_addr;
 		dma_params.dst_start		= dma_data->port_addr;
 		dma_params.dst_port		= OMAP_DMA_PORT_MPUI;
+		if (dma_data->dma_word_size == 32) {
+			printk(KERN_DEBUG "playback: 32 bit wordsize, xsize=%d\n",
+				dma_data->xfer_size);
+			if (dma_data->xfer_size != 0) {
+				dma_params.sync_mode	= OMAP_DMA_SYNC_PACKET;
+				dma_params.dst_fi	= dma_data->xfer_size;
+			} else {
+				dma_params.sync_mode	= OMAP_DMA_SYNC_ELEMENT;
+			}
+			dma_params.data_type	= OMAP_DMA_DATA_TYPE_S32;
+		}
 	} else {
 		dma_params.src_amode		= OMAP_DMA_AMODE_CONSTANT;
 		dma_params.dst_amode		= OMAP_DMA_AMODE_POST_INC;
@@ -162,6 +173,10 @@
 		dma_params.src_start		= dma_data->port_addr;
 		dma_params.dst_start		= runtime->dma_addr;
 		dma_params.src_port		= OMAP_DMA_PORT_MPUI;
+		if (dma_data->dma_word_size == 32) {
+			printk(KERN_DEBUG "record: Configure for 32 bit word size\n");
+			dma_params.data_type	= OMAP_DMA_DATA_TYPE_S32;
+		}
 	}
 	/*
 	 * Set DMA transfer frame size equal to ALSA period size and frame
@@ -169,12 +184,21 @@
 	 * we can transfer the whole ALSA buffer with single DMA transfer but
 	 * still can get an interrupt at each period bounary
 	 */
-	dma_params.elem_count	= snd_pcm_lib_period_bytes(substream) / 2;
+	if (dma_data->dma_word_size == 32)
+		dma_params.elem_count = runtime->period_size;
+	else
+		dma_params.elem_count = snd_pcm_lib_period_bytes(substream) / 2;
 	dma_params.frame_count	= runtime->periods;
 	omap_set_dma_params(prtd->dma_ch, &dma_params);
 
 	omap_enable_dma_irq(prtd->dma_ch, OMAP_DMA_FRAME_IRQ);
 
+	if (dma_data->xfer_size) {
+		omap_set_dma_src_burst_mode(prtd->dma_ch,
+					OMAP_DMA_DATA_BURST_16);
+		omap_set_dma_dest_burst_mode(prtd->dma_ch,
+					OMAP_DMA_DATA_BURST_16);
+	}
 	return 0;
 }
 
@@ -182,7 +206,7 @@
 {
 	struct snd_pcm_runtime *runtime = substream->runtime;
 	struct omap_runtime_data *prtd = runtime->private_data;
-	unsigned long flags;
+	unsigned long uninitialized_var(flags);
 	int ret = 0;
 
 	spin_lock_irqsave(&prtd->lock, flags);
@@ -195,11 +219,15 @@
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
 		prtd->period_index = -1;
 		omap_stop_dma(prtd->dma_ch);
 		break;
+
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		omap_stop_dma(prtd->dma_ch);
+		omap_disable_lch(prtd->dma_ch);
+		break;
 	default:
 		ret = -EINVAL;
 	}
diff --git a/sound/soc/omap/omap-pcm.h b/sound/soc/omap/omap-pcm.h
index e4369bd..0262467 100644
--- a/sound/soc/omap/omap-pcm.h
+++ b/sound/soc/omap/omap-pcm.h
@@ -28,6 +28,8 @@
 	char		*name;		/* stream identifier */
 	int		dma_req;	/* DMA request line */
 	unsigned long	port_addr;	/* transmit/receive register */
+	int		xfer_size;	/* DMA transfer size */
+	int 		dma_word_size;	/* DMA word size 32/16 */
 };
 
 extern struct snd_soc_platform omap_soc_platform;
diff --git a/sound/soc/omap/zoom2.c b/sound/soc/omap/zoom2.c
index c23b792..1053350 100644
--- a/sound/soc/omap/zoom2.c
+++ b/sound/soc/omap/zoom2.c
@@ -53,7 +53,7 @@
 	/* Set codec DAI configuration */
 	ret = snd_soc_dai_set_fmt(codec_dai,
 				  SND_SOC_DAIFMT_I2S |
-				  SND_SOC_DAIFMT_NB_NF |
+				  SND_SOC_DAIFMT_NB_IF |
 				  SND_SOC_DAIFMT_CBM_CFM);
 	if (ret < 0) {
 		printk(KERN_ERR "can't set codec DAI configuration\n");
@@ -62,8 +62,8 @@
 
 	/* Set cpu DAI configuration */
 	ret = snd_soc_dai_set_fmt(cpu_dai,
-				  SND_SOC_DAIFMT_I2S |
-				  SND_SOC_DAIFMT_NB_NF |
+				  SND_SOC_DAIFMT_I2S_1PHASE |
+				  SND_SOC_DAIFMT_NB_IF |
 				  SND_SOC_DAIFMT_CBM_CFM);
 	if (ret < 0) {
 		printk(KERN_ERR "can't set cpu DAI configuration\n");
@@ -78,11 +78,116 @@
 		return ret;
 	}
 
+	/* enable 256 FS clk for HDMI */
+	ret = twl4030_set_ext_clock(codec_dai->codec, 1);
+	if (ret < 0) {
+		printk(KERN_ERR "can't set 256 FS clock\n");
+		return ret;
+	}
+
+	/* Use external clock for mcBSP2 */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_EXT,
+			0, SND_SOC_CLOCK_OUT);
+
+	/*
+	 * Set headset EXTMUTE signal to ON to make sure we
+	 * get correct headset status
+	 */
+	gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 1);
+
 	return 0;
 }
 
+int zoom2_i2s_hw_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+
+	/* Use function clock for mcBSP2 */
+	ret = snd_soc_dai_set_sysclk(cpu_dai, OMAP_MCBSP_SYSCLK_CLKS_FCLK,
+			0, SND_SOC_CLOCK_OUT);
+	return 0;
+}
+
+
 static struct snd_soc_ops zoom2_i2s_ops = {
 	.hw_params = zoom2_i2s_hw_params,
+	.hw_free = zoom2_i2s_hw_free,
+};
+
+static int zoom2_hw_voice_params(struct snd_pcm_substream *substream,
+					struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+	int ret;
+
+	omap_mux_config("MCBSP3_SLAVE");
+
+	/* Set codec DAI configuration */
+	ret = snd_soc_dai_set_fmt(codec_dai,
+					SND_SOC_DAIFMT_DSP_A |
+					SND_SOC_DAIFMT_IB_NF |
+					SND_SOC_DAIFMT_CBS_CFM);
+
+	if (ret) {
+			printk(KERN_ERR "can't set codec DAI configuration\n");
+			return ret;
+	}
+
+	/* set codec Voice IF to application mode*/
+	ret = snd_soc_dai_set_tristate(codec_dai, 0);
+
+	if (ret) {
+			printk(KERN_ERR "can't disable codec VIF tristate\n");
+			return ret;
+	}
+
+	/* Set cpu DAI configuration */
+	ret = snd_soc_dai_set_fmt(cpu_dai,
+					SND_SOC_DAIFMT_DSP_A |
+					SND_SOC_DAIFMT_IB_NF |
+					SND_SOC_DAIFMT_CBM_CFM);
+
+	if (ret < 0) {
+			printk(KERN_ERR "can't set cpu DAI configuration\n");
+			return ret;
+	}
+
+	/* Set the codec system clock for DAC and ADC */
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, 26000000,
+						SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+			printk(KERN_ERR "can't set codec system clock\n");
+			return ret;
+	}
+
+	return 0;
+}
+
+int zoom2_hw_voice_free(struct snd_pcm_substream *substream)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
+	int ret;
+
+	omap_mux_config("MCBSP3_TRISTATE");
+
+	/* set codec Voice IF to tristate*/
+	ret = snd_soc_dai_set_tristate(codec_dai, 1);
+
+	if (ret) {
+			printk(KERN_ERR "can't set codec VIF tristate\n");
+			return ret;
+	}
+
+	return 0;
+}
+static struct snd_soc_ops zoom2_voice_ops = {
+	.hw_params = zoom2_hw_voice_params,
+	.hw_free = zoom2_hw_voice_free,
 };
 
 static int zoom2_pcm_hw_params(struct snd_pcm_substream *substream,
@@ -363,6 +468,14 @@
 	.ops = &zoom2_i2s_ops,
 },
 {
+	.name = "TWL4030 VOICE",
+	.stream_name = "TWL4030 Voice",
+	.cpu_dai = &omap_mcbsp_dai[1],
+	.codec_dai = &twl4030_dai[TWL4030_DAI_VOICE],
+	.init = zoom2_twl4030_voice_init,
+	.ops = &zoom2_voice_ops,
+},
+{
 	.name = "TWL4030_PCM",
 	.stream_name = "TWL4030_PCM",
 	.cpu_dai = &omap_mcbsp_dai[1],
@@ -422,10 +535,13 @@
 {
 	int ret;
 
-	if (!machine_is_omap_zoom2()) {
-		pr_debug("Not Zoom2!\n");
+
+	if (!(machine_is_omap_zoom2() ||
+			machine_is_omap_zoom3())) {
+		pr_debug("Not Zoom2/3!\n");
 		return -ENODEV;
 	}
+
 	printk(KERN_INFO "Zoom2 SoC init\n");
 
 	omap_mux_config("MCBSP2_SLAVE");
@@ -446,7 +562,8 @@
 	zoom2_snd_devdata.dev = &zoom2_snd_device->dev;
 	*(unsigned int *)zoom2_dai[0].cpu_dai->private_data = 1; /* McBSP2 */
 	*(unsigned int *)zoom2_dai[1].cpu_dai->private_data = 2; /* McBSP3 */
-	*(unsigned int *)zoom2_dai[2].cpu_dai->private_data = 3; /* McBSP4 */
+	*(unsigned int *)zoom2_dai[2].cpu_dai->private_data = 2; /* McBSP3 */
+	*(unsigned int *)zoom2_dai[3].cpu_dai->private_data = 3; /* McBSP4 */
 
 	ret = platform_device_add(zoom2_snd_device);
 	if (ret)
@@ -456,7 +573,8 @@
 	gpio_direction_output(ZOOM2_HEADSET_MUX_GPIO, 0);
 
 	BUG_ON(gpio_request(ZOOM2_HEADSET_EXTMUTE_GPIO, "ext_mute") < 0);
-	gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 0);
+	/* set EXTMUTE on for initial headset detection */
+	gpio_direction_output(ZOOM2_HEADSET_EXTMUTE_GPIO, 1);
 
 	return 0;