linux: Initial support for the Ka-Ro TX27 (rev. 4)
authorFlorian Boor <florian.boor@kernelconcepts.de>
Fri, 29 May 2009 17:11:19 +0000 (19:11 +0200)
committerFlorian Boor <florian.boor@kernelconcepts.de>
Fri, 29 May 2009 17:14:18 +0000 (19:14 +0200)
recipes/linux/linux-2.6.28/tx27/defconfig [new file with mode: 0644]
recipes/linux/linux-2.6.28/tx27/linux-2.6.28-karo4.diff [new file with mode: 0644]
recipes/linux/linux_2.6.28.bb

diff --git a/recipes/linux/linux-2.6.28/tx27/defconfig b/recipes/linux/linux-2.6.28/tx27/defconfig
new file mode 100644 (file)
index 0000000..ba5a699
--- /dev/null
@@ -0,0 +1,1799 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28
+# Thu Mar 12 15:05:31 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=17
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_SYSFS_DEPRECATED_V2 is not set
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_ELF_CORE is not set
+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 is not set
+# CONFIG_VM_EVENT_COUNTERS is not set
+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_KPROBES=y
+CONFIG_HAVE_KRETPROBES=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
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+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
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_DEFAULT_AS is not set
+# CONFIG_DEFAULT_DEADLINE is not set
+CONFIG_DEFAULT_CFQ=y
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="cfq"
+CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# 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
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+CONFIG_ARCH_MXC=y
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Freescale MXC Implementations
+#
+CONFIG_ARCH_MX2=y
+# CONFIG_ARCH_MX3 is not set
+
+#
+# MX2 family CPU support
+#
+CONFIG_MACH_MX27=y
+
+#
+# MX2 Platforms
+#
+# CONFIG_MACH_MX27ADS is not set
+# CONFIG_MACH_PCM038 is not set
+CONFIG_MACH_TX27=y
+CONFIG_BASE_CLK_26MHz=y
+# CONFIG_KARO_DEBUG is not set
+CONFIG_MXC_EMMA=y
+# CONFIG_MXC_IRQ_PRIOR is not set
+CONFIG_MXC_ULPI=y
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+CONFIG_ARM_THUMB=y
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+# CONFIG_OUTER_CACHE is not set
+
+#
+# Bus support
+#
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+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=y
+CONFIG_HZ=100
+CONFIG_AEABI=y
+CONFIG_OABI_COMPAT=y
+CONFIG_ARCH_FLATMEM_HAS_HOLES=y
+# 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_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="root=/dev/mtdblock1 rootfstype=jffs2 console=ttymxc0,115200 ro panic=5"
+# CONFIG_XIP_KERNEL is not set
+# CONFIG_KEXEC is not set
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# 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 is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_APM_EMULATION=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# 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
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# 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
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=m
+CONFIG_NL80211=y
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_MAC80211=m
+
+#
+# Rate control algorithm selection
+#
+CONFIG_MAC80211_RC_PID=y
+# CONFIG_MAC80211_RC_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT_PID=y
+# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
+CONFIG_MAC80211_RC_DEFAULT="pid"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_IEEE80211=m
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=m
+CONFIG_IEEE80211_CRYPT_CCMP=m
+CONFIG_IEEE80211_CRYPT_TKIP=m
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=m
+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 is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+CONFIG_MTD_REDBOOT_PARTS=y
+CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-5
+CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
+CONFIG_MTD_REDBOOT_PARTS_READONLY=y
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# 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_MUSEUM_IDS is not set
+# CONFIG_MTD_NAND_GPIO is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_MXC_FLASH_BBT=y
+# CONFIG_MTD_NAND_NANDSIM is not set
+# CONFIG_MTD_NAND_PLATFORM is not set
+# CONFIG_MTD_ALAUDA is not set
+CONFIG_MTD_NAND_MXC=y
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+# CONFIG_MTD_UBI is not set
+# CONFIG_PARPORT is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+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
+CONFIG_MISC_DEVICES=y
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_C2PORT is not set
+CONFIG_HAVE_IDE=y
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=m
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP 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
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH 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=y
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_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 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_FEC=y
+# CONFIG_FEC2 is not set
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_USB=m
+# CONFIG_LIBERTAS_SDIO is not set
+# CONFIG_LIBERTAS_DEBUG is not set
+# CONFIG_LIBERTAS_THINFIRM is not set
+# CONFIG_USB_ZD1201 is not set
+# CONFIG_USB_NET_RNDIS_WLAN is not set
+# CONFIG_RTL8187 is not set
+# CONFIG_MAC80211_HWSIM is not set
+# CONFIG_P54_COMMON is not set
+# CONFIG_IWLWIFI_LEDS is not set
+# CONFIG_HOSTAP is not set
+# CONFIG_B43 is not set
+# CONFIG_B43LEGACY is not set
+# CONFIG_ZD1211RW is not set
+# CONFIG_RT2X00 is not set
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+CONFIG_USB_USBNET=m
+# CONFIG_USB_NET_AX8817X is not set
+CONFIG_USB_NET_CDCETHER=m
+# CONFIG_USB_NET_DM9601 is not set
+# CONFIG_USB_NET_SMSC95XX is not set
+# CONFIG_USB_NET_GL620A is not set
+# CONFIG_USB_NET_NET1080 is not set
+# CONFIG_USB_NET_PLUSB is not set
+# CONFIG_USB_NET_MCS7830 is not set
+CONFIG_USB_NET_RNDIS_HOST=m
+CONFIG_USB_NET_CDC_SUBSET=m
+# CONFIG_USB_ALI_M5632 is not set
+# CONFIG_USB_AN2720 is not set
+# CONFIG_USB_BELKIN is not set
+CONFIG_USB_ARMLINUX=y
+# CONFIG_USB_EPSON2888 is not set
+# CONFIG_USB_KC2190 is not set
+# CONFIG_USB_NET_ZAURUS is not set
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+CONFIG_INPUT_EVBUG=m
+# CONFIG_INPUT_APMPOWER is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_GPIO=m
+# 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_FUJITSU is not set
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO 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_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
+CONFIG_TOUCHSCREEN_USB_EGALAX=y
+# CONFIG_TOUCHSCREEN_USB_PANJIT is not set
+# CONFIG_TOUCHSCREEN_USB_3M is not set
+# CONFIG_TOUCHSCREEN_USB_ITM is not set
+# CONFIG_TOUCHSCREEN_USB_ETURBO is not set
+# CONFIG_TOUCHSCREEN_USB_GUNZE is not set
+# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set
+CONFIG_TOUCHSCREEN_USB_IRTOUCH=y
+CONFIG_TOUCHSCREEN_USB_IDEALTEK=y
+CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y
+CONFIG_TOUCHSCREEN_USB_GOTOP=y
+# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+# CONFIG_CONSOLE_TRANSLATIONS is not set
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+CONFIG_VT_HW_CONSOLE_BINDING=y
+# CONFIG_DEVKMEM is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_IMX=y
+CONFIG_SERIAL_IMX_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=16
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+# CONFIG_NVRAM is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_I2C=y
+CONFIG_I2C_BOARDINFO=y
+CONFIG_I2C_CHARDEV=m
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+CONFIG_I2C_GPIO=m
+CONFIG_I2C_MXC=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+CONFIG_AT24=m
+# 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_TPS65010 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_BITBANG=m
+CONFIG_SPI_MXC=m
+# CONFIG_SPI_MXC_TEST_LOOPBACK is not set
+CONFIG_SPI_MXC_SELECT1=y
+# CONFIG_SPI_MXC_SELECT2 is not set
+# CONFIG_SPI_MXC_SELECT3 is not set
+CONFIG_SPI_MXC_REV0=y
+# CONFIG_SPI_MXC_REV4 is not set
+# CONFIG_SPI_MXC_REV5 is not set
+# CONFIG_SPI_MXC_REV7 is not set
+
+#
+# SPI Protocol Masters
+#
+CONFIG_SPI_AT25=m
+CONFIG_SPI_SPIDEV=m
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+CONFIG_GPIO_SYSFS=y
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+# CONFIG_GPIO_MAX732X is not set
+# CONFIG_GPIO_PCA953X is not set
+# CONFIG_GPIO_PCF857X is not set
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+CONFIG_W1=m
+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_MXC=m
+# CONFIG_W1_MASTER_GPIO is not set
+
+#
+# 1-wire Slaves
+#
+# CONFIG_W1_SLAVE_THERM is not set
+CONFIG_W1_SLAVE_SMEM=m
+CONFIG_W1_SLAVE_DS2433=m
+CONFIG_W1_SLAVE_DS2433_CRC=y
+# CONFIG_W1_SLAVE_DS2760 is not set
+# CONFIG_W1_SLAVE_BQ27000 is not set
+CONFIG_POWER_SUPPLY=m
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_APM_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+CONFIG_LP3972=m
+CONFIG_HWMON=m
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADCXX is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM70 is not set
+# CONFIG_SENSORS_LM75 is not set
+CONFIG_SENSORS_LM77=m
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_MAX1111 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+# CONFIG_THERMAL is not set
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO 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
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+CONFIG_VIDEO_DEV=m
+CONFIG_VIDEO_V4L2_COMMON=m
+# CONFIG_VIDEO_ALLOW_V4L1 is not set
+# CONFIG_VIDEO_V4L1_COMPAT is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_VIDEO_MEDIA=m
+
+#
+# Multimedia drivers
+#
+# CONFIG_MEDIA_ATTACH is not set
+CONFIG_MEDIA_TUNER=m
+CONFIG_MEDIA_TUNER_CUSTOMIZE=y
+# CONFIG_MEDIA_TUNER_SIMPLE is not set
+# CONFIG_MEDIA_TUNER_TDA8290 is not set
+# CONFIG_MEDIA_TUNER_TDA827X is not set
+# CONFIG_MEDIA_TUNER_TDA18271 is not set
+# CONFIG_MEDIA_TUNER_TDA9887 is not set
+# CONFIG_MEDIA_TUNER_TEA5761 is not set
+# CONFIG_MEDIA_TUNER_TEA5767 is not set
+# CONFIG_MEDIA_TUNER_MT20XX is not set
+# CONFIG_MEDIA_TUNER_MT2060 is not set
+# CONFIG_MEDIA_TUNER_MT2266 is not set
+# CONFIG_MEDIA_TUNER_MT2131 is not set
+# CONFIG_MEDIA_TUNER_QT1010 is not set
+# CONFIG_MEDIA_TUNER_XC2028 is not set
+# CONFIG_MEDIA_TUNER_XC5000 is not set
+# CONFIG_MEDIA_TUNER_MXL5005S is not set
+# CONFIG_MEDIA_TUNER_MXL5007T is not set
+CONFIG_VIDEO_V4L2=m
+CONFIG_VIDEOBUF_GEN=m
+CONFIG_VIDEOBUF_DMA_CONTIG=m
+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_OV7670 is not set
+# CONFIG_VIDEO_TCM825X is not set
+# CONFIG_VIDEO_SAA711X is not set
+# CONFIG_VIDEO_SAA717X is not set
+# CONFIG_VIDEO_TVP5150 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
+
+#
+# Video improvement chips
+#
+# CONFIG_VIDEO_UPD64031A is not set
+# CONFIG_VIDEO_UPD64083 is not set
+# CONFIG_VIDEO_VIVI is not set
+CONFIG_VIDEO_MXC_CAMERA=m
+
+#
+# MXC Camera/V4L2 PRP Features support
+#
+# CONFIG_MXC_CAMERA_MICRON111 is not set
+# CONFIG_MXC_CAMERA_MC521DA is not set
+# CONFIG_MXC_CAMERA_OV2640 is not set
+CONFIG_VIDEO_MXC_OUTPUT=m
+# CONFIG_VIDEO_MXC_OUTPUT_DEBUG is not set
+CONFIG_VIDEO_MXC_EMMA_OUTPUT=m
+# CONFIG_VIDEO_MXC_OPL is not set
+# CONFIG_VIDEO_SAA5246A is not set
+# CONFIG_VIDEO_SAA5249 is not set
+CONFIG_SOC_CAMERA=m
+# CONFIG_SOC_CAMERA_MT9M001 is not set
+# CONFIG_SOC_CAMERA_MT9M111 is not set
+# CONFIG_SOC_CAMERA_MT9V022 is not set
+CONFIG_SOC_CAMERA_PLATFORM=m
+# CONFIG_VIDEO_SH_MOBILE_CEU is not set
+# CONFIG_V4L_USB_DRIVERS is not set
+CONFIG_VIDEO_MX27=m
+# 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=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 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_IMX=y
+# 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_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# 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=y
+# 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 is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=m
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=m
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+
+#
+# Special HID drivers
+#
+# CONFIG_HID_COMPAT is not set
+# CONFIG_HID_A4TECH is not set
+# CONFIG_HID_APPLE is not set
+# CONFIG_HID_BELKIN is not set
+# CONFIG_HID_BRIGHT is not set
+# CONFIG_HID_CHERRY is not set
+# CONFIG_HID_CHICONY is not set
+# CONFIG_HID_CYPRESS is not set
+# CONFIG_HID_DELL 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_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_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 is not set
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=m
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+CONFIG_USB_SUSPEND=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 is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+CONFIG_USB_EHCI_ROOT_HUB_TT=y
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+CONFIG_USB_EHCI_MXC=y
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# Enable Host or Gadget support to see Inventra options
+#
+
+#
+# USB Device Class drivers
+#
+# 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 depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# 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
+# 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
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+CONFIG_USB_SERIAL=m
+# CONFIG_USB_EZUSB is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRCABLE is not set
+# CONFIG_USB_SERIAL_ARK3116 is not set
+CONFIG_USB_SERIAL_BELKIN=m
+# 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 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=m
+# 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_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_DEBUG is not set
+
+#
+# USB Miscellaneous drivers
+#
+# 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
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# 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=m
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+CONFIG_MMC=m
+# CONFIG_MMC_DEBUG is not set
+# CONFIG_MMC_UNSAFE_RESUME is not set
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=m
+CONFIG_MMC_BLOCK_BOUNCE=y
+# CONFIG_SDIO_UART is not set
+# CONFIG_MMC_TEST is not set
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+# CONFIG_MMC_SDHCI is not set
+CONFIG_MMC_MXC=m
+# CONFIG_MMC_SPI is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+# CONFIG_LEDS_PCA9532 is not set
+CONFIG_LEDS_GPIO=y
+# CONFIG_LEDS_PCA955X is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
+# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# I2C RTC drivers
+#
+# CONFIG_RTC_DRV_DS1307 is not set
+CONFIG_RTC_DRV_DS13XX=y
+# CONFIG_RTC_DRV_DS1374 is not set
+# CONFIG_RTC_DRV_DS1672 is not set
+# CONFIG_RTC_DRV_MAX6900 is not set
+# CONFIG_RTC_DRV_RS5C372 is not set
+# CONFIG_RTC_DRV_ISL1208 is not set
+# CONFIG_RTC_DRV_X1205 is not set
+# CONFIG_RTC_DRV_PCF8563 is not set
+# CONFIG_RTC_DRV_PCF8583 is not set
+# CONFIG_RTC_DRV_M41T80 is not set
+# 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_RTC_MXC=y
+# CONFIG_DMADEVICES is not set
+CONFIG_DRIVERS_MXC=y
+
+#
+# MXC VPU(Video Processing Unit) support
+#
+CONFIG_MXC_VPU=m
+# CONFIG_MXC_VPU_DEBUG is not set
+# CONFIG_REGULATOR is not set
+# CONFIG_UIO is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=m
+CONFIG_EXT3_FS_XATTR=y
+# CONFIG_EXT3_FS_POSIX_ACL is not set
+# CONFIG_EXT3_FS_SECURITY is not set
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=m
+CONFIG_FS_MBCACHE=m
+# 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_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+CONFIG_AUTOFS4_FS=m
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=m
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=m
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+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=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+CONFIG_JFFS2_SUMMARY=y
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+# CONFIG_JFFS2_LZO is not set
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+# CONFIG_NFS_V4 is not set
+CONFIG_ROOT_NFS=y
+# CONFIG_NFSD is not set
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+# CONFIG_RPCSEC_GSS_KRB5 is not set
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+# CONFIG_SMB_FS is not set
+# CONFIG_CIFS is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=m
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=m
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=m
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+CONFIG_NLS_ASCII=m
+CONFIG_NLS_ISO8859_1=m
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+CONFIG_NLS_ISO8859_15=m
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
+# CONFIG_ENABLE_MUST_CHECK is not set
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG 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_SYSCTL_SYSCALL_CHECK is not set
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER 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
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=m
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=m
+CONFIG_CRYPTO_ALGAPI2=m
+CONFIG_CRYPTO_AEAD2=m
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=m
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_HASH2=m
+CONFIG_CRYPTO_RNG2=m
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=m
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+# CONFIG_CRYPTO_CBC is not set
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_PCBC is not set
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=m
+CONFIG_CRYPTO_MICHAEL_MIC=m
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=m
+# CONFIG_CRYPTO_ANUBIS is not set
+CONFIG_CRYPTO_ARC4=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_DES is not set
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# 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_CRC_CCITT=m
+CONFIG_CRC16=m
+# CONFIG_CRC_T10DIF is not set
+# CONFIG_CRC_ITU_T is not set
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
diff --git a/recipes/linux/linux-2.6.28/tx27/linux-2.6.28-karo4.diff b/recipes/linux/linux-2.6.28/tx27/linux-2.6.28-karo4.diff
new file mode 100644 (file)
index 0000000..a1be6ca
--- /dev/null
@@ -0,0 +1,40137 @@
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/Kconfig linux-2.6.28-karo/arch/arm/Kconfig
+--- linux-2.6.28/arch/arm/Kconfig      2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/Kconfig 2009-03-11 13:16:24.000000000 +0100
+@@ -1268,6 +1268,8 @@ source "drivers/rtc/Kconfig"
+ source "drivers/dma/Kconfig"
++source "drivers/mxc/Kconfig"
++
+ source "drivers/dca/Kconfig"
+ source "drivers/auxdisplay/Kconfig"
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/configs/karo_tx27_defconfig linux-2.6.28-karo/arch/arm/configs/karo_tx27_defconfig
+--- linux-2.6.28/arch/arm/configs/karo_tx27_defconfig  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/configs/karo_tx27_defconfig     2009-03-12 16:52:26.000000000 +0100
+@@ -0,0 +1,1799 @@
++#
++# Automatically generated make config: don't edit
++# Linux kernel version: 2.6.28
++# Thu Mar 12 15:05:31 2009
++#
++CONFIG_ARM=y
++CONFIG_SYS_SUPPORTS_APM_EMULATION=y
++CONFIG_GENERIC_GPIO=y
++CONFIG_GENERIC_TIME=y
++CONFIG_GENERIC_CLOCKEVENTS=y
++CONFIG_MMU=y
++# CONFIG_NO_IOPORT is not set
++CONFIG_GENERIC_HARDIRQS=y
++CONFIG_STACKTRACE_SUPPORT=y
++CONFIG_HAVE_LATENCYTOP_SUPPORT=y
++CONFIG_LOCKDEP_SUPPORT=y
++CONFIG_TRACE_IRQFLAGS_SUPPORT=y
++CONFIG_HARDIRQS_SW_RESEND=y
++CONFIG_GENERIC_IRQ_PROBE=y
++CONFIG_RWSEM_GENERIC_SPINLOCK=y
++# CONFIG_ARCH_HAS_ILOG2_U32 is not set
++# CONFIG_ARCH_HAS_ILOG2_U64 is not set
++CONFIG_GENERIC_HWEIGHT=y
++CONFIG_GENERIC_CALIBRATE_DELAY=y
++CONFIG_ARCH_MTD_XIP=y
++CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
++CONFIG_VECTORS_BASE=0xffff0000
++CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
++
++#
++# General setup
++#
++CONFIG_EXPERIMENTAL=y
++CONFIG_BROKEN_ON_SMP=y
++CONFIG_LOCK_KERNEL=y
++CONFIG_INIT_ENV_ARG_LIMIT=32
++CONFIG_LOCALVERSION=""
++# CONFIG_LOCALVERSION_AUTO is not set
++# CONFIG_SWAP is not set
++CONFIG_SYSVIPC=y
++CONFIG_SYSVIPC_SYSCTL=y
++CONFIG_POSIX_MQUEUE=y
++# CONFIG_BSD_PROCESS_ACCT is not set
++# CONFIG_TASKSTATS is not set
++# CONFIG_AUDIT is not set
++# CONFIG_IKCONFIG is not set
++CONFIG_LOG_BUF_SHIFT=17
++# CONFIG_CGROUPS is not set
++# CONFIG_GROUP_SCHED is not set
++# CONFIG_SYSFS_DEPRECATED_V2 is not set
++# CONFIG_RELAY is not set
++# CONFIG_NAMESPACES is not set
++# CONFIG_BLK_DEV_INITRD is not set
++CONFIG_CC_OPTIMIZE_FOR_SIZE=y
++CONFIG_SYSCTL=y
++CONFIG_EMBEDDED=y
++CONFIG_UID16=y
++CONFIG_SYSCTL_SYSCALL=y
++CONFIG_KALLSYMS=y
++CONFIG_KALLSYMS_ALL=y
++# CONFIG_KALLSYMS_EXTRA_PASS is not set
++CONFIG_HOTPLUG=y
++CONFIG_PRINTK=y
++CONFIG_BUG=y
++# CONFIG_ELF_CORE is not set
++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 is not set
++# CONFIG_VM_EVENT_COUNTERS is not set
++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_KPROBES=y
++CONFIG_HAVE_KRETPROBES=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
++CONFIG_MODULE_UNLOAD=y
++# CONFIG_MODULE_FORCE_UNLOAD is not set
++# CONFIG_MODVERSIONS is not set
++# CONFIG_MODULE_SRCVERSION_ALL is not set
++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
++
++#
++# IO Schedulers
++#
++CONFIG_IOSCHED_NOOP=y
++CONFIG_IOSCHED_AS=y
++CONFIG_IOSCHED_DEADLINE=y
++CONFIG_IOSCHED_CFQ=y
++# CONFIG_DEFAULT_AS is not set
++# CONFIG_DEFAULT_DEADLINE is not set
++CONFIG_DEFAULT_CFQ=y
++# CONFIG_DEFAULT_NOOP is not set
++CONFIG_DEFAULT_IOSCHED="cfq"
++CONFIG_CLASSIC_RCU=y
++CONFIG_FREEZER=y
++
++#
++# System Type
++#
++# CONFIG_ARCH_AAEC2000 is not set
++# CONFIG_ARCH_INTEGRATOR is not set
++# 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
++# CONFIG_ARCH_FOOTBRIDGE is not set
++# CONFIG_ARCH_NETX is not set
++# CONFIG_ARCH_H720X is not set
++# CONFIG_ARCH_IMX is not set
++# CONFIG_ARCH_IOP13XX is not set
++# CONFIG_ARCH_IOP32X is not set
++# CONFIG_ARCH_IOP33X is not set
++# CONFIG_ARCH_IXP23XX is not set
++# CONFIG_ARCH_IXP2000 is not set
++# CONFIG_ARCH_IXP4XX is not set
++# CONFIG_ARCH_L7200 is not set
++# CONFIG_ARCH_KIRKWOOD is not set
++# CONFIG_ARCH_KS8695 is not set
++# CONFIG_ARCH_NS9XXX is not set
++# CONFIG_ARCH_LOKI is not set
++# CONFIG_ARCH_MV78XX0 is not set
++CONFIG_ARCH_MXC=y
++# CONFIG_ARCH_ORION5X is not set
++# CONFIG_ARCH_PNX4008 is not set
++# CONFIG_ARCH_PXA is not set
++# CONFIG_ARCH_RPC is not set
++# CONFIG_ARCH_SA1100 is not set
++# CONFIG_ARCH_S3C2410 is not set
++# CONFIG_ARCH_SHARK is not set
++# CONFIG_ARCH_LH7A40X is not set
++# CONFIG_ARCH_DAVINCI is not set
++# CONFIG_ARCH_OMAP is not set
++# CONFIG_ARCH_MSM is not set
++
++#
++# Boot options
++#
++
++#
++# Power management
++#
++
++#
++# Freescale MXC Implementations
++#
++CONFIG_ARCH_MX2=y
++# CONFIG_ARCH_MX3 is not set
++
++#
++# MX2 family CPU support
++#
++CONFIG_MACH_MX27=y
++
++#
++# MX2 Platforms
++#
++# CONFIG_MACH_MX27ADS is not set
++# CONFIG_MACH_PCM038 is not set
++CONFIG_MACH_TX27=y
++CONFIG_BASE_CLK_26MHz=y
++# CONFIG_KARO_DEBUG is not set
++CONFIG_MXC_EMMA=y
++# CONFIG_MXC_IRQ_PRIOR is not set
++CONFIG_MXC_ULPI=y
++
++#
++# Processor Type
++#
++CONFIG_CPU_32=y
++CONFIG_CPU_ARM926T=y
++CONFIG_CPU_32v5=y
++CONFIG_CPU_ABRT_EV5TJ=y
++CONFIG_CPU_PABRT_NOIFAR=y
++CONFIG_CPU_CACHE_VIVT=y
++CONFIG_CPU_COPY_V4WB=y
++CONFIG_CPU_TLB_V4WBI=y
++CONFIG_CPU_CP15=y
++CONFIG_CPU_CP15_MMU=y
++
++#
++# Processor Features
++#
++CONFIG_ARM_THUMB=y
++# CONFIG_CPU_ICACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_DISABLE is not set
++# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
++# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
++# CONFIG_OUTER_CACHE is not set
++
++#
++# Bus support
++#
++# CONFIG_PCI_SYSCALL is not set
++# CONFIG_ARCH_SUPPORTS_MSI is not set
++# CONFIG_PCCARD is not set
++
++#
++# Kernel Features
++#
++CONFIG_TICK_ONESHOT=y
++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=y
++CONFIG_HZ=100
++CONFIG_AEABI=y
++CONFIG_OABI_COMPAT=y
++CONFIG_ARCH_FLATMEM_HAS_HOLES=y
++# 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_PAGEFLAGS_EXTENDED=y
++CONFIG_SPLIT_PTLOCK_CPUS=4096
++# CONFIG_RESOURCES_64BIT is not set
++# CONFIG_PHYS_ADDR_T_64BIT is not set
++CONFIG_ZONE_DMA_FLAG=0
++CONFIG_VIRT_TO_BUS=y
++CONFIG_UNEVICTABLE_LRU=y
++CONFIG_ALIGNMENT_TRAP=y
++
++#
++# Boot options
++#
++CONFIG_ZBOOT_ROM_TEXT=0x0
++CONFIG_ZBOOT_ROM_BSS=0x0
++CONFIG_CMDLINE="root=/dev/mtdblock1 rootfstype=jffs2 console=ttymxc0,115200 ro panic=5"
++# CONFIG_XIP_KERNEL is not set
++# CONFIG_KEXEC is not set
++
++#
++# CPU Power Management
++#
++# CONFIG_CPU_IDLE is not set
++
++#
++# Floating point emulation
++#
++
++#
++# At least one emulation must be selected
++#
++CONFIG_FPE_NWFPE=y
++# CONFIG_FPE_NWFPE_XP is not set
++# CONFIG_FPE_FASTFPE is not set
++# CONFIG_VFP is not set
++
++#
++# 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 is not set
++
++#
++# Power management options
++#
++CONFIG_PM=y
++# CONFIG_PM_DEBUG is not set
++CONFIG_PM_SLEEP=y
++CONFIG_SUSPEND=y
++CONFIG_SUSPEND_FREEZER=y
++CONFIG_APM_EMULATION=y
++CONFIG_ARCH_SUSPEND_POSSIBLE=y
++CONFIG_NET=y
++
++#
++# Networking options
++#
++CONFIG_PACKET=y
++CONFIG_PACKET_MMAP=y
++CONFIG_UNIX=y
++# CONFIG_NET_KEY is not set
++CONFIG_INET=y
++CONFIG_IP_MULTICAST=y
++# CONFIG_IP_ADVANCED_ROUTER is not set
++CONFIG_IP_FIB_HASH=y
++CONFIG_IP_PNP=y
++CONFIG_IP_PNP_DHCP=y
++CONFIG_IP_PNP_BOOTP=y
++# CONFIG_IP_PNP_RARP is not set
++# 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
++# CONFIG_INET_ESP is not set
++# CONFIG_INET_IPCOMP is not set
++# CONFIG_INET_XFRM_TUNNEL is not set
++# CONFIG_INET_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
++# CONFIG_INET_XFRM_MODE_TUNNEL is not set
++# CONFIG_INET_XFRM_MODE_BEET is not set
++# CONFIG_INET_LRO is not set
++CONFIG_INET_DIAG=y
++CONFIG_INET_TCP_DIAG=y
++# CONFIG_TCP_CONG_ADVANCED is not set
++CONFIG_TCP_CONG_CUBIC=y
++CONFIG_DEFAULT_TCP_CONG="cubic"
++# CONFIG_TCP_MD5SIG is not set
++# CONFIG_IPV6 is not set
++# CONFIG_NETWORK_SECMARK is not set
++# CONFIG_NETFILTER is not set
++# CONFIG_IP_DCCP is not set
++# CONFIG_IP_SCTP is not set
++# 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
++# CONFIG_IPX is not set
++# CONFIG_ATALK is not set
++# CONFIG_X25 is not set
++# CONFIG_LAPB is not set
++# CONFIG_ECONET is not set
++# CONFIG_WAN_ROUTER is not set
++# CONFIG_NET_SCHED is not set
++
++#
++# Network testing
++#
++# CONFIG_NET_PKTGEN is not set
++# CONFIG_HAMRADIO is not set
++# CONFIG_CAN is not set
++# CONFIG_IRDA is not set
++# CONFIG_BT is not set
++# CONFIG_AF_RXRPC is not set
++# CONFIG_PHONET is not set
++CONFIG_WIRELESS=y
++CONFIG_CFG80211=m
++CONFIG_NL80211=y
++CONFIG_WIRELESS_OLD_REGULATORY=y
++CONFIG_WIRELESS_EXT=y
++CONFIG_WIRELESS_EXT_SYSFS=y
++CONFIG_MAC80211=m
++
++#
++# Rate control algorithm selection
++#
++CONFIG_MAC80211_RC_PID=y
++# CONFIG_MAC80211_RC_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT_PID=y
++# CONFIG_MAC80211_RC_DEFAULT_MINSTREL is not set
++CONFIG_MAC80211_RC_DEFAULT="pid"
++# CONFIG_MAC80211_MESH is not set
++# CONFIG_MAC80211_LEDS is not set
++# CONFIG_MAC80211_DEBUG_MENU is not set
++CONFIG_IEEE80211=m
++# CONFIG_IEEE80211_DEBUG is not set
++CONFIG_IEEE80211_CRYPT_WEP=m
++CONFIG_IEEE80211_CRYPT_CCMP=m
++CONFIG_IEEE80211_CRYPT_TKIP=m
++# CONFIG_RFKILL is not set
++# CONFIG_NET_9P is not set
++
++#
++# Device Drivers
++#
++
++#
++# Generic Driver Options
++#
++CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
++CONFIG_STANDALONE=y
++CONFIG_PREVENT_FIRMWARE_BUILD=y
++CONFIG_FW_LOADER=m
++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 is not set
++# CONFIG_MTD_CONCAT is not set
++CONFIG_MTD_PARTITIONS=y
++CONFIG_MTD_REDBOOT_PARTS=y
++CONFIG_MTD_REDBOOT_DIRECTORY_BLOCK=-5
++CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED=y
++CONFIG_MTD_REDBOOT_PARTS_READONLY=y
++CONFIG_MTD_CMDLINE_PARTS=y
++# CONFIG_MTD_AFS_PARTS is not set
++# CONFIG_MTD_AR7_PARTS is not set
++
++#
++# User Modules And Translation Layers
++#
++CONFIG_MTD_CHAR=y
++CONFIG_MTD_BLKDEVS=y
++CONFIG_MTD_BLOCK=y
++# CONFIG_FTL is not set
++# CONFIG_NFTL is not set
++# CONFIG_INFTL is not set
++# CONFIG_RFD_FTL is not set
++# CONFIG_SSFDC is not set
++# CONFIG_MTD_OOPS is not set
++
++#
++# RAM/ROM/Flash chip drivers
++#
++# CONFIG_MTD_CFI is not set
++# CONFIG_MTD_JEDECPROBE is not set
++CONFIG_MTD_MAP_BANK_WIDTH_1=y
++CONFIG_MTD_MAP_BANK_WIDTH_2=y
++CONFIG_MTD_MAP_BANK_WIDTH_4=y
++# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
++# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
++CONFIG_MTD_CFI_I1=y
++CONFIG_MTD_CFI_I2=y
++# CONFIG_MTD_CFI_I4 is not set
++# CONFIG_MTD_CFI_I8 is not set
++# CONFIG_MTD_RAM is not set
++# CONFIG_MTD_ROM is not set
++# CONFIG_MTD_ABSENT is not set
++
++#
++# Mapping drivers for chip access
++#
++# CONFIG_MTD_COMPLEX_MAPPINGS is not set
++# CONFIG_MTD_PLATRAM is not set
++
++#
++# Self-contained MTD device drivers
++#
++# CONFIG_MTD_DATAFLASH is not set
++# CONFIG_MTD_M25P80 is not set
++# CONFIG_MTD_SLRAM is not set
++# CONFIG_MTD_PHRAM is not set
++# CONFIG_MTD_MTDRAM is not set
++# CONFIG_MTD_BLOCK2MTD is not set
++
++#
++# Disk-On-Chip Device Drivers
++#
++# CONFIG_MTD_DOC2000 is not set
++# CONFIG_MTD_DOC2001 is not set
++# 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_MUSEUM_IDS is not set
++# CONFIG_MTD_NAND_GPIO is not set
++CONFIG_MTD_NAND_IDS=y
++# CONFIG_MTD_NAND_DISKONCHIP is not set
++CONFIG_MTD_NAND_MXC_FLASH_BBT=y
++# CONFIG_MTD_NAND_NANDSIM is not set
++# CONFIG_MTD_NAND_PLATFORM is not set
++# CONFIG_MTD_ALAUDA is not set
++CONFIG_MTD_NAND_MXC=y
++# CONFIG_MTD_ONENAND is not set
++
++#
++# UBI - Unsorted block images
++#
++# CONFIG_MTD_UBI is not set
++# CONFIG_PARPORT is not set
++CONFIG_BLK_DEV=y
++# CONFIG_BLK_DEV_COW_COMMON is not set
++CONFIG_BLK_DEV_LOOP=y
++# CONFIG_BLK_DEV_CRYPTOLOOP is not set
++# CONFIG_BLK_DEV_NBD is not set
++# CONFIG_BLK_DEV_UB is not set
++CONFIG_BLK_DEV_RAM=y
++CONFIG_BLK_DEV_RAM_COUNT=16
++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
++CONFIG_MISC_DEVICES=y
++# CONFIG_EEPROM_93CX6 is not set
++# CONFIG_ICS932S401 is not set
++# CONFIG_ENCLOSURE_SERVICES is not set
++# CONFIG_C2PORT is not set
++CONFIG_HAVE_IDE=y
++# CONFIG_IDE is not set
++
++#
++# SCSI device support
++#
++# CONFIG_RAID_ATTRS is not set
++CONFIG_SCSI=m
++CONFIG_SCSI_DMA=y
++# CONFIG_SCSI_TGT is not set
++# CONFIG_SCSI_NETLINK is not set
++CONFIG_SCSI_PROC_FS=y
++
++#
++# SCSI support type (disk, tape, CD-ROM)
++#
++CONFIG_BLK_DEV_SD=m
++# CONFIG_CHR_DEV_ST is not set
++# CONFIG_CHR_DEV_OSST is not set
++# CONFIG_BLK_DEV_SR is not set
++# CONFIG_CHR_DEV_SG is not set
++# CONFIG_CHR_DEV_SCH is not set
++
++#
++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
++#
++CONFIG_SCSI_MULTI_LUN=y
++# CONFIG_SCSI_CONSTANTS is not set
++# CONFIG_SCSI_LOGGING is not set
++# CONFIG_SCSI_SCAN_ASYNC is not set
++CONFIG_SCSI_WAIT_SCAN=m
++
++#
++# SCSI Transports
++#
++# CONFIG_SCSI_SPI_ATTRS is not set
++# CONFIG_SCSI_FC_ATTRS is not set
++# CONFIG_SCSI_ISCSI_ATTRS is not set
++# CONFIG_SCSI_SAS_LIBSAS is not set
++# CONFIG_SCSI_SRP_ATTRS is not set
++CONFIG_SCSI_LOWLEVEL=y
++# CONFIG_ISCSI_TCP 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
++CONFIG_NETDEVICES=y
++# CONFIG_DUMMY is not set
++# CONFIG_BONDING is not set
++# CONFIG_MACVLAN is not set
++# CONFIG_EQUALIZER is not set
++# CONFIG_TUN is not set
++# CONFIG_VETH 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=y
++# CONFIG_BROADCOM_PHY is not set
++# CONFIG_ICPLUS_PHY is not set
++# CONFIG_REALTEK_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 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_FEC=y
++# CONFIG_FEC2 is not set
++# CONFIG_NETDEV_1000 is not set
++# CONFIG_NETDEV_10000 is not set
++
++#
++# Wireless LAN
++#
++# CONFIG_WLAN_PRE80211 is not set
++CONFIG_WLAN_80211=y
++CONFIG_LIBERTAS=m
++CONFIG_LIBERTAS_USB=m
++# CONFIG_LIBERTAS_SDIO is not set
++# CONFIG_LIBERTAS_DEBUG is not set
++# CONFIG_LIBERTAS_THINFIRM is not set
++# CONFIG_USB_ZD1201 is not set
++# CONFIG_USB_NET_RNDIS_WLAN is not set
++# CONFIG_RTL8187 is not set
++# CONFIG_MAC80211_HWSIM is not set
++# CONFIG_P54_COMMON is not set
++# CONFIG_IWLWIFI_LEDS is not set
++# CONFIG_HOSTAP is not set
++# CONFIG_B43 is not set
++# CONFIG_B43LEGACY is not set
++# CONFIG_ZD1211RW is not set
++# CONFIG_RT2X00 is not set
++
++#
++# USB Network Adapters
++#
++# CONFIG_USB_CATC is not set
++# CONFIG_USB_KAWETH is not set
++# CONFIG_USB_PEGASUS is not set
++# CONFIG_USB_RTL8150 is not set
++CONFIG_USB_USBNET=m
++# CONFIG_USB_NET_AX8817X is not set
++CONFIG_USB_NET_CDCETHER=m
++# CONFIG_USB_NET_DM9601 is not set
++# CONFIG_USB_NET_SMSC95XX is not set
++# CONFIG_USB_NET_GL620A is not set
++# CONFIG_USB_NET_NET1080 is not set
++# CONFIG_USB_NET_PLUSB is not set
++# CONFIG_USB_NET_MCS7830 is not set
++CONFIG_USB_NET_RNDIS_HOST=m
++CONFIG_USB_NET_CDC_SUBSET=m
++# CONFIG_USB_ALI_M5632 is not set
++# CONFIG_USB_AN2720 is not set
++# CONFIG_USB_BELKIN is not set
++CONFIG_USB_ARMLINUX=y
++# CONFIG_USB_EPSON2888 is not set
++# CONFIG_USB_KC2190 is not set
++# CONFIG_USB_NET_ZAURUS is not set
++# CONFIG_WAN is not set
++# CONFIG_PPP is not set
++# CONFIG_SLIP is not set
++# CONFIG_NETCONSOLE is not set
++# CONFIG_NETPOLL is not set
++# CONFIG_NET_POLL_CONTROLLER is not set
++# CONFIG_ISDN is not set
++
++#
++# Input device support
++#
++CONFIG_INPUT=y
++# CONFIG_INPUT_FF_MEMLESS is not set
++# CONFIG_INPUT_POLLDEV is not set
++
++#
++# Userland interfaces
++#
++# CONFIG_INPUT_MOUSEDEV is not set
++# CONFIG_INPUT_JOYDEV is not set
++CONFIG_INPUT_EVDEV=y
++CONFIG_INPUT_EVBUG=m
++# CONFIG_INPUT_APMPOWER is not set
++
++#
++# Input Device Drivers
++#
++CONFIG_INPUT_KEYBOARD=y
++# CONFIG_KEYBOARD_ATKBD is not set
++# CONFIG_KEYBOARD_SUNKBD is not set
++# CONFIG_KEYBOARD_LKKBD is not set
++# CONFIG_KEYBOARD_XTKBD is not set
++# CONFIG_KEYBOARD_NEWTON is not set
++# CONFIG_KEYBOARD_STOWAWAY is not set
++CONFIG_KEYBOARD_GPIO=m
++# 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_FUJITSU is not set
++# CONFIG_TOUCHSCREEN_GUNZE is not set
++# CONFIG_TOUCHSCREEN_ELO 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_TOUCHRIGHT is not set
++# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
++CONFIG_TOUCHSCREEN_USB_COMPOSITE=m
++CONFIG_TOUCHSCREEN_USB_EGALAX=y
++# CONFIG_TOUCHSCREEN_USB_PANJIT is not set
++# CONFIG_TOUCHSCREEN_USB_3M is not set
++# CONFIG_TOUCHSCREEN_USB_ITM is not set
++# CONFIG_TOUCHSCREEN_USB_ETURBO is not set
++# CONFIG_TOUCHSCREEN_USB_GUNZE is not set
++# CONFIG_TOUCHSCREEN_USB_DMC_TSC10 is not set
++CONFIG_TOUCHSCREEN_USB_IRTOUCH=y
++CONFIG_TOUCHSCREEN_USB_IDEALTEK=y
++CONFIG_TOUCHSCREEN_USB_GENERAL_TOUCH=y
++CONFIG_TOUCHSCREEN_USB_GOTOP=y
++# CONFIG_TOUCHSCREEN_TOUCHIT213 is not set
++# CONFIG_INPUT_MISC is not set
++
++#
++# Hardware I/O ports
++#
++# CONFIG_SERIO is not set
++# CONFIG_GAMEPORT is not set
++
++#
++# Character devices
++#
++CONFIG_VT=y
++# CONFIG_CONSOLE_TRANSLATIONS is not set
++CONFIG_VT_CONSOLE=y
++CONFIG_HW_CONSOLE=y
++CONFIG_VT_HW_CONSOLE_BINDING=y
++# CONFIG_DEVKMEM is not set
++# CONFIG_SERIAL_NONSTANDARD is not set
++
++#
++# Serial drivers
++#
++# CONFIG_SERIAL_8250 is not set
++
++#
++# Non-8250 serial port support
++#
++CONFIG_SERIAL_IMX=y
++CONFIG_SERIAL_IMX_CONSOLE=y
++CONFIG_SERIAL_CORE=y
++CONFIG_SERIAL_CORE_CONSOLE=y
++CONFIG_UNIX98_PTYS=y
++CONFIG_LEGACY_PTYS=y
++CONFIG_LEGACY_PTY_COUNT=16
++# CONFIG_IPMI_HANDLER is not set
++# CONFIG_HW_RANDOM is not set
++# CONFIG_NVRAM is not set
++# CONFIG_R3964 is not set
++# CONFIG_RAW_DRIVER is not set
++# CONFIG_TCG_TPM is not set
++CONFIG_I2C=y
++CONFIG_I2C_BOARDINFO=y
++CONFIG_I2C_CHARDEV=m
++CONFIG_I2C_HELPER_AUTO=y
++CONFIG_I2C_ALGOBIT=m
++
++#
++# I2C Hardware Bus support
++#
++
++#
++# I2C system bus drivers (mostly embedded / system-on-chip)
++#
++CONFIG_I2C_GPIO=m
++CONFIG_I2C_MXC=y
++# CONFIG_I2C_OCORES is not set
++# CONFIG_I2C_SIMTEC is not set
++
++#
++# External I2C/SMBus adapter drivers
++#
++# CONFIG_I2C_PARPORT_LIGHT is not set
++# CONFIG_I2C_TAOS_EVM is not set
++# CONFIG_I2C_TINY_USB is not set
++
++#
++# Other I2C/SMBus bus drivers
++#
++# CONFIG_I2C_PCA_PLATFORM is not set
++# CONFIG_I2C_STUB is not set
++
++#
++# Miscellaneous I2C Chip support
++#
++# CONFIG_DS1682 is not set
++CONFIG_AT24=m
++# 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_TPS65010 is not set
++# CONFIG_SENSORS_MAX6875 is not set
++# CONFIG_SENSORS_TSL2550 is not set
++# CONFIG_I2C_DEBUG_CORE is not set
++# CONFIG_I2C_DEBUG_ALGO is not set
++# CONFIG_I2C_DEBUG_BUS is not set
++# CONFIG_I2C_DEBUG_CHIP is not set
++CONFIG_SPI=y
++# CONFIG_SPI_DEBUG is not set
++CONFIG_SPI_MASTER=y
++
++#
++# SPI Master Controller Drivers
++#
++CONFIG_SPI_BITBANG=m
++CONFIG_SPI_MXC=m
++# CONFIG_SPI_MXC_TEST_LOOPBACK is not set
++CONFIG_SPI_MXC_SELECT1=y
++# CONFIG_SPI_MXC_SELECT2 is not set
++# CONFIG_SPI_MXC_SELECT3 is not set
++CONFIG_SPI_MXC_REV0=y
++# CONFIG_SPI_MXC_REV4 is not set
++# CONFIG_SPI_MXC_REV5 is not set
++# CONFIG_SPI_MXC_REV7 is not set
++
++#
++# SPI Protocol Masters
++#
++CONFIG_SPI_AT25=m
++CONFIG_SPI_SPIDEV=m
++# CONFIG_SPI_TLE62X0 is not set
++CONFIG_ARCH_REQUIRE_GPIOLIB=y
++CONFIG_GPIOLIB=y
++# CONFIG_DEBUG_GPIO is not set
++CONFIG_GPIO_SYSFS=y
++
++#
++# Memory mapped GPIO expanders:
++#
++
++#
++# I2C GPIO expanders:
++#
++# CONFIG_GPIO_MAX732X is not set
++# CONFIG_GPIO_PCA953X is not set
++# CONFIG_GPIO_PCF857X is not set
++
++#
++# PCI GPIO expanders:
++#
++
++#
++# SPI GPIO expanders:
++#
++# CONFIG_GPIO_MAX7301 is not set
++# CONFIG_GPIO_MCP23S08 is not set
++CONFIG_W1=m
++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_MXC=m
++# CONFIG_W1_MASTER_GPIO is not set
++
++#
++# 1-wire Slaves
++#
++# CONFIG_W1_SLAVE_THERM is not set
++CONFIG_W1_SLAVE_SMEM=m
++CONFIG_W1_SLAVE_DS2433=m
++CONFIG_W1_SLAVE_DS2433_CRC=y
++# CONFIG_W1_SLAVE_DS2760 is not set
++# CONFIG_W1_SLAVE_BQ27000 is not set
++CONFIG_POWER_SUPPLY=m
++# CONFIG_POWER_SUPPLY_DEBUG is not set
++# CONFIG_PDA_POWER is not set
++# CONFIG_APM_POWER is not set
++# CONFIG_BATTERY_DS2760 is not set
++# CONFIG_BATTERY_BQ27x00 is not set
++CONFIG_LP3972=m
++CONFIG_HWMON=m
++# CONFIG_HWMON_VID is not set
++# CONFIG_SENSORS_AD7414 is not set
++# CONFIG_SENSORS_AD7418 is not set
++# CONFIG_SENSORS_ADCXX is not set
++# CONFIG_SENSORS_ADM1021 is not set
++# CONFIG_SENSORS_ADM1025 is not set
++# CONFIG_SENSORS_ADM1026 is not set
++# CONFIG_SENSORS_ADM1029 is not set
++# CONFIG_SENSORS_ADM1031 is not set
++# CONFIG_SENSORS_ADM9240 is not set
++# CONFIG_SENSORS_ADT7462 is not set
++# CONFIG_SENSORS_ADT7470 is not set
++# CONFIG_SENSORS_ADT7473 is not set
++# CONFIG_SENSORS_ATXP1 is not set
++# CONFIG_SENSORS_DS1621 is not set
++# CONFIG_SENSORS_F71805F is not set
++# CONFIG_SENSORS_F71882FG is not set
++# CONFIG_SENSORS_F75375S is not set
++# CONFIG_SENSORS_GL518SM is not set
++# CONFIG_SENSORS_GL520SM is not set
++# CONFIG_SENSORS_IT87 is not set
++# CONFIG_SENSORS_LM63 is not set
++# CONFIG_SENSORS_LM70 is not set
++# CONFIG_SENSORS_LM75 is not set
++CONFIG_SENSORS_LM77=m
++# CONFIG_SENSORS_LM78 is not set
++# CONFIG_SENSORS_LM80 is not set
++# CONFIG_SENSORS_LM83 is not set
++# CONFIG_SENSORS_LM85 is not set
++# CONFIG_SENSORS_LM87 is not set
++# CONFIG_SENSORS_LM90 is not set
++# CONFIG_SENSORS_LM92 is not set
++# CONFIG_SENSORS_LM93 is not set
++# CONFIG_SENSORS_MAX1111 is not set
++# CONFIG_SENSORS_MAX1619 is not set
++# CONFIG_SENSORS_MAX6650 is not set
++# CONFIG_SENSORS_PC87360 is not set
++# CONFIG_SENSORS_PC87427 is not set
++# CONFIG_SENSORS_DME1737 is not set
++# CONFIG_SENSORS_SMSC47M1 is not set
++# CONFIG_SENSORS_SMSC47M192 is not set
++# CONFIG_SENSORS_SMSC47B397 is not set
++# CONFIG_SENSORS_ADS7828 is not set
++# CONFIG_SENSORS_THMC50 is not set
++# CONFIG_SENSORS_VT1211 is not set
++# CONFIG_SENSORS_W83781D is not set
++# CONFIG_SENSORS_W83791D is not set
++# CONFIG_SENSORS_W83792D is not set
++# CONFIG_SENSORS_W83793 is not set
++# CONFIG_SENSORS_W83L785TS is not set
++# CONFIG_SENSORS_W83L786NG is not set
++# CONFIG_SENSORS_W83627HF is not set
++# CONFIG_SENSORS_W83627EHF is not set
++# CONFIG_HWMON_DEBUG_CHIP is not set
++# CONFIG_THERMAL is not set
++CONFIG_WATCHDOG=y
++CONFIG_WATCHDOG_NOWAYOUT=y
++
++#
++# Watchdog Device Drivers
++#
++# CONFIG_SOFT_WATCHDOG is not set
++
++#
++# USB-based Watchdog Cards
++#
++# CONFIG_USBPCWATCHDOG is not set
++CONFIG_SSB_POSSIBLE=y
++
++#
++# Sonics Silicon Backplane
++#
++# CONFIG_SSB is not set
++
++#
++# Multifunction device drivers
++#
++# CONFIG_MFD_CORE is not set
++# CONFIG_MFD_SM501 is not set
++# CONFIG_MFD_ASIC3 is not set
++# CONFIG_HTC_EGPIO is not set
++# CONFIG_HTC_PASIC3 is not set
++# CONFIG_MFD_TMIO 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
++
++#
++# Multimedia devices
++#
++
++#
++# Multimedia core support
++#
++CONFIG_VIDEO_DEV=m
++CONFIG_VIDEO_V4L2_COMMON=m
++# CONFIG_VIDEO_ALLOW_V4L1 is not set
++# CONFIG_VIDEO_V4L1_COMPAT is not set
++# CONFIG_DVB_CORE is not set
++CONFIG_VIDEO_MEDIA=m
++
++#
++# Multimedia drivers
++#
++# CONFIG_MEDIA_ATTACH is not set
++CONFIG_MEDIA_TUNER=m
++CONFIG_MEDIA_TUNER_CUSTOMIZE=y
++# CONFIG_MEDIA_TUNER_SIMPLE is not set
++# CONFIG_MEDIA_TUNER_TDA8290 is not set
++# CONFIG_MEDIA_TUNER_TDA827X is not set
++# CONFIG_MEDIA_TUNER_TDA18271 is not set
++# CONFIG_MEDIA_TUNER_TDA9887 is not set
++# CONFIG_MEDIA_TUNER_TEA5761 is not set
++# CONFIG_MEDIA_TUNER_TEA5767 is not set
++# CONFIG_MEDIA_TUNER_MT20XX is not set
++# CONFIG_MEDIA_TUNER_MT2060 is not set
++# CONFIG_MEDIA_TUNER_MT2266 is not set
++# CONFIG_MEDIA_TUNER_MT2131 is not set
++# CONFIG_MEDIA_TUNER_QT1010 is not set
++# CONFIG_MEDIA_TUNER_XC2028 is not set
++# CONFIG_MEDIA_TUNER_XC5000 is not set
++# CONFIG_MEDIA_TUNER_MXL5005S is not set
++# CONFIG_MEDIA_TUNER_MXL5007T is not set
++CONFIG_VIDEO_V4L2=m
++CONFIG_VIDEOBUF_GEN=m
++CONFIG_VIDEOBUF_DMA_CONTIG=m
++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_OV7670 is not set
++# CONFIG_VIDEO_TCM825X is not set
++# CONFIG_VIDEO_SAA711X is not set
++# CONFIG_VIDEO_SAA717X is not set
++# CONFIG_VIDEO_TVP5150 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
++
++#
++# Video improvement chips
++#
++# CONFIG_VIDEO_UPD64031A is not set
++# CONFIG_VIDEO_UPD64083 is not set
++# CONFIG_VIDEO_VIVI is not set
++CONFIG_VIDEO_MXC_CAMERA=m
++
++#
++# MXC Camera/V4L2 PRP Features support
++#
++# CONFIG_MXC_CAMERA_MICRON111 is not set
++# CONFIG_MXC_CAMERA_MC521DA is not set
++# CONFIG_MXC_CAMERA_OV2640 is not set
++CONFIG_VIDEO_MXC_OUTPUT=m
++# CONFIG_VIDEO_MXC_OUTPUT_DEBUG is not set
++CONFIG_VIDEO_MXC_EMMA_OUTPUT=m
++# CONFIG_VIDEO_MXC_OPL is not set
++# CONFIG_VIDEO_SAA5246A is not set
++# CONFIG_VIDEO_SAA5249 is not set
++CONFIG_SOC_CAMERA=m
++# CONFIG_SOC_CAMERA_MT9M001 is not set
++# CONFIG_SOC_CAMERA_MT9M111 is not set
++# CONFIG_SOC_CAMERA_MT9V022 is not set
++CONFIG_SOC_CAMERA_PLATFORM=m
++# CONFIG_VIDEO_SH_MOBILE_CEU is not set
++# CONFIG_V4L_USB_DRIVERS is not set
++CONFIG_VIDEO_MX27=m
++# 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=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 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_IMX=y
++# 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_BACKLIGHT_LCD_SUPPORT is not set
++
++#
++# Display device support
++#
++# CONFIG_DISPLAY_SUPPORT is not set
++
++#
++# Console display driver support
++#
++# 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=y
++# 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 is not set
++CONFIG_HID_SUPPORT=y
++CONFIG_HID=m
++# CONFIG_HID_DEBUG is not set
++# CONFIG_HIDRAW is not set
++
++#
++# USB Input Devices
++#
++CONFIG_USB_HID=m
++# CONFIG_HID_PID is not set
++# CONFIG_USB_HIDDEV is not set
++
++#
++# USB HID Boot Protocol drivers
++#
++# CONFIG_USB_KBD is not set
++# CONFIG_USB_MOUSE is not set
++
++#
++# Special HID drivers
++#
++# CONFIG_HID_COMPAT is not set
++# CONFIG_HID_A4TECH is not set
++# CONFIG_HID_APPLE is not set
++# CONFIG_HID_BELKIN is not set
++# CONFIG_HID_BRIGHT is not set
++# CONFIG_HID_CHERRY is not set
++# CONFIG_HID_CHICONY is not set
++# CONFIG_HID_CYPRESS is not set
++# CONFIG_HID_DELL 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_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_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 is not set
++CONFIG_USB_ARCH_HAS_EHCI=y
++CONFIG_USB=m
++# CONFIG_USB_DEBUG is not set
++# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
++
++#
++# Miscellaneous USB options
++#
++CONFIG_USB_DEVICEFS=y
++CONFIG_USB_DEVICE_CLASS=y
++# CONFIG_USB_DYNAMIC_MINORS is not set
++CONFIG_USB_SUSPEND=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 is not set
++# CONFIG_USB_WUSB is not set
++# CONFIG_USB_WUSB_CBAF is not set
++
++#
++# USB Host Controller Drivers
++#
++# CONFIG_USB_C67X00_HCD is not set
++CONFIG_USB_EHCI_HCD=m
++CONFIG_USB_EHCI_ROOT_HUB_TT=y
++# CONFIG_USB_EHCI_TT_NEWSCHED is not set
++CONFIG_USB_EHCI_MXC=y
++# CONFIG_USB_ISP116X_HCD is not set
++# CONFIG_USB_SL811_HCD is not set
++# CONFIG_USB_R8A66597_HCD is not set
++# CONFIG_USB_HWA_HCD is not set
++
++#
++# Enable Host or Gadget support to see Inventra options
++#
++
++#
++# USB Device Class drivers
++#
++# 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 depends on SCSI but BLK_DEV_SD may also be needed;
++#
++
++#
++# see USB_STORAGE Help for more information
++#
++CONFIG_USB_STORAGE=m
++# CONFIG_USB_STORAGE_DEBUG is not set
++# 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
++# 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
++
++#
++# USB Imaging devices
++#
++# CONFIG_USB_MDC800 is not set
++# CONFIG_USB_MICROTEK is not set
++
++#
++# USB port drivers
++#
++CONFIG_USB_SERIAL=m
++# CONFIG_USB_EZUSB is not set
++CONFIG_USB_SERIAL_GENERIC=y
++# CONFIG_USB_SERIAL_AIRCABLE is not set
++# CONFIG_USB_SERIAL_ARK3116 is not set
++CONFIG_USB_SERIAL_BELKIN=m
++# 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 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=m
++# 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_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_DEBUG is not set
++
++#
++# USB Miscellaneous drivers
++#
++# 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
++# CONFIG_USB_BERRY_CHARGE is not set
++# CONFIG_USB_LED is not set
++# CONFIG_USB_CYPRESS_CY7C63 is not set
++# CONFIG_USB_CYTHERM is not set
++# CONFIG_USB_PHIDGET is not set
++# 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=m
++# CONFIG_USB_ISIGHTFW is not set
++# CONFIG_USB_VST is not set
++# CONFIG_USB_GADGET is not set
++CONFIG_MMC=m
++# CONFIG_MMC_DEBUG is not set
++# CONFIG_MMC_UNSAFE_RESUME is not set
++
++#
++# MMC/SD/SDIO Card Drivers
++#
++CONFIG_MMC_BLOCK=m
++CONFIG_MMC_BLOCK_BOUNCE=y
++# CONFIG_SDIO_UART is not set
++# CONFIG_MMC_TEST is not set
++
++#
++# MMC/SD/SDIO Host Controller Drivers
++#
++# CONFIG_MMC_SDHCI is not set
++CONFIG_MMC_MXC=m
++# CONFIG_MMC_SPI is not set
++# CONFIG_MEMSTICK is not set
++# CONFIG_ACCESSIBILITY is not set
++CONFIG_NEW_LEDS=y
++CONFIG_LEDS_CLASS=y
++
++#
++# LED drivers
++#
++# CONFIG_LEDS_PCA9532 is not set
++CONFIG_LEDS_GPIO=y
++# CONFIG_LEDS_PCA955X is not set
++
++#
++# LED Triggers
++#
++CONFIG_LEDS_TRIGGERS=y
++CONFIG_LEDS_TRIGGER_TIMER=m
++CONFIG_LEDS_TRIGGER_HEARTBEAT=y
++# CONFIG_LEDS_TRIGGER_BACKLIGHT is not set
++# CONFIG_LEDS_TRIGGER_DEFAULT_ON is not set
++CONFIG_RTC_LIB=y
++CONFIG_RTC_CLASS=y
++CONFIG_RTC_HCTOSYS=y
++CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
++# CONFIG_RTC_DEBUG is not set
++
++#
++# RTC interfaces
++#
++CONFIG_RTC_INTF_SYSFS=y
++CONFIG_RTC_INTF_PROC=y
++CONFIG_RTC_INTF_DEV=y
++# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
++# CONFIG_RTC_DRV_TEST is not set
++
++#
++# I2C RTC drivers
++#
++# CONFIG_RTC_DRV_DS1307 is not set
++CONFIG_RTC_DRV_DS13XX=y
++# CONFIG_RTC_DRV_DS1374 is not set
++# CONFIG_RTC_DRV_DS1672 is not set
++# CONFIG_RTC_DRV_MAX6900 is not set
++# CONFIG_RTC_DRV_RS5C372 is not set
++# CONFIG_RTC_DRV_ISL1208 is not set
++# CONFIG_RTC_DRV_X1205 is not set
++# CONFIG_RTC_DRV_PCF8563 is not set
++# CONFIG_RTC_DRV_PCF8583 is not set
++# CONFIG_RTC_DRV_M41T80 is not set
++# 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_RTC_MXC=y
++# CONFIG_DMADEVICES is not set
++CONFIG_DRIVERS_MXC=y
++
++#
++# MXC VPU(Video Processing Unit) support
++#
++CONFIG_MXC_VPU=m
++# CONFIG_MXC_VPU_DEBUG is not set
++# CONFIG_REGULATOR is not set
++# CONFIG_UIO is not set
++
++#
++# File systems
++#
++CONFIG_EXT2_FS=y
++# CONFIG_EXT2_FS_XATTR is not set
++# CONFIG_EXT2_FS_XIP is not set
++CONFIG_EXT3_FS=m
++CONFIG_EXT3_FS_XATTR=y
++# CONFIG_EXT3_FS_POSIX_ACL is not set
++# CONFIG_EXT3_FS_SECURITY is not set
++# CONFIG_EXT4_FS is not set
++CONFIG_JBD=m
++CONFIG_FS_MBCACHE=m
++# 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_DNOTIFY=y
++CONFIG_INOTIFY=y
++CONFIG_INOTIFY_USER=y
++# CONFIG_QUOTA is not set
++# CONFIG_AUTOFS_FS is not set
++CONFIG_AUTOFS4_FS=m
++# CONFIG_FUSE_FS is not set
++
++#
++# CD-ROM/DVD Filesystems
++#
++# CONFIG_ISO9660_FS is not set
++# CONFIG_UDF_FS is not set
++
++#
++# DOS/FAT/NT Filesystems
++#
++CONFIG_FAT_FS=m
++CONFIG_MSDOS_FS=m
++CONFIG_VFAT_FS=m
++CONFIG_FAT_DEFAULT_CODEPAGE=437
++CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
++# CONFIG_NTFS_FS is not set
++
++#
++# Pseudo filesystems
++#
++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=m
++
++#
++# Miscellaneous filesystems
++#
++# CONFIG_ADFS_FS is not set
++# CONFIG_AFFS_FS is not set
++# CONFIG_HFS_FS is not set
++# CONFIG_HFSPLUS_FS is not set
++# CONFIG_BEFS_FS is not set
++# CONFIG_BFS_FS is not set
++# CONFIG_EFS_FS is not set
++CONFIG_JFFS2_FS=y
++CONFIG_JFFS2_FS_DEBUG=0
++CONFIG_JFFS2_FS_WRITEBUFFER=y
++# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
++CONFIG_JFFS2_SUMMARY=y
++# CONFIG_JFFS2_FS_XATTR is not set
++# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
++CONFIG_JFFS2_ZLIB=y
++# CONFIG_JFFS2_LZO is not set
++CONFIG_JFFS2_RTIME=y
++# CONFIG_JFFS2_RUBIN is not set
++CONFIG_CRAMFS=y
++# CONFIG_VXFS_FS is not set
++# CONFIG_MINIX_FS is not set
++# CONFIG_OMFS_FS is not set
++# CONFIG_HPFS_FS is not set
++# CONFIG_QNX4FS_FS is not set
++# CONFIG_ROMFS_FS is not set
++# CONFIG_SYSV_FS is not set
++# CONFIG_UFS_FS is not set
++CONFIG_NETWORK_FILESYSTEMS=y
++CONFIG_NFS_FS=y
++CONFIG_NFS_V3=y
++# CONFIG_NFS_V3_ACL is not set
++# CONFIG_NFS_V4 is not set
++CONFIG_ROOT_NFS=y
++# CONFIG_NFSD is not set
++CONFIG_LOCKD=y
++CONFIG_LOCKD_V4=y
++CONFIG_NFS_COMMON=y
++CONFIG_SUNRPC=y
++# CONFIG_SUNRPC_REGISTER_V4 is not set
++# CONFIG_RPCSEC_GSS_KRB5 is not set
++# CONFIG_RPCSEC_GSS_SPKM3 is not set
++# CONFIG_SMB_FS is not set
++# CONFIG_CIFS is not set
++# CONFIG_NCP_FS is not set
++# CONFIG_CODA_FS is not set
++# CONFIG_AFS_FS is not set
++
++#
++# Partition Types
++#
++CONFIG_PARTITION_ADVANCED=y
++# CONFIG_ACORN_PARTITION is not set
++# CONFIG_OSF_PARTITION is not set
++# CONFIG_AMIGA_PARTITION is not set
++# CONFIG_ATARI_PARTITION is not set
++# CONFIG_MAC_PARTITION is not set
++CONFIG_MSDOS_PARTITION=y
++# CONFIG_BSD_DISKLABEL is not set
++# CONFIG_MINIX_SUBPARTITION is not set
++# CONFIG_SOLARIS_X86_PARTITION is not set
++# CONFIG_UNIXWARE_DISKLABEL is not set
++# CONFIG_LDM_PARTITION is not set
++# CONFIG_SGI_PARTITION is not set
++# CONFIG_ULTRIX_PARTITION is not set
++# CONFIG_SUN_PARTITION is not set
++# CONFIG_KARMA_PARTITION is not set
++# CONFIG_EFI_PARTITION is not set
++# CONFIG_SYSV68_PARTITION is not set
++CONFIG_NLS=m
++CONFIG_NLS_DEFAULT="iso8859-1"
++CONFIG_NLS_CODEPAGE_437=m
++# CONFIG_NLS_CODEPAGE_737 is not set
++# CONFIG_NLS_CODEPAGE_775 is not set
++CONFIG_NLS_CODEPAGE_850=m
++# CONFIG_NLS_CODEPAGE_852 is not set
++# CONFIG_NLS_CODEPAGE_855 is not set
++# CONFIG_NLS_CODEPAGE_857 is not set
++# CONFIG_NLS_CODEPAGE_860 is not set
++# CONFIG_NLS_CODEPAGE_861 is not set
++# CONFIG_NLS_CODEPAGE_862 is not set
++# CONFIG_NLS_CODEPAGE_863 is not set
++# CONFIG_NLS_CODEPAGE_864 is not set
++# CONFIG_NLS_CODEPAGE_865 is not set
++# CONFIG_NLS_CODEPAGE_866 is not set
++# CONFIG_NLS_CODEPAGE_869 is not set
++# CONFIG_NLS_CODEPAGE_936 is not set
++# CONFIG_NLS_CODEPAGE_950 is not set
++# CONFIG_NLS_CODEPAGE_932 is not set
++# CONFIG_NLS_CODEPAGE_949 is not set
++# CONFIG_NLS_CODEPAGE_874 is not set
++# CONFIG_NLS_ISO8859_8 is not set
++# CONFIG_NLS_CODEPAGE_1250 is not set
++# CONFIG_NLS_CODEPAGE_1251 is not set
++CONFIG_NLS_ASCII=m
++CONFIG_NLS_ISO8859_1=m
++# CONFIG_NLS_ISO8859_2 is not set
++# CONFIG_NLS_ISO8859_3 is not set
++# CONFIG_NLS_ISO8859_4 is not set
++# CONFIG_NLS_ISO8859_5 is not set
++# CONFIG_NLS_ISO8859_6 is not set
++# CONFIG_NLS_ISO8859_7 is not set
++# CONFIG_NLS_ISO8859_9 is not set
++# CONFIG_NLS_ISO8859_13 is not set
++# CONFIG_NLS_ISO8859_14 is not set
++CONFIG_NLS_ISO8859_15=m
++# CONFIG_NLS_KOI8_R is not set
++# CONFIG_NLS_KOI8_U is not set
++CONFIG_NLS_UTF8=m
++# CONFIG_DLM is not set
++
++#
++# Kernel hacking
++#
++# CONFIG_PRINTK_TIME is not set
++# CONFIG_ENABLE_WARN_DEPRECATED is not set
++# CONFIG_ENABLE_MUST_CHECK is not set
++CONFIG_FRAME_WARN=1024
++CONFIG_MAGIC_SYSRQ=y
++# CONFIG_UNUSED_SYMBOLS is not set
++# CONFIG_DEBUG_FS is not set
++# CONFIG_HEADERS_CHECK is not set
++CONFIG_DEBUG_KERNEL=y
++# CONFIG_DEBUG_SHIRQ is not set
++# CONFIG_DETECT_SOFTLOCKUP is not set
++# CONFIG_SCHED_DEBUG is not set
++# CONFIG_SCHEDSTATS is not set
++# CONFIG_TIMER_STATS is not set
++# CONFIG_DEBUG_OBJECTS is not set
++# CONFIG_DEBUG_SLAB is not set
++# CONFIG_DEBUG_PREEMPT is not set
++# CONFIG_DEBUG_RT_MUTEXES is not set
++# CONFIG_RT_MUTEX_TESTER is not set
++# CONFIG_DEBUG_SPINLOCK is not set
++# CONFIG_DEBUG_MUTEXES is not set
++# CONFIG_DEBUG_LOCK_ALLOC is not set
++# CONFIG_PROVE_LOCKING is not set
++# CONFIG_LOCK_STAT is not set
++# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
++# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
++# CONFIG_DEBUG_KOBJECT is not set
++CONFIG_DEBUG_BUGVERBOSE=y
++# CONFIG_DEBUG_INFO is not set
++# CONFIG_DEBUG_VM is not set
++# CONFIG_DEBUG_WRITECOUNT is not set
++# CONFIG_DEBUG_MEMORY_INIT is not set
++# CONFIG_DEBUG_LIST is not set
++# CONFIG_DEBUG_SG 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_SYSCTL_SYSCALL_CHECK is not set
++CONFIG_HAVE_FUNCTION_TRACER=y
++
++#
++# Tracers
++#
++# CONFIG_FUNCTION_TRACER is not set
++# CONFIG_IRQSOFF_TRACER is not set
++# CONFIG_PREEMPT_TRACER is not set
++# CONFIG_SCHED_TRACER is not set
++# CONFIG_CONTEXT_SWITCH_TRACER is not set
++# CONFIG_BOOT_TRACER 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
++CONFIG_DEBUG_USER=y
++CONFIG_DEBUG_ERRORS=y
++# CONFIG_DEBUG_STACK_USAGE is not set
++# CONFIG_DEBUG_LL is not set
++
++#
++# Security options
++#
++# CONFIG_KEYS is not set
++# CONFIG_SECURITY is not set
++# CONFIG_SECURITYFS is not set
++# CONFIG_SECURITY_FILE_CAPABILITIES is not set
++CONFIG_CRYPTO=m
++
++#
++# Crypto core or helper
++#
++# CONFIG_CRYPTO_FIPS is not set
++CONFIG_CRYPTO_ALGAPI=m
++CONFIG_CRYPTO_ALGAPI2=m
++CONFIG_CRYPTO_AEAD2=m
++CONFIG_CRYPTO_BLKCIPHER=m
++CONFIG_CRYPTO_BLKCIPHER2=m
++CONFIG_CRYPTO_HASH=m
++CONFIG_CRYPTO_HASH2=m
++CONFIG_CRYPTO_RNG2=m
++CONFIG_CRYPTO_MANAGER=m
++CONFIG_CRYPTO_MANAGER2=m
++# CONFIG_CRYPTO_GF128MUL is not set
++# CONFIG_CRYPTO_NULL is not set
++# CONFIG_CRYPTO_CRYPTD is not set
++# CONFIG_CRYPTO_AUTHENC is not set
++# CONFIG_CRYPTO_TEST is not set
++
++#
++# Authenticated Encryption with Associated Data
++#
++# CONFIG_CRYPTO_CCM is not set
++# CONFIG_CRYPTO_GCM is not set
++# CONFIG_CRYPTO_SEQIV is not set
++
++#
++# Block modes
++#
++# CONFIG_CRYPTO_CBC is not set
++# CONFIG_CRYPTO_CTR is not set
++# CONFIG_CRYPTO_CTS is not set
++CONFIG_CRYPTO_ECB=m
++# CONFIG_CRYPTO_LRW is not set
++# CONFIG_CRYPTO_PCBC is not set
++# CONFIG_CRYPTO_XTS is not set
++
++#
++# Hash modes
++#
++CONFIG_CRYPTO_HMAC=m
++# CONFIG_CRYPTO_XCBC is not set
++
++#
++# Digest
++#
++# CONFIG_CRYPTO_CRC32C is not set
++# CONFIG_CRYPTO_MD4 is not set
++CONFIG_CRYPTO_MD5=m
++CONFIG_CRYPTO_MICHAEL_MIC=m
++# CONFIG_CRYPTO_RMD128 is not set
++# CONFIG_CRYPTO_RMD160 is not set
++# CONFIG_CRYPTO_RMD256 is not set
++# CONFIG_CRYPTO_RMD320 is not set
++# CONFIG_CRYPTO_SHA1 is not set
++# CONFIG_CRYPTO_SHA256 is not set
++# CONFIG_CRYPTO_SHA512 is not set
++# CONFIG_CRYPTO_TGR192 is not set
++# CONFIG_CRYPTO_WP512 is not set
++
++#
++# Ciphers
++#
++CONFIG_CRYPTO_AES=m
++# CONFIG_CRYPTO_ANUBIS is not set
++CONFIG_CRYPTO_ARC4=m
++# CONFIG_CRYPTO_BLOWFISH is not set
++# CONFIG_CRYPTO_CAMELLIA is not set
++# CONFIG_CRYPTO_CAST5 is not set
++# CONFIG_CRYPTO_CAST6 is not set
++# CONFIG_CRYPTO_DES is not set
++# CONFIG_CRYPTO_FCRYPT is not set
++# CONFIG_CRYPTO_KHAZAD is not set
++# CONFIG_CRYPTO_SALSA20 is not set
++# CONFIG_CRYPTO_SEED is not set
++# CONFIG_CRYPTO_SERPENT is not set
++# CONFIG_CRYPTO_TEA is not set
++# CONFIG_CRYPTO_TWOFISH is not set
++
++#
++# Compression
++#
++# 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_CRC_CCITT=m
++CONFIG_CRC16=m
++# CONFIG_CRC_T10DIF is not set
++# CONFIG_CRC_ITU_T is not set
++CONFIG_CRC32=y
++# CONFIG_CRC7 is not set
++# CONFIG_LIBCRC32C is not set
++CONFIG_ZLIB_INFLATE=y
++CONFIG_ZLIB_DEFLATE=y
++CONFIG_PLIST=y
++CONFIG_HAS_IOMEM=y
++CONFIG_HAS_IOPORT=y
++CONFIG_HAS_DMA=y
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-imx/include/mach/imx-regs.h linux-2.6.28-karo/arch/arm/mach-imx/include/mach/imx-regs.h
+--- linux-2.6.28/arch/arm/mach-imx/include/mach/imx-regs.h     2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-imx/include/mach/imx-regs.h        2009-03-11 13:16:24.000000000 +0100
+@@ -416,7 +416,8 @@
+ #define PCR_BPIX_4      (2<<25)
+ #define PCR_BPIX_8      (3<<25)
+ #define PCR_BPIX_12     (4<<25)
+-#define PCR_BPIX_16     (4<<25)
++#define PCR_BPIX_16     (5<<25)
++#define PCR_BPIX_18     (6<<25)
+ #define PCR_PIXPOL      (1<<24)
+ #define PCR_FLMPOL      (1<<23)
+ #define PCR_LPPOL       (1<<22)
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-imx/include/mach/imxfb.h linux-2.6.28-karo/arch/arm/mach-imx/include/mach/imxfb.h
+--- linux-2.6.28/arch/arm/mach-imx/include/mach/imxfb.h        2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-imx/include/mach/imxfb.h   1970-01-01 01:00:00.000000000 +0100
+@@ -1,37 +0,0 @@
+-/*
+- * This structure describes the machine which we are running on.
+- */
+-struct imxfb_mach_info {
+-      u_long          pixclock;
+-
+-      u_short         xres;
+-      u_short         yres;
+-
+-      u_int           nonstd;
+-      u_char          bpp;
+-      u_char          hsync_len;
+-      u_char          left_margin;
+-      u_char          right_margin;
+-
+-      u_char          vsync_len;
+-      u_char          upper_margin;
+-      u_char          lower_margin;
+-      u_char          sync;
+-
+-      u_int           cmap_greyscale:1,
+-                      cmap_inverse:1,
+-                      cmap_static:1,
+-                      unused:29;
+-
+-      u_int           pcr;
+-      u_int           pwmr;
+-      u_int           lscr1;
+-      u_int           dmacr;
+-
+-      u_char * fixed_screen_cpu;
+-      dma_addr_t fixed_screen_dma;
+-
+-      void (*lcd_power)(int);
+-      void (*backlight_power)(int);
+-};
+-void set_imx_fb_info(struct imxfb_mach_info *hard_imx_fb_info);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/Kconfig linux-2.6.28-karo/arch/arm/mach-mx2/Kconfig
+--- linux-2.6.28/arch/arm/mach-mx2/Kconfig     2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/Kconfig        2009-03-11 13:16:24.000000000 +0100
+@@ -24,6 +24,28 @@ config MACH_PCM038
+         Include support for phyCORE-i.MX27 (aka pcm038) platform. This
+         includes specific configurations for the module and its peripherals.
++config MACH_TX27
++      bool "Support Ka-Ro electronics TX27 module"
++      depends on MACH_MX27
++      select MXC_ULPI
++      help
++        Include support for Ka-Ro TX27 processor module
++
++config BASE_CLK_26MHz
++      bool "Use external 26MHz oscillator"
++      depends on MACH_TX27
++      default yes
++      help
++        Unselect this option to switch off the external 26MHz oscillator
++        and use the 32.768kHz reference and i.MX27 internal FPM
++
++config KARO_DEBUG
++      bool "Enable Ka-Ro specific debug messages"
++      depends on MACH_TX27
++      help
++        Compile the architecture specific files with -DDEBUG to enable
++        additional debug messages
++
+ choice
+       prompt "Baseboard"
+       depends on MACH_PCM038
+@@ -32,6 +54,7 @@ choice
+ config MACH_PCM970_BASEBOARD
+       prompt "PHYTEC PCM970 development board"
+       bool
++      select MXC_ULPI
+       help
+         This adds board specific devices that can be found on Phytec's
+         PCM970 evaluation board.
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/Makefile linux-2.6.28-karo/arch/arm/mach-mx2/Makefile
+--- linux-2.6.28/arch/arm/mach-mx2/Makefile    2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/Makefile       2009-03-11 13:16:24.000000000 +0100
+@@ -2,13 +2,19 @@
+ # Makefile for the linux kernel.
+ #
++ifeq ($(CONFIG_KARO_DEBUG),y)
++      EXTRA_CFLAGS += -DDEBUG
++endif
++
+ # Object file lists.
+ obj-y :=  system.o generic.o devices.o serial.o
+ obj-$(CONFIG_MACH_MX27) += cpu_imx27.o
+ obj-$(CONFIG_MACH_MX27) += clock_imx27.o
++obj-$(CONFIG_PM)      += pm.o mxc_pm.o
+-obj-$(CONFIG_MACH_MX27ADS) += mx27ads.o
+-obj-$(CONFIG_MACH_PCM038) += pcm038.o
+-obj-$(CONFIG_MACH_PCM970_BASEBOARD) += pcm970-baseboard.o
++obj-$(CONFIG_MACH_MX27ADS)            += mx27ads.o
++obj-$(CONFIG_MACH_PCM038)             += pcm038.o
++obj-$(CONFIG_MACH_PCM970_BASEBOARD)   += pcm970-baseboard.o
++obj-$(CONFIG_MACH_TX27)                       += karo-tx27.o tx27_gpio.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/clock_imx27.c linux-2.6.28-karo/arch/arm/mach-mx2/clock_imx27.c
+--- linux-2.6.28/arch/arm/mach-mx2/clock_imx27.c       2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/clock_imx27.c  2009-03-11 13:16:24.000000000 +0100
+@@ -21,6 +21,7 @@
+ #include <linux/io.h>
+ #include <linux/module.h>
+ #include <linux/spinlock.h>
++#include <linux/delay.h>
+ #include <mach/clock.h>
+ #include <mach/common.h>
+@@ -233,9 +234,23 @@ static void _clk_mstick1_disable(struct 
+       _clk_pccr10_disable(CCM_PCCR1_MSHC_BAUD_MASK, CCM_PCCR0_MSHC_MASK);
+ }
+-#define CSCR() (__raw_readl(CCM_CSCR))
+-#define PCDR0() (__raw_readl(CCM_PCDR0))
+-#define PCDR1() (__raw_readl(CCM_PCDR1))
++static int _clk_wdog_enable(struct clk *clk)
++{
++      u32 cscr;
++
++      cscr = __raw_readl(CCM_CSCR);
++      if (!(cscr & CCM_CSCR_FPM)) {
++              cscr |= CCM_CSCR_FPM;
++              __raw_writel(cscr, CCM_CSCR);
++              /* wait for FPM startup */
++              udelay(90);
++      }
++      return _clk_enable(clk);
++}
++
++#define CSCR() __raw_readl(CCM_CSCR)
++#define PCDR0() __raw_readl(CCM_PCDR0)
++#define PCDR1() __raw_readl(CCM_PCDR1)
+ static int _clk_cpu_set_parent(struct clk *clk, struct clk *parent)
+ {
+@@ -288,7 +303,7 @@ static int _clk_cpu_set_rate(struct clk 
+       div = parent_rate / rate;
+-      if (div > 4 || div < 1 || ((parent_rate / div) != rate))
++      if (div > 4 || div < 1 || ((parent_rate / div / 100) != rate / 100))
+               return -EINVAL;
+       div--;
+@@ -297,10 +312,13 @@ static int _clk_cpu_set_rate(struct clk 
+       if (mx27_revision() >= CHIP_REV_2_0) {
+               reg &= ~CCM_CSCR_ARM_MASK;
+               reg |= div << CCM_CSCR_ARM_OFFSET;
++#if 0
++              // FIXME: What's this? This breaks _clk_spll_enable()!
+               reg &= ~0x06;
++#endif
+               __raw_writel(reg | 0x80000000, CCM_CSCR);
+       } else {
+-              printk(KERN_ERR "Cant set CPU frequency!\n");
++              printk(KERN_ERR "Can't set CPU frequency!\n");
+       }
+       return 0;
+@@ -361,6 +379,24 @@ static unsigned long _clk_usb_recalc(str
+       return parent_rate / (usb_pdf + 1U);
+ }
++static int _clk_usb_set_rate(struct clk *clk, unsigned long rate)
++{
++      u32 div, reg;
++      unsigned long parent_rate;
++
++      parent_rate = clk_get_rate(clk->parent);
++      div = parent_rate / rate;
++
++      if (div > 8 || div < 1 || ((parent_rate / div) != rate)) {
++              return -EINVAL;
++      }
++      div--;
++
++      reg = (CSCR() & ~CCM_CSCR_USB_MASK) | (div << CCM_CSCR_USB_OFFSET);
++      __raw_writel(reg, CCM_CSCR);
++      return 0;
++}
++
+ static unsigned long _clk_ssi1_recalc(struct clk *clk)
+ {
+       unsigned long ssi1_pdf;
+@@ -488,10 +524,13 @@ static unsigned long get_mpll_clk(struct
+ {
+       uint32_t reg;
+       unsigned long ref_clk;
+-      unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
++      int mfi, mfn, mfd, pdf;
+       unsigned long long temp;
++      int sign = 1;
+       ref_clk = clk_get_rate(clk->parent);
++      if (clk->parent == &ckil_clk)
++              ref_clk *= 1024;
+       reg = __raw_readl(CCM_MPCTL0);
+       pdf = (reg & CCM_MPCTL0_PD_MASK) >> CCM_MPCTL0_PD_OFFSET;
+@@ -500,9 +539,13 @@ static unsigned long get_mpll_clk(struct
+       mfn = (reg & CCM_MPCTL0_MFN_MASK) >> CCM_MPCTL0_MFN_OFFSET;
+       mfi = (mfi <= 5) ? 5 : mfi;
++      if (mfn >= 512) {
++              mfn = 1024 - mfn;
++              sign = -1;
++      }
+       temp = 2LL * ref_clk * mfn;
+       do_div(temp, mfd + 1);
+-      temp = 2LL * ref_clk * mfi + temp;
++      temp = temp * sign + 2LL * ref_clk * mfi;
+       do_div(temp, pdf + 1);
+       return (unsigned long)temp;
+@@ -555,10 +598,13 @@ static unsigned long get_spll_clk(struct
+ {
+       uint32_t reg;
+       unsigned long ref_clk;
+-      unsigned long mfi = 0, mfn = 0, mfd = 0, pdf = 0;
+-      unsigned long long temp;
++      int mfi, mfn, mfd, pdf;
++      u64 temp;
++      int sign = 1;
+       ref_clk = clk_get_rate(clk->parent);
++      if (clk->parent == &ckil_clk)
++              ref_clk *= 1024;
+       reg = __raw_readl(CCM_SPCTL0);
+       /*TODO: This is TO2 Bug */
+@@ -571,9 +617,13 @@ static unsigned long get_spll_clk(struct
+       mfn = (reg & CCM_SPCTL0_MFN_MASK) >> CCM_SPCTL0_MFN_OFFSET;
+       mfi = (mfi <= 5) ? 5 : mfi;
++      if (mfn >= 512) {
++              sign = -1;
++              mfn = 1024 - mfn;
++      }
+       temp = 2LL * ref_clk * mfn;
+       do_div(temp, mfd + 1);
+-      temp = 2LL * ref_clk * mfi + temp;
++      temp = temp * sign + 2LL * ref_clk * mfi;
+       do_div(temp, pdf + 1);
+       return (unsigned long)temp;
+@@ -1079,6 +1129,7 @@ static struct clk usb_clk[] = {
+               .name = "usb_clk",
+               .parent = &spll_clk,
+               .get_rate = _clk_usb_recalc,
++              .set_rate = _clk_usb_set_rate,
+               .enable = _clk_enable,
+               .enable_reg = CCM_PCCR1,
+               .enable_shift = CCM_PCCR1_USBOTG_OFFSET,
+@@ -1234,7 +1285,7 @@ static struct clk mstick1_clk = {
+ static struct clk wdog_clk = {
+       .name = "wdog_clk",
+       .parent = &ipg_clk,
+-      .enable = _clk_enable,
++      .enable = _clk_wdog_enable,
+       .enable_reg = CCM_PCCR1,
+       .enable_shift = CCM_PCCR1_WDT_OFFSET,
+       .disable = _clk_disable,
+@@ -1537,26 +1588,22 @@ void __init change_external_low_referenc
+       external_low_reference = new_ref;
+ }
+-unsigned long __init clk_early_get_timer_rate(void)
+-{
+-      return clk_get_rate(&per_clk[0]);
+-}
+-
+ static void __init probe_mxc_clocks(void)
+ {
+       int i;
++      u32 cscr = CSCR();
+       if (mx27_revision() >= CHIP_REV_2_0) {
+-              if (CSCR() & 0x8000)
++              if (cscr & 0x8000)
+                       cpu_clk.parent = &mpll_main_clk[0];
+-              if (!(CSCR() & 0x00800000))
++              if (!(cscr & 0x00800000))
+                       ssi2_clk[0].parent = &spll_clk;
+-              if (!(CSCR() & 0x00400000))
++              if (!(cscr & 0x00400000))
+                       ssi1_clk[0].parent = &spll_clk;
+-              if (!(CSCR() & 0x00200000))
++              if (!(cscr & 0x00200000))
+                       vpu_clk.parent = &spll_clk;
+       } else {
+               cpu_clk.parent = &mpll_clk;
+@@ -1618,7 +1665,7 @@ int __init mxc_clocks_init(unsigned long
+       clk_enable(&gpio_clk);
+       clk_enable(&iim_clk);
+       clk_enable(&gpt1_clk[0]);
+-#ifdef CONFIG_DEBUG_LL_CONSOLE
++#ifdef CONFIG_DEBUG_LL
+       clk_enable(&uart1_clk[0]);
+ #endif
+       return 0;
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/crm_regs.h linux-2.6.28-karo/arch/arm/mach-mx2/crm_regs.h
+--- linux-2.6.28/arch/arm/mach-mx2/crm_regs.h  2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/crm_regs.h     2009-03-11 13:16:24.000000000 +0100
+@@ -22,252 +22,276 @@
+ #include <mach/hardware.h>
++#define SYSCTRL_BASE          IO_ADDRESS(SYSCTRL_BASE_ADDR)
++
+ /* Register offsets */
+-#define CCM_CSCR                (IO_ADDRESS(CCM_BASE_ADDR) + 0x0)
+-#define CCM_MPCTL0              (IO_ADDRESS(CCM_BASE_ADDR) + 0x4)
+-#define CCM_MPCTL1              (IO_ADDRESS(CCM_BASE_ADDR) + 0x8)
+-#define CCM_SPCTL0              (IO_ADDRESS(CCM_BASE_ADDR) + 0xC)
+-#define CCM_SPCTL1              (IO_ADDRESS(CCM_BASE_ADDR) + 0x10)
+-#define CCM_OSC26MCTL           (IO_ADDRESS(CCM_BASE_ADDR) + 0x14)
+-#define CCM_PCDR0               (IO_ADDRESS(CCM_BASE_ADDR) + 0x18)
+-#define CCM_PCDR1               (IO_ADDRESS(CCM_BASE_ADDR) + 0x1c)
+-#define CCM_PCCR0               (IO_ADDRESS(CCM_BASE_ADDR) + 0x20)
+-#define CCM_PCCR1               (IO_ADDRESS(CCM_BASE_ADDR) + 0x24)
+-#define CCM_CCSR                (IO_ADDRESS(CCM_BASE_ADDR) + 0x28)
+-#define CCM_PMCTL               (IO_ADDRESS(CCM_BASE_ADDR) + 0x2c)
+-#define CCM_PMCOUNT             (IO_ADDRESS(CCM_BASE_ADDR) + 0x30)
+-#define CCM_WKGDCTL             (IO_ADDRESS(CCM_BASE_ADDR) + 0x34)
+-
+-#define CCM_CSCR_USB_OFFSET     28
+-#define CCM_CSCR_USB_MASK       (0x7 << 28)
+-#define CCM_CSCR_SD_OFFSET      24
+-#define CCM_CSCR_SD_MASK        (0x3 << 24)
+-#define CCM_CSCR_SSI2           (1 << 23)
+-#define CCM_CSCR_SSI2_OFFSET    23
+-#define CCM_CSCR_SSI1           (1 << 22)
+-#define CCM_CSCR_SSI1_OFFSET    22
+-#define CCM_CSCR_VPU           (1 << 21)
+-#define CCM_CSCR_VPU_OFFSET    21
+-#define CCM_CSCR_MSHC           (1 << 20)
+-#define CCM_CSCR_SPLLRES        (1 << 19)
+-#define CCM_CSCR_MPLLRES        (1 << 18)
+-#define CCM_CSCR_SP             (1 << 17)
+-#define CCM_CSCR_MCU            (1 << 16)
++#define CCM_CSCR              (IO_ADDRESS(CCM_BASE_ADDR) + 0x0)
++#define CCM_MPCTL0            (IO_ADDRESS(CCM_BASE_ADDR) + 0x4)
++#define CCM_MPCTL1            (IO_ADDRESS(CCM_BASE_ADDR) + 0x8)
++#define CCM_SPCTL0            (IO_ADDRESS(CCM_BASE_ADDR) + 0xC)
++#define CCM_SPCTL1            (IO_ADDRESS(CCM_BASE_ADDR) + 0x10)
++#define CCM_OSC26MCTL         (IO_ADDRESS(CCM_BASE_ADDR) + 0x14)
++#define CCM_PCDR0             (IO_ADDRESS(CCM_BASE_ADDR) + 0x18)
++#define CCM_PCDR1             (IO_ADDRESS(CCM_BASE_ADDR) + 0x1c)
++#define CCM_PCCR0             (IO_ADDRESS(CCM_BASE_ADDR) + 0x20)
++#define CCM_PCCR1             (IO_ADDRESS(CCM_BASE_ADDR) + 0x24)
++#define CCM_CCSR              (IO_ADDRESS(CCM_BASE_ADDR) + 0x28)
++#define CCM_PMCTL             (IO_ADDRESS(CCM_BASE_ADDR) + 0x2c)
++#define CCM_PMCOUNT           (IO_ADDRESS(CCM_BASE_ADDR) + 0x30)
++#define CCM_WKGDCTL           (IO_ADDRESS(CCM_BASE_ADDR) + 0x34)
++#define MXC_CCM_PMCR0         (SYSCTRL_BASE + 0x60)
++#define MXC_CCM_DCVR0         (SYSCTRL_BASE + 0x64)
++#define MXC_CCM_DCVR1         (SYSCTRL_BASE + 0x68)
++#define MXC_CCM_DCVR2         (SYSCTRL_BASE + 0x72)
++#define MXC_CCM_DCVR3         (SYSCTRL_BASE + 0x76)
++#define MXC_CCM_PMCR0_DPTEN   0x00000001
++#define MXC_CCM_DIE           0x00000002
++#define MXC_CCM_DIM           0x0000000C
++#define MXC_CCM_DCR           0x00000200
++#define MXC_CCM_PMCR0_DRCE0   0x00000010
++#define MXC_CCM_PMCR0_DRCE1   0x00000020
++#define MXC_CCM_PMCR0_DRCE2   0x00000040
++#define MXC_CCM_PMCR0_DRCE3   0x00000080
++#define MXC_CCM_PMCR0_PTVAIM  MXC_CCM_DIM
++
++#define CCM_CSCR_USB_OFFSET   28
++#define CCM_CSCR_USB_MASK     (0x7 << CCM_CSCR_USB_OFFSET)
++#define CCM_CSCR_SD_OFFSET    24
++#define CCM_CSCR_SD_MASK      (0x3 << CCM_CSCR_SD_OFFSET)
++#define CCM_CSCR_SSI2_OFFSET  23
++#define CCM_CSCR_SSI2         (1 << CCM_CSCR_SSI2_OFFSET)
++#define CCM_CSCR_SSI1_OFFSET  22
++#define CCM_CSCR_SSI1         (1 << CCM_CSCR_SSI1_OFFSET)
++#define CCM_CSCR_VPU_OFFSET   21
++#define CCM_CSCR_VPU          (1 << CCM_CSCR_VPU_OFFSET)
++#define CCM_CSCR_MSHC         (1 << 20)
++#define CCM_CSCR_SPLLRES      (1 << 19)
++#define CCM_CSCR_MPLLRES      (1 << 18)
++#define CCM_CSCR_SP           (1 << 17)
++#define CCM_CSCR_MCU          (1 << 16)
+ /* CCM_CSCR_ARM_xxx just be avaliable on i.MX27 TO2*/
+-#define CCM_CSCR_ARM_SRC        (1 << 15)
+-#define CCM_CSCR_ARM_OFFSET     12
+-#define CCM_CSCR_ARM_MASK       (0x3 << 12)
++#define CCM_CSCR_ARM_SRC      (1 << 15)
++#define CCM_CSCR_ARM_OFFSET   12
++#define CCM_CSCR_ARM_MASK     (0x3 << CCM_CSCR_ARM_OFFSET)
+ /* CCM_CSCR_ARM_xxx just be avaliable on i.MX27 TO2*/
+-#define CCM_CSCR_PRESC_OFFSET   13
+-#define CCM_CSCR_PRESC_MASK     (0x7 << 13)
+-#define CCM_CSCR_BCLK_OFFSET    9
+-#define CCM_CSCR_BCLK_MASK      (0xf << 9)
+-#define CCM_CSCR_IPDIV_OFFSET   8
+-#define CCM_CSCR_IPDIV          (1 << 8)
++#define CCM_CSCR_PRESC_OFFSET 13
++#define CCM_CSCR_PRESC_MASK   (0x7 << CCM_CSCR_PRESC_OFFSET)
++#define CCM_CSCR_BCLK_OFFSET  9
++#define CCM_CSCR_BCLK_MASK    (0xf << CCM_CSCR_BCLK_OFFSET)
++#define CCM_CSCR_IPDIV_OFFSET 8
++#define CCM_CSCR_IPDIV                (1 << CCM_CSCR_IPDIV_OFFSET)
+ /* CCM_CSCR_AHB_xxx just be avaliable on i.MX27 TO2*/
+-#define CCM_CSCR_AHB_OFFSET     8
+-#define CCM_CSCR_AHB_MASK       (0x3 << 8)
++#define CCM_CSCR_AHB_OFFSET   8
++#define CCM_CSCR_AHB_MASK     (0x3 << CCM_CSCR_AHB_OFFSET)
+ /* CCM_CSCR_AHB_xxx just be avaliable on i.MX27 TO2*/
+-#define CCM_CSCR_OSC26MDIV      (1 << 4)
+-#define CCM_CSCR_OSC26M         (1 << 3)
+-#define CCM_CSCR_FPM            (1 << 2)
+-#define CCM_CSCR_SPEN           (1 << 1)
+-#define CCM_CSCR_MPEN           1
+-
+-#define CCM_MPCTL0_CPLM         (1 << 31)
+-#define CCM_MPCTL0_PD_OFFSET    26
+-#define CCM_MPCTL0_PD_MASK      (0xf << 26)
+-#define CCM_MPCTL0_MFD_OFFSET   16
+-#define CCM_MPCTL0_MFD_MASK     (0x3ff << 16)
+-#define CCM_MPCTL0_MFI_OFFSET   10
+-#define CCM_MPCTL0_MFI_MASK     (0xf << 10)
+-#define CCM_MPCTL0_MFN_OFFSET   0
+-#define CCM_MPCTL0_MFN_MASK     0x3ff
+-
+-#define CCM_MPCTL1_LF           (1 << 15)
+-#define CCM_MPCTL1_BRMO         (1 << 6)
+-
+-#define CCM_SPCTL0_CPLM         (1 << 31)
+-#define CCM_SPCTL0_PD_OFFSET    26
+-#define CCM_SPCTL0_PD_MASK      (0xf << 26)
+-#define CCM_SPCTL0_MFD_OFFSET   16
+-#define CCM_SPCTL0_MFD_MASK     (0x3ff << 16)
+-#define CCM_SPCTL0_MFI_OFFSET   10
+-#define CCM_SPCTL0_MFI_MASK     (0xf << 10)
+-#define CCM_SPCTL0_MFN_OFFSET   0
+-#define CCM_SPCTL0_MFN_MASK     0x3ff
+-
+-#define CCM_SPCTL1_LF           (1 << 15)
+-#define CCM_SPCTL1_BRMO         (1 << 6)
+-
+-#define CCM_OSC26MCTL_PEAK_OFFSET       16
+-#define CCM_OSC26MCTL_PEAK_MASK         (0x3 << 16)
+-#define CCM_OSC26MCTL_AGC_OFFSET        8
+-#define CCM_OSC26MCTL_AGC_MASK          (0x3f << 8)
+-#define CCM_OSC26MCTL_ANATEST_OFFSET    0
+-#define CCM_OSC26MCTL_ANATEST_MASK      0x3f
+-
+-#define CCM_PCDR0_SSI2BAUDDIV_OFFSET    26
+-#define CCM_PCDR0_SSI2BAUDDIV_MASK      (0x3f << 26)
+-#define CCM_PCDR0_CLKO_EN               25
+-#define CCM_PCDR0_CLKODIV_OFFSET        22
+-#define CCM_PCDR0_CLKODIV_MASK          (0x7 << 22)
+-#define CCM_PCDR0_SSI1BAUDDIV_OFFSET    16
+-#define CCM_PCDR0_SSI1BAUDDIV_MASK      (0x3f << 16)
++#define CCM_CSCR_OSC26MDIV    (1 << 4)
++#define CCM_CSCR_OSC26M               (1 << 3)
++#define CCM_CSCR_FPM          (1 << 2)
++#define CCM_CSCR_SPEN         (1 << 1)
++#define CCM_CSCR_MPEN         1
++
++#define CCM_MPCTL0_CPLM               (1 << 31)
++#define CCM_MPCTL0_PD_OFFSET  26
++#define CCM_MPCTL0_PD_MASK    (0xf << CCM_MPCTL0_PD_OFFSET)
++#define CCM_MPCTL0_PD_VAL(n)  (((n) << CCM_MPCTL0_PD_OFFSET) & CCM_MPCTL0_PD_MASK)
++#define CCM_MPCTL0_MFD_OFFSET 16
++#define CCM_MPCTL0_MFD_MASK   (0x3ff << CCM_MPCTL0_MFD_OFFSET)
++#define CCM_MPCTL0_MFD_VAL(n) (((n) << CCM_MPCTL0_MFD_OFFSET) & CCM_MPCTL0_MFD_MASK)
++#define CCM_MPCTL0_MFI_OFFSET 10
++#define CCM_MPCTL0_MFI_MASK   (0xf << CCM_MPCTL0_MFI_OFFSET)
++#define CCM_MPCTL0_MFI_VAL(n) (((n) << CCM_MPCTL0_MFI_OFFSET) & CCM_MPCTL0_MFI_MASK)
++#define CCM_MPCTL0_MFN_OFFSET 0
++#define CCM_MPCTL0_MFN_MASK   (0x3ff << CCM_MPCTL0_MFN_OFFSET)
++#define CCM_MPCTL0_MFN_VAL(n) (((n) << CCM_MPCTL0_MFN_OFFSET) & CCM_MPCTL0_MFN_MASK)
++
++#define CCM_MPCTL1_LF         (1 << 15)
++#define CCM_MPCTL1_BRMO               (1 << 6)
++
++#define CCM_SPCTL0_CPLM               (1 << 31)
++#define CCM_SPCTL0_PD_OFFSET  26
++#define CCM_SPCTL0_PD_MASK    (0xf << CCM_SPCTL0_PD_OFFSET)
++#define CCM_SPCTL0_PD_VAL(n)  (((n) << CCM_SPCTL0_PD_OFFSET) & CCM_SPCTL0_PD_MASK)
++#define CCM_SPCTL0_MFD_OFFSET 16
++#define CCM_SPCTL0_MFD_MASK   (0x3ff << CCM_SPCTL0_MFD_OFFSET)
++#define CCM_SPCTL0_MFD_VAL(n) (((n) << CCM_SPCTL0_MFD_OFFSET) & CCM_SPCTL0_MFD_MASK)
++#define CCM_SPCTL0_MFI_OFFSET 10
++#define CCM_SPCTL0_MFI_MASK   (0xf << CCM_SPCTL0_MFI_OFFSET)
++#define CCM_SPCTL0_MFI_VAL(n) (((n) << CCM_SPCTL0_MFI_OFFSET) & CCM_SPCTL0_MFI_MASK)
++#define CCM_SPCTL0_MFN_OFFSET 0
++#define CCM_SPCTL0_MFN_MASK   (0x3ff << CCM_SPCTL0_MFN_OFFSET)
++#define CCM_SPCTL0_MFN_VAL(n) (((n) << CCM_SPCTL0_MFN_OFFSET) & CCM_SPCTL0_MFN_MASK)
++
++#define CCM_SPCTL1_LF                 (1 << 15)
++#define CCM_SPCTL1_BRMO                       (1 << 6)
++
++#define CCM_OSC26MCTL_PEAK_OFFSET     16
++#define CCM_OSC26MCTL_PEAK_MASK               (0x3 << CCM_OSC26MCTL_PEAK_OFFSET)
++#define CCM_OSC26MCTL_AGC_OFFSET      8
++#define CCM_OSC26MCTL_AGC_MASK                (0x3f << CCM_OSC26MCTL_AGC_OFFSET)
++#define CCM_OSC26MCTL_ANATEST_OFFSET  0
++#define CCM_OSC26MCTL_ANATEST_MASK    0x3f
++
++#define CCM_PCDR0_SSI2BAUDDIV_OFFSET  26
++#define CCM_PCDR0_SSI2BAUDDIV_MASK    (0x3f << CCM_PCDR0_SSI2BAUDDIV_OFFSET)
++#define CCM_PCDR0_CLKO_EN             25
++#define CCM_PCDR0_CLKODIV_OFFSET      22
++#define CCM_PCDR0_CLKODIV_MASK                (0x7 << CCM_PCDR0_CLKODIV_OFFSET)
++#define CCM_PCDR0_SSI1BAUDDIV_OFFSET  16
++#define CCM_PCDR0_SSI1BAUDDIV_MASK    (0x3f << CCM_PCDR0_SSI1BAUDDIV_OFFSET)
+ /*The difinition for i.MX27 TO2*/
+-#define CCM_PCDR0_VPUDIV2_OFFSET        10
+-#define CCM_PCDR0_VPUDIV2_MASK          (0x3f << 10)
+-#define CCM_PCDR0_NFCDIV2_OFFSET         6
+-#define CCM_PCDR0_NFCDIV2_MASK           (0xf << 6)
+-#define CCM_PCDR0_MSHCDIV2_MASK          0x3f
++#define CCM_PCDR0_VPUDIV2_OFFSET      10
++#define CCM_PCDR0_VPUDIV2_MASK                (0x3f << CCM_PCDR0_VPUDIV2_OFFSET)
++#define CCM_PCDR0_NFCDIV2_OFFSET      6
++#define CCM_PCDR0_NFCDIV2_MASK                (0xf << CCM_PCDR0_NFCDIV2_OFFSET)
++#define CCM_PCDR0_MSHCDIV2_MASK               0x3f
+ /*The difinition for i.MX27 TO2*/
+-#define CCM_PCDR0_NFCDIV_OFFSET         12
+-#define CCM_PCDR0_NFCDIV_MASK           (0xf << 12)
+-#define CCM_PCDR0_VPUDIV_OFFSET        8
+-#define CCM_PCDR0_VPUDIV_MASK          (0xf << 8)
+-#define CCM_PCDR0_MSHCDIV_OFFSET        0
+-#define CCM_PCDR0_MSHCDIV_MASK          0x1f
+-
+-#define CCM_PCDR1_PERDIV4_OFFSET        24
+-#define CCM_PCDR1_PERDIV4_MASK          (0x3f << 24)
+-#define CCM_PCDR1_PERDIV3_OFFSET        16
+-#define CCM_PCDR1_PERDIV3_MASK          (0x3f << 16)
+-#define CCM_PCDR1_PERDIV2_OFFSET        8
+-#define CCM_PCDR1_PERDIV2_MASK          (0x3f << 8)
+-#define CCM_PCDR1_PERDIV1_OFFSET        0
+-#define CCM_PCDR1_PERDIV1_MASK          0x3f
+-
+-#define CCM_PCCR0_CSPI1_OFFSET          31
+-#define CCM_PCCR0_CSPI1_MASK            (1 << 31)
+-#define CCM_PCCR0_CSPI2_OFFSET          30
+-#define CCM_PCCR0_CSPI2_MASK            (1 << 30)
+-#define CCM_PCCR0_CSPI3_OFFSET          29
+-#define CCM_PCCR0_CSPI3_MASK            (1 << 29)
+-#define CCM_PCCR0_DMA_OFFSET            28
+-#define CCM_PCCR0_DMA_MASK              (1 << 28)
+-#define CCM_PCCR0_EMMA_OFFSET           27
+-#define CCM_PCCR0_EMMA_MASK             (1 << 27)
+-#define CCM_PCCR0_FEC_OFFSET            26
+-#define CCM_PCCR0_FEC_MASK              (1 << 26)
+-#define CCM_PCCR0_GPIO_OFFSET           25
+-#define CCM_PCCR0_GPIO_MASK             (1 << 25)
+-#define CCM_PCCR0_GPT1_OFFSET           24
+-#define CCM_PCCR0_GPT1_MASK             (1 << 24)
+-#define CCM_PCCR0_GPT2_OFFSET           23
+-#define CCM_PCCR0_GPT2_MASK             (1 << 23)
+-#define CCM_PCCR0_GPT3_OFFSET           22
+-#define CCM_PCCR0_GPT3_MASK             (1 << 22)
+-#define CCM_PCCR0_GPT4_OFFSET           21
+-#define CCM_PCCR0_GPT4_MASK             (1 << 21)
+-#define CCM_PCCR0_GPT5_OFFSET           20
+-#define CCM_PCCR0_GPT5_MASK             (1 << 20)
+-#define CCM_PCCR0_GPT6_OFFSET           19
+-#define CCM_PCCR0_GPT6_MASK             (1 << 19)
+-#define CCM_PCCR0_I2C1_OFFSET           18
+-#define CCM_PCCR0_I2C1_MASK             (1 << 18)
+-#define CCM_PCCR0_I2C2_OFFSET           17
+-#define CCM_PCCR0_I2C2_MASK             (1 << 17)
+-#define CCM_PCCR0_IIM_OFFSET            16
+-#define CCM_PCCR0_IIM_MASK              (1 << 16)
+-#define CCM_PCCR0_KPP_OFFSET            15
+-#define CCM_PCCR0_KPP_MASK              (1 << 15)
+-#define CCM_PCCR0_LCDC_OFFSET           14
+-#define CCM_PCCR0_LCDC_MASK             (1 << 14)
+-#define CCM_PCCR0_MSHC_OFFSET           13
+-#define CCM_PCCR0_MSHC_MASK             (1 << 13)
+-#define CCM_PCCR0_OWIRE_OFFSET          12
+-#define CCM_PCCR0_OWIRE_MASK            (1 << 12)
+-#define CCM_PCCR0_PWM_OFFSET            11
+-#define CCM_PCCR0_PWM_MASK              (1 << 11)
+-#define CCM_PCCR0_RTC_OFFSET            9
+-#define CCM_PCCR0_RTC_MASK              (1 << 9)
+-#define CCM_PCCR0_RTIC_OFFSET           8
+-#define CCM_PCCR0_RTIC_MASK             (1 << 8)
+-#define CCM_PCCR0_SAHARA_OFFSET         7
+-#define CCM_PCCR0_SAHARA_MASK           (1 << 7)
+-#define CCM_PCCR0_SCC_OFFSET            6
+-#define CCM_PCCR0_SCC_MASK              (1 << 6)
+-#define CCM_PCCR0_SDHC1_OFFSET          5
+-#define CCM_PCCR0_SDHC1_MASK            (1 << 5)
+-#define CCM_PCCR0_SDHC2_OFFSET          4
+-#define CCM_PCCR0_SDHC2_MASK            (1 << 4)
+-#define CCM_PCCR0_SDHC3_OFFSET          3
+-#define CCM_PCCR0_SDHC3_MASK            (1 << 3)
+-#define CCM_PCCR0_SLCDC_OFFSET          2
+-#define CCM_PCCR0_SLCDC_MASK            (1 << 2)
+-#define CCM_PCCR0_SSI1_IPG_OFFSET       1
+-#define CCM_PCCR0_SSI1_IPG_MASK         (1 << 1)
+-#define CCM_PCCR0_SSI2_IPG_OFFSET       0
+-#define CCM_PCCR0_SSI2_IPG_MASK         (1 << 0)
+-
+-#define CCM_PCCR1_UART1_OFFSET          31
+-#define CCM_PCCR1_UART1_MASK            (1 << 31)
+-#define CCM_PCCR1_UART2_OFFSET          30
+-#define CCM_PCCR1_UART2_MASK            (1 << 30)
+-#define CCM_PCCR1_UART3_OFFSET          29
+-#define CCM_PCCR1_UART3_MASK            (1 << 29)
+-#define CCM_PCCR1_UART4_OFFSET          28
+-#define CCM_PCCR1_UART4_MASK            (1 << 28)
+-#define CCM_PCCR1_UART5_OFFSET          27
+-#define CCM_PCCR1_UART5_MASK            (1 << 27)
+-#define CCM_PCCR1_UART6_OFFSET          26
+-#define CCM_PCCR1_UART6_MASK            (1 << 26)
+-#define CCM_PCCR1_USBOTG_OFFSET         25
+-#define CCM_PCCR1_USBOTG_MASK           (1 << 25)
+-#define CCM_PCCR1_WDT_OFFSET            24
+-#define CCM_PCCR1_WDT_MASK              (1 << 24)
+-#define CCM_PCCR1_HCLK_ATA_OFFSET       23
+-#define CCM_PCCR1_HCLK_ATA_MASK         (1 << 23)
+-#define CCM_PCCR1_HCLK_BROM_OFFSET      22
+-#define CCM_PCCR1_HCLK_BROM_MASK        (1 << 22)
+-#define CCM_PCCR1_HCLK_CSI_OFFSET       21
+-#define CCM_PCCR1_HCLK_CSI_MASK         (1 << 21)
+-#define CCM_PCCR1_HCLK_DMA_OFFSET       20
+-#define CCM_PCCR1_HCLK_DMA_MASK         (1 << 20)
+-#define CCM_PCCR1_HCLK_EMI_OFFSET       19
+-#define CCM_PCCR1_HCLK_EMI_MASK         (1 << 19)
+-#define CCM_PCCR1_HCLK_EMMA_OFFSET      18
+-#define CCM_PCCR1_HCLK_EMMA_MASK        (1 << 18)
+-#define CCM_PCCR1_HCLK_FEC_OFFSET       17
+-#define CCM_PCCR1_HCLK_FEC_MASK         (1 << 17)
+-#define CCM_PCCR1_HCLK_VPU_OFFSET       16
+-#define CCM_PCCR1_HCLK_VPU_MASK         (1 << 16)
+-#define CCM_PCCR1_HCLK_LCDC_OFFSET      15
+-#define CCM_PCCR1_HCLK_LCDC_MASK        (1 << 15)
+-#define CCM_PCCR1_HCLK_RTIC_OFFSET      14
+-#define CCM_PCCR1_HCLK_RTIC_MASK        (1 << 14)
+-#define CCM_PCCR1_HCLK_SAHARA_OFFSET    13
+-#define CCM_PCCR1_HCLK_SAHARA_MASK      (1 << 13)
+-#define CCM_PCCR1_HCLK_SLCDC_OFFSET     12
+-#define CCM_PCCR1_HCLK_SLCDC_MASK       (1 << 12)
+-#define CCM_PCCR1_HCLK_USBOTG_OFFSET    11
+-#define CCM_PCCR1_HCLK_USBOTG_MASK      (1 << 11)
+-#define CCM_PCCR1_PERCLK1_OFFSET        10
+-#define CCM_PCCR1_PERCLK1_MASK          (1 << 10)
+-#define CCM_PCCR1_PERCLK2_OFFSET        9
+-#define CCM_PCCR1_PERCLK2_MASK          (1 << 9)
+-#define CCM_PCCR1_PERCLK3_OFFSET        8
+-#define CCM_PCCR1_PERCLK3_MASK          (1 << 8)
+-#define CCM_PCCR1_PERCLK4_OFFSET        7
+-#define CCM_PCCR1_PERCLK4_MASK          (1 << 7)
+-#define CCM_PCCR1_VPU_BAUD_OFFSET       6
+-#define CCM_PCCR1_VPU_BAUD_MASK         (1 << 6)
+-#define CCM_PCCR1_SSI1_BAUD_OFFSET      5
+-#define CCM_PCCR1_SSI1_BAUD_MASK        (1 << 5)
+-#define CCM_PCCR1_SSI2_BAUD_OFFSET      4
+-#define CCM_PCCR1_SSI2_BAUD_MASK        (1 << 4)
+-#define CCM_PCCR1_NFC_BAUD_OFFSET       3
+-#define CCM_PCCR1_NFC_BAUD_MASK         (1 << 3)
+-#define CCM_PCCR1_MSHC_BAUD_OFFSET      2
+-#define CCM_PCCR1_MSHC_BAUD_MASK        (1 << 2)
+-
+-#define CCM_CCSR_32KSR          (1 << 15)
+-#define CCM_CCSR_CLKMODE1       (1 << 9)
+-#define CCM_CCSR_CLKMODE0       (1 << 8)
+-#define CCM_CCSR_CLKOSEL_OFFSET 0
+-#define CCM_CCSR_CLKOSEL_MASK   0x1f
++#define CCM_PCDR0_NFCDIV_OFFSET               12
++#define CCM_PCDR0_NFCDIV_MASK         (0xf << CCM_PCDR0_NFCDIV_OFFSET)
++#define CCM_PCDR0_VPUDIV_OFFSET               8
++#define CCM_PCDR0_VPUDIV_MASK         (0xf << CCM_PCDR0_VPUDIV_OFFSET)
++#define CCM_PCDR0_MSHCDIV_OFFSET      0
++#define CCM_PCDR0_MSHCDIV_MASK                (0x1f << CCM_PCDR0_MSHCDIV_OFFSET)
++
++#define CCM_PCDR1_PERDIV4_OFFSET      24
++#define CCM_PCDR1_PERDIV4_MASK                (0x3f << CCM_PCDR1_PERDIV4_OFFSET)
++#define CCM_PCDR1_PERDIV3_OFFSET      16
++#define CCM_PCDR1_PERDIV3_MASK                (0x3f << CCM_PCDR1_PERDIV3_OFFSET)
++#define CCM_PCDR1_PERDIV2_OFFSET      8
++#define CCM_PCDR1_PERDIV2_MASK                (0x3f << CCM_PCDR1_PERDIV2_OFFSET)
++#define CCM_PCDR1_PERDIV1_OFFSET      0
++#define CCM_PCDR1_PERDIV1_MASK                (0x3f << CCM_PCDR1_PERDIV1_OFFSET)
++
++#define CCM_PCCR0_CSPI1_OFFSET                31
++#define CCM_PCCR0_CSPI1_MASK          (1 << CCM_PCCR0_CSPI1_OFFSET)
++#define CCM_PCCR0_CSPI2_OFFSET                30
++#define CCM_PCCR0_CSPI2_MASK          (1 << CCM_PCCR0_CSPI2_OFFSET)
++#define CCM_PCCR0_CSPI3_OFFSET                29
++#define CCM_PCCR0_CSPI3_MASK          (1 << CCM_PCCR0_CSPI3_OFFSET)
++#define CCM_PCCR0_DMA_OFFSET          28
++#define CCM_PCCR0_DMA_MASK            (1 << CCM_PCCR0_DMA_OFFSET)
++#define CCM_PCCR0_EMMA_OFFSET         27
++#define CCM_PCCR0_EMMA_MASK           (1 << CCM_PCCR0_EMMA_OFFSET)
++#define CCM_PCCR0_FEC_OFFSET          26
++#define CCM_PCCR0_FEC_MASK            (1 << CCM_PCCR0_FEC_OFFSET)
++#define CCM_PCCR0_GPIO_OFFSET         25
++#define CCM_PCCR0_GPIO_MASK           (1 << CCM_PCCR0_GPIO_OFFSET)
++#define CCM_PCCR0_GPT1_OFFSET         24
++#define CCM_PCCR0_GPT1_MASK           (1 << CCM_PCCR0_GPT1_OFFSET)
++#define CCM_PCCR0_GPT2_OFFSET         23
++#define CCM_PCCR0_GPT2_MASK           (1 << CCM_PCCR0_GPT2_OFFSET)
++#define CCM_PCCR0_GPT3_OFFSET         22
++#define CCM_PCCR0_GPT3_MASK           (1 << CCM_PCCR0_GPT3_OFFSET)
++#define CCM_PCCR0_GPT4_OFFSET         21
++#define CCM_PCCR0_GPT4_MASK           (1 << CCM_PCCR0_GPT4_OFFSET)
++#define CCM_PCCR0_GPT5_OFFSET         20
++#define CCM_PCCR0_GPT5_MASK           (1 << CCM_PCCR0_GPT5_OFFSET)
++#define CCM_PCCR0_GPT6_OFFSET         19
++#define CCM_PCCR0_GPT6_MASK           (1 << CCM_PCCR0_GPT6_OFFSET)
++#define CCM_PCCR0_I2C1_OFFSET         18
++#define CCM_PCCR0_I2C1_MASK           (1 << CCM_PCCR0_I2C1_OFFSET)
++#define CCM_PCCR0_I2C2_OFFSET         17
++#define CCM_PCCR0_I2C2_MASK           (1 << CCM_PCCR0_I2C2_OFFSET)
++#define CCM_PCCR0_IIM_OFFSET          16
++#define CCM_PCCR0_IIM_MASK            (1 << CCM_PCCR0_IIM_OFFSET)
++#define CCM_PCCR0_KPP_OFFSET          15
++#define CCM_PCCR0_KPP_MASK            (1 << CCM_PCCR0_KPP_OFFSET)
++#define CCM_PCCR0_LCDC_OFFSET         14
++#define CCM_PCCR0_LCDC_MASK           (1 << CCM_PCCR0_LCDC_OFFSET)
++#define CCM_PCCR0_MSHC_OFFSET         13
++#define CCM_PCCR0_MSHC_MASK           (1 << CCM_PCCR0_MSHC_OFFSET)
++#define CCM_PCCR0_OWIRE_OFFSET                12
++#define CCM_PCCR0_OWIRE_MASK          (1 << CCM_PCCR0_OWIRE_OFFSET)
++#define CCM_PCCR0_PWM_OFFSET          11
++#define CCM_PCCR0_PWM_MASK            (1 << CCM_PCCR0_PWM_OFFSET)
++#define CCM_PCCR0_RTC_OFFSET          9
++#define CCM_PCCR0_RTC_MASK            (1 << CCM_PCCR0_RTC_OFFSET)
++#define CCM_PCCR0_RTIC_OFFSET         8
++#define CCM_PCCR0_RTIC_MASK           (1 << CCM_PCCR0_RTIC_OFFSET)
++#define CCM_PCCR0_SAHARA_OFFSET               7
++#define CCM_PCCR0_SAHARA_MASK         (1 << CCM_PCCR0_SAHARA_OFFSET)
++#define CCM_PCCR0_SCC_OFFSET          6
++#define CCM_PCCR0_SCC_MASK            (1 << CCM_PCCR0_SCC_OFFSET)
++#define CCM_PCCR0_SDHC1_OFFSET                5
++#define CCM_PCCR0_SDHC1_MASK          (1 << CCM_PCCR0_SDHC1_OFFSET)
++#define CCM_PCCR0_SDHC2_OFFSET                4
++#define CCM_PCCR0_SDHC2_MASK          (1 << CCM_PCCR0_SDHC2_OFFSET)
++#define CCM_PCCR0_SDHC3_OFFSET                3
++#define CCM_PCCR0_SDHC3_MASK          (1 << CCM_PCCR0_SDHC3_OFFSET)
++#define CCM_PCCR0_SLCDC_OFFSET                2
++#define CCM_PCCR0_SLCDC_MASK          (1 << CCM_PCCR0_SLCDC_OFFSET)
++#define CCM_PCCR0_SSI1_IPG_OFFSET     1
++#define CCM_PCCR0_SSI1_IPG_MASK               (1 << CCM_PCCR0_SSI1_IPG_OFFSET)
++#define CCM_PCCR0_SSI2_IPG_OFFSET     0
++#define CCM_PCCR0_SSI2_IPG_MASK               (1 << CCM_PCCR0_SSI2_IPG_OFFSET)
++
++#define CCM_PCCR1_UART1_OFFSET                31
++#define CCM_PCCR1_UART1_MASK          (1 << CCM_PCCR1_UART1_OFFSET)
++#define CCM_PCCR1_UART2_OFFSET                30
++#define CCM_PCCR1_UART2_MASK          (1 << CCM_PCCR1_UART2_OFFSET)
++#define CCM_PCCR1_UART3_OFFSET                29
++#define CCM_PCCR1_UART3_MASK          (1 << CCM_PCCR1_UART3_OFFSET)
++#define CCM_PCCR1_UART4_OFFSET                28
++#define CCM_PCCR1_UART4_MASK          (1 << CCM_PCCR1_UART4_OFFSET)
++#define CCM_PCCR1_UART5_OFFSET                27
++#define CCM_PCCR1_UART5_MASK          (1 << CCM_PCCR1_UART5_OFFSET)
++#define CCM_PCCR1_UART6_OFFSET                26
++#define CCM_PCCR1_UART6_MASK          (1 << CCM_PCCR1_UART6_OFFSET)
++#define CCM_PCCR1_USBOTG_OFFSET               25
++#define CCM_PCCR1_USBOTG_MASK         (1 << CCM_PCCR1_USBOTG_OFFSET)
++#define CCM_PCCR1_WDT_OFFSET          24
++#define CCM_PCCR1_WDT_MASK            (1 << CCM_PCCR1_WDT_OFFSET)
++#define CCM_PCCR1_HCLK_ATA_OFFSET     23
++#define CCM_PCCR1_HCLK_ATA_MASK               (1 << CCM_PCCR1_HCLK_ATA_OFFSET)
++#define CCM_PCCR1_HCLK_BROM_OFFSET    22
++#define CCM_PCCR1_HCLK_BROM_MASK      (1 << CCM_PCCR1_HCLK_BROM_OFFSET)
++#define CCM_PCCR1_HCLK_CSI_OFFSET     21
++#define CCM_PCCR1_HCLK_CSI_MASK               (1 << CCM_PCCR1_HCLK_CSI_OFFSET)
++#define CCM_PCCR1_HCLK_DMA_OFFSET     20
++#define CCM_PCCR1_HCLK_DMA_MASK               (1 << CCM_PCCR1_HCLK_DMA_OFFSET)
++#define CCM_PCCR1_HCLK_EMI_OFFSET     19
++#define CCM_PCCR1_HCLK_EMI_MASK               (1 << CCM_PCCR1_HCLK_EMI_OFFSET)
++#define CCM_PCCR1_HCLK_EMMA_OFFSET    18
++#define CCM_PCCR1_HCLK_EMMA_MASK      (1 << CCM_PCCR1_HCLK_EMMA_OFFSET)
++#define CCM_PCCR1_HCLK_FEC_OFFSET     17
++#define CCM_PCCR1_HCLK_FEC_MASK               (1 << CCM_PCCR1_HCLK_FEC_OFFSET)
++#define CCM_PCCR1_HCLK_VPU_OFFSET     16
++#define CCM_PCCR1_HCLK_VPU_MASK               (1 << CCM_PCCR1_HCLK_VPU_OFFSET)
++#define CCM_PCCR1_HCLK_LCDC_OFFSET    15
++#define CCM_PCCR1_HCLK_LCDC_MASK      (1 << CCM_PCCR1_HCLK_LCDC_OFFSET)
++#define CCM_PCCR1_HCLK_RTIC_OFFSET    14
++#define CCM_PCCR1_HCLK_RTIC_MASK      (1 << CCM_PCCR1_HCLK_RTIC_OFFSET)
++#define CCM_PCCR1_HCLK_SAHARA_OFFSET  13
++#define CCM_PCCR1_HCLK_SAHARA_MASK    (1 << CCM_PCCR1_HCLK_SAHARA_OFFSET)
++#define CCM_PCCR1_HCLK_SLCDC_OFFSET   12
++#define CCM_PCCR1_HCLK_SLCDC_MASK     (1 << CCM_PCCR1_HCLK_SLCDC_OFFSET)
++#define CCM_PCCR1_HCLK_USBOTG_OFFSET  11
++#define CCM_PCCR1_HCLK_USBOTG_MASK    (1 << CCM_PCCR1_HCLK_USBOTG_OFFSET)
++#define CCM_PCCR1_PERCLK1_OFFSET      10
++#define CCM_PCCR1_PERCLK1_MASK                (1 << CCM_PCCR1_PERCLK1_OFFSET)
++#define CCM_PCCR1_PERCLK2_OFFSET      9
++#define CCM_PCCR1_PERCLK2_MASK                (1 << CCM_PCCR1_PERCLK2_OFFSET)
++#define CCM_PCCR1_PERCLK3_OFFSET      8
++#define CCM_PCCR1_PERCLK3_MASK                (1 << CCM_PCCR1_PERCLK3_OFFSET)
++#define CCM_PCCR1_PERCLK4_OFFSET      7
++#define CCM_PCCR1_PERCLK4_MASK                (1 << CCM_PCCR1_PERCLK4_OFFSET)
++#define CCM_PCCR1_VPU_BAUD_OFFSET     6
++#define CCM_PCCR1_VPU_BAUD_MASK               (1 << CCM_PCCR1_VPU_BAUD_OFFSET)
++#define CCM_PCCR1_SSI1_BAUD_OFFSET    5
++#define CCM_PCCR1_SSI1_BAUD_MASK      (1 << CCM_PCCR1_SSI1_BAUD_OFFSET)
++#define CCM_PCCR1_SSI2_BAUD_OFFSET    4
++#define CCM_PCCR1_SSI2_BAUD_MASK      (1 << CCM_PCCR1_SSI2_BAUD_OFFSET)
++#define CCM_PCCR1_NFC_BAUD_OFFSET     3
++#define CCM_PCCR1_NFC_BAUD_MASK               (1 << CCM_PCCR1_NFC_BAUD_OFFSET)
++#define CCM_PCCR1_MSHC_BAUD_OFFSET    2
++#define CCM_PCCR1_MSHC_BAUD_MASK      (1 << CCM_PCCR1_MSHC_BAUD_OFFSET)
++
++#define CCM_CCSR_32KSR                        (1 << 15)
++#define CCM_CCSR_CLKMODE1             (1 << 9)
++#define CCM_CCSR_CLKMODE0             (1 << 8)
++#define CCM_CCSR_CLKOSEL_OFFSET       0
++#define CCM_CCSR_CLKOSEL_MASK         (0x1f << CCM_CCSR_CLKOSEL_OFFSET)
+-#define SYS_FMCR                0x14  /*  Functional Muxing Control Reg */
+-#define SYS_CHIP_ID             0x00  /* The offset of CHIP ID register */
++#define SYS_FMCR                      0x14    /*  Functional Muxing Control Reg */
++#define SYS_CHIP_ID                   0x00    /* The offset of CHIP ID register */
+ #endif /* __ARCH_ARM_MACH_MX2_CRM_REGS_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/devices.c linux-2.6.28-karo/arch/arm/mach-mx2/devices.c
+--- linux-2.6.28/arch/arm/mach-mx2/devices.c   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/devices.c      2009-03-11 13:16:24.000000000 +0100
+@@ -33,6 +33,7 @@
+ #include <linux/gpio.h>
+ #include <mach/hardware.h>
++#include <mach/mmc.h>
+ /*
+  * Resource definition for the MXC IrDA
+@@ -58,6 +59,118 @@ struct platform_device mxc_irda_device =
+       .resource = mxc_irda_resources,
+ };
++static u64 mxc_vpu_dmamask = 0xffffffffUL;
++
++/* Platform Data for MXC VPU */
++struct platform_device mxc_vpu_device = {
++      .name = "mxc_vpu",
++      .id = 0,
++      .dev = {
++              .dma_mask = &mxc_vpu_dmamask,
++              .coherent_dma_mask = ~0UL,
++      },
++};
++
++#ifdef CONFIG_MACH_MX27
++static struct resource mx27_camera_resources[] = {
++      {
++              .start = CSI_BASE_ADDR,
++              .end = CSI_BASE_ADDR + 0x1f,
++              .flags = IORESOURCE_MEM,
++      }, {
++              .start = EMMA_PRP_BASE_ADDR,
++              .end = EMMA_PRP_BASE_ADDR + 0x1f,
++              .flags = IORESOURCE_MEM,
++      }, {
++              .start = MXC_INT_CSI,
++              .end = MXC_INT_CSI,
++              .flags = IORESOURCE_IRQ,
++      }, {
++              .start = MXC_INT_EMMAPRP,
++              .end = MXC_INT_EMMAPRP,
++              .flags = IORESOURCE_IRQ,
++      },
++};
++
++struct platform_device mx27_camera_device = {
++      .name = "mx27-camera",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(mx27_camera_resources),
++      .resource = mx27_camera_resources,
++};
++#endif
++
++/*
++ * SPI master controller
++ *
++ * - i.MX1: 2 channel (slighly different register setting)
++ * - i.MX21: 2 channel
++ * - i.MX27: 3 channel
++ */
++static struct resource mxc_spi_resources0[] = {
++      [0] = {
++             .start = CSPI1_BASE_ADDR,
++             .end = CSPI1_BASE_ADDR + 0x1F,
++             .flags = IORESOURCE_MEM,
++      },
++      [1] = {
++             .start = MXC_INT_CSPI1,
++             .end = MXC_INT_CSPI1,
++             .flags = IORESOURCE_IRQ,
++      },
++};
++
++static struct resource mxc_spi_resources1[] = {
++      [0] = {
++              .start = CSPI2_BASE_ADDR,
++              .end = CSPI2_BASE_ADDR + SZ_4K - 1,
++              .flags = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start = MXC_INT_CSPI2,
++              .end = MXC_INT_CSPI2,
++              .flags = IORESOURCE_IRQ,
++      },
++};
++
++#ifdef CONFIG_MACH_MX27
++static struct resource mxc_spi_resources2[] = {
++      [0] = {
++              .start = CSPI3_BASE_ADDR,
++              .end = CSPI3_BASE_ADDR + SZ_4K - 1,
++              .flags = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start = MXC_INT_CSPI3,
++              .end = MXC_INT_CSPI3,
++              .flags = IORESOURCE_IRQ,
++      },
++};
++#endif
++
++struct platform_device mxc_spi_device0 = {
++      .name = "mxc_spi",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(mxc_spi_resources0),
++      .resource = mxc_spi_resources0,
++};
++
++struct platform_device mxc_spi_device1 = {
++      .name = "mxc_spi",
++      .id = 1,
++      .num_resources = ARRAY_SIZE(mxc_spi_resources1),
++      .resource = mxc_spi_resources1,
++};
++
++#ifdef CONFIG_MACH_MX27
++struct platform_device mxc_spi_device2 = {
++      .name = "mxc_spi",
++      .id = 2,
++      .num_resources = ARRAY_SIZE(mxc_spi_resources2),
++      .resource = mxc_spi_resources2,
++};
++#endif
++
+ /*
+  * General Purpose Timer
+  * - i.MX1: 2 timer (slighly different register handling)
+@@ -169,6 +282,72 @@ struct platform_device mxc_gpt5 = {
+ };
+ #endif
++/* I2C channel #1 */
++static struct resource imx_i2c_1_resources[] = {
++      [0] = {
++              .start  = I2C_BASE_ADDR,
++              .end    = I2C_BASE_ADDR + 0x0F,
++              .flags  = IORESOURCE_MEM
++      },
++      [1] = {
++              .start  = MXC_INT_I2C,
++              .end    = MXC_INT_I2C,
++              .flags  = IORESOURCE_IRQ
++      }
++};
++
++#ifdef CONFIG_MACH_MX27
++static struct resource imx_i2c_2_resources[] = {
++      [0] = {
++              .start  = I2C2_BASE_ADDR,
++              .end    = I2C2_BASE_ADDR + 0x0F,
++              .flags  = IORESOURCE_MEM
++      },
++      [1] = {
++              .start  = MXC_INT_I2C2,
++              .end    = MXC_INT_I2C2,
++              .flags  = IORESOURCE_IRQ
++      }
++};
++#endif
++
++struct platform_device imx_i2c_device0 = {
++      .name = "imx_i2c",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(imx_i2c_1_resources),
++      .resource = imx_i2c_1_resources
++};
++
++#ifdef CONFIG_MACH_MX27
++struct platform_device imx_i2c_device1 = {
++      .name = "imx_i2c",
++      .id = 1,
++      .num_resources = ARRAY_SIZE(imx_i2c_2_resources),
++      .resource = imx_i2c_2_resources
++};
++#endif
++
++#if defined(CONFIG_RTC_MXC) || defined(CONFIG_RTC_MXC_MODULE)
++static struct resource rtc_resources[] = {
++      {
++              .start = RTC_BASE_ADDR,
++              .end = RTC_BASE_ADDR + 0x30,
++              .flags = IORESOURCE_MEM,
++      },
++      {
++              .start = MXC_INT_RTC,
++              .flags = IORESOURCE_IRQ,
++      },
++};
++
++struct platform_device mxc_rtc_device = {
++      .name = "mxc_rtc",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(rtc_resources),
++      .resource = rtc_resources,
++};
++#endif
++
+ /*
+  * Watchdog:
+  * - i.MX1
+@@ -190,6 +369,291 @@ struct platform_device mxc_wdt = {
+       .resource = mxc_wdt_resources,
+ };
++static struct resource mxc_nand_resources[] = {
++      {
++              .start  = NFC_BASE_ADDR,
++              .end    = NFC_BASE_ADDR + 0xfff,
++              .flags  = IORESOURCE_MEM
++      }, {
++              .start  = MXC_INT_NANDFC,
++              .end    = MXC_INT_NANDFC,
++              .flags  = IORESOURCE_IRQ
++      },
++};
++
++struct platform_device mxc_nand_device = {
++      .name = "mxc_nand",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(mxc_nand_resources),
++      .resource = mxc_nand_resources,
++};
++
++static struct resource mxc_w1_master_resources[] = {
++      {
++              .start = OWIRE_BASE_ADDR,
++              .end   = OWIRE_BASE_ADDR + SZ_4K - 1,
++              .flags = IORESOURCE_MEM,
++      },
++};
++
++struct platform_device mxc_w1_master_device = {
++      .name = "mxc_w1",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(mxc_w1_master_resources),
++      .resource = mxc_w1_master_resources,
++};
++
++/*
++ * Resource definition for the MXC SDHC
++ */
++static struct resource mxc_sdhc1_resources[] = {
++      [0] = {
++              .start = SDHC1_BASE_ADDR,
++              .end   = SDHC1_BASE_ADDR + SZ_4K - 1,
++              .flags = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start = MXC_INT_SDHC1,
++              .end   = MXC_INT_SDHC1,
++              .flags = IORESOURCE_IRQ,
++      },
++      [2] = {
++              .name   = "sdhc1",
++              .start  = DMA_REQ_SDHC1,
++              .end    = DMA_REQ_SDHC1,
++              .flags  = IORESOURCE_DMA
++      },
++};
++
++static u64 mxc_sdhc1_dmamask = 0xffffffffUL;
++
++struct platform_device mxc_sdhc_device0 = {
++      .name           = "imx-mmc",
++      .id             = 0,
++      .dev            = {
++              .dma_mask = &mxc_sdhc1_dmamask,
++              .coherent_dma_mask = 0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(mxc_sdhc1_resources),
++      .resource       = mxc_sdhc1_resources,
++};
++
++static struct resource mxc_sdhc2_resources[] = {
++      [0] = {
++              .start = SDHC2_BASE_ADDR,
++              .end   = SDHC2_BASE_ADDR + SZ_4K - 1,
++              .flags = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start = MXC_INT_SDHC2,
++              .end   = MXC_INT_SDHC2,
++              .flags = IORESOURCE_IRQ,
++      },
++      [2] = {
++              .name   = "sdhc2",
++              .start  = DMA_REQ_SDHC2,
++              .end    = DMA_REQ_SDHC2,
++              .flags  = IORESOURCE_DMA
++      },
++};
++
++static u64 mxc_sdhc2_dmamask = 0xffffffffUL;
++
++struct platform_device mxc_sdhc_device1 = {
++      .name           = "imx-mmc",
++      .id             = 1,
++      .dev            = {
++              .dma_mask = &mxc_sdhc2_dmamask,
++              .coherent_dma_mask = 0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(mxc_sdhc2_resources),
++      .resource       = mxc_sdhc2_resources,
++};
++
++static u64 otg_dmamask = ~(u32) 0;
++
++static struct resource mxc_otg_resources[] = {
++      {
++              .start = OTG_BASE_ADDR + 0x000,
++              .end   = OTG_BASE_ADDR + 0x1ff,
++              .flags = IORESOURCE_MEM,
++      }, {
++              .start = MXC_INT_USB1,
++              .flags = IORESOURCE_IRQ,
++      },
++};
++
++/*
++ * lcdc:
++ * - i.MX1: the basic controller
++ * - i.MX21: to be checked
++ * - i.MX27: like i.MX1, with slightly variations
++ */
++static struct resource mxc_fb[] = {
++      {
++              .start = LCDC_BASE_ADDR,
++              .end   = LCDC_BASE_ADDR + 0xFFF,
++              .flags = IORESOURCE_MEM,
++      }, {
++              .start = MXC_INT_LCDC,
++              .end   = MXC_INT_LCDC,
++              .flags = IORESOURCE_IRQ,
++      },
++};
++
++/* mxc lcd driver */
++struct platform_device mxc_fb_device = {
++      .name = "imx-fb",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(mxc_fb),
++      .resource = mxc_fb,
++      .dev = {
++              .coherent_dma_mask = 0xFFFFFFFF,
++      },
++};
++
++struct platform_device mxc_otg = {
++      .name = "mxc-ehci",
++      .id = 0,
++      .dev = {
++              .coherent_dma_mask = 0xffffffff,
++              .dma_mask = &otg_dmamask,
++      },
++      .resource = mxc_otg_resources,
++      .num_resources = ARRAY_SIZE(mxc_otg_resources),
++};
++
++static struct resource mxc_ehci2_resources[] = {
++      {
++              .start = OTG_BASE_ADDR + 0x400,
++              .end   = OTG_BASE_ADDR + 0x5ff,
++              .flags = IORESOURCE_MEM,
++      }, {
++              .start = MXC_INT_USB2,
++              .flags = IORESOURCE_IRQ,
++      },
++};
++
++static u64 ehci2_dmamask = ~(u32) 0;
++
++struct platform_device mxc_ehci2 = {
++      .name = "mxc-ehci",
++      .id = 1,
++      .dev = {
++              .coherent_dma_mask = 0xffffffff,
++              .dma_mask = &ehci2_dmamask,
++      },
++      .num_resources = ARRAY_SIZE(mxc_ehci2_resources),
++      .resource = mxc_ehci2_resources,
++};
++
++/*
++ * SSI bus:
++ * - i.MX1: 2 channels
++ * - i.MX21: 2 channels
++ * - i.MX27: 2 channels
++ */
++static struct resource imx_ssi_resources0[] = {
++      [0] = {
++              .start  = SSI1_BASE_ADDR,
++              .end    = SSI1_BASE_ADDR + 0x6F,
++              .flags  = IORESOURCE_MEM
++      },
++      [1] = {
++              .start  = MXC_INT_SSI1,
++              .end    = MXC_INT_SSI1,
++              .flags  = IORESOURCE_IRQ
++      },
++      [2] = {
++              .name   = "tx0",
++              .start  = DMA_REQ_SSI1_TX0,
++              .end    = DMA_REQ_SSI1_TX0,
++              .flags  = IORESOURCE_DMA
++      },
++      [3] = {
++              .name   = "rx0",
++              .start  = DMA_REQ_SSI1_RX0,
++              .end    = DMA_REQ_SSI1_RX0,
++              .flags  = IORESOURCE_DMA
++      },
++      [4] = {
++              .name   = "tx1",
++              .start  = DMA_REQ_SSI1_TX1,
++              .end    = DMA_REQ_SSI1_TX1,
++              .flags  = IORESOURCE_DMA
++      },
++      [5] = {
++              .name   = "rx1",
++              .start  = DMA_REQ_SSI1_RX1,
++              .end    = DMA_REQ_SSI1_RX1,
++              .flags  = IORESOURCE_DMA
++      }
++};
++
++static struct resource imx_ssi_resources1[] = {
++      [0] = {
++              .start  = SSI2_BASE_ADDR,
++              .end    = SSI2_BASE_ADDR + 0x6F,
++              .flags  = IORESOURCE_MEM
++      },
++      [1] = {
++              .start  = MXC_INT_SSI2,
++              .end    = MXC_INT_SSI2,
++              .flags  = IORESOURCE_IRQ
++      },
++      [2] = {
++              .name   = "tx0",
++              .start  = DMA_REQ_SSI2_TX0,
++              .end    = DMA_REQ_SSI2_TX0,
++              .flags  = IORESOURCE_DMA
++      },
++      [3] = {
++              .name   = "rx0",
++              .start  = DMA_REQ_SSI2_RX0,
++              .end    = DMA_REQ_SSI2_RX0,
++              .flags  = IORESOURCE_DMA
++      },
++      [4] = {
++              .name   = "tx1",
++              .start  = DMA_REQ_SSI2_TX1,
++              .end    = DMA_REQ_SSI2_TX1,
++              .flags  = IORESOURCE_DMA
++      },
++      [5] = {
++              .name   = "rx1",
++              .start  = DMA_REQ_SSI2_RX1,
++              .end    = DMA_REQ_SSI2_RX1,
++              .flags  = IORESOURCE_DMA
++      }
++};
++
++struct platform_device imx_ssi_device0 = {
++      .name = "mxc-ssi",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(imx_ssi_resources0),
++      .resource = imx_ssi_resources0
++};
++
++struct platform_device imx_ssi_device1 = {
++      .name = "mxc-ssi",
++      .id = 1,
++      .num_resources = ARRAY_SIZE(imx_ssi_resources1),
++      .resource = imx_ssi_resources1
++};
++
++static struct resource mxc_dam_resources = {
++      .start  = AUDMUX_BASE_ADDR,
++      .end    = AUDMUX_BASE_ADDR + 0x1F,
++      .flags  = IORESOURCE_MEM
++};
++
++struct platform_device mxc_dam_device = {
++      .name = "mxc-dam",
++      .id = 0,
++      .num_resources = 1,
++      .resource = &mxc_dam_resources
++};
++
+ /* GPIO port description */
+ static struct mxc_gpio_port imx_gpio_ports[] = {
+       [0] = {
+@@ -229,3 +693,4 @@ int __init mxc_register_gpios(void)
+ {
+       return mxc_gpio_init(imx_gpio_ports, ARRAY_SIZE(imx_gpio_ports));
+ }
++//arch_initcall(mxc_register_gpios);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/devices.h linux-2.6.28-karo/arch/arm/mach-mx2/devices.h
+--- linux-2.6.28/arch/arm/mach-mx2/devices.h   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/devices.h      2009-03-11 13:16:24.000000000 +0100
+@@ -4,6 +4,7 @@ extern struct platform_device mxc_gpt2;
+ extern struct platform_device mxc_gpt3;
+ extern struct platform_device mxc_gpt4;
+ extern struct platform_device mxc_gpt5;
++extern struct platform_device mxc_rtc_device;
+ extern struct platform_device mxc_wdt;
+ extern struct platform_device mxc_irda_device;
+ extern struct platform_device mxc_uart_device0;
+@@ -12,4 +13,20 @@ extern struct platform_device mxc_uart_d
+ extern struct platform_device mxc_uart_device3;
+ extern struct platform_device mxc_uart_device4;
+ extern struct platform_device mxc_uart_device5;
+-
++extern struct platform_device mxc_nand_device;
++extern struct platform_device mxc_w1_master_device;
++extern struct platform_device mxc_sdhc_device0;
++extern struct platform_device mxc_sdhc_device1;
++extern struct platform_device mxc_otg;
++extern struct platform_device mxc_ehci2;
++extern struct platform_device mxc_spi_device0;
++extern struct platform_device mxc_spi_device1;
++extern struct platform_device mxc_spi_device2;
++extern struct platform_device imx_ssi_device0;
++extern struct platform_device imx_ssi_device1;
++extern struct platform_device mxc_dam_device;
++extern struct platform_device imx_i2c_device0;
++extern struct platform_device imx_i2c_device1;
++extern struct platform_device mx27_camera_device;
++extern struct platform_device mxc_fb_device;
++extern struct platform_device mxc_vpu_device;
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/generic.c linux-2.6.28-karo/arch/arm/mach-mx2/generic.c
+--- linux-2.6.28/arch/arm/mach-mx2/generic.c   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/generic.c      2009-03-11 13:16:24.000000000 +0100
+@@ -35,7 +35,7 @@ static struct map_desc mxc_io_desc[] __i
+        * - and some reserved space
+        */
+       {
+-              .virtual = AIPI_BASE_ADDR_VIRT,
++              .virtual = (unsigned long)AIPI_BASE_ADDR_VIRT,
+               .pfn = __phys_to_pfn(AIPI_BASE_ADDR),
+               .length = AIPI_SIZE,
+               .type = MT_DEVICE
+@@ -46,7 +46,7 @@ static struct map_desc mxc_io_desc[] __i
+        * - ATA
+        */
+       {
+-              .virtual = SAHB1_BASE_ADDR_VIRT,
++              .virtual = (unsigned long)SAHB1_BASE_ADDR_VIRT,
+               .pfn = __phys_to_pfn(SAHB1_BASE_ADDR),
+               .length = SAHB1_SIZE,
+               .type = MT_DEVICE
+@@ -56,7 +56,7 @@ static struct map_desc mxc_io_desc[] __i
+        * - EMI
+        */
+       {
+-              .virtual = X_MEMC_BASE_ADDR_VIRT,
++              .virtual = (unsigned long)X_MEMC_BASE_ADDR_VIRT,
+               .pfn = __phys_to_pfn(X_MEMC_BASE_ADDR),
+               .length = X_MEMC_SIZE,
+               .type = MT_DEVICE
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/include/mach/board-tx27.h linux-2.6.28-karo/arch/arm/mach-mx2/include/mach/board-tx27.h
+--- linux-2.6.28/arch/arm/mach-mx2/include/mach/board-tx27.h   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/include/mach/board-tx27.h      2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,94 @@
++/*
++ * arch/arm/mach-mx27/board-tx27.h
++ *
++ * Copyright 2008 <LW@KARO-electronics.de>
++ * based on arch/arm/mach-mx27/board-mx27ads.h by eescale Semiconductor, Inc.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++//#define FEC_MII_IRQ
++
++#define MXC_LL_UART_PADDR       UART1_BASE_ADDR
++#define MXC_LL_UART_VADDR       AIPI_IO_ADDRESS(UART1_BASE_ADDR)
++
++/*!
++ * These defines are used to enable or disable a particular UART port. If
++ * disabled, the UART will not be registered in the file system and the user
++ * will not be able to access it.
++ * Specify a value of 1 to enable the UART and 0 to disable it.
++ */
++#define UART1_ENABLED           1
++/* UART 2 configuration */
++#define UART2_ENABLED           1
++/* UART 3 configuration */
++#define UART3_ENABLED           1
++/* UART 4 configuration */
++#define UART4_ENABLED           0     /* Disable UART 4 as its pins are shared with ATA */
++#define UART5_ENABLED           0
++#define UART6_ENABLED           0
++
++#ifndef __ASSEMBLY__
++#include <mach/iomux.h>
++
++#define MXC_BD_LED1           0
++#define MXC_BD_LED2           (1 << 5)
++static inline void MXC_BD_LED_ON(unsigned int led)
++{
++      if (led & MXC_BD_LED2) {
++              __gpio_set_value(GPIO_PORTF | 13, 1);
++      }
++}
++static inline void MXC_BD_LED_OFF(unsigned int led)
++{
++      if (led & MXC_BD_LED2) {
++              __gpio_set_value(GPIO_PORTF | 13, 0);
++      }
++}
++
++extern int gpio_fec_active(void);
++extern void gpio_fec_inactive(void);
++extern int gpio_sdhc_active(int module);
++extern int gpio_sdhc_inactive(int module);
++extern int gpio_usbh2_active(void);
++extern void gpio_usbh2_inactive(void);
++#if 0
++extern int gpio_uart_active(int port, int irda);
++extern int gpio_uart_inactive(int port);
++extern int config_uartdma_event(int port);
++extern int gpio_usbh1_active(void);
++extern void gpio_usbh1_inactive(void);
++extern int gpio_usbotg_fs_active(void);
++extern void gpio_usbotg_fs_inactive(void);
++extern int gpio_i2c_active(int i2c_num);
++extern int gpio_i2c_inactive(int i2c_num);
++extern int gpio_spi_active(int cspi_mod);
++extern int gpio_spi_inactive(int cspi_mod);
++extern int gpio_nand_active(void);
++extern void gpio_nand_inactive(void);
++extern int gpio_sensor_active(void);
++extern void gpio_sensor_inactive(void);
++extern int gpio_keypad_active(void);
++extern void gpio_keypad_inactive(void);
++extern int gpio_ata_active(void);
++extern void gpio_ata_inactive(void);
++extern int gpio_slcdc_active(int type);
++extern int gpio_slcdc_inactive(int type);
++extern int gpio_ssi_active(int ssi_num);
++extern int gpio_ssi_inactive(int ssi_num);
++extern int gpio_owire_active(void);
++extern void gpio_owire_inactive(void);
++#endif
++extern int gpio_usbotg_hs_active(void);
++extern void gpio_usbotg_hs_inactive(void);
++extern int gpio_ac97_active(void);
++extern void gpio_ac97_inactive(void);
++
++#endif // __ASSEMBLY__
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/include/mach/iomux.h linux-2.6.28-karo/arch/arm/mach-mx2/include/mach/iomux.h
+--- linux-2.6.28/arch/arm/mach-mx2/include/mach/iomux.h        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/include/mach/iomux.h   2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,460 @@
++/*
++ * arch/arm/mach-mx1/include/mach/iomux.h
++ *
++ * Copyright (C) 2008 by Lothar Wassmann <LW@KARO-electronics.de>
++ *    derived from: arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h
++ *    Copyright (C) 2008 by Sascha Hauer <kernel@pengutronix.de>
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston,
++ * MA 02110-1301, USA.
++ *
++ * Pin definitions for the Freescale MX2 architecture
++ */
++
++#ifndef _MXC_GPIO_MX2_H
++#define _MXC_GPIO_MX2_H
++
++#define GPIO_PORT_MAX  5
++
++#include <mach/iomux-mx1-mx2.h>
++
++enum {
++      MXC_DEFINE_PIN(A,  0, PF, USBH2_CLK, 0),
++      MXC_DEFINE_PIN(A,  1, PF, USBH2_DIR, 0),
++      MXC_DEFINE_PIN(A,  2, PF, USBH2_DATA7, 0),
++      MXC_DEFINE_PIN(A,  3, PF, USBH2_NXT, 0),
++      MXC_DEFINE_PIN(A,  4, PF, USBH2_STP, 0),
++
++      MXC_DEFINE_PIN(A,  5, PF, LSCLK, GPIO_OUT),
++      MXC_DEFINE_PIN(A,  6, PF, LD0, GPIO_OUT),
++      MXC_DEFINE_PIN(A,  7, PF, LD1, GPIO_OUT),
++      MXC_DEFINE_PIN(A,  8, PF, LD2, GPIO_OUT),
++      MXC_DEFINE_PIN(A,  9, PF, LD3, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 10, PF, LD4, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 11, PF, LD5, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 12, PF, LD6, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 13, PF, LD7, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 14, PF, LD8, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 15, PF, LD9, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 16, PF, LD10, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 17, PF, LD11, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 18, PF, LD12, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 19, PF, LD13, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 20, PF, LD14, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 21, PF, LD15, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 22, PF, LD16, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 23, PF, LD17, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 24, PF, REV, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 25, PF, CLS, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 26, PF, PS, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 27, PF, SPL_SPR, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 28, PF, HSYNC, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 29, PF, VSYNC, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 30, PF, CONTRAST, GPIO_OUT),
++      MXC_DEFINE_PIN(A, 31, PF, OE_ACD, GPIO_OUT),
++
++      MXC_DEFINE_PIN(B, 10, PF, CSI_D0, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 11, PF, CSI_D1, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 12, PF, CSI_D2, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 13, PF, CSI_D3, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 14, PF, CSI_D4, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 15, PF, CSI_MCLK, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 16, PF, CSI_PIXCLK, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 17, PF, CSI_D5,  GPIO_OUT),
++      MXC_DEFINE_PIN(B, 18, PF, CSI_D6,  GPIO_OUT),
++
++      MXC_DEFINE_PIN(B, 10, AF, UART6_TXD, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 11, AF, UART6_RXD, GPIO_IN),
++      MXC_DEFINE_PIN(B, 12, AF, UART6_CTS, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 13, AF, UART6_RTS, GPIO_IN),
++
++      MXC_DEFINE_PIN(B, 18, AF, UART5_TXD,  GPIO_OUT),
++      MXC_DEFINE_PIN(B, 19, AF, UART5_RXD,  GPIO_IN),
++      MXC_DEFINE_PIN(B, 20, AF, UART5_CTS,  GPIO_OUT),
++      MXC_DEFINE_PIN(B, 21, AF, UART5_RTS,  GPIO_IN),
++
++      MXC_DEFINE_PIN(B, 19, PF, CSI_D7,  GPIO_OUT),
++      MXC_DEFINE_PIN(B, 20, PF, CSI_VSYNC,  GPIO_OUT),
++      MXC_DEFINE_PIN(B, 21, PF, CSI_HSYNC,  GPIO_OUT),
++
++      MXC_DEFINE_PIN(B, 22, PF, USBH1_SUSP, 0),
++      MXC_DEFINE_PIN(B, 23, PF, USB_PWR, 0),
++      MXC_DEFINE_PIN(B, 24, PF, USB_OC_B, 0),
++      MXC_DEFINE_PIN(B, 25, PF, USBH1_RCV, 0),
++      MXC_DEFINE_PIN(B, 26, PF, USBH1_FS, 0),
++      MXC_DEFINE_PIN(B, 27, PF, USBH1_OE_B, 0),
++      MXC_DEFINE_PIN(B, 28, PF, USBH1_TXDM, 0),
++      MXC_DEFINE_PIN(B, 29, PF, USBH1_TXDP, 0),
++      MXC_DEFINE_PIN(B, 30, PF, USBH1_RXDM, 0),
++      MXC_DEFINE_PIN(B, 31, PF, USBH1_RXDP, 0),
++
++      MXC_DEFINE_PIN(B, 26, AF, UART4_RTS, GPIO_IN),
++      MXC_DEFINE_PIN(B, 28, AF, UART4_TXD, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 29, AF, UART4_CTS, GPIO_OUT),
++      MXC_DEFINE_PIN(B, 31, AF, UART4_RXD, GPIO_IN),
++
++      MXC_DEFINE_PIN(C, 14, PF, TOUT, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 15, PF, TIN, GPIO_IN),
++
++      MXC_DEFINE_PIN(C, 5, PF, I2C2_SDA, GPIO_IN),
++      MXC_DEFINE_PIN(C, 6, PF, I2C2_SCL, GPIO_IN),
++
++      MXC_DEFINE_PIN(C, 7, PF, USBOTG_DATA5, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 8, PF, USBOTG_DATA6, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 9, PF, USBOTG_DATA0, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 10, PF, USBOTG_DATA2, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 11, PF, USBOTG_DATA1, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 12, PF, USBOTG_DATA4, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 13, PF, USBOTG_DATA3, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 0, PF, USBOTG_NXT, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 1, PF, USBOTG_STP, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 2, PF, USBOTG_DIR, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 24, PF, USBOTG_CLK, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 25, PF, USBOTG_DATA7, GPIO_OUT),
++
++      MXC_DEFINE_PIN(C, 20, PF, SSI1_FS, GPIO_IN),
++      MXC_DEFINE_PIN(C, 21, PF, SSI1_RXD, GPIO_IN),
++      MXC_DEFINE_PIN(C, 22, PF, SSI1_TXD, GPIO_IN),
++      MXC_DEFINE_PIN(C, 23, PF, SSI1_CLK, GPIO_IN),
++
++      MXC_DEFINE_PIN(C, 24, PF, SSI2_FS, GPIO_IN),
++      MXC_DEFINE_PIN(C, 25, PF, SSI2_RXD, GPIO_IN),
++      MXC_DEFINE_PIN(C, 26, PF, SSI2_TXD, GPIO_IN),
++      MXC_DEFINE_PIN(C, 27, PF, SSI2_CLK, GPIO_IN),
++
++      MXC_DEFINE_PIN(C, 28, PF, SSI3_FS, GPIO_IN),
++      MXC_DEFINE_PIN(C, 29, PF, SSI3_RXD, GPIO_IN),
++      MXC_DEFINE_PIN(C, 30, PF, SSI3_TXD, GPIO_IN),
++      MXC_DEFINE_PIN(C, 31, PF, SSI3_CLK, GPIO_IN),
++
++      MXC_DEFINE_PIN(C, 16, PF, SSI4_FS, GPIO_IN),
++      MXC_DEFINE_PIN(C, 17, PF, SSI4_RXD, GPIO_IN),
++      MXC_DEFINE_PIN(C, 18, PF, SSI4_TXD, GPIO_IN),
++      MXC_DEFINE_PIN(C, 19, PF, SSI4_CLK, GPIO_IN),
++
++      MXC_DEFINE_PIN(B,  5, AIN, SLCDC1_CLK, 0),
++      MXC_DEFINE_PIN(B,  6, AIN, SLCDC1_D0, 0),
++      MXC_DEFINE_PIN(B,  7, AIN, SLCDC1_RS, 0),
++      MXC_DEFINE_PIN(B,  8, AIN, SLCDC1_CS, 0),
++
++      MXC_DEFINE_PIN(C, 28, AIN, SLCDC2_D0, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 29, AIN, SLCDC2_RS, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 30, AIN, SLCDC2_CS, GPIO_OUT),
++      MXC_DEFINE_PIN(C, 31, AIN, SLCDC2_CLK, GPIO_OUT),
++
++      MXC_DEFINE_PIN(D, 2, PF, ATA_DATA0, 0),
++      MXC_DEFINE_PIN(D, 3, PF, ATA_DATA1, 0),
++      MXC_DEFINE_PIN(D, 4, PF, ATA_DATA2, 0),
++      MXC_DEFINE_PIN(D, 5, PF, ATA_DATA3, 0),
++      MXC_DEFINE_PIN(D, 6, PF, ATA_DATA4, 0),
++      MXC_DEFINE_PIN(D, 7, PF, ATA_DATA5, 0),
++      MXC_DEFINE_PIN(D, 8, PF, ATA_DATA6, 0),
++      MXC_DEFINE_PIN(D, 9, PF, ATA_DATA7, 0),
++      MXC_DEFINE_PIN(D, 10, PF, ATA_DATA8, 0),
++      MXC_DEFINE_PIN(D, 11, PF, ATA_DATA9, 0),
++      MXC_DEFINE_PIN(D, 12, PF, ATA_DATA10, 0),
++      MXC_DEFINE_PIN(D, 13, PF, ATA_DATA11, 0),
++      MXC_DEFINE_PIN(D, 14, PF, ATA_DATA12, 0),
++      MXC_DEFINE_PIN(D, 15, PF, ATA_DATA13, 0),
++      MXC_DEFINE_PIN(D, 16, PF, ATA_DATA14, 0),
++      MXC_DEFINE_PIN(F, 23, PF, ATA_DATA15, 0),
++
++      MXC_DEFINE_PIN(D, 0, AIN, FEC_TXD0, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 1, AIN, FEC_TXD1, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 2, AIN, FEC_TXD2, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 3, AIN, FEC_TXD3, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 4, AOUT, FEC_RX_ER, GPIO_IN),
++      MXC_DEFINE_PIN(D, 5, AOUT, FEC_RXD1, GPIO_IN),
++      MXC_DEFINE_PIN(D, 6, AOUT, FEC_RXD2, GPIO_IN),
++      MXC_DEFINE_PIN(D, 7, AOUT, FEC_RXD3, GPIO_IN),
++      MXC_DEFINE_PIN(D, 8, AF, FEC_MDIO, GPIO_IN),
++      MXC_DEFINE_PIN(D, 9, AIN, FEC_MDC, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 10, AOUT, FEC_CRS, GPIO_IN),
++      MXC_DEFINE_PIN(D, 11, AOUT, FEC_TX_CLK, GPIO_IN),
++      MXC_DEFINE_PIN(D, 12, AOUT, FEC_RXD0, GPIO_IN),
++      MXC_DEFINE_PIN(D, 13, AOUT, FEC_RX_DV, GPIO_IN),
++      MXC_DEFINE_PIN(D, 14, AOUT, FEC_RX_CLK, GPIO_IN),
++      MXC_DEFINE_PIN(D, 15, AOUT, FEC_COL, GPIO_IN),
++      MXC_DEFINE_PIN(D, 16, AIN, FEC_TX_ER, GPIO_OUT),
++
++      MXC_DEFINE_PIN(D, 17, PF, I2C_DATA, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 18, PF, I2C_CLK, GPIO_OUT),
++
++      MXC_DEFINE_PIN(D, 19, PF, CSPI2_SS2, 0),
++      MXC_DEFINE_PIN(D, 20, PF, CSPI2_SS1, 0),
++      MXC_DEFINE_PIN(D, 21, PF, CSPI2_SS0, 0),
++      MXC_DEFINE_PIN(D, 22, PF, CSPI2_SCLK, 0),
++      MXC_DEFINE_PIN(D, 23, PF, CSPI2_MISO, 0),
++      MXC_DEFINE_PIN(D, 24, PF, CSPI2_MOSI, 0),
++
++      MXC_DEFINE_PIN(D, 19, AF, USBH2_DATA4, 0),
++      MXC_DEFINE_PIN(D, 20, AF, USBH2_DATA3, 0),
++      MXC_DEFINE_PIN(D, 21, AF, USBH2_DATA6, 0),
++      MXC_DEFINE_PIN(D, 22, AF, USBH2_DATA0, 0),
++      MXC_DEFINE_PIN(D, 23, AF, USBH2_DATA2, 0),
++      MXC_DEFINE_PIN(D, 24, AF, USBH2_DATA1, 0),
++      MXC_DEFINE_PIN(D, 26, AF, USBH2_DATA5, 0),
++
++      MXC_DEFINE_PIN(D, 25, PF, CSPI1_RDY, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 26, PF, CSPI1_SS2, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 27, PF, CSPI1_SS1, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 28, PF, CSPI1_SS0, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 29, PF, CSPI1_SCLK, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 30, PF, CSPI1_MISO, GPIO_IN),
++      MXC_DEFINE_PIN(D, 31, PF, CSPI1_MOSI, GPIO_OUT),
++
++      MXC_DEFINE_PIN(E, 3, PF, UART2_CTS, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 4, PF, UART2_RTS, GPIO_IN),
++      MXC_DEFINE_PIN(E, 6, PF, UART2_TXD, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 7, PF, UART2_RXD, GPIO_IN),
++
++      MXC_DEFINE_PIN(E, 8, PF, UART3_TXD, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 9, PF, UART3_RXD, GPIO_IN),
++      MXC_DEFINE_PIN(E, 10, PF, UART3_CTS, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 11, PF, UART3_RTS, GPIO_IN),
++
++      MXC_DEFINE_PIN(E, 12, PF, UART1_TXD, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 13, PF, UART1_RXD, GPIO_IN),
++      MXC_DEFINE_PIN(E, 14, PF, UART1_CTS, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 15, PF, UART1_RTS, GPIO_IN),
++
++      MXC_DEFINE_PIN(E, 16, AF, OWIRE, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 16, PF, RTCK, GPIO_OUT),
++
++      MXC_DEFINE_PIN(E, 18, PF, SD1_D0, 0),
++      MXC_DEFINE_PIN(E, 19, PF, SD1_D1, 0),
++      MXC_DEFINE_PIN(E, 20, PF, SD1_D2, 0),
++      MXC_DEFINE_PIN(E, 21, PF, SD1_D3, 0),
++      MXC_DEFINE_PIN(E, 22, PF, SD1_CMD, 0),
++      MXC_DEFINE_PIN(E, 23, PF, SD1_CLK, 0),
++
++      MXC_DEFINE_PIN(B,  4, PF, SD2_D0, 0),
++      MXC_DEFINE_PIN(B,  5, PF, SD2_D1, 0),
++      MXC_DEFINE_PIN(B,  6, PF, SD2_D2, 0),
++      MXC_DEFINE_PIN(B,  7, PF, SD2_D3, 0),
++      MXC_DEFINE_PIN(B,  8, PF, SD2_CMD, 0),
++      MXC_DEFINE_PIN(B,  9, PF, SD2_CLK, 0),
++
++      MXC_DEFINE_PIN(D, 0, PF, SD3_CMD, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 1, PF, SD3_CLK, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 2, AF, SD3_D0, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 3, AF, SD3_D1, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 4, AF, SD3_D2, GPIO_OUT),
++      MXC_DEFINE_PIN(D, 5, AF, SD3_D3, GPIO_OUT),
++
++      MXC_DEFINE_PIN(E, 18, AF, CSPI3_MISO, GPIO_IN),
++      MXC_DEFINE_PIN(E, 21, AF, CSPI3_SS, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 22, AF, CSPI3_MOSI, GPIO_OUT),
++      MXC_DEFINE_PIN(E, 23, AF, CSPI3_SCLK, GPIO_OUT),
++
++      MXC_DEFINE_PIN(F, 0, PF, NFRB, GPIO_IN),
++      MXC_DEFINE_PIN(F, 1, PF, NFCLE, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 2, PF, NFWP_B, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 3, PF, NFCE_B, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 4, PF, NFALE, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 5, PF, NFRE_B, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 6, PF, NFWE_B, GPIO_OUT),
++
++      MXC_DEFINE_PIN(F, 7, AF, PC_POE, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 8, AF, PC_RW_B, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 9, AF, IOIS16, GPIO_IN),
++      MXC_DEFINE_PIN(F, 10, AF, PC_RST, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 11, AF, PC_BVD2, GPIO_IN),
++      MXC_DEFINE_PIN(F, 12, AF, PC_BVD1, GPIO_IN),
++      MXC_DEFINE_PIN(F, 13, AF, PC_VS2, GPIO_IN),
++      MXC_DEFINE_PIN(F, 14, AF, PC_VS1, GPIO_IN),
++      MXC_DEFINE_PIN(F, 15, PF, CLKO, GPIO_OUT),
++      MXC_DEFINE_PIN(F, 16, AF, PC_PWRON, GPIO_IN),
++      MXC_DEFINE_PIN(F, 17, AF, PC_READY, GPIO_IN),
++      MXC_DEFINE_PIN(F, 18, AF, PC_WAIT_B, GPIO_IN),
++      MXC_DEFINE_PIN(F, 19, AF, PC_CD2_B, GPIO_IN),
++      MXC_DEFINE_PIN(F, 20, AF, PC_CD1_B, GPIO_IN),
++
++      MXC_DEFINE_PIN(F, 23, AIN, FEC_TX_EN, GPIO_OUT),
++};
++
++#define _PIN_NAME(v)                          \
++      case v:                                 \
++              name = #v;                      \
++      break
++
++static inline const char *MX27_PIN_NAME(int iomux)
++{
++      const char *name = "<noname>";
++      switch (iomux) {
++              _PIN_NAME(PA0_PF_USBH2_CLK);
++              _PIN_NAME(PA1_PF_USBH2_DIR);
++              _PIN_NAME(PA2_PF_USBH2_DATA7);
++              _PIN_NAME(PA3_PF_USBH2_NXT);
++              _PIN_NAME(PA4_PF_USBH2_STP);
++              _PIN_NAME(PA5_PF_LSCLK);
++              _PIN_NAME(PA6_PF_LD0);
++              _PIN_NAME(PA7_PF_LD1);
++              _PIN_NAME(PA8_PF_LD2);
++              _PIN_NAME(PA9_PF_LD3);
++              _PIN_NAME(PA10_PF_LD4);
++              _PIN_NAME(PA11_PF_LD5);
++              _PIN_NAME(PA12_PF_LD6);
++              _PIN_NAME(PA13_PF_LD7);
++              _PIN_NAME(PA14_PF_LD8);
++              _PIN_NAME(PA15_PF_LD9);
++              _PIN_NAME(PA16_PF_LD10);
++              _PIN_NAME(PA17_PF_LD11);
++              _PIN_NAME(PA18_PF_LD12);
++              _PIN_NAME(PA19_PF_LD13);
++              _PIN_NAME(PA20_PF_LD14);
++              _PIN_NAME(PA21_PF_LD15);
++              _PIN_NAME(PA22_PF_LD16);
++              _PIN_NAME(PA23_PF_LD17);
++              _PIN_NAME(PA24_PF_REV);
++              _PIN_NAME(PA25_PF_CLS);
++              _PIN_NAME(PA26_PF_PS);
++              _PIN_NAME(PA27_PF_SPL_SPR);
++              _PIN_NAME(PA28_PF_HSYNC);
++              _PIN_NAME(PA29_PF_VSYNC);
++              _PIN_NAME(PA30_PF_CONTRAST);
++              _PIN_NAME(PA31_PF_OE_ACD);
++              _PIN_NAME(PB4_PF_SD2_D0);
++              _PIN_NAME(PB5_PF_SD2_D1);
++              _PIN_NAME(PB6_PF_SD2_D2);
++              _PIN_NAME(PB7_PF_SD2_D3);
++              _PIN_NAME(PB8_PF_SD2_CMD);
++              _PIN_NAME(PB9_PF_SD2_CLK);
++              _PIN_NAME(PB10_PF_CSI_D0);
++              _PIN_NAME(PB10_AF_UART6_TXD);
++              _PIN_NAME(PB11_PF_CSI_D1);
++              _PIN_NAME(PB11_AF_UART6_RXD);
++              _PIN_NAME(PB12_PF_CSI_D2);
++              _PIN_NAME(PB12_AF_UART6_CTS);
++              _PIN_NAME(PB13_PF_CSI_D3);
++              _PIN_NAME(PB13_AF_UART6_RTS);
++              _PIN_NAME(PB14_PF_CSI_D4);
++              _PIN_NAME(PB15_PF_CSI_MCLK);
++              _PIN_NAME(PB16_PF_CSI_PIXCLK);
++              _PIN_NAME(PB17_PF_CSI_D5);
++              _PIN_NAME(PB18_PF_CSI_D6);
++              _PIN_NAME(PB18_AF_UART5_TXD);
++              _PIN_NAME(PB19_PF_CSI_D7);
++              _PIN_NAME(PB19_AF_UART5_RXD);
++              _PIN_NAME(PB20_PF_CSI_VSYNC);
++              _PIN_NAME(PB20_AF_UART5_CTS);
++              _PIN_NAME(PB21_PF_CSI_HSYNC);
++              _PIN_NAME(PB21_AF_UART5_RTS);
++              _PIN_NAME(PB22_PF_USBH1_SUSP);
++              _PIN_NAME(PB23_PF_USB_PWR);
++              _PIN_NAME(PB24_PF_USB_OC_B);
++              _PIN_NAME(PB25_PF_USBH1_RCV);
++              _PIN_NAME(PB26_PF_USBH1_FS);
++              _PIN_NAME(PB27_PF_USBH1_OE_B);
++              _PIN_NAME(PB28_PF_USBH1_TXDM);
++              _PIN_NAME(PB29_PF_USBH1_TXDP);
++              _PIN_NAME(PB30_PF_USBH1_RXDM);
++              _PIN_NAME(PB31_PF_USBH1_RXDP);
++              _PIN_NAME(PB26_AF_UART4_RTS);
++              _PIN_NAME(PB28_AF_UART4_TXD);
++              _PIN_NAME(PB29_AF_UART4_CTS);
++              _PIN_NAME(PB31_AF_UART4_RXD);
++              _PIN_NAME(PC5_PF_I2C2_SDA);
++              _PIN_NAME(PC6_PF_I2C2_SCL);
++              _PIN_NAME(PC7_PF_USBOTG_DATA5);
++              _PIN_NAME(PC8_PF_USBOTG_DATA6);
++              _PIN_NAME(PC9_PF_USBOTG_DATA0);
++              _PIN_NAME(PC10_PF_USBOTG_DATA2);
++              _PIN_NAME(PC11_PF_USBOTG_DATA1);
++              _PIN_NAME(PC12_PF_USBOTG_DATA4);
++              _PIN_NAME(PC13_PF_USBOTG_DATA3);
++              _PIN_NAME(PC16_PF_SSI4_FS);
++              _PIN_NAME(PC17_PF_SSI4_RXD);
++              _PIN_NAME(PC18_PF_SSI4_TXD);
++              _PIN_NAME(PC19_PF_SSI4_CLK);
++              _PIN_NAME(PC20_PF_SSI1_FS);
++              _PIN_NAME(PC21_PF_SSI1_RXD);
++              _PIN_NAME(PC22_PF_SSI1_TXD);
++              _PIN_NAME(PC23_PF_SSI1_CLK);
++              _PIN_NAME(PC24_PF_SSI2_FS);
++              _PIN_NAME(PC25_PF_SSI2_RXD);
++              _PIN_NAME(PC26_PF_SSI2_TXD);
++              _PIN_NAME(PC27_PF_SSI2_CLK);
++              _PIN_NAME(PC28_PF_SSI3_FS);
++              _PIN_NAME(PC29_PF_SSI3_RXD);
++              _PIN_NAME(PC30_PF_SSI3_TXD);
++              _PIN_NAME(PC31_PF_SSI3_CLK);
++              _PIN_NAME(PD0_AIN_FEC_TXD0);
++              _PIN_NAME(PD1_AIN_FEC_TXD1);
++              _PIN_NAME(PD2_AIN_FEC_TXD2);
++              _PIN_NAME(PD3_AIN_FEC_TXD3);
++              _PIN_NAME(PD4_AOUT_FEC_RX_ER);
++              _PIN_NAME(PD5_AOUT_FEC_RXD1);
++              _PIN_NAME(PD6_AOUT_FEC_RXD2);
++              _PIN_NAME(PD7_AOUT_FEC_RXD3);
++              _PIN_NAME(PD8_AF_FEC_MDIO);
++              _PIN_NAME(PD9_AIN_FEC_MDC);
++              _PIN_NAME(PD10_AOUT_FEC_CRS);
++              _PIN_NAME(PD11_AOUT_FEC_TX_CLK);
++              _PIN_NAME(PD12_AOUT_FEC_RXD0);
++              _PIN_NAME(PD13_AOUT_FEC_RX_DV);
++              _PIN_NAME(PD14_AOUT_FEC_RX_CLK);
++              _PIN_NAME(PD15_AOUT_FEC_COL);
++              _PIN_NAME(PD16_AIN_FEC_TX_ER);
++              _PIN_NAME(PD17_PF_I2C_DATA);
++              _PIN_NAME(PD18_PF_I2C_CLK);
++              _PIN_NAME(PD19_AF_USBH2_DATA4);
++              _PIN_NAME(PD20_AF_USBH2_DATA3);
++              _PIN_NAME(PD21_AF_USBH2_DATA6);
++              _PIN_NAME(PD22_AF_USBH2_DATA0);
++              _PIN_NAME(PD23_AF_USBH2_DATA2);
++              _PIN_NAME(PD24_AF_USBH2_DATA1);
++              _PIN_NAME(PD25_PF_CSPI1_RDY);
++              _PIN_NAME(PD26_PF_CSPI1_SS2);
++              _PIN_NAME(PD26_AF_USBH2_DATA5);
++              _PIN_NAME(PD27_PF_CSPI1_SS1);
++              _PIN_NAME(PD28_PF_CSPI1_SS0);
++              _PIN_NAME(PD29_PF_CSPI1_SCLK);
++              _PIN_NAME(PD30_PF_CSPI1_MISO);
++              _PIN_NAME(PD31_PF_CSPI1_MOSI);
++              _PIN_NAME(PF23_AIN_FEC_TX_EN);
++              _PIN_NAME(PE0_PF_USBOTG_NXT);
++              _PIN_NAME(PE1_PF_USBOTG_STP);
++              _PIN_NAME(PE2_PF_USBOTG_DIR);
++              _PIN_NAME(PE3_PF_UART2_CTS);
++              _PIN_NAME(PE4_PF_UART2_RTS);
++              _PIN_NAME(PE6_PF_UART2_TXD);
++              _PIN_NAME(PE7_PF_UART2_RXD);
++              _PIN_NAME(PE8_PF_UART3_TXD);
++              _PIN_NAME(PE9_PF_UART3_RXD);
++              _PIN_NAME(PE10_PF_UART3_CTS);
++              _PIN_NAME(PE11_PF_UART3_RTS);
++              _PIN_NAME(PE12_PF_UART1_TXD);
++              _PIN_NAME(PE13_PF_UART1_RXD);
++              _PIN_NAME(PE14_PF_UART1_CTS);
++              _PIN_NAME(PE15_PF_UART1_RTS);
++              _PIN_NAME(PE16_AF_OWIRE);
++              _PIN_NAME(PE16_PF_RTCK);
++              _PIN_NAME(PE18_PF_SD1_D0);
++              _PIN_NAME(PE18_AF_CSPI3_MISO);
++              _PIN_NAME(PE19_PF_SD1_D1);
++              _PIN_NAME(PE20_PF_SD1_D2);
++              _PIN_NAME(PE21_PF_SD1_D3);
++              _PIN_NAME(PE21_AF_CSPI3_SS);
++              _PIN_NAME(PE22_PF_SD1_CMD);
++              _PIN_NAME(PE22_AF_CSPI3_MOSI);
++              _PIN_NAME(PE23_PF_SD1_CLK);
++              _PIN_NAME(PE23_AF_CSPI3_SCLK);
++              _PIN_NAME(PE24_PF_USBOTG_CLK);
++              _PIN_NAME(PE25_PF_USBOTG_DATA7);
++      }
++      return name;
++}
++
++#endif /* _MXC_GPIO_MX2_H */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/include/mach/mxc_pm.h linux-2.6.28-karo/arch/arm/mach-mx2/include/mach/mxc_pm.h
+--- linux-2.6.28/arch/arm/mach-mx2/include/mach/mxc_pm.h       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/include/mach/mxc_pm.h  2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,229 @@
++
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup LPMD Low-Level Power Management Driver
++ */
++
++/*!
++ * @file arch-mxc/mxc_pm.h
++ *
++ * @brief This file contains the  chip level configuration details and
++ * public API declarations for CRM_AP module
++ *
++ * @ingroup LPMD
++ */
++
++#ifndef __ASM_ARCH_MXC_PM_H__
++#define __ASM_ARCH_MXC_PM_H__
++
++#define WAIT_MODE               111
++#define DOZE_MODE               112
++#define STOP_MODE               113
++#define DSM_MODE                114
++
++#define GATE_STOP_WAIT          9
++#define GATE_STOP               10
++
++/*
++ * Used for MHz conversion
++ */
++#define MEGA_HERTZ              1000000
++
++/*
++ * If invalid frequency value other than the following
++ * CORE_133 - ARM desired to run @133MHz, LoV (1.2V)
++ * CORE_266 - ARM desired to run @266MHz, LoV (1.2V)
++ * CORE_399 - ARM desired to run @399MHz, LoV (1.2V)
++ * CORE_532 - ARM desired to run @133MHz, HiV (1.6V)
++ * are passed then this error is returned,
++ */
++#define ERR_FREQ_INVALID          1
++
++/*
++ * If PLL freq is less than desired ARM frequency during Integer
++ * DVFS, then return this error
++ */
++#define PLL_LESS_ARM_ERR        2
++
++/*
++ * Frequency change within the same-lo voltage is not approved.
++ * Inorder to do Integer DFS, move to the high voltage range and
++ * then set LFDF and move to the low voltage range
++ */
++#define INT_DFS_LOW_NOT_ALLOW   3
++
++/*
++ * If the desired AHB or IPG exceeds 133MHz or 66.5MHz respectively,
++ * then return this error
++ */
++#define AHB_IPG_EXCEED_LIMIT    4
++
++/*
++ * If the desired ARM frequency is too low to get by PLL scaling
++ * and the mxc_pm_pllscale API is called, return this error:
++ */
++#define PLL_DVFS_FREQ_TOO_LOW   5
++
++/*
++ * Invalid frequencies requested
++ */
++#define MXC_PM_INVALID_PARAM    6
++
++/*
++ * If AHB and/or IPG frequencies are greater than maximum allowed
++ */
++#define FREQ_OUT_OF_RANGE       2
++
++/*
++ * If AHB and/or IPG frequencies are other than 100 or 50Mhz
++ */
++#define BUS_FREQ_INVALID        2
++
++/*
++ * If MAX_PDF is greater than max value (8) then return this error
++ */
++#define AHB_MAX_DIV_ERR         3
++
++/*
++ * If IPG_PDF is greater than max value (2) then return this error
++ */
++#define IPG_MAX_DIV_ERR         4
++
++/*
++ * If ARM freq is out of range i.e., less than 133 or greater than
++ * 399 then return this error
++ */
++#define INVALID_ARM_FREQ        5
++
++/*
++ * This file includes all platform APIs. Some of the APIs are not
++ * appicable to some platforms. So, this error is used to indicate
++ * that a particular API is not available
++ */
++#define MXC_PM_API_NOT_SUPPORTED      6
++
++/*!
++ * Additional define for stop mode
++ */
++#define PM_SUSPEND_STOP         ((__force suspend_state_t) 2)
++
++/*!
++ * CKOH pins configuration
++ */
++#define CKOH_AP_SEL             1
++#define CKOH_AHB_SEL            2
++#define CKOH_IP_SEL             3
++
++/*!
++ * Defines for Stop and DSM mode acknowledgements
++ */
++#define MXC_PM_LOWPWR_ACK_SDMA  0x01
++#define MXC_PM_LOWPWR_ACK_IPU   0x02
++#define MXC_PM_LOWPWR_ACK_MAX   0x04
++#define MXC_PM_LOWPWR_ACK_MQSPI 0x08
++#define MXC_PM_LOWPWR_ACK_USB   0x10
++#define MXC_PM_LOWPWR_ACK_RTIC  0x20
++
++/*
++ * PMIC configuration
++ */
++#define MXC_PMIC_1_2_VOLT                      0xC
++#define MXC_PMIC_1_6_VOLT                      0x1C
++#define MXC_PMIC_1_0_VOLT                      0x4
++#define MXC_PMIC_DVS_SPEED                     0x3
++
++/*!
++ * Implementing Level 1 CRM Gate Control. Level 2 gate control
++ * is provided at module level using LPMD registers
++ *
++ * @param   group   The desired clock gate control register bits.
++ *                  Possible values are 0 through 6
++ * @param   opt     The desired option requesting clock to run during stop
++ *                  and wait modes or just during the stop mode. Possible
++ *                  values are GATE_STOP_WAIT and GATE_STOP.
++ *
++ */
++void mxc_pm_clockgate(int group, int opt);
++
++/*!
++ * Implementing steps required to transition to low-power modes
++ *
++ * @param   mode    The desired low-power mode. Possible values are,
++ *                  WAIT_MODE, STOP_MODE or DSM_MODE
++ *
++ */
++void mxc_pm_lowpower(int mode);
++
++/*!
++ * Enables acknowledgement from module when entering stop or DSM mode.
++ *
++ * @param   ack     The desired module acknowledgement to enable.
++ *
++ */
++void mxc_pm_lp_ack_enable(int ack);
++
++/*!
++ * Disables acknowledgement from module when entering stop or DSM mode.
++ *
++ * @param   ack     The desired module acknowledgement to disable.
++ *
++ */
++void mxc_pm_lp_ack_disable(int ack);
++
++/*!
++ * Implementing steps required to set Integer Scaling
++ *
++ * @param   armfreq    The desired ARM frequency. AHB and IP
++ *                     frequency are changed depending on ARM
++ *                     frequency and the divider values.
++ * @param   ahbfreq    The desired AHB frequency
++ * @param   ipfreq     The desired IP frequency
++ *
++ * @return             Returns 0 on success or
++ *                     Returns -PLL_LESS_ARM_ERR if pllfreq is less than
++ *                     desired core freq
++ */
++int mxc_pm_intscale(long armfreq, long ahbfreq, long ipfreq);
++
++/*!
++ * To calculate MFI, MFN, MFD values. Using this the output frequency
++ * whose value is calculated using,
++ * 2 * REF_FREQ * (MF / PDF), where
++ * REF_FREQ is 26 Mhz
++ * MF = MFI + (MFN + MFD)
++ * PDF is assumed to be 1
++ *
++ * @param   armfreq    The desired ARM frequency
++ * @param   ahbfreq    The desired AHB frequency
++ * @param   ipfreq     The desired IP frequency
++ *
++ * @return             Returns 0 on success or
++ *                     Returns -1 on error
++ */
++int mxc_pm_pllscale(long armfreq, long ahbfreq, long ipfreq);
++
++/*!
++ * To change AP core frequency and/or voltage suitably
++ *
++ * @param   armfreq    The desired ARM frequency
++ * @param   ahbfreq    The desired AHB frequency
++ * @param   ipfreq     The desired IP frequency
++ *
++ * @return             Returns -ERR_FREQ_INVALID on failure
++ *                     Returns 0 on success
++ */
++int mxc_pm_dvfs(unsigned long armfreq, long ahbfreq, long ipfreq);
++
++#endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/include/mach/mxc_v4l2.h linux-2.6.28-karo/arch/arm/mach-mx2/include/mach/mxc_v4l2.h
+--- linux-2.6.28/arch/arm/mach-mx2/include/mach/mxc_v4l2.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/include/mach/mxc_v4l2.h        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU Lesser General 
++ * Public License.  You may obtain a copy of the GNU Lesser General 
++ * Public License Version 2.1 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/lgpl-license.html
++ * http://www.gnu.org/copyleft/lgpl.html
++ */
++
++/*!
++ * @file arch-mxc/mxc_v4l2.h
++ *
++ * @brief mxc V4L2 private structures
++ *
++ * @ingroup MXC_V4L2_CAPTURE
++ */
++
++#ifndef __ASM_ARCH_MXC_V4L2_H__
++#define __ASM_ARCH_MXC_V4L2_H__
++
++#define V4L2_CID_MXC_ROT              (V4L2_CID_PRIVATE_BASE + 0)
++#define V4L2_CID_MXC_FLASH            (V4L2_CID_PRIVATE_BASE + 1)
++#define V4L2_CID_MXC_FLICKER          (V4L2_CID_PRIVATE_BASE + 2)
++#define V4L2_CID_MXC_TEAR_PROTECT     (V4L2_CID_PRIVATE_BASE + 3)
++#define V4L2_CID_MXC_GAIN_LIMIT               (V4L2_CID_PRIVATE_BASE + 4)
++
++/* V4L2_CID_MXC_ROT values */
++
++#define V4L2_MXC_ROTATE_NONE                  0
++#define V4L2_MXC_ROTATE_VERT_FLIP             1
++#define V4L2_MXC_ROTATE_HORIZ_FLIP            2
++#define V4L2_MXC_ROTATE_180                   3
++#define V4L2_MXC_ROTATE_90_RIGHT              4
++#define V4L2_MXC_ROTATE_90_RIGHT_VFLIP                5
++#define V4L2_MXC_ROTATE_90_RIGHT_HFLIP                6
++#define V4L2_MXC_ROTATE_90_LEFT                       7
++
++/* V4L2_CID_MXC_FLICKER values */
++
++#define V4L2_MXC_FLICKER_DISABLE              0
++#define V4L2_MXC_FLICKER_60HZ                 1
++#define V4L2_MXC_FLICKER_50HZ                 2
++#define V4L2_MXC_FLICKER_AUTO                 3
++
++struct v4l2_mxc_offset {
++      unsigned int y_offset;
++      unsigned int u_offset;
++      unsigned int v_offset;
++      unsigned int qp_offset;
++};
++
++#endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/karo-tx27.c linux-2.6.28-karo/arch/arm/mach-mx2/karo-tx27.c
+--- linux-2.6.28/arch/arm/mach-mx2/karo-tx27.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/karo-tx27.c    2009-03-11 13:31:40.000000000 +0100
+@@ -0,0 +1,1556 @@
++/*
++ * arch/arm/mach-mx27/karo-tx27.c
++ *
++ * Copyright (C) 2008  Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * based on: arch/arm/mach-mx27ads.c (C) Freescale Semiconductor, Inc.
++ *
++ * This program is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU General Public License
++ * version 2 as published by the Free Software Foundation
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ *
++ * You should have received a copy of the GNU General Public License
++ * along with this program; if not, write to the:
++ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
++ *
++ */
++
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/input.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/i2c.h>
++#include <linux/i2c/at24.h>
++#include <linux/spi/spi.h>
++#include <linux/serial_8250.h>
++#include <linux/fec_enet.h>
++#include <mtd/mtd-abi.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/partitions.h>
++#include <asm/mach/flash.h>
++
++#include <linux/serial.h>
++#include <linux/fsl_devices.h>
++#include <linux/rtc/ds13xx.h>
++#include <linux/irq.h>
++#include <linux/mmc/host.h>
++#include <linux/gpio_keys.h>
++#include <linux/leds.h>
++
++#include <asm/setup.h>
++#include <asm/irq.h>
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/time.h>
++#include <mach/common.h>
++#include <mach/hardware.h>
++#include <mach/gpio.h>
++#include <mach/iomux.h>
++#include <mach/irqs.h>
++#include <mach/clock.h>
++#include <mach/imxfb.h>
++#include <mach/imx_spi.h>
++#include <mach/imx_i2c.h>
++#include <mach/mmc.h>
++#include <mach/imx-uart.h>
++#include <mach/mxc_nand.h>
++#include <mach/ulpi.h>
++#include <mach/mxc_ehci.h>
++#include <mach/board-tx27.h>
++
++#include "crm_regs.h"
++#include "devices.h"
++
++#ifdef DEBUG
++int tx27_debug = 1;
++#define dbg_lvl(n)    ((n) < tx27_debug)
++module_param(tx27_debug, int, S_IRUGO | S_IWUSR);
++
++#define DBG(lvl, fmt...)      do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0)
++#else
++int tx27_debug;
++#define dbg_lvl(n)    0
++#define DBG(lvl, fmt...)      do { } while (0)
++#endif
++
++#include "karo.h"
++
++#if defined(CONFIG_SERIAL_IMX) || defined(CONFIG_SERIAL_IMX_MODULE)
++static int tx27_uart_pins[][4] = {
++      {
++              PE12_PF_UART1_TXD,
++              PE13_PF_UART1_RXD,
++              PE14_PF_UART1_CTS,
++              PE15_PF_UART1_RTS,
++      },{
++              PE6_PF_UART2_TXD,
++              PE7_PF_UART2_RXD,
++              PE3_PF_UART2_CTS,
++              PE4_PF_UART2_RTS,
++      },{
++              PE8_PF_UART3_TXD,
++              PE9_PF_UART3_RXD,
++              PE10_PF_UART3_CTS,
++              PE11_PF_UART3_RTS,
++      },{
++              PB28_AF_UART4_TXD,
++              PB31_AF_UART4_RXD,
++              PB29_AF_UART4_CTS,
++              PB26_AF_UART4_RTS,
++      },{
++              PB18_AF_UART5_TXD,
++              PB19_AF_UART5_RXD,
++              PB20_AF_UART5_CTS,
++              PB21_AF_UART5_RTS,
++      },{
++              PB10_AF_UART6_TXD,
++              PB11_AF_UART6_RXD,
++              PB12_AF_UART6_CTS,
++              PB13_AF_UART6_RTS,
++      },
++};
++
++static int tx27_uart_init(struct platform_device *pdev)
++{
++      DBG(0, "%s: \n", __FUNCTION__);
++      return mxc_gpio_setup_multiple_pins(tx27_uart_pins[pdev->id],
++                                          ARRAY_SIZE(tx27_uart_pins[pdev->id]), "UART");
++}
++
++static int tx27_uart_exit(struct platform_device *pdev)
++{
++      DBG(0, "%s: \n", __FUNCTION__);
++      mxc_gpio_release_multiple_pins(tx27_uart_pins[pdev->id],
++                      ARRAY_SIZE(tx27_uart_pins[pdev->id]));
++      return 0;
++}
++
++static struct imxuart_platform_data tx27_uart_ports[] = {
++      {
++              .init = tx27_uart_init,
++              .exit = tx27_uart_exit,
++              .flags = IMXUART_HAVE_RTSCTS,
++      },{
++              .init = tx27_uart_init,
++              .exit = tx27_uart_exit,
++              .flags = IMXUART_HAVE_RTSCTS,
++      },{
++              .init = tx27_uart_init,
++              .exit = tx27_uart_exit,
++              .flags = IMXUART_HAVE_RTSCTS,
++      },{
++              .init = tx27_uart_init,
++              .exit = tx27_uart_exit,
++              .flags = IMXUART_HAVE_RTSCTS,
++      },{
++              .init = tx27_uart_init,
++              .exit = tx27_uart_exit,
++              .flags = IMXUART_HAVE_RTSCTS,
++      },{
++              .init = tx27_uart_init,
++              .exit = tx27_uart_exit,
++              .flags = IMXUART_HAVE_RTSCTS,
++      },
++};
++
++static struct platform_device *tx27_uart_devices[] = {
++#if UART1_ENABLED
++      &mxc_uart_device0,
++#endif
++#if UART2_ENABLED
++      &mxc_uart_device1,
++#endif
++#if UART3_ENABLED
++      &mxc_uart_device2,
++#endif
++#if UART4_ENABLED
++      &mxc_uart_device3,
++#endif
++#if UART5_ENABLED
++      &mxc_uart_device4,
++#endif
++#if UART6_ENABLED
++      &mxc_uart_device5,
++#endif
++};
++#endif
++
++#ifdef CONFIG_USB_EHCI_MXC
++
++#define SMSC_VENDOR_ID                0x0424
++#define USB3317_PROD_ID               0x0006
++
++static int usb3317_set_vbus_power(void __iomem *view, int on)
++{
++      int vid, pid, ret = 0;
++
++      ret = ulpi_read(ISP1504_VID_HIGH, view);
++      if (ret < 0) {
++              goto err;
++      }
++      vid = ret << 8;
++
++      ret = ulpi_read(ISP1504_VID_LOW, view);
++      if (ret < 0) {
++              goto err;
++      }
++      vid |= ret;
++
++      ret = ulpi_read(ISP1504_PID_HIGH, view);
++      if (ret < 0) {
++              goto err;
++      }
++      pid = ret << 8;
++
++      ret = ulpi_read(ISP1504_PID_LOW, view);
++      if (ret < 0) {
++              goto err;
++      }
++      pid |= ret;
++
++      pr_info("ULPI Vendor ID 0x%x    Product ID 0x%x\n", vid, pid);
++      if (vid != SMSC_VENDOR_ID || pid != USB3317_PROD_ID) {
++              pr_err("No USB3317 found\n");
++              return -1;
++      }
++
++      if (on) {
++              ret = ulpi_set(DRV_VBUS_EXT |   /* enable external Vbus */
++                          DRV_VBUS |          /* enable internal Vbus */
++                          USE_EXT_VBUS_IND |  /* use external indicator */
++                          CHRG_VBUS,          /* charge Vbus */
++                          ISP1504_OTGCTL, view);
++      } else {
++              ret = ulpi_clear(DRV_VBUS_EXT | /* disable external Vbus */
++                            DRV_VBUS,         /* disable internal Vbus */
++                            ISP1504_OTGCTL, view);
++
++              ret |= ulpi_set(USE_EXT_VBUS_IND | /* use external indicator */
++                          DISCHRG_VBUS,          /* discharge Vbus */
++                          ISP1504_OTGCTL, view);
++      }
++      return 0;
++
++ err:
++      printk(KERN_ERR "ULPI read failed with error %d\n", ret);
++      return ret;
++}
++
++static int tx27_usb_host_init(struct platform_device *pdev)
++{
++      int ret;
++      u32 temp;
++      unsigned long freq;
++      unsigned long flags;
++      struct clk *usb_clk = clk_get(NULL, "usb_clk");
++
++      if (IS_ERR(usb_clk)) {
++              ret = PTR_ERR(usb_clk);
++              printk(KERN_ERR "Failed to get usb_clk: %d\n", ret);
++              goto err;
++      }
++
++      ret = gpio_usbh2_active();
++      if (ret != 0) {
++              return ret;
++      }
++
++      freq = clk_get_rate(usb_clk);
++      if ((freq < 59999000) || (freq > 60001000)) {
++              printk(KERN_ERR "USB_CLK=%lu.%03luMHz, should be 60MHz\n",
++                     freq / 1000000, freq / 1000 % 1000);
++              ret = clk_set_rate(usb_clk, 60000000);
++              if (ret != 0) {
++                      printk(KERN_ERR "Failed to set usb_clk rate: %d\n", ret);
++              }
++      }
++      clk_put(usb_clk);
++      if (ret != 0) {
++              goto err;
++      }
++
++      local_irq_save(flags);
++      temp = readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x600);
++      temp &= ~(3 << 21);
++      temp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 20);
++      writel(temp, IO_ADDRESS(OTG_BASE_ADDR) + 0x600);
++      local_irq_restore(flags);
++
++      temp = readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x584);
++      temp &= ~(3 << 30);
++      temp |= 2 << 30;
++      temp = 0x88001215;
++      /* select ULPI transceiver */
++      DBG(0, "%s: Changing USBH2_PORTSC1[%08lx] from %08x to %08x\n", __FUNCTION__,
++          OTG_BASE_ADDR + 0x584, readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x584), temp);
++      writel(temp, IO_ADDRESS(OTG_BASE_ADDR) + 0x584);
++
++      mdelay(10);
++
++      ret = usb3317_set_vbus_power(IO_ADDRESS(OTG_BASE_ADDR + 0x570), 1);
++      if (ret != 0) {
++//            goto err;
++      }
++      return 0;
++
++ err:
++      gpio_usbh2_inactive();
++      return ret;
++}
++
++static int tx27_usb_host_exit(struct platform_device *pdev)
++{
++      gpio_usbh2_inactive();
++      return 0;
++}
++
++static struct mxc_usbh_platform_data tx27_usbh2_data = {
++      .init   = tx27_usb_host_init,
++      .exit   = tx27_usb_host_exit,
++};
++
++int tx27_usbh2_init(void)
++{
++      int ret;
++
++      ret = mxc_register_device(&mxc_ehci2, &tx27_usbh2_data);
++      return ret;
++}
++device_initcall(tx27_usbh2_init);
++
++static int tx27_usb_otg_init(struct platform_device *pdev)
++{
++      int ret;
++      u32 temp;
++      unsigned long freq;
++      unsigned long flags;
++      struct clk *usb_clk = clk_get(NULL, "usb_clk");
++
++      if (IS_ERR(usb_clk)) {
++              ret = PTR_ERR(usb_clk);
++              printk(KERN_ERR "Failed to get usb_clk: %d\n", ret);
++              goto err;
++      }
++
++      ret = gpio_usbotg_hs_active();
++      if (ret != 0) {
++              return ret;
++      }
++
++      freq = clk_get_rate(usb_clk);
++      if ((freq < 59999000) || (freq > 60001000)) {
++              printk(KERN_ERR "USB_CLK=%lu.%03luMHz, should be 60MHz\n",
++                     freq / 1000000, freq / 1000 % 1000);
++              ret = clk_set_rate(usb_clk, 60000000);
++              if (ret != 0) {
++                      printk(KERN_ERR "Failed to set usb_clk rate: %d\n", ret);
++              }
++      }
++      clk_put(usb_clk);
++      if (ret != 0) {
++              goto err;
++      }
++
++      local_irq_save(flags);
++      temp = readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x600);
++      temp &= ~(3 << 21);
++      temp |= (1 << 5) | (1 << 16) | (1 << 19) | (1 << 20);
++      writel(temp, IO_ADDRESS(OTG_BASE_ADDR) + 0x600);
++      local_irq_restore(flags);
++
++      temp = readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x184);
++      temp &= ~(3 << 30);
++      temp |= 2 << 30;
++      temp = 0x88001215;
++      /* select ULPI transceiver */
++      DBG(0, "%s: Changing USBOTG_PORTSC1[%08lx] from %08x to %08x\n", __FUNCTION__,
++          OTG_BASE_ADDR + 0x184, readl(IO_ADDRESS(OTG_BASE_ADDR) + 0x184), temp);
++      writel(temp, IO_ADDRESS(OTG_BASE_ADDR) + 0x184);
++
++      mdelay(10);
++
++      ret = usb3317_set_vbus_power(IO_ADDRESS(OTG_BASE_ADDR + 0x170), 1);
++      if (ret != 0) {
++//            goto err;
++      }
++      return 0;
++
++ err:
++      gpio_usbotg_hs_active();
++      return ret;
++}
++
++static int tx27_usb_otg_exit(struct platform_device *pdev)
++{
++      gpio_usbotg_hs_inactive();
++      return 0;
++}
++
++static struct mxc_usbh_platform_data tx27_otg_data = {
++      .init   = tx27_usb_otg_init,
++      .exit   = tx27_usb_otg_exit,
++};
++
++int tx27_otg_init(void)
++{
++      int ret;
++
++      ret = mxc_register_device(&mxc_otg, &tx27_otg_data);
++      return ret;
++}
++device_initcall(tx27_otg_init);
++#endif // CONFIG_USB_EHCI_MXC
++
++#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
++static struct resource fec_resources[] = {
++      {
++              .start  = FEC_BASE_ADDR,
++              .end    = FEC_BASE_ADDR + 0x18f,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .start  = FEC_BASE_ADDR + 0x200,
++              .end    = FEC_BASE_ADDR + 0x2e3,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .start  = MXC_INT_FEC,
++              .end    = MXC_INT_FEC,
++              .flags  = IORESOURCE_IRQ,
++      },
++#ifdef FEC_MII_IRQ
++      {
++              .start  = IRQ_GPIOD(16),
++              .end    = IRQ_GPIOD(16),
++              .flags  = IORESOURCE_IRQ,
++      },
++#endif
++};
++
++static struct clk *fec_clk;
++static int tx27_fec_suspend(struct platform_device *pdev)
++{
++      BUG_ON(fec_clk == NULL);
++      DBG(1, "%s: Switching FEC PHY off\n", __FUNCTION__);
++      gpio_fec_inactive();
++      clk_disable(fec_clk);
++      return 0;
++}
++
++static int tx27_fec_resume(struct platform_device *pdev)
++{
++      BUG_ON(fec_clk == NULL);
++      DBG(1, "%s: Switching FEC PHY on\n", __FUNCTION__);
++      clk_enable(fec_clk);
++      gpio_fec_active();
++      return 0;
++}
++
++static int fec_arch_init(struct platform_device *pdev)
++{
++      int ret;
++
++      DBG(0, "%s: Activating FEC GPIOs\n", __FUNCTION__);
++      dump_regs();
++      ret = gpio_fec_active();
++      if (ret) {
++              printk(KERN_ERR "%s: could not enable FEC gpios: %d\n", __FUNCTION__, ret);
++              return ret;
++      }
++      BUG_ON(fec_clk != NULL);
++      fec_clk = clk_get(&pdev->dev, "fec_clk");
++      if (unlikely(IS_ERR(fec_clk))) {
++              printk(KERN_ERR "Failed to get fec_clk\n");
++              return PTR_ERR(fec_clk);
++      }
++      DBG(0, "%s: Enabling FEC clock\n", __FUNCTION__);
++      clk_enable(fec_clk);
++      dump_regs();
++      return 0;
++}
++
++static void fec_arch_exit(struct platform_device *pdev)
++{
++      BUG_ON(fec_clk == NULL);
++      if (unlikely(IS_ERR(fec_clk))) {
++              printk(KERN_ERR "Failed to get fec_clk\n");
++              return;
++      }
++      DBG(0, "%s: Disabling FEC clock\n", __FUNCTION__);
++      clk_disable(fec_clk);
++      clk_put(fec_clk);
++      fec_clk = NULL;
++      DBG(0, "%s: Deactivating FEC GPIOs\n", __FUNCTION__);
++      gpio_fec_inactive();
++}
++
++static struct fec_enet_platform_data fec_data = {
++      .arch_init = fec_arch_init,
++      .arch_exit = fec_arch_exit,
++      .suspend = tx27_fec_suspend,
++      .resume = tx27_fec_resume,
++};
++
++static struct platform_device fec_device = {
++      .name           = "fec_enet",
++      .id             = -1,
++      .num_resources  = ARRAY_SIZE(fec_resources),
++      .resource       = fec_resources,
++      .dev = {
++              .platform_data = &fec_data,
++              .coherent_dma_mask = 0xFFFFFFFF,
++      },
++};
++#endif
++
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++/* tx27 gpio keys driver */
++struct gpio_keys_button tx27_gpio_keys[] = {
++      {
++              .code = KEY_POWER,
++              .gpio = GPIO_PORTB + 24,
++              .active_low = 0,
++              .desc = "Power Button",
++              .type = EV_KEY,         /* input event type (EV_KEY, EV_SW) */
++              .wakeup = 1,            /* configure the button as a wake-up source */
++              .debounce_interval = 1, /* debounce ticks interval in msecs */
++      },
++};
++
++struct gpio_keys_platform_data tx27_gpio_keys_pdata = {
++      .buttons = tx27_gpio_keys,
++      .nbuttons = ARRAY_SIZE(tx27_gpio_keys),
++};
++
++static struct platform_device tx27_gpio_keys_device = {
++      .name           = "gpio-keys",
++      .id             = -1,
++      .dev            = {
++              .platform_data  = &tx27_gpio_keys_pdata,
++      },
++};
++#endif
++
++#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
++static struct gpio_led tx27_leds[] = {
++      {
++              .name = "Power-LED",
++              .default_trigger = "heartbeat",
++              .gpio = GPIO_PORTF + 13,
++      },
++};
++
++static struct gpio_led_platform_data tx27_led_data = {
++      .leds = tx27_leds,
++      .num_leds = ARRAY_SIZE(tx27_leds),
++};
++
++static struct platform_device tx27_led_device = {
++      .name = "leds-gpio",
++      .id = -1,
++      .dev = {
++              .platform_data = &tx27_led_data,
++      },
++};
++#endif
++
++#if defined(CONFIG_KEYBOARD_MXC) || defined(CONFIG_KEYBOARD_MXC_MODULE)
++/*!
++ * This array is used for mapping mx27 ADS keypad scancodes to input keyboard
++ * keycodes.
++ */
++static u16 tx27_kpd_keycodes[] = {
++      KEY_POWER,
++};
++
++static struct keypad_data tx27_keypad = {
++      .rowmax = 1,
++      .colmax = 1,
++      .irq = MXC_INT_KPP,
++      .learning = 0,
++      //.delay = 2, /* unused in the driver! */
++      .matrix = tx27_kpd_keycodes,
++};
++
++static struct resource tx27_kpp_resources[] = {
++      {
++              .start = MXC_INT_KPP,
++              .end = MXC_INT_KPP,
++              .flags = IORESOURCE_IRQ,
++      },
++};
++
++/* tx27 keypad driver */
++static struct platform_device tx27_keypad_device = {
++      .name = "mxc_keypad",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(tx27_kpp_resources),
++      .resource = tx27_kpp_resources,
++      .dev = {
++              .platform_data = &tx27_keypad,
++      },
++};
++#endif
++
++/* MTD NAND flash */
++#if defined(CONFIG_MTD_NAND_MXC) || defined(CONFIG_MTD_NAND_MXC_MODULE)
++#if 0
++static struct mtd_partition tx27_nand_partitions[] = {
++      {
++              .name = "RedBoot",
++              .offset = 0,
++              .size = 0x00040000,
++      },
++      {
++              .name = "kernel",
++              .offset = MTDPART_OFS_APPEND,
++              .size = 0x001A0000,
++      },
++      {
++              .name = "rootfs",
++              .offset = MTDPART_OFS_APPEND,
++              .size = 0x07E000000,
++      },
++      {
++              .name = "FIS directory",
++              .offset = MTDPART_OFS_APPEND,
++              .size = 0x00003000,
++              .mask_flags = MTD_WRITEABLE,
++      },
++      {
++              .name = "RedBoot config",
++              .offset = MTDPART_OFS_APPEND,
++              .size = 0x00001000,
++              .mask_flags = MTD_WRITEABLE,
++      },
++};
++
++static struct flash_platform_data tx27_nand_data = {
++      .map_name = "nand_probe",
++      .name = "tx27-nand",
++      .parts = tx27_nand_partitions,
++      .nr_parts = ARRAY_SIZE(tx27_nand_partitions),
++      .width = 1,
++};
++#else
++static struct mxc_nand_platform_data tx27_nand_data = {
++      .hw_ecc = 1,
++      .width = 1,
++};
++#endif
++
++static struct resource tx27_nand_resources[] = {
++      {
++              .start  = NFC_BASE_ADDR,
++              .end    = NFC_BASE_ADDR + 0xfff,
++              .flags  = IORESOURCE_MEM
++      }, {
++              .start  = MXC_INT_NANDFC,
++              .end    = MXC_INT_NANDFC,
++              .flags  = IORESOURCE_IRQ
++      },
++};
++
++static struct platform_device tx27_nand_mtd_device = {
++      .name = "mxc_nand",
++      .id = 0,
++      .num_resources = ARRAY_SIZE(tx27_nand_resources),
++      .resource = tx27_nand_resources,
++      .dev = {
++              .platform_data = &tx27_nand_data,
++      },
++};
++#endif
++
++#if defined(CONFIG_FB_IMX) || defined(CONFIG_FB_IMX_MODULE)
++/*
++ * Setup GPIO for LCDC device to be active
++ *
++ */
++static unsigned int mx27_lcdc_gpios[] = {
++      MXC_PIN(A, 30, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA30 */
++      MXC_PIN(A, 25, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA25 */
++      MXC_PIN(A, 26, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA26 */
++      MXC_PIN(A, 24, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA24 */
++      MXC_PIN(A, 27, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA27 */
++      PA5_PF_LSCLK,
++      PA6_PF_LD0,
++      PA7_PF_LD1,
++      PA8_PF_LD2,
++      PA9_PF_LD3,
++      PA10_PF_LD4,
++      PA11_PF_LD5,
++      PA12_PF_LD6,
++      PA13_PF_LD7,
++      PA14_PF_LD8,
++      PA15_PF_LD9,
++      PA16_PF_LD10,
++      PA17_PF_LD11,
++      PA18_PF_LD12,
++      PA19_PF_LD13,
++      PA20_PF_LD14,
++      PA21_PF_LD15,
++      PA22_PF_LD16,
++      PA23_PF_LD17,
++      PA28_PF_HSYNC,
++      PA29_PF_VSYNC,
++      PA31_PF_OE_ACD,
++};
++
++static int tx27_gpio_lcdc_active(struct platform_device *dev)
++{
++      int ret;
++
++      DBG(0, "%s: Setting up GPIO pins for LCD\n", __FUNCTION__);
++      ret = mxc_gpio_setup_multiple_pins(mx27_lcdc_gpios,
++                                         ARRAY_SIZE(mx27_lcdc_gpios), "LCD");
++      if (ret) {
++              DBG(0, "%s: Failed to setup GPIO pins for LCD: %d\n",
++                  __FUNCTION__, ret);
++              return ret;
++      }
++      return 0;
++}
++
++/*
++ * Setup GPIO for LCDC device to be inactive
++ *
++ */
++static int tx27_gpio_lcdc_inactive(struct platform_device *dev)
++{
++      mxc_gpio_release_multiple_pins(mx27_lcdc_gpios,
++                                     ARRAY_SIZE(mx27_lcdc_gpios));
++      return 0;
++}
++
++static struct imx_fb_platform_data tx27_fb_data[] __initdata = {
++      [0] = {
++              //.fb_mode = "Xenarc_700_Y-16",
++              .init = tx27_gpio_lcdc_active,
++              .exit = tx27_gpio_lcdc_inactive,
++              .lcd_power = NULL,
++              .backlight_power = NULL,
++
++              .pixclock       = 34576,
++              .xres           = 640,
++              .yres           = 480,
++
++              .bpp            = 16,
++
++              .hsync_len      = 64,
++              .right_margin   = 138 + 1,
++              .left_margin    = 118 + 3,
++
++              .vsync_len      = 7,
++              .upper_margin   = 44,
++              .lower_margin   = 44,
++#if 0
++              /* currently not used by driver! */
++              .sync           = ((0*FB_SYNC_HOR_HIGH_ACT) |
++                                 (0*FB_SYNC_VERT_HIGH_ACT) |
++                                 (1*FB_SYNC_OE_ACT_HIGH)),
++#else
++              .pcr            = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 |
++              PCR_BPIX_16 | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL,
++              .dmacr          = 0x80040060,
++#endif
++              .cmap_greyscale = 0,
++              .cmap_inverse   = 0,
++              .cmap_static    = 0,
++
++              .fixed_screen_cpu = NULL,
++      },
++      [1] = {
++              //.fb_mode = "SHARP LQ10D42-16",
++              .init = tx27_gpio_lcdc_active,
++              .exit = tx27_gpio_lcdc_inactive,
++              .lcd_power = NULL,
++              .backlight_power = NULL,
++
++              .pixclock       = 34576,
++              .xres           = 640,
++              .yres           = 480,
++
++#ifdef USE_18BPP
++              .bpp            = 32,
++#else
++              .bpp            = 16,
++#endif
++              .hsync_len      = 64,
++              .right_margin   = 138 + 1,
++              .left_margin    = 118 + 3,
++
++              .vsync_len      = 7,
++              .upper_margin   = 28,
++              .lower_margin   = 60,
++#if 0
++              /* currently not used by driver! */
++              .sync           = ((0*FB_SYNC_HOR_HIGH_ACT) |
++                                 (0*FB_SYNC_VERT_HIGH_ACT) |
++                                 (1*FB_SYNC_OE_ACT_HIGH)),
++#else
++              .pcr            = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 |
++#ifdef USE_18BPP
++              PCR_BPIX_18 | PCR_END_SEL | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL,
++#else
++              PCR_BPIX_16 | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL,
++#endif
++              .dmacr          = 0x80040060,
++#endif
++              .cmap_greyscale = 0,
++              .cmap_inverse   = 0,
++              .cmap_static    = 0,
++
++              .fixed_screen_cpu = NULL,
++      },
++      [2] = {
++              //.fb_mode = "SHARP LQ104V1DG61-16",
++              .init = tx27_gpio_lcdc_active,
++              .exit = tx27_gpio_lcdc_inactive,
++              .lcd_power = NULL,
++              .backlight_power = NULL,
++
++              .pixclock       = 40000,
++              .xres           = 640,
++              .yres           = 480,
++
++#ifdef USE_18BPP
++              .bpp            = 32,
++#else
++              .bpp            = 16,
++#endif
++              .hsync_len      = 32,
++              .right_margin   = 32 + 1,
++              .left_margin    = 0 + 3,
++
++              .vsync_len      = 35,
++              .upper_margin   = 0,
++              .lower_margin   = 0,
++#if 0
++              /* currently not used by driver! */
++              .sync           = ((0*FB_SYNC_HOR_HIGH_ACT) |
++                                 (0*FB_SYNC_VERT_HIGH_ACT) |
++                                 (1*FB_SYNC_OE_ACT_HIGH)),
++#else
++              .pcr            = PCR_TFT | PCR_COLOR | PCR_PBSIZ_8 |
++#ifdef USE_18BPP
++              PCR_BPIX_18 | PCR_END_SEL | PCR_FLMPOL | PCR_LPPOL | PCR_SCLK_SEL,
++#else
++              PCR_BPIX_16 | PCR_FLMPOL | PCR_LPPOL | PCR_CLKPOL | PCR_SCLK_SEL,
++#endif
++              .dmacr          = 0x80040060,
++#endif
++              .cmap_greyscale = 0,
++              .cmap_inverse   = 0,
++              .cmap_static    = 0,
++
++              .fixed_screen_cpu = NULL,
++      },
++};
++
++int __init karo_tx27_fb_init(void)
++{
++      int ret;
++
++      ret = mxc_register_device(&mxc_fb_device, &tx27_fb_data[0]);
++      if (ret != 0) {
++              DBG(0, "%s: Failed to register FB device: %d\n", __FUNCTION__, ret);
++      }
++      return ret;
++}
++device_initcall(karo_tx27_fb_init);
++#endif
++
++#if defined(CONFIG_MMC_MXC) || defined(CONFIG_MMC_MXC_MODULE)
++/*!
++ * Resource definition for the SDHC1
++ */
++static struct resource tx27_sdhc1_resources[] = {
++      {
++              .start = SDHC1_BASE_ADDR,
++              .end = SDHC1_BASE_ADDR + SZ_4K - 1,
++              .flags = IORESOURCE_MEM,
++      },
++      {
++              .start = MXC_INT_SDHC1,
++              .end = MXC_INT_SDHC1,
++              .flags = IORESOURCE_IRQ,
++      },
++      {
++              .start = IRQ_GPIOC(21),
++              .end = IRQ_GPIOC(21),
++              .flags = IORESOURCE_IRQ,
++      },
++      {
++              .name   = "sdhc1",
++              .start  = DMA_REQ_SDHC1,
++              .end    = DMA_REQ_SDHC1,
++              .flags  = IORESOURCE_DMA
++      },
++};
++
++/*!
++ * Resource definition for the SDHC2
++ */
++static struct resource tx27_sdhc2_resources[] = {
++      {
++              .start = SDHC2_BASE_ADDR,
++              .end = SDHC2_BASE_ADDR + SZ_4K - 1,
++              .flags = IORESOURCE_MEM,
++      },
++      {
++              .start = MXC_INT_SDHC2,
++              .end = MXC_INT_SDHC2,
++              .flags = IORESOURCE_IRQ,
++      },
++      {
++              .start = IRQ_GPIOC(22),
++              .end = IRQ_GPIOC(22),
++              .flags = IORESOURCE_IRQ,
++      },
++      {
++              .name   = "sdhc2",
++              .start  = DMA_REQ_SDHC2,
++              .end    = DMA_REQ_SDHC2,
++              .flags  = IORESOURCE_DMA
++      },
++};
++static inline int tx27_mmc_get_irq(int id)
++{
++      int irq;
++
++      switch (id) {
++      case 0:
++              irq = tx27_sdhc1_resources[2].start;
++              break;
++      case 1:
++              irq = tx27_sdhc2_resources[2].start;
++              break;
++      default:
++              BUG();
++      }
++      return irq;
++}
++
++static const char *tx27_mmc_irqdesc[] = {
++      "MMC card 0 detect",
++      "MMC card 1 detect",
++};
++
++static int tx27_mmc_init(struct device *dev, irqreturn_t (*mmc_detect_irq)(int, void *),
++                       void *data)
++{
++      int err;
++      int id = to_platform_device(dev)->id;
++      struct mmc_host *host = data;
++      int irq = tx27_mmc_get_irq(id);
++
++      err = gpio_sdhc_active(id);
++      if (err) {
++              return err;
++      }
++
++      host->caps |= MMC_CAP_4_BIT_DATA;
++
++      err = request_irq(irq, mmc_detect_irq,
++                        IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
++                        tx27_mmc_irqdesc[id], data);
++      if (err) {
++              printk(KERN_ERR "%s: MMC/SD: can't request MMC card detect IRQ %d\n",
++                     __FUNCTION__, irq);
++              return err;
++      }
++      device_set_wakeup_capable(dev, 1);
++
++      return 0;
++}
++
++static void tx27_mmc_exit(struct device *dev, void *data)
++{
++      int id = to_platform_device(dev)->id;
++      int irq = tx27_mmc_get_irq(id);
++
++      free_irq(irq, data);
++      gpio_sdhc_inactive(id);
++}
++
++static int tx27_mmc_suspend(struct device *dev, pm_message_t state)
++{
++      int id = to_platform_device(dev)->id;
++      int irq = tx27_mmc_get_irq(id);
++
++      if (device_may_wakeup(dev)) {
++              DBG(0, "%s: Enabling IRQ %d wakeup\n", __FUNCTION__, irq);
++              return enable_irq_wake(irq);
++      }
++      return 0;
++}
++
++static int tx27_mmc_resume(struct device *dev)
++{
++      int id = to_platform_device(dev)->id;
++      int irq = tx27_mmc_get_irq(id);
++
++      if (device_may_wakeup(dev)) {
++              DBG(0, "%s: Disabling IRQ %d wakeup\n", __FUNCTION__, irq);
++              return disable_irq_wake(irq);
++      }
++      return 0;
++}
++
++static struct imxmmc_platform_data tx27_sdhc1_data = {
++      //.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
++      //.min_clk = 150000,
++      //.max_clk = 25000000,
++      //.detect_delay = 20,
++      .init = tx27_mmc_init,
++      .exit = tx27_mmc_exit,
++      .suspend = tx27_mmc_suspend,
++      .resume = tx27_mmc_resume,
++};
++
++static struct imxmmc_platform_data tx27_sdhc2_data = {
++      //.ocr_mask = MMC_VDD_32_33 | MMC_VDD_33_34,
++      //.min_clk = 150000,
++      //.max_clk = 25000000,
++      //.detect_delay = 20,
++      .init = tx27_mmc_init,
++      .exit = tx27_mmc_exit,
++};
++
++static struct platform_device tx27_sdhc1_device = {
++      .name = "imx-mmc",
++      .id = 0,
++      .dev = {
++              .platform_data = &tx27_sdhc1_data,
++      },
++      .num_resources = ARRAY_SIZE(tx27_sdhc1_resources),
++      .resource = tx27_sdhc1_resources,
++};
++
++/*! Device Definition for MXC SDHC2 */
++static struct platform_device tx27_sdhc2_device = {
++      .name = "imx-mmc",
++      .id = 1,
++      .dev = {
++              .platform_data = &tx27_sdhc2_data,
++      },
++      .num_resources = ARRAY_SIZE(tx27_sdhc2_resources),
++      .resource = tx27_sdhc2_resources,
++};
++#endif
++
++#if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE)
++static struct resource mxcspi1_resources[] = {
++      [0] = {
++             .start = CSPI1_BASE_ADDR,
++             .end = CSPI1_BASE_ADDR + SZ_4K - 1,
++             .flags = IORESOURCE_MEM,
++      },
++      [1] = {
++             .start = MXC_INT_CSPI1,
++             .end = MXC_INT_CSPI1,
++             .flags = IORESOURCE_IRQ,
++      },
++};
++
++static struct mxc_spi_master mxcspi1_data = {
++      .maxchipselect = 2,
++      .spi_version = 0,
++};
++
++static struct platform_device mxcspi1_device = {
++      .name = "mxc_spi",
++      .id = 0,
++      .dev = {
++              .platform_data = &mxcspi1_data,
++      },
++      .num_resources = ARRAY_SIZE(mxcspi1_resources),
++      .resource = mxcspi1_resources,
++};
++#endif // defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE)
++
++#if defined(CONFIG_AC97_BUS) || defined(CONFIG_AC97_BUS_MODULE)
++static u64 tx27_dma_mask = ~0UL;
++
++static void tx27_ac97_gpio_release(void)
++{
++      gpio_ac97_inactive();
++}
++
++static int tx27_ac97_init(struct platform_device *dev)
++{
++      int ret;
++
++      DBG(0, "%s: \n", __FUNCTION__);
++      ret = gpio_ac97_active();
++      if (ret) {
++
++              return ret;
++      }
++      return 0;
++}
++
++static void tx27_ac97_exit(struct platform_device *dev)
++{
++      DBG(0, "%s: Releasing AC97 GPIO pins\n", __FUNCTION__);
++      tx27_ac97_gpio_release();
++}
++
++static struct mxc_ac97_audio_ops tx27_ac97_ops = {
++      .init = tx27_ac97_init,
++      .exit = tx27_ac97_exit,
++      .startup = NULL,
++      .shutdown = NULL,
++      .suspend = NULL,
++      .resume = NULL,
++      .priv = NULL,
++};
++
++static struct platform_device ac97_device = {
++      .name           = "mx27-ac97",
++      .id             = -1,
++      .dev = {
++              .dma_mask = &tx27_dma_mask,
++              .coherent_dma_mask = ~0UL,
++              .platform_data = &tx27_ac97_ops,
++      },
++};
++#endif
++
++#if defined(CONFIG_RTC_DRV_DS13XX) || defined(CONFIG_RTC_DRV_DS13XX_MODULE)
++static struct ds13xx_platform_data tx27_ds1339_data = {
++      .type = ds_1339,
++      .ctrl = 1 << 2, /* set INTCN to disable SQW output */
++      .trc = DS1339_TRC_ENABLE | DS1339_DIODE_ENABLE | DS1339_TRC_250R,
++};
++
++static struct platform_device tx27_ds1339_device = {
++      .name = "rtc-ds13xx",
++      .dev = {
++              .platform_data = &tx27_ds1339_data,
++      },
++};
++#endif
++
++#if defined(CONFIG_VIDEO_MXC_EMMA_OUTPUT) || defined(CONFIG_VIDEO_MXC_EMMA_OUTPUT_MODULE)
++static u64 mxc_emma_dmamask = 0xffffffffUL;
++
++static struct platform_device tx27_v4l2out_device = {
++      .name = "MXC Video Output",
++      .id = 0,
++      .dev = {
++              .dma_mask = &mxc_emma_dmamask,
++              .coherent_dma_mask = ~0UL,
++      },
++};
++#endif
++
++#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
++static int mxc_i2c0_pins[] = {
++      /*
++       * it seems the data line misses a pullup, so we must enable
++       * the internal pullup as a local workaround
++       */
++      PD17_PF_I2C_DATA,
++      PD18_PF_I2C_CLK,
++};
++
++static int karo_tx27_i2c_0_init(struct platform_device *pdev)
++{
++      return mxc_gpio_setup_multiple_pins(mxc_i2c0_pins,
++                      ARRAY_SIZE(mxc_i2c0_pins), "I2C0");
++}
++
++static int karo_tx27_i2c_0_exit(struct platform_device *pdev)
++{
++      mxc_gpio_release_multiple_pins(mxc_i2c0_pins,
++                      ARRAY_SIZE(mxc_i2c0_pins));
++
++      return 0;
++}
++
++static struct imx_i2c_platform_data karo_tx27_i2c_0_data = {
++      .max_clk = 100000,
++      .init = karo_tx27_i2c_0_init,
++      .exit = karo_tx27_i2c_0_exit,
++};
++
++#if defined(CONFIG_RTC_DRV_DS13XX) || defined(CONFIG_RTC_DRV_DS13XX_MODULE)
++static struct ds13xx_platform_data karo_ds1339_data = {
++      .type = ds_1339,
++      .ctrl = 0,
++      .trc = DS1339_TRC_ENABLE | DS1339_DIODE_ENABLE | DS1339_TRC_250R,
++};
++#endif
++
++static struct at24_platform_data karo_tx27_eeprom = {
++      .byte_len = 2048,
++      .page_size = 32,
++      .flags = AT24_FLAG_ADDR16 | AT24_FLAG_TAKE8ADDR,
++};
++
++static struct i2c_board_info karo_i2c_0_boardinfo[] __initdata = {
++      {
++              I2C_BOARD_INFO("24c16", 0x50),
++              .platform_data = &karo_tx27_eeprom,
++              .type = "24c16",
++      },
++#if defined(CONFIG_RTC_DRV_DS13XX) || defined(CONFIG_RTC_DRV_DS13XX_MODULE)
++      {
++              I2C_BOARD_INFO("ds1339", 0x68/*DS1339_CHIP_ID*/),
++              .type = "ds1339",
++              .platform_data = &karo_ds1339_data,
++      },
++#endif
++#if defined(CONFIG_RTC_DRV_DS1307) || defined(CONFIG_RTC_DRV_DS1307_MODULE)
++      {
++              I2C_BOARD_INFO("ds1339", 0x68/*DS1339_CHIP_ID*/),
++              .type = "ds1339",
++              //.platform_data = &karo_ds1339_data,
++      },
++#endif
++};
++
++static int mxc_i2c_1_pins[] = {
++      /*
++       * it seems the data line misses a pullup, so we must enable
++       * the internal pullup as a local workaround
++       */
++      PC5_PF_I2C2_SDA,
++      PC6_PF_I2C2_SCL,
++};
++
++static int karo_tx27_i2c_1_init(struct platform_device *pdev)
++{
++      return mxc_gpio_setup_multiple_pins(mxc_i2c_1_pins,
++                      ARRAY_SIZE(mxc_i2c_1_pins), "I2C_1");
++}
++
++static int karo_tx27_i2c_1_exit(struct platform_device *pdev)
++{
++      mxc_gpio_release_multiple_pins(mxc_i2c_1_pins,
++                      ARRAY_SIZE(mxc_i2c_1_pins));
++
++      return 0;
++}
++
++static struct imx_i2c_platform_data karo_tx27_i2c_1_data = {
++      .max_clk = 100000,
++      .init = karo_tx27_i2c_1_init,
++      .exit = karo_tx27_i2c_1_exit,
++};
++
++static struct i2c_board_info karo_i2c_1_boardinfo[] __initdata = {
++      {
++              I2C_BOARD_INFO("lp3972", 0x34),
++              .type = "lp3972",
++      },
++};
++
++int __init karo_i2c_init(void)
++{
++      int ret;
++
++      DBG(0, "%s: Registering I2C bus 0\n", __FUNCTION__);
++      ret = mxc_register_device(&imx_i2c_device0, &karo_tx27_i2c_0_data);
++      if (ret != 0) {
++              printk(KERN_ERR "Failed to register I2C device: %d\n", ret);
++              return ret;
++      }
++      ret = i2c_register_board_info(0, karo_i2c_0_boardinfo,
++                                    ARRAY_SIZE(karo_i2c_0_boardinfo));
++      if (ret != 0) {
++              printk(KERN_ERR "Failed to register I2C board info: %d\n", ret);
++              platform_device_unregister(&imx_i2c_device0);
++      }
++
++      DBG(0, "%s: Registering I2C bus 1\n", __FUNCTION__);
++      ret = mxc_register_device(&imx_i2c_device1, &karo_tx27_i2c_1_data);
++      if (ret != 0) {
++              printk(KERN_ERR "Failed to register I2C device: %d\n", ret);
++              return ret;
++      }
++      ret = i2c_register_board_info(1, karo_i2c_1_boardinfo,
++                                    ARRAY_SIZE(karo_i2c_1_boardinfo));
++      if (ret != 0) {
++              printk(KERN_ERR "Failed to register I2C board info: %d\n", ret);
++              platform_device_unregister(&imx_i2c_device1);
++      }
++      return ret;
++}
++device_initcall(karo_i2c_init);
++#endif
++
++struct platform_dev_list {
++      struct platform_device *pdev;
++      int flag;
++} tx27_devices[] __initdata = {
++#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
++      { .pdev = &tx27_gpio_keys_device, .flag = -1, },
++#endif
++#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
++      { .pdev = &tx27_led_device, .flag = -1, },
++#endif
++#if defined(CONFIG_RTC_MXC) || defined(CONFIG_RTC_MXC_MODULE)
++      { .pdev = &mxc_rtc_device, .flag = -1, },
++#endif
++#if defined(CONFIG_MTD_NAND_MXC) || defined(CONFIG_MTD_NAND_MXC_MODULE)
++      { .pdev = &tx27_nand_mtd_device, .flag = 1, },
++#endif
++#if defined(CONFIG_KEYBOARD_MXC) || defined(CONFIG_KEYBOARD_MXC_MODULE)
++      { .pdev = &tx27_keypad_device, .flag = 1, },
++#endif
++#if defined(CONFIG_FEC) || defined(CONFIG_FEC_MODULE)
++      { .pdev = &fec_device, .flag = 1, },
++#endif
++#if defined(CONFIG_SPI_MXC) || defined(CONFIG_SPI_MXC_MODULE)
++      { .pdev = &mxcspi1_device, .flag = 1, },
++#endif
++#if defined(CONFIG_AC97_BUS) || defined(CONFIG_AC97_BUS_MODULE)
++      { .pdev = &ac97_device, .flag = 1, },
++#endif
++#if defined(CONFIG_MMC_MXC) || defined(CONFIG_MMC_MXC_MODULE)
++      { .pdev = &tx27_sdhc1_device, .flag = 1, },
++      { .pdev = &tx27_sdhc2_device, .flag = 1, },
++#endif
++#if defined(CONFIG_RTC_DRV_DS13XX) || defined(CONFIG_RTC_DRV_DS13XX_MODULE)
++      { .pdev = &tx27_ds1339_device, .flag = 1, },
++#endif
++#if defined(CONFIG_VIDEO_MXC_EMMA_OUTPUT) || defined(CONFIG_VIDEO_MXC_EMMA_OUTPUT_MODULE)
++      { .pdev = &tx27_v4l2out_device, .flag = 1, },
++#endif
++#if defined(CONFIG_MXC_VPU) || defined(CONFIG_MXC_VPU_MODULE)
++      { .pdev = &mxc_vpu_device, .flag = 1, },
++#endif
++};
++#define TX27_NUM_DEVICES              ARRAY_SIZE(tx27_devices)
++
++#define OSC26M_ENABLE_PIN     (GPIO_PORTB | 22)
++
++static int _clk_26m_enable(struct clk *clk)
++{
++      int ret;
++
++      DBG(0, "%s: Switching 26MHz oscillator on\n", __FUNCTION__);
++      ret = gpio_request(OSC26M_ENABLE_PIN, "OSC26m");
++      if (ret != 0) {
++              printk(KERN_ERR "Failed to request 26MHz oscillator enable GPIO: %d\n", ret);
++              return ret;
++      }
++      gpio_set_value(OSC26M_ENABLE_PIN, 1);
++      mxc_gpio_mode(OSC26M_ENABLE_PIN | GPIO_GPIO | GPIO_OUT);
++      return 0;
++}
++
++static void _clk_26m_disable(struct clk *clk)
++{
++      DBG(0, "%s: Switching 26MHz oscillator off\n", __FUNCTION__);
++      gpio_set_value(OSC26M_ENABLE_PIN, 0);
++      gpio_free(OSC26M_ENABLE_PIN);
++}
++
++static struct clk clk_26m = {
++      .name = "clk_26m",
++      .enable = _clk_26m_enable,
++      .disable = _clk_26m_disable,
++};
++
++#ifdef CONFIG_BASE_CLK_26MHz
++static __init void karo_tx27_clock_switch(struct clk *_26m_clk)
++{
++      int loops = 0;
++      u32 cscr = __raw_readl(CCM_CSCR);
++      u32 ccsr;
++
++      if (_26m_clk != NULL) {
++              DBG(0, "%s: Enabling 26MHz clock\n", __FUNCTION__);
++              clk_enable(_26m_clk);
++
++              __raw_writel(CCM_MPCTL0_PD_VAL(0) |
++                           CCM_MPCTL0_MFD_VAL(51) |
++                           CCM_MPCTL0_MFI_VAL(7) |
++                           CCM_MPCTL0_MFN_VAL(35), CCM_MPCTL0);
++
++              __raw_writel(CCM_SPCTL0_PD_VAL(1) |
++                           CCM_SPCTL0_MFD_VAL(12) |
++                           CCM_SPCTL0_MFI_VAL(9) |
++                           CCM_SPCTL0_MFN_VAL(3), CCM_SPCTL0);
++
++              cscr |= CCM_CSCR_MCU | CCM_CSCR_SP;
++              __raw_writel(cscr, CCM_CSCR);
++
++              cscr |= CCM_CSCR_MPLLRES | CCM_CSCR_SPLLRES;
++              __raw_writel(cscr, CCM_CSCR);
++              while (__raw_readl(CCM_CSCR) & (CCM_CSCR_MPLLRES | CCM_CSCR_SPLLRES)) {
++                      udelay(1);
++                      loops++;
++              }
++              printk("PLLs locked after %d loops: CSCR=%08x(%08x)\n", loops,
++                     __raw_readl(CCM_CSCR), cscr);
++
++      cscr &= ~CCM_CSCR_FPM;
++      __raw_writel(cscr, CCM_CSCR);
++      DBG(9, "%s: Disabling FPM, DPLL and OSC26M\n", __FUNCTION__);
++      ccsr = __raw_readl(CCM_CCSR);
++      __raw_writel(ccsr & ~0x300, CCM_CCSR);
++      DBG(9, "changing CCSR from %08x to %08x(%08x)\n",
++          ccsr, ccsr & ~0x300, __raw_readl(CCM_CCSR));
++      } else {
++              printk(KERN_INFO "Changing SPCTL0 from %08x to %08x\n",
++                     __raw_readl(CCM_SPCTL0), CCM_SPCTL0_PD_VAL(2) |
++                     CCM_SPCTL0_MFD_VAL(755) |
++                     CCM_SPCTL0_MFI_VAL(11) |
++                     CCM_SPCTL0_MFN_VAL(-205));
++
++              __raw_writel(CCM_SPCTL0_PD_VAL(2) |
++                           CCM_SPCTL0_MFD_VAL(755) |
++                           CCM_SPCTL0_MFI_VAL(11) |
++                           CCM_SPCTL0_MFN_VAL(-205), CCM_SPCTL0);
++      }
++}
++#else
++static inline void karo_tx27_clock_switch(struct clk *_26m_clk)
++{
++      printk(KERN_INFO "Changing SPCTL0 from %08x to %08x\n",
++             __raw_readl(CCM_SPCTL0), CCM_SPCTL0_PD_VAL(2) |
++             CCM_SPCTL0_MFD_VAL(755) |
++             CCM_SPCTL0_MFI_VAL(11) |
++             CCM_SPCTL0_MFN_VAL(-205));
++
++      __raw_writel(CCM_SPCTL0_PD_VAL(2) |
++                   CCM_SPCTL0_MFD_VAL(755) |
++                   CCM_SPCTL0_MFI_VAL(11) |
++                   CCM_SPCTL0_MFN_VAL(-205), CCM_SPCTL0);
++}
++#endif
++
++static __init void karo_tx27_clock_init(void)
++{
++      struct clk *cpu_clk;
++      struct clk *_26m_clk = NULL;
++      int ret;
++
++      ret = clk_register(&clk_26m);
++      if (ret != 0) {
++              printk(KERN_ERR "Failed to register 26MHz clock: %d\n", ret);
++              goto no_26m;
++      }
++      _26m_clk = clk_get(NULL, "clk_26m");
++      if (IS_ERR(_26m_clk)) {
++              printk(KERN_ERR "Cannot request 26MHz clock: %ld\n", PTR_ERR(_26m_clk));
++              _26m_clk = NULL;
++      }
++ no_26m:
++      karo_tx27_clock_switch(_26m_clk);
++      mxc_clocks_init(26000000);
++      cpu_clk = clk_get(NULL, "cpu_clk");
++      if (!IS_ERR(cpu_clk)) {
++              printk(KERN_DEBUG "%s: Setting CPU clock to 400MHz\n", __FUNCTION__);
++              if (clk_set_rate(cpu_clk, 399000000) != 0) {
++                      printk(KERN_ERR "Failed to set CPU clock rate\n");
++              }
++      } else {
++              printk(KERN_ERR "Failed to get CPU clock: %ld\n",
++                     PTR_ERR(cpu_clk));
++      }
++      SHOW_REG(CCM_CSCR);
++}
++
++static __init void karo_tx27_board_init(void)
++{
++      int i;
++
++      DBG(0, "%s: \n", __FUNCTION__);
++      SHOW_REG(CCM_CSCR);
++
++      for (i = 0; i < ARRAY_SIZE(tx27_uart_devices); i++) {
++              int ret;
++              int port = tx27_uart_devices[i]->id;
++
++              DBG(0, "%s: Registering platform device[%d] @ %p dev %p: %s\n",
++                  __FUNCTION__, i, tx27_uart_devices[i],
++                  &tx27_uart_devices[i]->dev, tx27_uart_devices[i]->name);
++              ret = mxc_register_device(tx27_uart_devices[i],
++                                        &tx27_uart_ports[port]);
++              if (ret != 0) {
++                      printk(KERN_WARNING "%s: Failed to register platform_device[%d]: %s: %d\n",
++                             __FUNCTION__, i, tx27_uart_devices[i]->name, ret);
++              }
++      }
++      //mxc_cpu_common_init();
++      //karo_tx27_clock_init();
++      //early_console_setup(saved_command_line);
++
++      /* configure PF13 as output for Starterkit-5 LED */
++      //mxc_gpio_mode(MXC_PIN(F, 13, GPIO, GPIO_OUT | GPIO_DFLT_LOW));
++      dump_regs();
++
++      /* enable SSI3_INT (PC23) for IRQ probing */
++      set_irq_flags(gpio_to_irq(GPIO_PORTC | 23), IRQF_VALID | IRQF_PROBE);
++
++      for (i = 0; i < TX27_NUM_DEVICES; i++) {
++              int ret;
++
++              if (tx27_devices[i].pdev == NULL) continue;
++              if (!tx27_devices[i].flag) {
++                      DBG(0, "%s: Skipping platform device[%d] @ %p dev %p: %s\n",
++                          __FUNCTION__, i, tx27_devices[i].pdev, &tx27_devices[i].pdev->dev,
++                          tx27_devices[i].pdev->name);
++                      continue;
++              }
++              DBG(0, "%s: Registering platform device[%d] @ %p dev %p: %s\n",
++                  __FUNCTION__, i, tx27_devices[i].pdev, &tx27_devices[i].pdev->dev,
++                  tx27_devices[i].pdev->name);
++              ret = platform_device_register(tx27_devices[i].pdev);
++              if (ret) {
++                      printk(KERN_WARNING "%s: Failed to register platform_device[%d]: %s: %d\n",
++                             __FUNCTION__, i, tx27_devices[i].pdev->name, ret);
++              }
++      }
++      DBG(0, "%s: Done\n", __FUNCTION__);
++}
++
++static void __init karo_tx27_map_io(void)
++{
++      mxc_map_io();
++}
++
++static void __init karo_tx27_fixup(struct machine_desc *desc, struct tag *tags,
++                                 char **cmdline, struct meminfo *mi)
++{
++}
++
++static void __init karo_tx27_timer_init(void)
++{
++      DBG(0, "%s: \n", __FUNCTION__);
++      karo_tx27_clock_init();
++      mxc_timer_init("gpt_clk.0");
++      DBG(0, "%s: Done\n", __FUNCTION__);
++}
++
++struct sys_timer karo_tx27_timer = {
++      .init   = karo_tx27_timer_init,
++};
++
++MACHINE_START(TX27, "Ka-Ro electronics TX27 module (Freescale i.MX27)")
++      /* Maintainer: <LW@KARO-electronics.de> */
++      .phys_io        = AIPI_BASE_ADDR,
++      .io_pg_offst    = ((unsigned long)AIPI_BASE_ADDR_VIRT >> 18) & 0xfffc,
++      .fixup          = karo_tx27_fixup,
++      .map_io         = karo_tx27_map_io,
++      .init_irq       = mxc_init_irq,
++      .init_machine   = karo_tx27_board_init,
++      .timer          = &karo_tx27_timer,
++MACHINE_END
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/karo.h linux-2.6.28-karo/arch/arm/mach-mx2/karo.h
+--- linux-2.6.28/arch/arm/mach-mx2/karo.h      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/karo.h 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,45 @@
++#ifdef DEBUG
++#include <mach/iomux.h>
++
++#define SHOW_REG(reg) DBG(0, "%s[%08lx]=%08x\n", #reg, MXC_PHYS_ADDRESS(reg), __raw_readl(reg))
++#define SHOW_GPIO_REG(reg, port)                                              \
++      DBG(0, "PT%c_%s[%08lx]=%08x\n", 'A' + port, #reg,                                       \
++          GPIO_BASE_ADDR + MXC_##reg(port), __raw_readl(VA_GPIO_BASE + MXC_##reg(port)))
++
++static void dump_regs(void)
++{
++      int i;
++
++      SHOW_REG(CCM_CSCR);
++      SHOW_REG(CCM_MPCTL0);
++      SHOW_REG(CCM_MPCTL1);
++      SHOW_REG(CCM_SPCTL0);
++      SHOW_REG(CCM_SPCTL1);
++      SHOW_REG(CCM_OSC26MCTL);
++      SHOW_REG(CCM_PCDR0);
++      SHOW_REG(CCM_PCDR1);
++      SHOW_REG(CCM_PCCR0);
++      SHOW_REG(CCM_PCCR1);
++      SHOW_REG(CCM_CCSR);
++      SHOW_REG(CCM_PMCTL);
++      SHOW_REG(CCM_PMCOUNT);
++      SHOW_REG(CCM_WKGDCTL);
++      for (i = 0; i < 6; i++) {
++              SHOW_GPIO_REG(GIUS, i);
++              SHOW_GPIO_REG(DDIR, i);
++              SHOW_GPIO_REG(SSR, i);
++              SHOW_GPIO_REG(GPR, i);
++              SHOW_GPIO_REG(OCR1, i);
++              SHOW_GPIO_REG(OCR2, i);
++              SHOW_GPIO_REG(ICONFA1, i);
++              SHOW_GPIO_REG(ICONFA2, i);
++              SHOW_GPIO_REG(ICONFB1, i);
++              SHOW_GPIO_REG(ICONFB2, i);
++      }
++}
++#else
++static inline void dump_regs(void)
++{
++}
++#define SHOW_REG(reg) do {} while (0)
++#endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/mxc_pm.c linux-2.6.28-karo/arch/arm/mach-mx2/mxc_pm.c
+--- linux-2.6.28/arch/arm/mach-mx2/mxc_pm.c    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/mxc_pm.c       2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,460 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup DPM_MX27 Power Management
++ * @ingroup MSL_MX27
++ */
++/*!
++ * @file mach-mx27/mxc_pm.c
++ *
++ * @brief This file contains the implementation of the Low-level power
++ * management driver. It modifies the registers of the PLL and clock module
++ * of the i.MX27.
++ *
++ * @ingroup DPM_MX27
++ */
++
++/*
++ * Include Files
++ */
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <asm/irq.h>
++#include <mach/mxc_pm.h>
++#include <mach/mxc.h>
++#include <mach/system.h>
++#include <asm/io.h>
++
++#include "crm_regs.h"
++
++/* Local defines */
++#define MAX_ARM_FREQ        400000000
++#define MAX_AHB_FREQ        133000000
++#define MAX_IPG_FREQ        66500000
++#define FREQ_COMP_TOLERANCE      100  /* tolerance percentage times 100 */
++#define MX27_LLPM_DEBUG           0
++
++/*
++ * Global variables
++ */
++#if 0
++/*!
++ * These variables hold the various clock values when the module is loaded.
++ * This is needed because these clocks are derived from MPLL and when MPLL
++ * output changes, these clocks need to be adjusted.
++ */
++static u32 perclk1, perclk2, perclk3, perclk4, nfcclk, cpuclk;
++
++/*!
++ * Compare two frequences using allowable tolerance
++ *
++ * The MX27 PLL can generate many frequencies. This function
++ * compares the generated frequency to the requested frequency
++ * and determines it they are within and acceptable tolerance.
++ *
++ * @param   freq1  desired frequency
++ * @param   freq2  generated frequency
++ *
++ * @return       Returns 0 is frequencies are within talerance
++ *               and non-zero is they are not.
++ */
++static s32 freq_equal(u32 freq1, u32 freq2)
++{
++      if (freq1 > freq2) {
++              return (freq1 - freq2) <= (freq1 / FREQ_COMP_TOLERANCE);
++      }
++      return (freq2 - freq1) <= (freq1 / FREQ_COMP_TOLERANCE);
++}
++
++/*!
++ * Select the PLL frequency based on the desired ARM frequency.
++ *
++ * The MPLL will be configured to output three frequencies, 400/333/266 MHz.
++ *
++ * @param       armfreq         Desired ARM frequency
++ *
++ * @return      Returns one of the selected PLL frequency (400/333/266 MHz).
++ *              Returns -1 on error.
++ *
++ */
++static s32 select_freq_pll(u32 armfreq)
++{
++      u32 div;
++
++      div = 266000000 / armfreq;
++      if ((div == 0) || (!freq_equal(armfreq, 266000000 / div))) {
++              div = 400000000 / armfreq;
++              if ((div == 0) || (!freq_equal(armfreq, 400000000 / div))) {
++                      return -1;
++              }
++
++              return 400000000;
++      }
++
++      return 266000000;
++}
++
++/*!
++ * Check whether the desired ARM and AHB frequencies are valid.
++ *
++ * @param       armfreq         Desired ARM frequency
++ * @param       ahbfreq         Desired AHB frequency
++ *
++ * @return      Returns 0 on success
++ *              Return -1 on error
++ */
++static s32 mx27_pm_check_parameters(u32 armfreq, u32 ahbfreq)
++{
++      u32 ahbdiv;
++
++      /* No idea about minimum frequencies.. just a guess! */
++      if ((armfreq < 1000000) || (ahbfreq < 1000000)) {
++              printk("arm or ahb freq. too low\n");
++              return -1;
++      }
++
++      if ((armfreq > MAX_ARM_FREQ) || (ahbfreq > MAX_AHB_FREQ)) {
++              printk("arm or ahb freq. too high\n");
++              return -1;
++      }
++
++      /* AHB divider value is restricted to less than 8 */
++      ahbdiv = armfreq / ahbfreq;
++      if ((ahbdiv == 0) || (ahbdiv > 8)) {
++              printk("Invalid ahb frequency\n");
++              return -1;
++      }
++
++      return 0;
++}
++
++/*!
++ * Integer clock scaling
++ *
++ * Change the main ARM clock frequencies without changing the MPLL.
++ * The integer dividers (PRESC and BCLKDIV) are changed to obtain the
++ * desired frequency. Since NFC clock is derived from ARM frequency,
++ * NFCDIV is also adjusted.
++ *
++ * @param       arm_freq        Desired ARM frequency
++ * @param       ahb_freq        Desired AHB frequency
++ * @param       pll_freq        Current PLL frequency
++ *
++ * @return      Returns 0
++ */
++static s32 mx27_pm_intscale(u32 arm_freq, u32 ahb_freq, s32 pll_freq)
++{
++      u32 pre_div, bclk_div, nfc_div;
++
++      /* Calculate ARM divider */
++      pre_div = pll_freq / arm_freq;
++      if (pre_div == 0)
++              pre_div = 1;
++
++      /* Calculate AHB divider */
++      bclk_div = arm_freq / ahb_freq;
++      if (bclk_div == 0)
++              bclk_div = 1;
++
++      if ((arm_freq / bclk_div) > ahb_freq)
++              bclk_div++;
++
++      /* NFC clock is dependent on ARM clock */
++      nfc_div = arm_freq / nfcclk;
++      if ((arm_freq / nfc_div) > nfcclk)
++              nfc_div++;
++
++      /* Adjust NFC divider */
++      mxc_set_clocks_div(NFC_CLK, nfc_div);
++
++#if MX27_LLPM_DEBUG
++      printk("DIVIDERS: PreDiv = %d BCLKDIV = %d \n", pre_div, bclk_div);
++      printk("Integer scaling\n");
++      printk("PLL = %d : ARM = %d: AHB = %d\n", pll_freq, arm_freq, ahb_freq);
++#endif
++
++      /*
++       * This part is tricky. What to adjust first (PRESC or BCLKDIV)?
++       * After trial and error, if current ARM frequency is greater than
++       * desired ARM frequency, then adjust PRESC first, else if current
++       * ARM frequency is less than desired ARM frequency, then adjust
++       * BCLKDIV first.
++       */
++      if (cpuclk > arm_freq) {
++              mxc_set_clocks_div(CPU_CLK, pre_div);
++              mxc_set_clocks_div(AHB_CLK, bclk_div);
++      } else {
++              mxc_set_clocks_div(AHB_CLK, bclk_div);
++              mxc_set_clocks_div(CPU_CLK, pre_div);
++      }
++
++      cpuclk = arm_freq;
++      mdelay(50);
++      return 0;
++}
++
++/*!
++ * Set dividers for various peripheral clocks.
++ *
++ * PERCLK1, PERCLK2, PERCLK3 and PERCLK4 are adjusted based on the MPLL
++ * output frequency.
++ *
++ * @param       pll_freq        Desired MPLL output frequency
++ */
++static void mx27_set_dividers(u32 pll_freq)
++{
++      s32 perdiv1, perdiv2, perdiv3, perdiv4;
++
++      perdiv1 = pll_freq / perclk1;
++      if ((pll_freq / perdiv1) > perclk1)
++              perdiv1++;
++
++      perdiv2 = pll_freq / perclk2;
++      if ((pll_freq / perdiv2) > perclk2)
++              perdiv2++;
++
++      perdiv3 = pll_freq / perclk3;
++      if ((pll_freq / perdiv3) > perclk3)
++              perdiv3++;
++
++      perdiv4 = pll_freq / perclk4;
++      if ((pll_freq / perdiv4) > perclk4)
++              perdiv4++;
++
++      mxc_set_clocks_div(PERCLK1, perdiv1);
++      mxc_set_clocks_div(PERCLK2, perdiv2);
++      mxc_set_clocks_div(PERCLK3, perdiv3);
++      mxc_set_clocks_div(PERCLK4, perdiv4);
++}
++
++/*!
++ * Change MPLL output frequency and adjust derived clocks to produce the
++ * desired frequencies.
++ *
++ * @param       arm_freq        Desired ARM frequency
++ * @param       ahb_freq        Desired AHB frequency
++ * @param       org_pll         Current PLL frequency
++ *
++ * @return      Returns 0 on success
++ *              Returns -1 on error
++ */
++static s32 mx27_pm_pllscale(u32 arm_freq, u32 ahb_freq, s32 org_pll)
++{
++      u32 mfi, mfn, mfd, pd = 1, cscr;
++      s32 pll_freq;
++
++      /* Obtain the PLL frequency for the desired ARM frequency */
++      pll_freq = select_freq_pll(arm_freq);
++      if (pll_freq == -1) {
++              return -1;
++      }
++
++      /* The MPCTL0 register values are programmed based on the oscillator */
++      cscr = __raw_readl(CCM_CSCR);
++      if ((cscr & CCM_CSCR_OSC26M) == 0) {
++              /* MPCTL0 register values are programmed for 400/266 MHz */
++              switch (pll_freq) {
++              case 400000000:
++                      mfi = 7;
++                      mfn = 9;
++                      mfd = 12;
++                      pd = 0;
++                      break;
++
++              case 266000000:
++                      mfi = 10;
++                      mfn = 6;
++                      mfd = 25;
++                      break;
++
++              default:
++                      return -1;
++              }
++      } else {
++              /* MPCTL0 register values are programmed for 400/266 MHz */
++              switch (pll_freq) {
++              case 400000000:
++                      mfi = 12;
++                      mfn = 2;
++                      mfd = 3;
++                      break;
++
++              case 266000000:
++                      mfi = 8;
++                      mfn = 10;
++                      mfd = 31;
++                      break;
++
++              default:
++                      return -1;
++              }
++      }
++
++#if MX27_LLPM_DEBUG
++      printk("PLL scaling\n");
++      printk("PLL = %d : ARM = %d: AHB = %d\n", pll_freq, arm_freq, ahb_freq);
++#endif
++
++      /* Adjust the peripheral clock dividers for new PLL frequency */
++      mx27_set_dividers(pll_freq);
++
++      if (pll_freq > org_pll) {
++              /* Set the dividers first */
++              mx27_pm_intscale(arm_freq, ahb_freq, pll_freq);
++
++              /* Set the PLL */
++              mxc_pll_set(MCUPLL, mfi, pd, mfd, mfn);
++              mdelay(50);
++      } else {
++              /* Set the PLL first */
++              mxc_pll_set(MCUPLL, mfi, pd, mfd, mfn);
++              mdelay(50);
++
++              /* Set the dividers later */
++              mx27_pm_intscale(arm_freq, ahb_freq, pll_freq);
++      }
++
++      return 0;
++}
++#endif
++/*!
++ * Implement steps required to transition to low-power modes.
++ *
++ * @param       mode    The desired low-power mode. Possible values are,
++ *                      DOZE_MODE
++ *                      WAIT_MODE
++ *                      STOP_MODE
++ *                      DSM_MODE
++ */
++void mxc_pm_lowpower(s32 mode)
++{
++      u32 cscr;
++
++      local_irq_disable();
++
++      /* WAIT and DOZE execute WFI only */
++      switch (mode) {
++      case STOP_MODE:
++      case DSM_MODE:
++              /* Clear MPEN and SPEN to disable MPLL/SPLL */
++              cscr = __raw_readl(CCM_CSCR);
++              cscr &= 0xFFFFFFFC;
++              __raw_writel(cscr, CCM_CSCR);
++              break;
++      }
++
++      /* Executes WFI */
++      arch_idle();
++
++      local_irq_enable();
++}
++
++#if 0
++/*!
++ * Called to change the core frequency. This function internally decides
++ * whether to do integer scaling or pll scaling.
++ *
++ * @param       arm_freq        Desired ARM frequency
++ * @param       ahb_freq        Desired AHB frequency
++ * @param       ipg_freq        Desired IP frequency, constant AHB / 2 always.
++ *
++ * @return      Returns 0 on success
++ *              Returns -1 on error
++ */
++int mxc_pm_dvfs(unsigned long arm_freq, long ahb_freq, long ipg_freq)
++{
++      u32 divider;
++      s32 pll_freq, ret;
++      unsigned long flags;
++
++      if (mx27_pm_check_parameters(arm_freq, ahb_freq) != 0) {
++              return -1;
++      }
++
++      local_irq_save(flags);
++
++      /* Get the current PLL frequency */
++      pll_freq = mxc_pll_clock(MCUPLL);
++
++#if MX27_LLPM_DEBUG
++      printk("MCU PLL frequency is %d\n", pll_freq);
++#endif
++
++      /* Decide whether to do integer scaling or pll scaling */
++      if (arm_freq > pll_freq) {
++              /* Do PLL scaling */
++              ret = mx27_pm_pllscale(arm_freq, ahb_freq, pll_freq);
++      } else {
++              /* We need integer divider values */
++              divider = pll_freq / arm_freq;
++              if (!freq_equal(arm_freq, pll_freq / divider)) {
++                      /* Do PLL scaling */
++                      ret = mx27_pm_pllscale(arm_freq, ahb_freq, pll_freq);
++              } else {
++                      /* Do integer scaling */
++                      ret = mx27_pm_intscale(arm_freq, ahb_freq, pll_freq);
++              }
++      }
++
++      local_irq_restore(flags);
++      return ret;
++}
++#endif
++/*
++ * This API is not supported on i.MX27
++ */
++int mxc_pm_intscale(long armfreq, long ahbfreq, long ipfreq)
++{
++      return -MXC_PM_API_NOT_SUPPORTED;
++}
++
++/*
++ * This API is not supported on i.MX27
++ */
++int mxc_pm_pllscale(long armfreq, long ahbfreq, long ipfreq)
++{
++      return -MXC_PM_API_NOT_SUPPORTED;
++}
++
++/*!
++ * This function is used to load the module.
++ *
++ * @return   Returns an Integer on success
++ */
++static int __init mxc_pm_init_module(void)
++{
++      printk(KERN_INFO "MX27: Power management module initialized\n");
++      return 0;
++}
++
++/*!
++ * This function is used to unload the module
++ */
++static void __exit mxc_pm_cleanup_module(void)
++{
++      printk(KERN_INFO "MX27: Power management module exit\n");
++}
++
++module_init(mxc_pm_init_module);
++module_exit(mxc_pm_cleanup_module);
++
++EXPORT_SYMBOL(mxc_pm_lowpower);
++//EXPORT_SYMBOL(mxc_pm_dvfs);
++EXPORT_SYMBOL(mxc_pm_pllscale);
++EXPORT_SYMBOL(mxc_pm_intscale);
++
++MODULE_AUTHOR("Freescale Semiconductor");
++MODULE_DESCRIPTION("i.MX27 low level PM driver");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/pm.c linux-2.6.28-karo/arch/arm/mach-mx2/pm.c
+--- linux-2.6.28/arch/arm/mach-mx2/pm.c        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/pm.c   2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,88 @@
++/*
++ * linux/arch/arm/mach-mx27/pm.c
++ *
++ * MX27 Power Management Routines
++ *
++ * Original code for the SA11x0:
++ * Copyright (c) 2001 Cliff Brake <cbrake@accelent.com>
++ *
++ * Modified for the PXA250 by Nicolas Pitre:
++ * Copyright (c) 2002 Monta Vista Software, Inc.
++ *
++ * Modified for the OMAP1510 by David Singleton:
++ * Copyright (c) 2002 Monta Vista Software, Inc.
++ *
++ * Cleanup 2004 for OMAP1510/1610 by Dirk Behme <dirk.behme@de.bosch.com>
++ *
++ * Modified for the MX27
++ * Copyright 2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ *
++ * This program is free software; you can redistribute it and/or modify it
++ * under the terms of the GNU General Public License as published by the
++ * Free Software Foundation; either version 2 of the License, or (at your
++ * option) any later version.
++ *
++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
++ *
++ * 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.
++ */
++
++#include <linux/pm.h>
++#include <linux/sched.h>
++#include <linux/proc_fs.h>
++#include <linux/suspend.h>
++
++#include <asm/io.h>
++#include <mach/mxc_pm.h>
++
++/*
++ * TODO: whatta save?
++ */
++
++static int mx27_pm_enter(suspend_state_t state)
++{
++      pr_debug("%s: Entering state %d\n", __FUNCTION__, state);
++      switch (state) {
++      case PM_SUSPEND_MEM:
++              mxc_pm_lowpower(STOP_MODE);
++              break;
++
++      case PM_SUSPEND_STANDBY:
++              mxc_pm_lowpower(WAIT_MODE);
++              break;
++
++      case PM_SUSPEND_STOP:
++              mxc_pm_lowpower(DSM_MODE);
++              break;
++
++      default:
++              return -1;
++      }
++      return 0;
++}
++
++struct platform_suspend_ops mx27_pm_ops = {
++      .enter = mx27_pm_enter,
++      .valid = suspend_valid_only_mem,
++};
++
++static int __init mx27_pm_init(void)
++{
++      pr_debug("Power Management for Freescale MX27\n");
++      suspend_set_ops(&mx27_pm_ops);
++
++      return 0;
++}
++
++late_initcall(mx27_pm_init);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/system.c linux-2.6.28-karo/arch/arm/mach-mx2/system.c
+--- linux-2.6.28/arch/arm/mach-mx2/system.c    2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/system.c       2009-03-11 13:31:09.000000000 +0100
+@@ -21,7 +21,9 @@
+ #include <linux/kernel.h>
+ #include <linux/clk.h>
++#include <linux/err.h>
+ #include <linux/io.h>
++#include <linux/init.h>
+ #include <mach/hardware.h>
+ #include <asm/proc-fns.h>
+@@ -43,21 +45,33 @@ void arch_idle(void)
+ #define WDOG_WCR_REG                    IO_ADDRESS(WDOG_BASE_ADDR)
+ #define WDOG_WCR_SRS                    (1 << 4)
++static struct clk *wdog_clk;
++
+ /*
+  * Reset the system. It is called by machine_restart().
+  */
+ void arch_reset(char mode)
+ {
+-      struct clk *clk;
+-
+-      clk = clk_get(NULL, "wdog_clk");
+-      if (!clk) {
+-              printk(KERN_ERR"Cannot activate the watchdog. Giving up\n");
+-              return;
++      if (mode == 's') {
++              cpu_reset(0);
++      }
++      if (likely(wdog_clk != NULL)) {
++              clk_enable(wdog_clk);
+       }
+-
+-      clk_enable(clk);
+       /* Assert SRS signal */
+       __raw_writew(__raw_readw(WDOG_WCR_REG) & ~WDOG_WCR_SRS, WDOG_WCR_REG);
+ }
++
++int __init mxc_wdog_init(void)
++{
++      wdog_clk = clk_get(NULL, "wdog_clk");
++      if (IS_ERR(wdog_clk)) {
++              int ret = PTR_ERR(wdog_clk);
++              printk(KERN_CRIT "Cannot get wdog clock; watchdog reset may not work\n");
++              wdog_clk = NULL;
++              return ret;
++      }
++      return 0;
++}
++postcore_initcall(mxc_wdog_init);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/mach-mx2/tx27_gpio.c linux-2.6.28-karo/arch/arm/mach-mx2/tx27_gpio.c
+--- linux-2.6.28/arch/arm/mach-mx2/tx27_gpio.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/mach-mx2/tx27_gpio.c    2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,1019 @@
++/*
++ * arch/arm/mach-mx27/tx27_gpio.c
++ *
++ * Copyright (C) 2008  Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * 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 Street, Fifth Floor, Boston, MA 02110-1301
++ */
++
++#include <linux/module.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/err.h>
++#include <linux/clk.h>
++#include <mach/hardware.h>
++#include <mach/gpio.h>
++#include <mach/iomux.h>
++#include <mach/board-tx27.h>
++
++#include "crm_regs.h"
++
++#ifdef DEBUG
++extern int tx27_debug;
++#define dbg_lvl(n)    ((n) < tx27_debug)
++#define DBG(lvl, fmt...)      do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0)
++#else
++#define dbg_lvl(n)    0
++
++#define DBG(lvl, fmt...)      do { } while (0)
++#endif
++
++#ifdef DEBUG
++#define try_request_mux(gmd)  _try_request_mux(gmd, ARRAY_SIZE((gmd)), __FUNCTION__)
++static int _try_request_mux(const unsigned int *gmd, int num_gpios, const char *func)
++#else
++#define try_request_mux(gmd)  _try_request_mux(gmd, ARRAY_SIZE((gmd)))
++static int _try_request_mux(const unsigned int *gmd, int num_gpios)
++#endif
++{
++      int i;
++      for (i = 0; i < num_gpios; i++) {
++              unsigned gpio = gmd[i] & (GPIO_PIN_MASK | GPIO_PORT_MASK);
++              int ret;
++
++              DBG(0, "Requesting GPIO: P%c%d (%s) for %s\n",
++                  GPIO_PORT(gmd[i]) + 'A', GPIO_INDEX(gmd[i]),
++                  MX27_PIN_NAME(gmd[i]), func);
++              ret = gpio_request(gpio, "");
++              if (ret != 0) {
++                      while (--i >= 0) {
++                              gpio_free(gmd[i] & (GPIO_PIN_MASK | GPIO_PORT_MASK));
++                      }
++                      return ret;
++              }
++              DBG(0, "%s: Configuring %s: %08x\n", __FUNCTION__,
++                  MX27_PIN_NAME(gmd[i]), gmd[i]);
++              mxc_gpio_mode(gmd[i]);
++      }
++      return 0;
++}
++
++#ifdef DEBUG
++#define release_mux(gmd)      _release_mux(gmd, ARRAY_SIZE((gmd)), __FUNCTION__)
++static void _release_mux(const unsigned int *gmd, int num_gpios,
++                       const char *func)
++#else
++#define release_mux(gmd)      _release_mux(gmd, ARRAY_SIZE((gmd)))
++static void _release_mux(const unsigned int *gmd, int num_gpios)
++#endif
++{
++      int i;
++
++      for (i = 0; i < num_gpios; i++) {
++              unsigned gpio = gmd[i] & (GPIO_PIN_MASK | GPIO_PORT_MASK);
++#ifdef DEBUG
++              DBG(0, "%s: Releasing GPIO port P%c%d (%s)\n", func,
++                  GPIO_PORT(gpio) + 'A', GPIO_INDEX(gpio),
++                  MX27_PIN_NAME(gmd[i]));
++#endif
++              gpio_free(gpio);
++      }
++}
++
++#define tx27_config_mux(__gmd, __puen)        _tx27_config_mux(__gmd, ARRAY_SIZE((__gmd)), __puen)
++static void _tx27_config_mux(const unsigned int *gmd, int num_gpios, int puen)
++{
++      int i;
++
++      for (i = 0; i < num_gpios; i++) {
++              switch (puen) {
++              case 1:
++                      DBG(0, "Enabling Pullup on %s\n",
++                          MX27_PIN_NAME(gmd[i]));
++                      mxc_gpio_mode(gmd[i] | GPIO_PUEN);
++                      break;
++              case -1:
++              case 0:
++                      DBG(0, "Disabling Pullup on %s\n",
++                          MX27_PIN_NAME(gmd[i]));
++                      mxc_gpio_mode(gmd[i] & ~GPIO_PUEN);
++                      break;
++              }
++      }       
++}
++
++#ifdef DEBUG
++#define dump_pins(__gmd)      _dump_pins(__gmd, ARRAY_SIZE((__gmd)), __FUNCTION__)
++static void _dump_pins(const unsigned int *gmd, int num_gpios, const char *func)
++{
++      int i;
++
++      for (i = 0; i < num_gpios; i++) {
++              int gpio = IOMUX_TO_GPIO(gmd[i]);
++
++              DBG(0, "%s: %s (P%c%d) is: %d\n", func,
++                  MX27_PIN_NAME(gmd[i]),
++                  GPIO_PORT(gpio) + 'A', GPIO_INDEX(gpio),
++                  gpio_get_value(gpio));
++      }
++}
++#else
++#define dump_pins(arg) do { } while (0)
++#endif
++
++/*
++ Setup GPIO for USB
++
++ PB22: 26MHz oscillator enable
++
++   PIN Configuration for USBOTG:   High/Full speed OTG
++      PE2,PE1,PE0,PE24,PE25 -- PRIMARY
++      PC7 - PC13  -- PRIMARY
++      PB23,PB24 -- PRIMARY
++
++   PIN Configuration for USBH2:    : High/Full/Low speed host
++      PA0 - PA4 -- PRIMARY
++      PD19, PD20,PD21,PD22,PD23,PD24,PD26 --Alternate (SECONDARY)
++
++   USBH1:  Full/low speed host
++   not supported on TX27
++ */
++
++static unsigned int mx27_usbh2_gpios_active[] = {
++      PD19_AF_USBH2_DATA4,
++      PD20_AF_USBH2_DATA3,
++      PD21_AF_USBH2_DATA6,
++      PD22_AF_USBH2_DATA0,
++      PD23_AF_USBH2_DATA2,
++      PD24_AF_USBH2_DATA1,
++      PD26_AF_USBH2_DATA5,
++
++      PA0_PF_USBH2_CLK,
++      PA1_PF_USBH2_DIR,
++      PA2_PF_USBH2_DATA7,
++      PA3_PF_USBH2_NXT,
++      PA4_PF_USBH2_STP,
++
++      MXC_PIN(B, 31, AOUT,  GPIO_IN), /* OC detect */
++};
++
++static unsigned int mx27_usbh2_gpios_inactive[] = {
++      MXC_PIN(D, 19, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(D, 20, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(D, 21, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(D, 22, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(D, 23, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(D, 24, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(D, 26, AOUT, GPIO_IN | GPIO_PUEN),
++                                                        
++      MXC_PIN(A, 0, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(A, 1, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(A, 2, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(A, 3, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(A, 4, AOUT, GPIO_IN | GPIO_PUEN),
++                                                        
++      MXC_PIN(B, 31, AOUT, GPIO_IN),  /* OC detect */
++};
++
++/*
++ * conflicts with CSPI1 and CSPI2
++ */
++static struct clk *usbh2_clk;
++
++int gpio_usbh2_active(void)
++{
++      int ret;
++
++      DBG(0, "%s: \n", __FUNCTION__);
++      usbh2_clk = clk_get(NULL, "clk_26m");
++      if (IS_ERR(usbh2_clk)) {
++              ret = PTR_ERR(usbh2_clk);
++              printk(KERN_ERR "Cannot request 26MHz clock: %d\n", ret);
++              clk_put(usbh2_clk);
++              usbh2_clk = NULL;
++              return ret;
++      } else {
++              clk_enable(usbh2_clk);
++      }
++
++      ret = try_request_mux(mx27_usbh2_gpios_active);
++      return ret;
++}
++
++void gpio_usbh2_inactive(void)
++{
++      int i;
++
++      DBG(0, "%s: \n", __FUNCTION__);
++      if (usbh2_clk != NULL) {
++              clk_disable(usbh2_clk);
++              clk_put(usbh2_clk);
++              usbh2_clk = NULL;
++      }
++
++      for (i = ARRAY_SIZE(mx27_usbh2_gpios_inactive) - 1; i >= 0; i--) {
++              DBG(0, "Enabling Pullup on %s\n",
++                  MX27_PIN_NAME(mx27_usbh2_gpios_inactive[i]));
++              mxc_gpio_mode(mx27_usbh2_gpios_inactive[i]);
++      }
++      release_mux(mx27_usbh2_gpios_active);
++}
++
++static unsigned int mx27_usbotg_hs_gpios_active[] = {
++      PC7_PF_USBOTG_DATA5,
++      PC8_PF_USBOTG_DATA6,
++      PC9_PF_USBOTG_DATA0,
++      PC10_PF_USBOTG_DATA2,
++      PC11_PF_USBOTG_DATA1,
++      PC13_PF_USBOTG_DATA3,
++      PC12_PF_USBOTG_DATA4,
++
++      PE24_PF_USBOTG_CLK,
++      PE2_PF_USBOTG_DIR,
++      PE25_PF_USBOTG_DATA7,
++      PE0_PF_USBOTG_NXT,
++      PE1_PF_USBOTG_STP,
++
++      MXC_PIN(B, 29, AOUT, GPIO_IN),  /* OC detect */
++};
++
++static unsigned int mx27_usbotg_hs_gpios_inactive[] = {
++      MXC_PIN(C, 7, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(C, 8, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(C, 9, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(C, 10, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(C, 11, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(C, 13, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(C, 12, AOUT, GPIO_IN | GPIO_PUEN),
++
++      MXC_PIN(E, 24, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(E, 2, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(E, 25, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(E, 0, AOUT, GPIO_IN | GPIO_PUEN),
++      MXC_PIN(E, 1, AOUT, GPIO_IN | GPIO_PUEN),
++
++      MXC_PIN(B, 29, AOUT, GPIO_IN),  /* OC detect */
++};
++
++static struct clk *usbotg_clk;
++
++int gpio_usbotg_hs_active(void)
++{
++      int ret;
++
++      usbotg_clk = clk_get(NULL, "clk_26m");
++      if (IS_ERR(usbotg_clk)) {
++              ret = PTR_ERR(usbotg_clk);
++              printk(KERN_ERR "Cannot request 26MHz clock: %d\n", ret);
++              clk_put(usbotg_clk);
++              usbotg_clk = NULL;
++              return ret;
++      } else {
++              clk_enable(usbotg_clk);
++      }
++
++      ret = try_request_mux(mx27_usbotg_hs_gpios_active);
++      return ret;
++}
++
++void gpio_usbotg_hs_inactive(void)
++{
++      int i;
++
++      if (usbotg_clk != NULL) {
++              clk_disable(usbotg_clk);
++              clk_put(usbotg_clk);
++              usbotg_clk = NULL;
++      }
++
++      for (i = 0; i < ARRAY_SIZE(mx27_usbotg_hs_gpios_inactive); i++) {
++              DBG(0, "Enabling Pullup on %s\n",
++                  MX27_PIN_NAME(mx27_usbotg_hs_gpios_inactive[i]));
++              mxc_gpio_mode(mx27_usbotg_hs_gpios_inactive[i]);
++      }
++      release_mux(mx27_usbotg_hs_gpios_active);
++}
++
++int gpio_usbotg_fs_active(void)
++{
++      return gpio_usbotg_hs_active();
++}
++
++void gpio_usbotg_fs_inactive(void)
++{
++      gpio_usbotg_hs_inactive();
++}
++
++/************************************************************************/
++/* for i2c gpio                                                         */
++/* I2C1:  PD17,PD18 -- Primary                                                */
++/* I2C2:  PC5,PC6    -- Primary                                               */
++/************************************************************************/
++/*
++ * Setup GPIO for an I2C device to be active
++ */
++static unsigned int mx27_i2c_gpios[][2] = {
++      {
++              PD18_PF_I2C_CLK,
++              PD17_PF_I2C_DATA,
++      },{
++              PC6_PF_I2C2_SCL,
++              PC5_PF_I2C2_SDA,
++      }
++};
++
++int gpio_i2c_active(int i2c_num)
++{
++      if (i2c_num < 0 || i2c_num >= ARRAY_SIZE(mx27_i2c_gpios)) {
++              printk(KERN_ERR "%s: no compatible I2C adapter\n", __FUNCTION__);
++              return -EINVAL;
++      }
++      return try_request_mux(mx27_i2c_gpios[i2c_num]);
++}
++
++/*
++ * Setup GPIO for an I2C device to be inactive
++ */
++int gpio_i2c_inactive(int i2c_num)
++{
++      if (i2c_num < 0 || i2c_num >= ARRAY_SIZE(mx27_i2c_gpios)) {
++              return -EINVAL;
++      }
++      release_mux(mx27_i2c_gpios[i2c_num]);
++      return 0;
++}
++
++/*
++ * Setup GPIO for a CSPI device to be active
++ */
++static unsigned int mx27_cspi1_gpios[] = {
++      PD31_PF_CSPI1_MOSI,
++      PD30_PF_CSPI1_MISO,
++      PD29_PF_CSPI1_SCLK,
++      PD25_PF_CSPI1_RDY,
++      PD28_PF_CSPI1_SS0,
++      PD27_PF_CSPI1_SS1,
++      //PD26_PF_CSPI1_SS2, /* already in use by the USB controller */
++};
++
++static unsigned int mx27_cspi2_gpios[] = {
++      PD24_PF_CSPI2_MOSI,
++      PD23_PF_CSPI2_MISO,
++      PD22_PF_CSPI2_SCLK,
++      PD21_PF_CSPI2_SS0,
++      PD20_PF_CSPI2_SS1,
++      PD19_PF_CSPI2_SS2,
++};
++
++static unsigned int mx27_cspi3_gpios[] = {
++      PE18_AF_CSPI3_MISO,
++      PE22_AF_CSPI3_MOSI,
++      PE23_AF_CSPI3_SCLK,
++      PE21_AF_CSPI3_SS,
++};
++
++int gpio_spi_active(int cspi_mod)
++{
++
++      switch (cspi_mod) {
++      case 0:
++              /* SPI1 */
++              return try_request_mux(mx27_cspi1_gpios);
++      case 1:
++              /*SPI2  */
++              return try_request_mux(mx27_cspi2_gpios);
++      case 2:
++              /*SPI3  */
++              return try_request_mux(mx27_cspi3_gpios);
++      default:
++              return -EINVAL;
++      }
++}
++
++/*
++ * Setup GPIO for a CSPI device to be inactive
++ */
++int gpio_spi_inactive(int cspi_mod)
++{
++      switch (cspi_mod) {
++      case 0:
++              /* SPI1 */
++              release_mux(mx27_cspi1_gpios);
++              break;
++      case 1:
++              /*SPI2  */
++              release_mux(mx27_cspi2_gpios);
++              break;
++      case 2:
++              /*SPI3  */
++              release_mux(mx27_cspi3_gpios);
++              break;
++
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/*
++ * Setup GPIO for a nand flash device to be active
++ *
++ */
++static unsigned int mx27_nand_gpios[] = {
++      PF0_PF_NFRB,
++      PF3_PF_NFCE_B,
++      PF2_PF_NFWP_B,
++      PF1_PF_NFCLE,
++      PF4_PF_NFALE,
++      PF5_PF_NFRE_B,
++      PF6_PF_NFWE_B,
++};
++
++int gpio_nand_active(void)
++{
++      return try_request_mux(mx27_nand_gpios);
++}
++
++/*
++ * Setup GPIO for a nand flash device to be inactive
++ *
++ */
++void gpio_nand_inactive(void)
++{
++      release_mux(mx27_nand_gpios);
++}
++
++/*
++ * Setup GPIO for CSI device to be active
++ *
++ */
++static unsigned int mx27_csi_gpios[] = {
++      PB10_PF_CSI_D0,
++      PB11_PF_CSI_D1,
++      PB12_PF_CSI_D2,
++      PB13_PF_CSI_D3,
++      PB14_PF_CSI_D4,
++      PB15_PF_CSI_MCLK,
++      PB16_PF_CSI_PIXCLK,
++      PB17_PF_CSI_D5,
++      PB18_PF_CSI_D6,
++      PB19_PF_CSI_D7,
++      PB20_PF_CSI_VSYNC,
++      PB21_PF_CSI_HSYNC,
++};
++
++int gpio_sensor_active(void)
++{
++      return try_request_mux(mx27_csi_gpios);
++}
++
++void gpio_sensor_inactive(void)
++{
++      release_mux(mx27_csi_gpios);
++}
++
++#if 0
++/*
++ * Setup GPIO for LCDC device to be active
++ *
++ */
++static unsigned int mx27_lcdc_gpios[] = {
++      MXC_PIN(A, 30, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA30 */
++      MXC_PIN(A, 25, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA25 */
++      MXC_PIN(A, 26, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA26 */
++      MXC_PIN(A, 24, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA24 */
++      MXC_PIN(A, 27, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* PA27 */
++      PA5_PF_LSCLK,
++      PA6_PF_LD0,
++      PA7_PF_LD1,
++      PA8_PF_LD2,
++      PA9_PF_LD3,
++      PA10_PF_LD4,
++      PA11_PF_LD5,
++      PA12_PF_LD6,
++      PA13_PF_LD7,
++      PA14_PF_LD8,
++      PA15_PF_LD9,
++      PA16_PF_LD10,
++      PA17_PF_LD11,
++      PA18_PF_LD12,
++      PA19_PF_LD13,
++      PA20_PF_LD14,
++      PA21_PF_LD15,
++      PA22_PF_LD16,
++      PA23_PF_LD17,
++      PA28_PF_HSYNC,
++      PA29_PF_VSYNC,
++      PA31_PF_OE_ACD,
++};
++
++int tx27_gpio_lcdc_active(void)
++{
++      int ret;
++      ret = try_request_mux(mx27_lcdc_gpios);
++      if (ret) {
++              return ret;
++      }
++      return 0;
++}
++
++/*
++ * Setup GPIO for LCDC device to be inactive
++ *
++ */
++int tx27_gpio_lcdc_inactive(void)
++{
++      release_mux(mx27_lcdc_gpios);
++      return 0;
++}
++#endif
++
++/*
++ * GPIO settings not required for keypad
++ *
++ */
++int gpio_keypad_active(void)
++{
++      return 0;
++}
++
++/*
++ * GPIO settings not required for keypad
++ *
++ */
++void gpio_keypad_inactive(void)
++{
++}
++
++/*
++ * Setup GPIO for ATA device to be active
++ *
++ */
++static unsigned int mx27_ata_gpios[] = {
++      PD2_PF_ATA_DATA0,
++      PD3_PF_ATA_DATA1,
++      PD4_PF_ATA_DATA2,
++      PD5_PF_ATA_DATA3,
++      PD6_PF_ATA_DATA4,
++      PD7_PF_ATA_DATA5,
++      PD8_PF_ATA_DATA6,
++      PD9_PF_ATA_DATA7,
++      PD10_PF_ATA_DATA8,
++      PD11_PF_ATA_DATA9,
++      PD12_PF_ATA_DATA10,
++      PD13_PF_ATA_DATA11,
++      PD14_PF_ATA_DATA12,
++      PD15_PF_ATA_DATA13,
++      PD16_PF_ATA_DATA14,
++      PF23_PF_ATA_DATA15,
++
++      PF20_AF_PC_CD1_B,
++      PF19_AF_PC_CD2_B,
++      PF18_AF_PC_WAIT_B,
++      PF17_AF_PC_READY,
++      PF16_AF_PC_PWRON,
++      PF14_AF_PC_VS1,
++      PF13_AF_PC_VS2,
++      PF12_AF_PC_BVD1,
++      PF11_AF_PC_BVD2,
++      PF10_AF_PC_RST,
++      PF9_AF_IOIS16,
++      PF8_AF_PC_RW_B,
++      PF7_AF_PC_POE,
++};
++
++int gpio_ata_active(void)
++{
++      return try_request_mux(mx27_ata_gpios);
++}
++
++/*
++ * Setup GPIO for ATA device to be inactive
++ *
++ */
++void gpio_ata_inactive(void)
++{
++      release_mux(mx27_ata_gpios);
++}
++
++/*
++ * Setup GPIO for FEC device to be active
++ *
++ */
++static unsigned int mx27_fec_gpios_off[] = {
++      /* configure the PHY strap pins to the correct values */
++      MXC_PIN(D, 0, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 1, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 2, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 3, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 4, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 5, GPIO, GPIO_OUT | GPIO_DFLT_HIGH),
++      MXC_PIN(D, 6, GPIO, GPIO_OUT | GPIO_DFLT_HIGH),
++      MXC_PIN(D, 7, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 8, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 9, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 10, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 11, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 12, GPIO, GPIO_OUT | GPIO_DFLT_HIGH),
++      MXC_PIN(D, 13, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 14, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++      MXC_PIN(D, 15, GPIO, GPIO_OUT | GPIO_DFLT_LOW),
++};
++
++static unsigned int mx27_fec_pwr_gpios[] = {
++      MXC_PIN(B, 27, GPIO, GPIO_OUT),         /* FEC PHY power on pin */
++      MXC_PIN(B, 30, GPIO, GPIO_OUT),         /* keep FEC reset in original state */
++};
++
++static unsigned int mx27_fec_gpios_on[] = {
++      PD0_AIN_FEC_TXD0,
++      PD1_AIN_FEC_TXD1,
++      PD2_AIN_FEC_TXD2,
++      PD3_AIN_FEC_TXD3,
++      PD4_AOUT_FEC_RX_ER,
++      PD5_AOUT_FEC_RXD1,
++      PD6_AOUT_FEC_RXD2,
++      PD7_AOUT_FEC_RXD3,
++      PD8_AF_FEC_MDIO,
++      PD9_AIN_FEC_MDC,
++      PD10_AOUT_FEC_CRS,
++      PD11_AOUT_FEC_TX_CLK,
++      PD12_AOUT_FEC_RXD0,
++      PD13_AOUT_FEC_RX_DV,
++      PD14_AOUT_FEC_RX_CLK,
++      PD15_AOUT_FEC_COL,
++#ifndef FEC_MII_IRQ
++      PD16_AIN_FEC_TX_ER,     /* TX_ER */
++#else
++      MXC_PIN(D, 16, AOUT, GPIO_IN),  /* #INT */
++#endif
++      PF23_AIN_FEC_TX_EN,
++};
++
++#define TX27_FEC_PWR_GPIO     (GPIO_PORTB | 27)
++#define TX27_FEC_RST_GPIO     (GPIO_PORTB | 30)
++
++int gpio_fec_active(void)
++{
++      int ret;
++
++      ret = try_request_mux(mx27_fec_pwr_gpios);
++      if (ret) {
++              return ret;
++      }
++      /*
++       * If the PHY is already powered on, assume it has been
++       * correctly configured (by the boot loader)
++      */
++      if (0 && gpio_get_value(TX27_FEC_PWR_GPIO) &&
++          gpio_get_value(TX27_FEC_RST_GPIO)) {
++              ret = try_request_mux(mx27_fec_gpios_on);
++              if (ret) {
++                      release_mux(mx27_fec_pwr_gpios);
++                      return ret;
++              }
++      } else {
++              DBG(0, "%s: Switching FEC PHY power on\n", __FUNCTION__);
++              gpio_set_value(TX27_FEC_PWR_GPIO, 1);
++              DBG(0, "%s: Asserting FEC PHY reset\n", __FUNCTION__);
++              gpio_set_value(TX27_FEC_RST_GPIO, 0);
++              dump_pins(mx27_fec_pwr_gpios);
++              dump_pins(mx27_fec_gpios_on);
++              /* switch PHY strap pins into required state */
++              ret = try_request_mux(mx27_fec_gpios_off);
++              if (ret) {
++                      release_mux(mx27_fec_pwr_gpios);
++                      return ret;
++              }
++              DBG(0, "%s: Delaying for 22ms\n", __FUNCTION__);
++              mdelay(22);
++              dump_pins(mx27_fec_pwr_gpios);
++              dump_pins(mx27_fec_gpios_on);
++              DBG(0, "%s: Deasserting FEC PHY reset\n", __FUNCTION__);
++              gpio_set_value(TX27_FEC_RST_GPIO, 1);
++              tx27_config_mux(mx27_fec_gpios_on, -1);
++      }
++      return 0;
++}
++
++/*
++ * Setup GPIO for FEC device to be inactive
++ *
++ */
++void gpio_fec_inactive(void)
++{
++      tx27_config_mux(mx27_fec_gpios_off, -1);
++      DBG(0, "%s: Asserting FEC PHY reset\n", __FUNCTION__);
++      gpio_set_value(TX27_FEC_RST_GPIO, 0);
++      DBG(0, "%s: Switching FEC PHY power off\n", __FUNCTION__);
++      gpio_set_value(TX27_FEC_PWR_GPIO, 0);
++      release_mux(mx27_fec_gpios_off);
++      release_mux(mx27_fec_pwr_gpios);
++}
++
++/*
++ * Setup GPIO for SLCDC device to be active
++ *
++ */
++static unsigned int mx27_slcdc0_gpios[] = {
++      PC31_AIN_SLCDC2_CLK,    /* CLK */
++      PC30_AIN_SLCDC2_CS,     /* CS  */
++      PC29_AIN_SLCDC2_RS,     /* RS  */
++      PC28_AIN_SLCDC2_D0,     /* D0  */
++};
++
++static unsigned int mx27_slcdc1_gpios[] = {
++      PB5_AIN_SLCDC1_CLK,     /* CLK */
++      PB6_AIN_SLCDC1_D0,      /* D0  */
++      PB7_AIN_SLCDC1_RS,      /* RS  */
++      PB8_AIN_SLCDC1_CS,      /* CS  */
++};
++
++static unsigned int mx27_slcdc2_gpios[] = {
++      MXC_PIN(A, 6, GPIO, GPIO_OUT),
++      MXC_PIN(A, 7, GPIO, GPIO_OUT),
++      MXC_PIN(A, 8, GPIO, GPIO_OUT),
++      MXC_PIN(A, 9, GPIO, GPIO_OUT),
++      MXC_PIN(A, 10, GPIO, GPIO_OUT),
++      MXC_PIN(A, 11, GPIO, GPIO_OUT),
++      MXC_PIN(A, 12, GPIO, GPIO_OUT),
++      MXC_PIN(A, 13, GPIO, GPIO_OUT),
++      MXC_PIN(A, 14, GPIO, GPIO_OUT),
++      MXC_PIN(A, 15, GPIO, GPIO_OUT),
++      MXC_PIN(A, 16, GPIO, GPIO_OUT),
++      MXC_PIN(A, 17, GPIO, GPIO_OUT),
++      MXC_PIN(A, 18, GPIO, GPIO_OUT),
++      MXC_PIN(A, 19, GPIO, GPIO_OUT),
++      MXC_PIN(A, 20, GPIO, GPIO_OUT),
++      MXC_PIN(A, 21, GPIO, GPIO_OUT),
++};
++
++int gpio_slcdc_active(int type)
++{
++      switch (type) {
++      case 0:
++              return try_request_mux(mx27_slcdc0_gpios);
++      case 1:
++              return try_request_mux(mx27_slcdc1_gpios);
++      case 2:
++              return try_request_mux(mx27_slcdc2_gpios);
++      }
++      return -EINVAL;
++}
++
++/*
++ * Setup GPIO for SLCDC device to be inactive
++ *
++ */
++int gpio_slcdc_inactive(int type)
++{
++      switch (type) {
++      case 0:
++              release_mux(mx27_slcdc0_gpios);
++              break;
++      case 1:
++              release_mux(mx27_slcdc1_gpios);
++              break;
++      case 2:
++              release_mux(mx27_slcdc2_gpios);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++static unsigned int mx27_ssi_gpios[][4] = {
++      {
++              PC28_PF_SSI3_FS,
++              PC29_PF_SSI3_RXD,
++              PC30_PF_SSI3_TXD,
++              PC31_PF_SSI3_CLK,
++      },
++      {
++              PC16_PF_SSI4_FS,
++              PC17_PF_SSI4_RXD,
++              PC18_PF_SSI4_TXD,
++              PC19_PF_SSI4_CLK,
++      },
++};
++
++int gpio_ssi_active(int ssi_num)
++{
++      int ret;
++      switch (ssi_num) {
++      case 0:
++      case 1:
++              ret = try_request_mux(mx27_ssi_gpios[ssi_num]);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return ret;
++}
++
++/*
++ * Setup GPIO for a SSI port to be inactive
++ */
++int gpio_ssi_inactive(int ssi_num)
++{
++      if (ssi_num < 0 || ssi_num >= ARRAY_SIZE(mx27_ssi_gpios)) {
++              return -EINVAL;
++      }
++      release_mux(mx27_ssi_gpios[ssi_num]);
++      return 0;
++}
++
++static unsigned int mx27_ac97_gpios_off[] = {
++      MXC_PIN(E, 17, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* RESET_OUT_B */
++      PC31_PF_SSI3_CLK,       /* AC97_BITCLK */
++      PC29_PF_SSI3_RXD,       /* AC97_SDATAIN */
++      MXC_PIN(C, 23, AOUT, GPIO_IN),          /* UCB1400 interrupt */
++      /* keep SDATA_OUT and SYNC deasserted to prevent UCB1400 from entering test mode */
++      MXC_PIN(C, 30, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* AC97_SDATAOUT */
++      MXC_PIN(C, 28, GPIO, GPIO_OUT | GPIO_DFLT_LOW), /* AC97_SYNC */
++};
++
++static unsigned int mx27_ac97_gpios_on[] = {
++      MXC_PIN(E, 17, GPIO, GPIO_OUT | GPIO_DFLT_HIGH),        /* RESET_OUT_B */
++      PC30_PF_SSI3_TXD,       /* AC97_SDATAOUT */
++      PC28_PF_SSI3_FS,                /* AC97_SYNC */
++};
++
++int gpio_ac97_active(void)
++{
++      int ret;
++
++      ret = try_request_mux(mx27_ac97_gpios_off);
++      if (ret == 0) {
++              udelay(1);
++              dump_pins(mx27_ac97_gpios_off);
++              /* deassert UCB1400 reset and reconfigure SDATA_OUT and SYNC */
++              tx27_config_mux(mx27_ac97_gpios_on, -1);
++      }
++      return ret;
++}
++
++void gpio_ac97_inactive(void)
++{
++      DBG(0, "%s: Releasing AC97 GPIOS\n", __FUNCTION__);
++      release_mux(mx27_ac97_gpios_off);
++      DBG(0, "%s: Done\n", __FUNCTION__);
++}
++
++/*
++ * Setup GPIO for SDHC to be active
++ */
++static unsigned int mx27_sdhc_gpios[][6] = {
++      {
++              PE23_PF_SD1_CLK,
++              PE22_PF_SD1_CMD,
++              PE18_PF_SD1_D0,
++              PE19_PF_SD1_D1,
++              PE20_PF_SD1_D2,
++              PE21_PF_SD1_D3,
++      },
++      {
++              PB9_PF_SD2_CLK,
++              PB8_PF_SD2_CMD,
++              PB4_PF_SD2_D0,
++              PB5_PF_SD2_D1,
++              PB6_PF_SD2_D2,
++              PB7_PF_SD2_D3,
++      },
++      {
++              PD1_PF_SD3_CLK,
++              PD0_PF_SD3_CMD,
++              PD2_AF_SD3_D0,
++              PD3_AF_SD3_D1,
++              PD4_AF_SD3_D2,
++              PD5_AF_SD3_D3,
++      },
++};
++
++int gpio_sdhc_active(int module)
++{
++      int ret;
++      u16 data;
++      switch (module) {
++      case 0:
++              ret = try_request_mux(mx27_sdhc_gpios[module]);
++              if (ret == 0) {
++                      /* 22k pull up for sd1 dat3 pins */
++                      data = __raw_readw(IO_ADDRESS(SYSCTRL_BASE_ADDR + 0x54));
++                      data |= 0x0c;
++                      __raw_writew(data, IO_ADDRESS(SYSCTRL_BASE_ADDR + 0x54));
++              }
++              break;
++      case 1:
++              ret = try_request_mux(mx27_sdhc_gpios[module]);
++              if (ret == 0) {
++                      /* 22k pull up for sd2 pins */
++                      data = __raw_readw(IO_ADDRESS(SYSCTRL_BASE_ADDR + 0x54));
++                      data |= 0xfff0;
++                      __raw_writew(data, IO_ADDRESS(SYSCTRL_BASE_ADDR + 0x54));
++              }
++              break;
++      case 2:
++              ret = try_request_mux(mx27_sdhc_gpios[module]);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return ret;
++}
++
++/*
++ * Setup GPIO for SDHC to be inactive
++ */
++int gpio_sdhc_inactive(int module)
++{
++      switch (module) {
++      case 0:
++      case 1:
++      case 2:
++              release_mux(mx27_sdhc_gpios[module]);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++int gpio_owire_active(void)
++{
++      int ret;
++
++      ret = gpio_request(IOMUX_TO_GPIO(PE16_AF_OWIRE), "1Wire");
++      if (ret == 0) {
++              mxc_gpio_mode(PE16_AF_OWIRE);
++      }
++      return ret;
++}
++
++void gpio_owire_inactive(void)
++{
++      gpio_free(IOMUX_TO_GPIO(PE16_AF_OWIRE));
++}
++
++#define TX27_EXT_WAKEUP_GPIO  (GPIO_PORTB | 24)
++
++#if 0
++static int tx27_gpio_init(void)
++{
++      int ret;
++
++      DBG(0, "%s: \n", __FUNCTION__);
++
++      /* USB_OC_B => EXT_WAKEUP */
++      ret = gpio_request(TX27_EXT_WAKEUP_GPIO, "EXT Wakeup");
++      if (ret) {
++              printk(KERN_WARNING "%s: Failed to request %s\n", __FUNCTION__,
++                     MX27_PIN_NAME(TX27_EXT_WAKEUP_GPIO));
++              return ret;
++      }
++      mxc_gpio_mode(MXC_PIN(B, 24, AOUT, GPIO_IN));
++      return ret;
++}
++arch_initcall(tx27_gpio_init);
++#endif
++
++EXPORT_SYMBOL(gpio_usbh2_active);
++EXPORT_SYMBOL(gpio_usbh2_inactive);
++EXPORT_SYMBOL(gpio_usbotg_hs_active);
++EXPORT_SYMBOL(gpio_usbotg_hs_inactive);
++EXPORT_SYMBOL(gpio_usbotg_fs_active);
++EXPORT_SYMBOL(gpio_usbotg_fs_inactive);
++EXPORT_SYMBOL(gpio_i2c_active);
++EXPORT_SYMBOL(gpio_i2c_inactive);
++EXPORT_SYMBOL(gpio_spi_active);
++EXPORT_SYMBOL(gpio_spi_inactive);
++EXPORT_SYMBOL(gpio_nand_active);
++EXPORT_SYMBOL(gpio_nand_inactive);
++EXPORT_SYMBOL(gpio_sensor_active);
++EXPORT_SYMBOL(gpio_sensor_inactive);
++EXPORT_SYMBOL(gpio_keypad_active);
++EXPORT_SYMBOL(gpio_keypad_inactive);
++EXPORT_SYMBOL(gpio_ata_active);
++EXPORT_SYMBOL(gpio_ata_inactive);
++EXPORT_SYMBOL(gpio_fec_active);
++EXPORT_SYMBOL(gpio_fec_inactive);
++EXPORT_SYMBOL(gpio_slcdc_active);
++EXPORT_SYMBOL(gpio_slcdc_inactive);
++EXPORT_SYMBOL(gpio_ssi_active);
++EXPORT_SYMBOL(gpio_ssi_inactive);
++EXPORT_SYMBOL(gpio_sdhc_active);
++EXPORT_SYMBOL(gpio_sdhc_inactive);
++EXPORT_SYMBOL(gpio_owire_active);
++EXPORT_SYMBOL(gpio_owire_inactive);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/Kconfig linux-2.6.28-karo/arch/arm/plat-mxc/Kconfig
+--- linux-2.6.28/arch/arm/plat-mxc/Kconfig     2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/Kconfig        2009-03-11 13:16:24.000000000 +0100
+@@ -8,6 +8,7 @@ choice
+ config ARCH_MX2
+       bool "MX2-based"
++      select MXC_EMMA
+       help
+         This enables support for systems based on the Freescale i.MX2 family
+@@ -23,6 +24,14 @@ source "arch/arm/mach-mx3/Kconfig"
+ endmenu
++config MXC_EMMA
++      bool
++      depends on ARCH_MXC
++
++config MXC_FB_IRAM
++      bool
++      depends on ARCH_MXC
++
+ config MXC_IRQ_PRIOR
+       bool "Use IRQ priority"
+       depends on ARCH_MXC
+@@ -34,4 +43,6 @@ config MXC_IRQ_PRIOR
+         requirements for timing.
+         Say N here, unless you have a specialized requirement.
++config MXC_ULPI
++      bool
+ endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/Makefile linux-2.6.28-karo/arch/arm/plat-mxc/Makefile
+--- linux-2.6.28/arch/arm/plat-mxc/Makefile    2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/Makefile       2009-03-11 13:16:24.000000000 +0100
+@@ -5,4 +5,6 @@
+ # Common support
+ obj-y := irq.o clock.o gpio.o time.o devices.o
++obj-$(CONFIG_ARCH_MX1) += iomux-mx1-mx2.o dma-mx1-mx2.o
+ obj-$(CONFIG_ARCH_MX2) += iomux-mx1-mx2.o dma-mx1-mx2.o
++obj-$(CONFIG_MXC_ULPI) += ulpi.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/dma-mx1-mx2.c linux-2.6.28-karo/arch/arm/plat-mxc/dma-mx1-mx2.c
+--- linux-2.6.28/arch/arm/plat-mxc/dma-mx1-mx2.c       2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/dma-mx1-mx2.c  2009-03-11 13:16:24.000000000 +0100
+@@ -151,7 +151,7 @@ static inline int imx_dma_sg_next(int ch
+       unsigned long now;
+       if (!imxdma->name) {
+-              printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
++              printk(KERN_CRIT "%s: called for unallocated channel %d\n",
+                      __func__, channel);
+               return 0;
+       }
+@@ -390,20 +390,21 @@ imx_dma_setup_handlers(int channel,
+ {
+       struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+       unsigned long flags;
++      int ret = 0;
+-      if (!imxdma->name) {
+-              printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
++      local_irq_save(flags);
++      if (imxdma->name) {
++              __raw_writel(1 << channel, DMA_BASE + DMA_DISR);
++              imxdma->irq_handler = irq_handler;
++              imxdma->err_handler = err_handler;
++              imxdma->data = data;
++      } else {
++              ret = -ENODEV;
++              printk(KERN_CRIT "%s: called for unallocated channel %d\n",
+                      __func__, channel);
+-              return -ENODEV;
+       }
+-
+-      local_irq_save(flags);
+-      __raw_writel(1 << channel, DMA_BASE + DMA_DISR);
+-      imxdma->irq_handler = irq_handler;
+-      imxdma->err_handler = err_handler;
+-      imxdma->data = data;
+       local_irq_restore(flags);
+-      return 0;
++      return ret;
+ }
+ EXPORT_SYMBOL(imx_dma_setup_handlers);
+@@ -419,17 +420,18 @@ imx_dma_setup_progression_handler(int ch
+ {
+       struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+       unsigned long flags;
++      int ret = 0;
+-      if (!imxdma->name) {
+-              printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
++      local_irq_save(flags);
++      if (imxdma->name) {
++              imxdma->prog_handler = prog_handler;
++      } else {
++              printk(KERN_CRIT "%s: called for unallocated channel %d\n",
+                      __func__, channel);
+-              return -ENODEV;
++              ret = -ENODEV;
+       }
+-
+-      local_irq_save(flags);
+-      imxdma->prog_handler = prog_handler;
+       local_irq_restore(flags);
+-      return 0;
++      return ret;
+ }
+ EXPORT_SYMBOL(imx_dma_setup_progression_handler);
+@@ -451,16 +453,16 @@ void imx_dma_enable(int channel)
+       pr_debug("imxdma%d: imx_dma_enable\n", channel);
++      local_irq_save(flags);
+       if (!imxdma->name) {
+-              printk(KERN_CRIT "%s: called for  not allocated channel %d\n",
++              printk(KERN_CRIT "%s: called for unallocated channel %d\n",
+                      __func__, channel);
+-              return;
++              goto out;
+       }
+-      if (imxdma->in_use)
+-              return;
+-
+-      local_irq_save(flags);
++      if (imxdma->in_use) {
++              goto out;
++      }
+       __raw_writel(1 << channel, DMA_BASE + DMA_DISR);
+       __raw_writel(__raw_readl(DMA_BASE + DMA_DIMR) & ~(1 << channel),
+@@ -482,7 +484,7 @@ void imx_dma_enable(int channel)
+       }
+ #endif
+       imxdma->in_use = 1;
+-
++ out:
+       local_irq_restore(flags);
+ }
+ EXPORT_SYMBOL(imx_dma_enable);
+@@ -512,6 +514,7 @@ void imx_dma_disable(int channel)
+ }
+ EXPORT_SYMBOL(imx_dma_disable);
++#ifdef CONFIG_ARCH_MX2
+ static void imx_dma_watchdog(unsigned long chno)
+ {
+       struct imx_dma_channel *imxdma = &imx_dma_channels[chno];
+@@ -523,6 +526,7 @@ static void imx_dma_watchdog(unsigned lo
+       if (imxdma->err_handler)
+               imxdma->err_handler(chno, imxdma->data, IMX_DMA_ERR_TIMEOUT);
+ }
++#endif
+ static irqreturn_t dma_err_handler(int irq, void *dev_id)
+ {
+@@ -675,16 +679,16 @@ int imx_dma_request(int channel, const c
+ {
+       struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
+       unsigned long flags;
+-      int ret;
++      int ret = -EINVAL;
+       /* basic sanity checks */
+       if (!name)
+-              return -EINVAL;
++              return ret;
+       if (channel >= IMX_DMA_CHANNELS) {
+               printk(KERN_CRIT "%s: called for  non-existed channel %d\n",
+                      __func__, channel);
+-              return -EINVAL;
++              return ret;
+       }
+       local_irq_save(flags);
+@@ -692,6 +696,8 @@ int imx_dma_request(int channel, const c
+               local_irq_restore(flags);
+               return -EBUSY;
+       }
++      imxdma->name = name;
++      local_irq_restore(flags);
+ #ifdef CONFIG_ARCH_MX2
+       ret = request_irq(MXC_INT_DMACH0 + channel, dma_irq_handler, 0, "DMA",
+@@ -706,13 +712,11 @@ int imx_dma_request(int channel, const c
+       imxdma->watchdog.data = channel;
+ #endif
+-      imxdma->name = name;
+       imxdma->irq_handler = NULL;
+       imxdma->err_handler = NULL;
+       imxdma->data = NULL;
+       imxdma->sg = NULL;
+-      local_irq_restore(flags);
+       return 0;
+ }
+ EXPORT_SYMBOL(imx_dma_request);
+@@ -726,14 +730,14 @@ void imx_dma_free(int channel)
+       unsigned long flags;
+       struct imx_dma_channel *imxdma = &imx_dma_channels[channel];
++      local_irq_save(flags);
+       if (!imxdma->name) {
+               printk(KERN_CRIT
+                      "%s: trying to free free channel %d\n",
+                      __func__, channel);
+-              return;
++              goto out;
+       }
+-      local_irq_save(flags);
+       /* Disable interrupts */
+       __raw_writel(__raw_readl(DMA_BASE + DMA_DIMR) | (1 << channel),
+               DMA_BASE + DMA_DIMR);
+@@ -744,7 +748,7 @@ void imx_dma_free(int channel)
+ #ifdef CONFIG_ARCH_MX2
+       free_irq(MXC_INT_DMACH0 + channel, NULL);
+ #endif
+-
++ out:
+       local_irq_restore(flags);
+ }
+ EXPORT_SYMBOL(imx_dma_free);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/gpio.c linux-2.6.28-karo/arch/arm/plat-mxc/gpio.c
+--- linux-2.6.28/arch/arm/plat-mxc/gpio.c      2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/gpio.c 2009-03-11 18:50:00.000000000 +0100
+@@ -22,18 +22,42 @@
+ #include <linux/init.h>
+ #include <linux/io.h>
+ #include <linux/irq.h>
++#include <linux/interrupt.h>
+ #include <linux/gpio.h>
++#include <linux/sysdev.h>
++#include <linux/pm.h>
+ #include <mach/hardware.h>
+ #include <asm-generic/bug.h>
+ static struct mxc_gpio_port *mxc_gpio_ports;
+ static int gpio_table_size;
++#ifdef DEBUG
++static inline void __mxc_gpio_writel(unsigned int val,
++                                   volatile unsigned int __force *addr,
++                                   const char *fn)
++{
++      printk(KERN_DEBUG "%s: Writing %08x to %p\n", fn, val, addr);
++      __raw_writel(val addr);
++}
++
++static inline unsigned int __mxc_gpio_readl(volatile unsigned int __force *addr)
++{
++      printk(KERN_DEBUG "Writing %08x to %p\n", val, addr);
++      __raw_readl(val addr);
++}
++#define mxc_gpio_writel(v,a) __mxc_gpio_writel(v, a, __func__)
++#define mxc_gpio_readl(a) __mxc_gpio_readl(a, __func__)
++#else
++#define mxc_gpio_writel __raw_writel
++#define mxc_gpio_readl __raw_readl
++#endif
++
+ /* Note: This driver assumes 32 GPIOs are handled in one register */
+ static void _clear_gpio_irqstatus(struct mxc_gpio_port *port, u32 index)
+ {
+-      __raw_writel(1 << index, port->base + GPIO_ISR);
++      mxc_gpio_writel(1 << index, port->base + GPIO_ISR);
+ }
+ static void _set_gpio_irqenable(struct mxc_gpio_port *port, u32 index,
+@@ -41,15 +65,21 @@ static void _set_gpio_irqenable(struct m
+ {
+       u32 l;
+-      l = __raw_readl(port->base + GPIO_IMR);
++      l = mxc_gpio_readl(port->base + GPIO_IMR);
+       l = (l & (~(1 << index))) | (!!enable << index);
+-      __raw_writel(l, port->base + GPIO_IMR);
++      mxc_gpio_writel(l, port->base + GPIO_IMR);
+ }
+-static void gpio_ack_irq(u32 irq)
++static void _set_gpio_edge_ctrl(struct mxc_gpio_port *port, u32 index,
++                              int edge)
+ {
+-      u32 gpio = irq_to_gpio(irq);
+-      _clear_gpio_irqstatus(&mxc_gpio_ports[gpio / 32], gpio & 0x1f);
++      void __iomem *reg = port->base;
++      u32 bit, val;
++
++      reg += (index >> 4) ? GPIO_ICR2 : GPIO_ICR1;
++      bit = (index & 0xf) << 1;
++      val = mxc_gpio_readl(reg) & ~(0x3 << bit);
++      mxc_gpio_writel(val | (edge << bit), reg);
+ }
+ static void gpio_mask_irq(u32 irq)
+@@ -64,35 +94,73 @@ static void gpio_unmask_irq(u32 irq)
+       _set_gpio_irqenable(&mxc_gpio_ports[gpio / 32], gpio & 0x1f, 1);
+ }
++static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset);
++
++static void gpio_ack_irq(u32 irq)
++{
++      u32 gpio = irq_to_gpio(irq);
++      struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32];
++      int bit = 1 << (gpio & 0x1f);
++
++      if (port->level_irq & bit) {
++              gpio_mask_irq(irq);
++      } else if (port->both_edge_irq & bit) {
++              if (mxc_gpio_get(&port->chip, gpio & 0x1f)) {
++                      _set_gpio_edge_ctrl(port, gpio, GPIO_INT_FALL_EDGE);
++              } else {
++                      _set_gpio_edge_ctrl(port, gpio, GPIO_INT_RISE_EDGE);
++              }
++      }
++      _clear_gpio_irqstatus(port, gpio & 0x1f);
++}
++
+ static int gpio_set_irq_type(u32 irq, u32 type)
+ {
+       u32 gpio = irq_to_gpio(irq);
+       struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32];
+-      u32 bit, val;
++      u32 bitmask = 1 << (gpio & 0x1f);
+       int edge;
+-      void __iomem *reg = port->base;
+       switch (type) {
+       case IRQ_TYPE_EDGE_RISING:
+               edge = GPIO_INT_RISE_EDGE;
++              port->level_irq &= ~bitmask;
++              port->both_edge_irq &= ~bitmask;
++              __set_irq_handler_unlocked(irq, handle_edge_irq);
+               break;
+       case IRQ_TYPE_EDGE_FALLING:
+               edge = GPIO_INT_FALL_EDGE;
++              port->level_irq &= ~bitmask;
++              port->both_edge_irq &= ~bitmask;
++              __set_irq_handler_unlocked(irq, handle_edge_irq);
+               break;
+       case IRQ_TYPE_LEVEL_LOW:
++              port->level_irq |= bitmask;
++              port->both_edge_irq &= ~bitmask;
+               edge = GPIO_INT_LOW_LEV;
++              __set_irq_handler_unlocked(irq, handle_level_irq);
+               break;
+       case IRQ_TYPE_LEVEL_HIGH:
++              port->level_irq |= bitmask;
++              port->both_edge_irq &= ~bitmask;
+               edge = GPIO_INT_HIGH_LEV;
++              __set_irq_handler_unlocked(irq, handle_level_irq);
++              break;
++      case IRQ_TYPE_EDGE_BOTH:
++              port->level_irq &= ~bitmask;
++              port->both_edge_irq |= bitmask;
++              if (mxc_gpio_get(&port->chip, gpio & 0x1f)) {
++                      edge = GPIO_INT_FALL_EDGE;
++              } else {
++                      edge = GPIO_INT_RISE_EDGE;
++              }
++              __set_irq_handler_unlocked(irq, handle_edge_irq);
+               break;
+-      default:        /* this includes IRQ_TYPE_EDGE_BOTH */
++      default:
+               return -EINVAL;
+       }
+-      reg += GPIO_ICR1 + ((gpio & 0x10) >> 2); /* lower or upper register */
+-      bit = gpio & 0xf;
+-      val = __raw_readl(reg) & ~(0x3 << (bit << 1));
+-      __raw_writel(val | (edge << (bit << 1)), reg);
++      _set_gpio_edge_ctrl(port, gpio, edge);
+       _clear_gpio_irqstatus(port, gpio & 0x1f);
+       return 0;
+@@ -115,15 +183,15 @@ static void mxc_gpio_irq_handler(struct 
+       }
+ }
+-#ifdef CONFIG_ARCH_MX3
+-/* MX3 has one interrupt *per* gpio port */
++#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX1)
++/* MX1 and MX3 has one interrupt *per* gpio port */
+ static void mx3_gpio_irq_handler(u32 irq, struct irq_desc *desc)
+ {
+       u32 irq_stat;
+-      struct mxc_gpio_port *port = (struct mxc_gpio_port *)get_irq_data(irq);
++      struct mxc_gpio_port *port = get_irq_data(irq);
+-      irq_stat = __raw_readl(port->base + GPIO_ISR) &
+-                      __raw_readl(port->base + GPIO_IMR);
++      irq_stat = mxc_gpio_readl(port->base + GPIO_ISR) &
++                      mxc_gpio_readl(port->base + GPIO_IMR);
+       BUG_ON(!irq_stat);
+       mxc_gpio_irq_handler(port, irq_stat);
+ }
+@@ -135,26 +203,52 @@ static void mx2_gpio_irq_handler(u32 irq
+ {
+       int i;
+       u32 irq_msk, irq_stat;
+-      struct mxc_gpio_port *port = (struct mxc_gpio_port *)get_irq_data(irq);
++      struct mxc_gpio_port *port = get_irq_data(irq);
+       /* walk through all interrupt status registers */
+       for (i = 0; i < gpio_table_size; i++) {
+-              irq_msk = __raw_readl(port[i].base + GPIO_IMR);
++              irq_msk = mxc_gpio_readl(port[i].base + GPIO_IMR);
+               if (!irq_msk)
+                       continue;
+-              irq_stat = __raw_readl(port[i].base + GPIO_ISR) & irq_msk;
++              irq_stat = mxc_gpio_readl(port[i].base + GPIO_ISR) & irq_msk;
+               if (irq_stat)
+                       mxc_gpio_irq_handler(&port[i], irq_stat);
+       }
+ }
+ #endif
++/*
++ * Set interrupt number "irq" in the GPIO as a wakeup source.
++ * While system is running all registered GPIO interrupts need to have 
++ * wakeup enabled. When system is suspended, only selected GPIO interrupts 
++ * need to have wakeup enabled.
++ * @param  irq          interrupt source number
++ * @param  enable       enable as wakeup if equal to non-zero
++ * @return       This function returns 0 on success.
++ */
++static int gpio_set_wake_irq(u32 irq, u32 enable)
++{
++      u32 gpio = irq_to_gpio(irq);
++      u32 gpio_idx = gpio & 0x1f;
++      struct mxc_gpio_port *port = &mxc_gpio_ports[gpio / 32];
++
++      if ((gpio / 32) >= gpio_table_size)
++              return -EINVAL;
++
++      if (enable)
++              port->suspend_wakeup |= (1 << gpio_idx);
++      else
++              port->suspend_wakeup &= ~(1 << gpio_idx);
++      return 0;
++}
++
+ static struct irq_chip gpio_irq_chip = {
+       .ack = gpio_ack_irq,
+       .mask = gpio_mask_irq,
+       .unmask = gpio_unmask_irq,
+       .set_type = gpio_set_irq_type,
++      .set_wake = gpio_set_wake_irq,
+ };
+ static void _set_gpio_direction(struct gpio_chip *chip, unsigned offset,
+@@ -164,12 +258,12 @@ static void _set_gpio_direction(struct g
+               container_of(chip, struct mxc_gpio_port, chip);
+       u32 l;
+-      l = __raw_readl(port->base + GPIO_GDIR);
++      l = mxc_gpio_readl(port->base + GPIO_GDIR);
+       if (dir)
+               l |= 1 << offset;
+       else
+               l &= ~(1 << offset);
+-      __raw_writel(l, port->base + GPIO_GDIR);
++      mxc_gpio_writel(l, port->base + GPIO_GDIR);
+ }
+ static void mxc_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+@@ -178,9 +272,12 @@ static void mxc_gpio_set(struct gpio_chi
+               container_of(chip, struct mxc_gpio_port, chip);
+       void __iomem *reg = port->base + GPIO_DR;
+       u32 l;
++      unsigned long flags;
+-      l = (__raw_readl(reg) & (~(1 << offset))) | (value << offset);
+-      __raw_writel(l, reg);
++      local_irq_save(flags);
++      l = (mxc_gpio_readl(reg) & (~(1 << offset))) | (value << offset);
++      mxc_gpio_writel(l, reg);
++      local_irq_restore(flags);
+ }
+ static int mxc_gpio_get(struct gpio_chip *chip, unsigned offset)
+@@ -188,20 +285,32 @@ static int mxc_gpio_get(struct gpio_chip
+       struct mxc_gpio_port *port =
+               container_of(chip, struct mxc_gpio_port, chip);
+-      return (__raw_readl(port->base + GPIO_PSR) >> offset) & 1;
++      return (mxc_gpio_readl(port->base + GPIO_PSR) >> offset) & 1;
+ }
+ static int mxc_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+ {
++      unsigned long flags;
++
++      local_irq_save(flags);
+       _set_gpio_direction(chip, offset, 0);
++      local_irq_restore(flags);
+       return 0;
+ }
+ static int mxc_gpio_direction_output(struct gpio_chip *chip,
+                                    unsigned offset, int value)
+ {
+-      _set_gpio_direction(chip, offset, 1);
++      unsigned long flags;
++
++      local_irq_save(flags);
++      /* 
++       * set the output data register _before_ potentially changing
++       * the pin direction to prevent glitches on the output
++       */
+       mxc_gpio_set(chip, offset, value);
++      _set_gpio_direction(chip, offset, 1);
++      local_irq_restore(flags);
+       return 0;
+ }
+@@ -217,10 +326,10 @@ int __init mxc_gpio_init(struct mxc_gpio
+       for (i = 0; i < cnt; i++) {
+               /* disable the interrupt and clear the status */
+-              __raw_writel(0, port[i].base + GPIO_IMR);
+-              __raw_writel(~0, port[i].base + GPIO_ISR);
++              mxc_gpio_writel(0, port[i].base + GPIO_IMR);
++              mxc_gpio_writel(~0, port[i].base + GPIO_ISR);
+               for (j = port[i].virtual_irq_start;
+-                      j < port[i].virtual_irq_start + 32; j++) {
++                              j < port[i].virtual_irq_start + 32; j++) {
+                       set_irq_chip(j, &gpio_irq_chip);
+                       set_irq_handler(j, handle_edge_irq);
+                       set_irq_flags(j, IRQF_VALID);
+@@ -235,9 +344,9 @@ int __init mxc_gpio_init(struct mxc_gpio
+               port[i].chip.ngpio = 32;
+               /* its a serious configuration bug when it fails */
+-              BUG_ON( gpiochip_add(&port[i].chip) < 0 );
++              BUG_ON(gpiochip_add(&port[i].chip) < 0);
+-#ifdef CONFIG_ARCH_MX3
++#if defined(CONFIG_ARCH_MX3) || defined(CONFIG_ARCH_MX1)
+               /* setup one handler for each entry */
+               set_irq_chained_handler(port[i].irq, mx3_gpio_irq_handler);
+               set_irq_data(port[i].irq, &port[i]);
+@@ -251,3 +360,126 @@ int __init mxc_gpio_init(struct mxc_gpio
+ #endif
+       return 0;
+ }
++
++#ifdef CONFIG_PM
++/*
++ * This function puts the GPIO in low-power mode/state.
++ * All the interrupts that are enabled are first saved.
++ * Only those interrupts which registers as a wake source by calling
++ * enable_irq_wake are enabled. All other interrupts are disabled.
++ *
++ * @param   dev  the system device structure used to give information 
++ *                on GPIO to suspend
++ * @param   mesg the power state the device is entering
++ *
++ * @return  The function always returns 0.
++ */
++static int mxc_gpio_suspend(struct sys_device *dev, pm_message_t mesg)
++{
++      int ret = 0;
++      int i;
++      int wakeup = 0;
++
++      for (i = 0; i < gpio_table_size; i++) {
++              struct mxc_gpio_port *port = &mxc_gpio_ports[i];
++
++              if (__raw_readl(port->base + GPIO_ISR) & port->suspend_wakeup)
++                      return -EBUSY;
++
++              port->saved_wakeup = __raw_readl(port->base + GPIO_IMR);
++              __raw_writel(port->suspend_wakeup, port->base + GPIO_IMR);
++
++              if (port->suspend_wakeup) {
++                      wakeup = 1;
++              }
++              if (ret != 0) {
++                      while (--i >= 0) {
++                              port = &mxc_gpio_ports[i];
++                              __raw_writel(port->saved_wakeup,
++                                           port->base + GPIO_IMR);
++                      }
++                      return ret;
++              }
++      }
++      if (wakeup)
++              ret = enable_irq_wake(MXC_INT_GPIO);
++
++      return ret;
++}
++
++/*
++ * This function brings the GPIO back from low-power state.
++ * All the interrupts enabled before suspension are re-enabled from 
++ * the saved information.
++ *
++ * @param   dev  the system device structure used to give information 
++ *                on GPIO to resume
++ *
++ * @return  The function always returns 0.
++ */
++static int mxc_gpio_resume(struct sys_device *dev)
++{
++      int i;
++      int wakeup = 0;
++
++      for (i = 0; i < gpio_table_size; i++) {
++              struct mxc_gpio_port *port = &mxc_gpio_ports[i];
++
++              __raw_writel(port->saved_wakeup, port->base + GPIO_IMR);
++              if (port->suspend_wakeup) {
++                      wakeup = 1;
++              }
++      }
++      if (wakeup)
++              disable_irq_wake(MXC_INT_GPIO);
++
++      return 0;
++}
++#else
++#define mxc_gpio_suspend  NULL
++#define mxc_gpio_resume   NULL
++#endif                                /* CONFIG_PM */
++
++/*
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct sysdev_class mxc_gpio_sysclass = {
++      .name = "mxc_gpio",
++      .suspend = mxc_gpio_suspend,
++      .resume = mxc_gpio_resume,
++};
++
++/*
++ * This structure represents GPIO as a system device.
++ * System devices follow a slightly different driver model. 
++ * They don't need to do dynammic driver binding, can't be probed, 
++ * and don't reside on any type of peripheral bus. 
++ * So, it is represented and treated a little differently.
++ */
++static struct sys_device mxc_gpio_device = {
++      .cls = &mxc_gpio_sysclass,
++};
++
++/*
++ * This function registers GPIO hardware as a system device and 
++ * intializes all the GPIO ports if not already done.
++ * System devices will only be suspended with interrupts disabled, and
++ * after all other devices have been suspended. On resume, they will be
++ * resumed before any other devices, and also with interrupts disabled.
++ * This may get called early from board specific init
++ *
++ * @return       This function returns 0 on success.
++ */
++int __init mxc_gpio_sys_init(void)
++{
++      int ret = 0;
++
++      ret = sysdev_class_register(&mxc_gpio_sysclass);
++      if (ret)
++              return ret;
++      ret = sysdev_register(&mxc_gpio_device);
++      if (ret != 0)
++              sysdev_class_unregister(&mxc_gpio_sysclass);
++
++      return ret;
++}
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/debug-macro.S linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/debug-macro.S
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/debug-macro.S  2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/debug-macro.S     2009-03-11 13:16:24.000000000 +0100
+@@ -28,6 +28,9 @@
+ #ifdef CONFIG_MACH_PCM038
+ #include <mach/board-pcm038.h>
+ #endif
++#ifdef CONFIG_MACH_TX27
++#include <mach/board-tx27.h>
++#endif
+               .macro  addruart,rx
+               mrc     p15, 0, \rx, c1, c0
+               tst     \rx, #1                 @ MMU enabled?
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/gpio.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/gpio.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/gpio.h 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/gpio.h    2009-03-11 13:16:24.000000000 +0100
+@@ -35,6 +35,12 @@ struct mxc_gpio_port {
+       int irq;
+       int virtual_irq_start;
+       struct gpio_chip chip;
++      u32 level_irq;
++      u32 both_edge_irq;
++#ifdef CONFIG_PM
++      u32 suspend_wakeup;
++      u32 saved_wakeup;
++#endif
+ };
+ int mxc_gpio_init(struct mxc_gpio_port*, int);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/imx_cam.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imx_cam.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/imx_cam.h      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imx_cam.h 2009-01-05 17:47:15.000000000 +0100
+@@ -0,0 +1,47 @@
++/*
++    imx-cam.h - i.MX27 camera driver header file
++
++    Copyright (C) 2003, Intel Corporation
++    Copyright (C) 2008, Sascha Hauer <s.hauer@pengutronix.de>
++
++    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.
++*/
++
++#ifndef __ASM_ARCH_CAMERA_H_
++#define __ASM_ARCH_CAMERA_H_
++
++#define MX27_CAMERA_SWAP16            (1 << 0)
++#define MX27_CAMERA_EXT_VSYNC         (1 << 1)
++#define MX27_CAMERA_CCIR              (1 << 2)
++#define MX27_CAMERA_CCIR_INTERLACE    (1 << 3)
++#define MX27_CAMERA_HSYNC_HIGH                (1 << 4)
++#define MX27_CAMERA_GATED_CLOCK               (1 << 5)
++#define MX27_CAMERA_INV_DATA          (1 << 6)
++#define MX27_CAMERA_PCLK_SAMPLE_RISING        (1 << 7)
++#define MX27_CAMERA_PACK_DIR_MSB      (1 << 8)
++
++struct mx27_camera_platform_data {
++      int (*init)(struct platform_device *);
++      int (*exit)(struct platform_device *);
++
++      unsigned long flags;
++
++      unsigned long clk;
++};
++
++extern int mx27_init_camera(struct mx27_camera_platform_data *);
++
++#endif /* __ASM_ARCH_CAMERA_H_ */
++
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/imx_i2c.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imx_i2c.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/imx_i2c.h      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imx_i2c.h 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,81 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef __ASM_ARCH_MXC_I2C_H__
++#define __ASM_ARCH_MXC_I2C_H__
++
++struct imx_i2c_platform_data {
++      u32 max_clk;
++      int (*init)(struct platform_device *pdev);
++      int (*exit)(struct platform_device *pdev);
++};
++
++/*
++ * This file contains the I2C chip level configuration details.
++ *
++ * It also contains the API function that other drivers can use to read/write
++ * to the I2C device registers.
++ */
++
++/*
++ * This defines the string used to identify MXC I2C Bus drivers
++ */
++#define MXC_ADAPTER_NAME        "MXC I2C Adapter"
++
++#define MXC_I2C_FLAG_READ     0x01    /* if set, is read; else is write */
++#define MXC_I2C_FLAG_POLLING  0x02    /* if set, is polling mode; else is interrupt mode */
++
++int mxc_i2c_read(int bus_id, unsigned int addr, char *reg, int reg_len,
++               char *buf, int num);
++
++int mxc_i2c_write(int bus_id, unsigned int addr, char *reg, int reg_len,
++                char *buf, int num);
++
++int mxc_i2c_polling_read(int bus_id, unsigned int addr, char *reg, int reg_len,
++                       char *buf, int num);
++
++int mxc_i2c_polling_write(int bus_id, unsigned int addr, char *reg, int reg_len,
++                        char *buf, int num);
++
++/* FIXME: This should be in a generic register file */
++
++/* Address offsets of the I2C registers */
++#define MXC_IADR                0x00  /* Address Register */
++#define MXC_IFDR                0x04  /* Freq div register */
++#define MXC_I2CR                0x08  /* Control regsiter */
++#define MXC_I2SR                0x0C  /* Status register */
++#define MXC_I2DR                0x10  /* Data I/O register */
++
++/* Bit definitions of I2CR */
++#define MXC_I2CR_IEN            0x0080
++#define MXC_I2CR_IIEN           0x0040
++#define MXC_I2CR_MSTA           0x0020
++#define MXC_I2CR_MTX            0x0010
++#define MXC_I2CR_TXAK           0x0008
++#define MXC_I2CR_RSTA           0x0004
++
++/* Bit definitions of I2SR */
++#define MXC_I2SR_ICF            0x0080
++#define MXC_I2SR_IAAS           0x0040
++#define MXC_I2SR_IBB            0x0020
++#define MXC_I2SR_IAL            0x0010
++#define MXC_I2SR_SRW            0x0004
++#define MXC_I2SR_IIF            0x0002
++#define MXC_I2SR_RXAK           0x0001
++
++#endif /* __ASM_ARCH_MXC_I2C_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/imx_spi.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imx_spi.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/imx_spi.h      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imx_spi.h 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,220 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
++ * Copyright 2008 Luotao Fu, kernel@pengutronix.de
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef __MXC_SPI_MX27_H__
++#define __MXC_SPI_MX27_H__
++
++#include <mach/hardware.h>
++#include <asm/mach-types.h>
++
++/*
++ * This structure is used to define the SPI master controller's platform
++ * data. It includes the SPI  bus number and the maximum number of
++ * slaves/chips it supports.
++ */
++struct mxc_spi_master {
++      unsigned int bus_num;           /* bus number. */
++      unsigned int maxchipselect;     /* number of chip selects. */
++      unsigned int spi_version;       /* CSPI Hardware Version. */
++
++      int (*init)(struct platform_device *pdev);
++      int (*exit)(struct platform_device *pdev);
++};
++
++/* Register definitions.
++ * XXX: The ifdef CONFIG_ARCH_MX2 segments are merged from the
++ * freescale mxc_spi_mx27.h. This is actually highly strange, since according
++ * to the processor reference manuals the spi controllers on mx27 and mx31 are
++ * identical. We might want to clearify this after chatting with freescale on
++ * this issue */
++
++#define MXC_CSPIRXDATA                0x00
++#define MXC_CSPITXDATA                0x04
++#define MXC_CSPICTRL          0x08
++#define MXC_CSPIINT           0x0C
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPIDMA           0x18
++#define MXC_CSPISTAT          0x0C
++#define MXC_CSPIPERIOD                0x14
++#define MXC_CSPITEST          0x10
++#define MXC_CSPIRESET         0x1C
++#define MXC_CSPICTRL_ENABLE   (1 << 10)
++#else
++#define MXC_CSPIDMA           0x10
++#define MXC_CSPISTAT          0x14
++#define MXC_CSPIPERIOD                0x18
++#define MXC_CSPITEST          0x1C
++#define MXC_CSPIRESET         0x00
++#define MXC_CSPICTRL_ENABLE   0x1
++#endif
++
++#define MXC_CSPICTRL_DISABLE  0x0
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPICTRL_MASTER   (1 << 11)
++#else
++#define MXC_CSPICTRL_MASTER   (1 << 1)
++#endif
++
++#define MXC_CSPICTRL_SLAVE    0x0
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPICTRL_XCH      (1 << 9)
++#define MXC_CSPICTRL_LOWPOL   (1 << 5)
++#else
++#define MXC_CSPICTRL_XCH      (1 << 2)
++#define MXC_CSPICTRL_SMC      (1 << 3)
++#define MXC_CSPICTRL_LOWPOL   (1 << 4)
++#endif
++
++#define MXC_CSPICTRL_HIGHPOL  0x0
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPICTRL_PHA      (1 << 6)
++#else
++#define MXC_CSPICTRL_PHA      (1 << 5)
++#endif
++
++#define MXC_CSPICTRL_NOPHA    0x0
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPICTRL_SSCTL    (1 << 7)
++#define MXC_CSPICTRL_HIGHSSPOL        (1 << 8)
++#else
++#define MXC_CSPICTRL_SSCTL    (1 << 6)
++#define MXC_CSPICTRL_HIGHSSPOL        (1 << 7)
++#endif
++
++#define MXC_CSPICTRL_LOWSSPOL 0x0
++#define MXC_CSPICTRL_CSMASK   0x3
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPICTRL_MAXDATRATE       0x10
++#define MXC_CSPICTRL_DATAMASK 0x1F
++#define MXC_CSPICTRL_DATASHIFT        14
++/* This adjustment in the shift is valid only for even states only(i.e. divide
++   ratio of 2). SDHC_SPIEN is not set by default. If SDHC_SPIEN bit is set in
++   MXC_CSPICTRL, then divide ratio is 3, this shift adjustment is invalid. */
++#define MXC_CSPICTRL_ADJUST_SHIFT(x) ((x) = ((x) - 1) * 2)
++#else
++#define MXC_CSPICTRL_MAXDATRATE       0x7
++#define MXC_CSPICTRL_DATAMASK 0x7
++#define MXC_CSPICTRL_DATASHIFT        16
++#define MXC_CSPICTRL_ADJUST_SHIFT(x) ((x) -= 2)
++#endif
++
++#define MXC_CSPICTRL_CSSHIFT_0_7      12
++#define MXC_CSPICTRL_BCSHIFT_0_7      20
++#define MXC_CSPICTRL_BCMASK_0_7               0xFFF
++#define MXC_CSPICTRL_DRCTRLSHIFT_0_7  8
++
++#define MXC_CSPICTRL_CSSHIFT_0_5      12
++#define MXC_CSPICTRL_BCSHIFT_0_5      20
++#define MXC_CSPICTRL_BCMASK_0_5               0xFFF
++#define MXC_CSPICTRL_DRCTRLSHIFT_0_5  8
++
++#define MXC_CSPICTRL_CSSHIFT_0_4      24
++#define MXC_CSPICTRL_BCSHIFT_0_4      8
++#define MXC_CSPICTRL_BCMASK_0_4               0x1F
++#define MXC_CSPICTRL_DRCTRLSHIFT_0_4  20
++
++#define MXC_CSPICTRL_CSSHIFT_0_0      19
++#define MXC_CSPICTRL_BCSHIFT_0_0      0
++#define MXC_CSPICTRL_BCMASK_0_0               0x1F
++#define MXC_CSPICTRL_DRCTRLSHIFT_0_0  12
++
++#define MXC_CSPIINT_IRQSHIFT_0_7      8
++#define MXC_CSPIINT_IRQSHIFT_0_5      9
++#define MXC_CSPIINT_IRQSHIFT_0_4      9
++#define MXC_CSPIINT_IRQSHIFT_0_0      18
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPIINT_TEEN      (1 << 9)
++#define MXC_CSPIINT_THEN      (1 << 10)
++#define MXC_CSPIINT_TFEN      (1 << 11)
++#define MXC_CSPIINT_RREN      (1 << 13)
++#define MXC_CSPIINT_RHEN        (1 << 14)
++#define MXC_CSPIINT_RFEN        (1 << 15)
++#define MXC_CSPIINT_ROEN        (1 << 16)
++#else
++#define MXC_CSPIINT_TEEN      (1 << 0)
++#define MXC_CSPIINT_THEN      (1 << 1)
++#define MXC_CSPIINT_TFEN      (1 << 2)
++#define MXC_CSPIINT_RREN      (1 << 3)
++#define MXC_CSPIINT_RHEN        (1 << 4)
++#define MXC_CSPIINT_RFEN        (1 << 5)
++#define MXC_CSPIINT_ROEN        (1 << 6)
++#endif
++
++#define MXC_CSPIINT_TCEN_0_7  (1 << 7)
++#define MXC_CSPIINT_TCEN_0_5  (1 << 8)
++#define MXC_CSPIINT_TCEN_0_4  (1 << 8)
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPIINT_TCEN_0_0  (1 << 12)
++#else
++#define MXC_CSPIINT_TCEN_0_0  (1 << 3)
++#endif
++
++#define MXC_CSPIINT_BOEN_0_7  0
++#define MXC_CSPIINT_BOEN_0_5  (1 << 7)
++#define MXC_CSPIINT_BOEN_0_4  (1 << 7)
++
++#ifdef CONFIG_ARCH_MX2
++#define MXC_CSPIINT_BOEN_0_0  (1 << 17)
++#else
++#define MXC_CSPIINT_BOEN_0_0  (1 << 8)
++#endif
++
++#define MXC_CSPISTAT_TE               (1 << 0)
++#define MXC_CSPISTAT_TH               (1 << 1)
++#define MXC_CSPISTAT_TF               (1 << 2)
++#define MXC_CSPISTAT_RR               (1 << 3)
++#define MXC_CSPISTAT_RH         (1 << 4)
++#define MXC_CSPISTAT_RF         (1 << 5)
++#define MXC_CSPISTAT_RO         (1 << 6)
++#define MXC_CSPISTAT_TC_0_7   (1 << 7)
++#define MXC_CSPISTAT_TC_0_5   (1 << 8)
++#define MXC_CSPISTAT_TC_0_4   (1 << 8)
++#define MXC_CSPISTAT_TC_0_0   (1 << 3)
++#define MXC_CSPISTAT_BO_0_7   0
++#define MXC_CSPISTAT_BO_0_5   (1 << 7)
++#define MXC_CSPISTAT_BO_0_4   (1 << 7)
++#define MXC_CSPISTAT_BO_0_0   (1 << 8)
++
++#define MXC_CSPIPERIOD_32KHZ  (1 << 15)
++
++#define MXC_CSPITEST_LBC      (1 << 14)
++
++/*
++ * This structure contains information that differs with
++ * SPI master controller hardware version
++ */
++struct mxc_spi_unique_def {
++      unsigned int intr_bit_shift;    /* Width of valid bits in MXC_CSPIINT. */
++      unsigned int cs_shift;  /* Chip Select shift. */
++      unsigned int bc_shift;  /* Bit count shift. */
++      unsigned int bc_mask;   /* Bit count mask. */
++      unsigned int drctrl_shift;      /* Data Control shift. */
++      unsigned int xfer_complete;     /* Transfer Complete shift. */
++      unsigned int bc_overflow;       /* Bit counnter overflow shift. */
++};
++
++#endif /*__MXC_SPI_MX27_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/imx_ssi.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imx_ssi.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/imx_ssi.h      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imx_ssi.h 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,191 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#ifndef __ASM_ARCH_MXC_SSI_H
++#define __ASM_ARCH_MXC_SSI_H
++
++#include <linux/platform_device.h>
++
++struct imx_ssi_platform_data {
++      int (*init)(struct platform_device *pdev);
++      int (*exit)(struct platform_device *pdev);
++};
++
++#define SSI_STX0      0x00
++#define SSI_STX1      0x04
++#define SSI_SRX0      0x08
++#define SSI_SRX1      0x0c
++
++#define SSI_SCR               0x10
++# define SSI_SCR_CLK_IST (1 << 9)
++#  define SSI_SCR_CLK_IST_SHIFT 9
++# define SSI_SCR_TCH_EN       (1 << 8)
++# define SSI_SCR_SYS_CLK_EN (1 << 7)
++# define SSI_SCR_I2S_MODE_NORM (0 << 5)
++# define SSI_SCR_I2S_MODE_MSTR (1 << 5)
++# define SSI_SCR_I2S_MODE_SLAVE (2 << 5)
++# define SSI_SCR_SYN  (1 << 4)
++# define SSI_SCR_NET  (1 << 3)
++# define SSI_SCR_RE   (1 << 2)
++# define SSI_SCR_TE   (1 << 1)
++# define SSI_SCR_SSIEN        (1 << 0)
++# define SSI_I2S_MODE_SHIFT 5
++
++#define SSI_SISR      0x14
++# define SSI_SISR_MASK ((1 << 19) - 1)
++# define SSI_SISR_CMDAU       (1 << 18)
++# define SSI_SISR_CMDDU       (1 << 17)
++# define SSI_SISR_RXT (1 << 16)
++# define SSI_SISR_RDR1        (1 << 15)
++# define SSI_SISR_RDR0        (1 << 14)
++# define SSI_SISR_TDE1        (1 << 13)
++# define SSI_SISR_TDE0        (1 << 12)
++# define SSI_SISR_ROE1        (1 << 11)
++# define SSI_SISR_ROE0        (1 << 10)
++# define SSI_SISR_TUE1        (1 << 9)
++# define SSI_SISR_TUE0        (1 << 8)
++# define SSI_SISR_TFS (1 << 7)
++# define SSI_SISR_RFS (1 << 6)
++# define SSI_SISR_TLS (1 << 5)
++# define SSI_SISR_RLS (1 << 4)
++# define SSI_SISR_RFF1        (1 << 3)
++# define SSI_SISR_RFF0        (1 << 2)
++# define SSI_SISR_TFE1        (1 << 1)
++# define SSI_SISR_TFE0        (1 << 0)
++
++#define SSI_SIER      0x18
++# define SSI_SIER_RDMAE       (1 << 22)
++# define SSI_SIER_RIE (1 << 21)
++# define SSI_SIER_TDMAE       (1 << 20)
++# define SSI_SIER_TIE (1 << 19)
++# define SSI_SIER_CMDAU_EN (1 << 18)
++# define SSI_SIER_CMDDU_EN (1 << 17)
++# define SSI_SIER_RXT_EN (1 << 16)
++# define SSI_SIER_RDR1_EN (1 << 15)
++# define SSI_SIER_RDR0_EN (1 << 14)
++# define SSI_SIER_TDE1_EN (1 << 13)
++# define SSI_SIER_TDE0_EN (1 << 12)
++# define SSI_SIER_ROE1_EN (1 << 11)
++# define SSI_SIER_ROE0_EN (1 << 10)
++# define SSI_SIER_TUE1_EN (1 << 9)
++# define SSI_SIER_TUE0_EN (1 << 8)
++# define SSI_SIER_TFS_EN (1 << 7)
++# define SSI_SIER_RFS_EN (1 << 6)
++# define SSI_SIER_TLS_EN (1 << 5)
++# define SSI_SIER_RLS_EN (1 << 4)
++# define SSI_SIER_RFF1_EN (1 << 3)
++# define SSI_SIER_RFF0_EN (1 << 2)
++# define SSI_SIER_TFE1_EN (1 << 1)
++# define SSI_SIER_TFE0_EN (1 << 0)
++
++#define SSI_STCR      0x1c
++# define SSI_STCR_TXBIT0 (1 << 9)
++# define SSI_STCR_TFEN1       (1 << 8)
++# define SSI_STCR_TFEN0       (1 << 7)
++#  define SSI_FIFO_ENABLE_0_SHIFT 7
++# define SSI_STCR_TFDIR       (1 << 6)
++# define SSI_STCR_TXDIR       (1 << 5)
++# define SSI_STCR_TSHFD       (1 << 4)
++# define SSI_STCR_TSCKP       (1 << 3)
++# define SSI_STCR_TFSI        (1 << 2)
++# define SSI_STCR_TFSL        (1 << 1)
++# define SSI_STCR_TEFS        (1 << 0)
++
++#define SSI_SRCR      0x20
++# define SSI_SRCR_RXBIT0 (1 << 9)
++# define SSI_SRCR_RFEN1       (1 << 8)
++# define SSI_SRCR_RFEN0       (1 << 7)
++#  define SSI_FIFO_ENABLE_0_SHIFT 7
++# define SSI_SRCR_RFDIR       (1 << 6)
++# define SSI_SRCR_RXDIR       (1 << 5)
++# define SSI_SRCR_RSHFD       (1 << 4)
++# define SSI_SRCR_RSCKP       (1 << 3)
++# define SSI_SRCR_RFSI        (1 << 2)
++# define SSI_SRCR_RFSL        (1 << 1)
++# define SSI_SRCR_REFS        (1 << 0)
++
++#define SSI_SRCCR     0x28
++# define SSI_SRCCR_DIV2       (1 << 18)
++# define SSI_SRCCR_PSR        (1 << 17)
++# define SSI_SRCCR_WL(x) ((((x) - 2) >> 1) << 13)
++# define SSI_SRCCR_DC(x) (((x) & 0x1f) << 8)
++# define SSI_SRCCR_PM(x) (((x) & 0xff) << 0)
++# define SSI_SRCCR_WL_MASK (0xf << 13)
++# define SSI_SRCCR_DC_MASK (0x1f << 8)
++# define SSI_SRCCR_PM_MASK (0xff << 0)
++
++#define SSI_STCCR  0x24
++# define SSI_STCCR_DIV2 (1 << 18)
++# define SSI_STCCR_PSR (1 << 17)
++# define SSI_STCCR_WL(x) ((((x) - 2) >> 1) << 13)
++# define SSI_STCCR_DC(x) (((x) & 0x1f) << 8)
++# define SSI_STCCR_PM(x) (((x) & 0xff) << 0)
++# define SSI_STCCR_WL_MASK (0xf << 13)
++# define SSI_STCCR_DC_MASK (0x1f << 8)
++# define SSI_STCCR_PM_MASK (0xff << 0)
++
++#define SSI_SFCSR     0x2c
++# define SSI_SFCSR_RFCNT1(x) (((x) & 0xf) << 28)
++#  define SSI_RX_FIFO_1_COUNT_SHIFT 28
++# define SSI_SFCSR_TFCNT1(x) (((x) & 0xf) << 24)
++#  define SSI_TX_FIFO_1_COUNT_SHIFT 24
++# define SSI_SFCSR_RFWM1(x) (((x) & 0xf) << 20)
++# define SSI_SFCSR_TFWM1(x) (((x) & 0xf) << 16)
++# define SSI_SFCSR_RFCNT0(x) (((x) & 0xf) << 12)
++#  define SSI_RX_FIFO_0_COUNT_SHIFT 12
++# define SSI_SFCSR_TFCNT0(x) (((x) & 0xf) <<  8)
++#  define SSI_TX_FIFO_0_COUNT_SHIFT 8
++# define SSI_SFCSR_RFWM0(x) (((x) & 0xf) <<  4)
++# define SSI_SFCSR_TFWM0(x) (((x) & 0xf) <<  0)
++# define SSI_SFCSR_RFWM0_MASK (0xf <<  4)
++# define SSI_SFCSR_TFWM0_MASK (0xf <<  0)
++
++#define SSI_STR               0x30
++# define SSI_STR_TEST (1 << 15)
++# define SSI_STR_RCK2TCK (1 << 14)
++# define SSI_STR_RFS2TFS (1 << 13)
++# define SSI_STR_RXSTATE(x) (((x) & 0xf) << 8)
++# define SSI_STR_TXD2RXD (1 <<  7)
++# define SSI_STR_TCK2RCK (1 <<  6)
++# define SSI_STR_TFS2RFS (1 <<  5)
++# define SSI_STR_TXSTATE(x) (((x) & 0xf) << 0)
++
++#define SSI_SOR               0x34
++# define SSI_SOR_CLKOFF       (1 << 6)
++# define SSI_SOR_RX_CLR       (1 << 5)
++# define SSI_SOR_TX_CLR       (1 << 4)
++# define SSI_SOR_INIT (1 << 3)
++# define SSI_SOR_WAIT(x) (((x) & 0x3) << 1)
++# define SSI_SOR_WAIT_MASK (0x3 << 1)
++# define SSI_SOR_SYNRST       (1 << 0)
++
++#define SSI_SACNT     0x38
++# define SSI_SACNT_FRDIV(x) (((x) & 0x3f) << 5)
++# define SSI_SACNT_WR (x << 4)
++# define SSI_SACNT_RD (x << 3)
++# define SSI_SACNT_TIF        (x << 2)
++# define SSI_SACNT_FV (x << 1)
++# define SSI_SACNT_AC97EN (x << 0)
++
++#define SSI_SACADD    0x3c
++#define SSI_SRMSK     0x4c
++#define SSI_SACDAT    0x40
++#define SSI_SATAG     0x44
++#define SSI_STMSK     0x48
++
++#endif /* __ASM_ARCH_MXC_SSI_H */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/imxfb.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imxfb.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/imxfb.h        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/imxfb.h   2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,88 @@
++/*
++ * This structure describes the machine which we are running on.
++ */
++
++#define PCR_TFT               (1 << 31)
++#define PCR_COLOR     (1 << 30)
++#define PCR_PBSIZ_1   (0 << 28)
++#define PCR_PBSIZ_2   (1 << 28)
++#define PCR_PBSIZ_4   (2 << 28)
++#define PCR_PBSIZ_8   (3 << 28)
++#define PCR_BPIX_1    (0 << 25)
++#define PCR_BPIX_2    (1 << 25)
++#define PCR_BPIX_4    (2 << 25)
++#define PCR_BPIX_8    (3 << 25)
++#define PCR_BPIX_12   (4 << 25)
++#define PCR_BPIX_16   (5 << 25)
++#define PCR_BPIX_18   (6 << 25)
++#define PCR_PIXPOL    (1 << 24)
++#define PCR_FLMPOL    (1 << 23)
++#define PCR_LPPOL     (1 << 22)
++#define PCR_CLKPOL    (1 << 21)
++#define PCR_OEPOL     (1 << 20)
++#define PCR_SCLKIDLE  (1 << 19)
++#define PCR_END_SEL   (1 << 18)
++#define PCR_END_BYTE_SWAP (1 << 17)
++#define PCR_REV_VS    (1 << 16)
++#define PCR_ACD_SEL   (1 << 15)
++#define PCR_ACD(x)    (((x) & 0x7f) << 8)
++#define PCR_SCLK_SEL  (1 << 7)
++#define PCR_SHARP     (1 << 6)
++#define PCR_PCD(x)    ((x) & 0x3f)
++
++#define PWMR_CLS(x)   (((x) & 0x1ff) << 16)
++#define PWMR_LDMSK    (1 << 15)
++#define PWMR_SCR1     (1 << 10)
++#define PWMR_SCR0     (1 << 9)
++#define PWMR_CC_EN    (1 << 8)
++#define PWMR_PW(x)    ((x) & 0xff)
++
++#define LSCR1_PS_RISE_DELAY(x)    (((x) & 0x7f) << 26)
++#define LSCR1_CLS_RISE_DELAY(x)   (((x) & 0x3f) << 16)
++#define LSCR1_REV_TOGGLE_DELAY(x) (((x) & 0xf) << 8)
++#define LSCR1_GRAY2(x)            (((x) & 0xf) << 4)
++#define LSCR1_GRAY1(x)            (((x) & 0xf))
++
++#define DMACR_BURST   (1 << 31)
++#define DMACR_HM(x)   (((x) & 0xf) << 16)
++#define DMACR_TM(x)   ((x) & 0xf)
++
++struct imx_fb_platform_data {
++      u_long          pixclock;
++
++      u_short         xres;
++      u_short         yres;
++
++      u_int           nonstd;
++      u_char          bpp;
++      u_char          hsync_len;
++      u_char          left_margin;
++      u_char          right_margin;
++
++      u_char          vsync_len;
++      u_char          upper_margin;
++      u_char          lower_margin;
++      u_char          sync;
++
++      u_int           cmap_greyscale:1,
++                      cmap_inverse:1,
++                      cmap_static:1,
++                      unused:29;
++
++      u_int           pcr;
++      u_int           pwmr;
++      u_int           lscr1;
++      u_int           dmacr;
++
++      u_char * fixed_screen_cpu;
++      dma_addr_t fixed_screen_dma;
++
++      int (*init)(struct platform_device*);
++      int (*exit)(struct platform_device*);
++      void (*lcd_power)(int);
++      void (*backlight_power)(int);
++};
++
++#ifdef ARCH_IMX
++void set_imx_fb_info(struct imx_fb_platform_data *);
++#endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h        2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/iomux-mx1-mx2.h   2009-03-11 13:16:24.000000000 +0100
+@@ -19,14 +19,12 @@
+ #ifndef _MXC_GPIO_MX1_MX2_H
+ #define _MXC_GPIO_MX1_MX2_H
++#if !defined(_MXC_GPIO_MX1_H) && !defined(_MXC_GPIO_MX2_H)
++#error "Please don't include mach/iomux-mx1-mx2.h directly, include <mach/iomux.h> instead"
++#endif
++ 
+ #include <linux/io.h>
+-#define MXC_GPIO_ALLOC_MODE_NORMAL    0
+-#define MXC_GPIO_ALLOC_MODE_NO_ALLOC  1
+-#define MXC_GPIO_ALLOC_MODE_TRY_ALLOC 2
+-#define MXC_GPIO_ALLOC_MODE_ALLOC_ONLY        4
+-#define MXC_GPIO_ALLOC_MODE_RELEASE   8
+-
+ /*
+  *  GPIO Module and I/O Multiplexer
+  *  x = 0..3 for reg_A, reg_B, reg_C, reg_D
+@@ -50,13 +48,6 @@
+ #define MXC_SWR(x)     (0x3c + ((x) << 8))
+ #define MXC_PUEN(x)    (0x40 + ((x) << 8))
+-#ifdef CONFIG_ARCH_MX1
+-# define GPIO_PORT_MAX  3
+-#endif
+-#ifdef CONFIG_ARCH_MX2
+-# define GPIO_PORT_MAX  5
+-#endif
+-
+ #ifndef GPIO_PORT_MAX
+ # error "GPIO config port count unknown!"
+ #endif
+@@ -66,331 +57,67 @@
+ #define GPIO_PORT_SHIFT 5
+ #define GPIO_PORT_MASK (0x7 << GPIO_PORT_SHIFT)
+-#define GPIO_PORTA (0 << GPIO_PORT_SHIFT)
+-#define GPIO_PORTB (1 << GPIO_PORT_SHIFT)
+-#define GPIO_PORTC (2 << GPIO_PORT_SHIFT)
+-#define GPIO_PORTD (3 << GPIO_PORT_SHIFT)
+-#define GPIO_PORTE (4 << GPIO_PORT_SHIFT)
+-#define GPIO_PORTF (5 << GPIO_PORT_SHIFT)
+-
+-#define GPIO_OUT   (1 << 8)
+-#define GPIO_IN    (0 << 8)
+-#define GPIO_PUEN  (1 << 9)
+-
+-#define GPIO_PF    (1 << 10)
+-#define GPIO_AF    (1 << 11)
+-
+-#define GPIO_OCR_SHIFT 12
+-#define GPIO_OCR_MASK (3 << GPIO_OCR_SHIFT)
+-#define GPIO_AIN   (0 << GPIO_OCR_SHIFT)
+-#define GPIO_BIN   (1 << GPIO_OCR_SHIFT)
+-#define GPIO_CIN   (2 << GPIO_OCR_SHIFT)
+-#define GPIO_GPIO  (3 << GPIO_OCR_SHIFT)
+-
+-#define GPIO_AOUT_SHIFT 14
+-#define GPIO_AOUT_MASK (3 << GPIO_AOUT_SHIFT)
+-#define GPIO_AOUT     (0 << GPIO_AOUT_SHIFT)
+-#define GPIO_AOUT_ISR (1 << GPIO_AOUT_SHIFT)
+-#define GPIO_AOUT_0   (2 << GPIO_AOUT_SHIFT)
+-#define GPIO_AOUT_1   (3 << GPIO_AOUT_SHIFT)
+-
+-#define GPIO_BOUT_SHIFT 16
+-#define GPIO_BOUT_MASK (3 << GPIO_BOUT_SHIFT)
+-#define GPIO_BOUT      (0 << GPIO_BOUT_SHIFT)
+-#define GPIO_BOUT_ISR  (1 << GPIO_BOUT_SHIFT)
+-#define GPIO_BOUT_0    (2 << GPIO_BOUT_SHIFT)
+-#define GPIO_BOUT_1    (3 << GPIO_BOUT_SHIFT)
++#define GPIO_INDEX(gpio_cookie)               ((gpio_cookie) & GPIO_PIN_MASK)
++#define GPIO_PORT(gpio_cookie)                (((gpio_cookie) & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT)
++#define IOMUX_TO_GPIO(gpio_cookie)    ((gpio_cookie) & (GPIO_PORT_MASK | GPIO_PIN_MASK))
++
++#define GPIO_PORTA    (0 << GPIO_PORT_SHIFT)
++#define GPIO_PORTB    (1 << GPIO_PORT_SHIFT)
++#define GPIO_PORTC    (2 << GPIO_PORT_SHIFT)
++#define GPIO_PORTD    (3 << GPIO_PORT_SHIFT)
++#define GPIO_PORTE    (4 << GPIO_PORT_SHIFT)
++#define GPIO_PORTF    (5 << GPIO_PORT_SHIFT)
++
++#define GPIO_OUT      (1 << 8)
++#define GPIO_IN               (0 << 8)
++#define GPIO_PUEN     (1 << 9)
++
++#define GPIO_PF               (1 << 10)
++#define GPIO_AF               (1 << 11)
++
++#define GPIO_OCR_SHIFT        12
++#define GPIO_OCR_MASK (3 << GPIO_OCR_SHIFT)
++#define GPIO_AIN      (0 << GPIO_OCR_SHIFT)
++#define GPIO_BIN      (1 << GPIO_OCR_SHIFT)
++#define GPIO_CIN      (2 << GPIO_OCR_SHIFT)
++#define GPIO_GPIO     (3 << GPIO_OCR_SHIFT)
++
++#define GPIO_AOUT_SHIFT       14
++#define GPIO_AOUT_MASK        (3 << GPIO_AOUT_SHIFT)
++#define GPIO_AOUT     (0 << GPIO_AOUT_SHIFT)
++#define GPIO_AOUT_ISR (1 << GPIO_AOUT_SHIFT)
++#define GPIO_AOUT_0   (2 << GPIO_AOUT_SHIFT)
++#define GPIO_AOUT_1   (3 << GPIO_AOUT_SHIFT)
++
++#define GPIO_BOUT_SHIFT       16
++#define GPIO_BOUT_MASK        (3 << GPIO_BOUT_SHIFT)
++#define GPIO_BOUT     (0 << GPIO_BOUT_SHIFT)
++#define GPIO_BOUT_ISR (1 << GPIO_BOUT_SHIFT)
++#define GPIO_BOUT_0   (2 << GPIO_BOUT_SHIFT)
++#define GPIO_BOUT_1   (3 << GPIO_BOUT_SHIFT)
++
++#define GPIO_DFLT_LOW (1 << 18)
++#define GPIO_DFLT_HIGH        (1 << 19)
+ extern void mxc_gpio_mode(int gpio_mode);
+ extern int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
+-                                      int alloc_mode, const char *label);
++                                      const char *label);
++extern void mxc_gpio_release_multiple_pins(const int *pin_list, int count);
+ /*-------------------------------------------------------------------------*/
+-/* assignements for GPIO alternate/primary functions */
+-
+-/* FIXME: This list is not completed. The correct directions are
+- * missing on some (many) pins
+- */
+-#ifdef CONFIG_ARCH_MX1
+-#define PA0_AIN_SPI2_CLK     (GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 0)
+-#define PA0_AF_ETMTRACESYNC  (GPIO_PORTA | GPIO_AF | 0)
+-#define PA1_AOUT_SPI2_RXD    (GPIO_GIUS | GPIO_PORTA | GPIO_IN | 1)
+-#define PA1_PF_TIN           (GPIO_PORTA | GPIO_PF | 1)
+-#define PA2_PF_PWM0          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 2)
+-#define PA3_PF_CSI_MCLK      (GPIO_PORTA | GPIO_PF | 3)
+-#define PA4_PF_CSI_D0        (GPIO_PORTA | GPIO_PF | 4)
+-#define PA5_PF_CSI_D1        (GPIO_PORTA | GPIO_PF | 5)
+-#define PA6_PF_CSI_D2        (GPIO_PORTA | GPIO_PF | 6)
+-#define PA7_PF_CSI_D3        (GPIO_PORTA | GPIO_PF | 7)
+-#define PA8_PF_CSI_D4        (GPIO_PORTA | GPIO_PF | 8)
+-#define PA9_PF_CSI_D5        (GPIO_PORTA | GPIO_PF | 9)
+-#define PA10_PF_CSI_D6       (GPIO_PORTA | GPIO_PF | 10)
+-#define PA11_PF_CSI_D7       (GPIO_PORTA | GPIO_PF | 11)
+-#define PA12_PF_CSI_VSYNC    (GPIO_PORTA | GPIO_PF | 12)
+-#define PA13_PF_CSI_HSYNC    (GPIO_PORTA | GPIO_PF | 13)
+-#define PA14_PF_CSI_PIXCLK   (GPIO_PORTA | GPIO_PF | 14)
+-#define PA15_PF_I2C_SDA      (GPIO_PORTA | GPIO_OUT | GPIO_PF | 15)
+-#define PA16_PF_I2C_SCL      (GPIO_PORTA | GPIO_OUT | GPIO_PF | 16)
+-#define PA17_AF_ETMTRACEPKT4 (GPIO_PORTA | GPIO_AF | 17)
+-#define PA17_AIN_SPI2_SS     (GPIO_GIUS | GPIO_PORTA | GPIO_OUT | 17)
+-#define PA18_AF_ETMTRACEPKT5 (GPIO_PORTA | GPIO_AF | 18)
+-#define PA19_AF_ETMTRACEPKT6 (GPIO_PORTA | GPIO_AF | 19)
+-#define PA20_AF_ETMTRACEPKT7 (GPIO_PORTA | GPIO_AF | 20)
+-#define PA21_PF_A0           (GPIO_PORTA | GPIO_PF | 21)
+-#define PA22_PF_CS4          (GPIO_PORTA | GPIO_PF | 22)
+-#define PA23_PF_CS5          (GPIO_PORTA | GPIO_PF | 23)
+-#define PA24_PF_A16          (GPIO_PORTA | GPIO_PF | 24)
+-#define PA24_AF_ETMTRACEPKT0 (GPIO_PORTA | GPIO_AF | 24)
+-#define PA25_PF_A17          (GPIO_PORTA | GPIO_PF | 25)
+-#define PA25_AF_ETMTRACEPKT1 (GPIO_PORTA | GPIO_AF | 25)
+-#define PA26_PF_A18          (GPIO_PORTA | GPIO_PF | 26)
+-#define PA26_AF_ETMTRACEPKT2 (GPIO_PORTA | GPIO_AF | 26)
+-#define PA27_PF_A19          (GPIO_PORTA | GPIO_PF | 27)
+-#define PA27_AF_ETMTRACEPKT3 (GPIO_PORTA | GPIO_AF | 27)
+-#define PA28_PF_A20          (GPIO_PORTA | GPIO_PF | 28)
+-#define PA28_AF_ETMPIPESTAT0 (GPIO_PORTA | GPIO_AF | 28)
+-#define PA29_PF_A21          (GPIO_PORTA | GPIO_PF | 29)
+-#define PA29_AF_ETMPIPESTAT1 (GPIO_PORTA | GPIO_AF | 29)
+-#define PA30_PF_A22          (GPIO_PORTA | GPIO_PF | 30)
+-#define PA30_AF_ETMPIPESTAT2 (GPIO_PORTA | GPIO_AF | 30)
+-#define PA31_PF_A23          (GPIO_PORTA | GPIO_PF | 31)
+-#define PA31_AF_ETMTRACECLK  (GPIO_PORTA | GPIO_AF | 31)
+-#define PB8_PF_SD_DAT0       (GPIO_PORTB | GPIO_PF | GPIO_PUEN | 8)
+-#define PB8_AF_MS_PIO        (GPIO_PORTB | GPIO_AF | 8)
+-#define PB9_PF_SD_DAT1       (GPIO_PORTB | GPIO_PF | GPIO_PUEN  | 9)
+-#define PB9_AF_MS_PI1        (GPIO_PORTB | GPIO_AF | 9)
+-#define PB10_PF_SD_DAT2      (GPIO_PORTB | GPIO_PF | GPIO_PUEN  | 10)
+-#define PB10_AF_MS_SCLKI     (GPIO_PORTB | GPIO_AF | 10)
+-#define PB11_PF_SD_DAT3      (GPIO_PORTB | GPIO_PF | 11)
+-#define PB11_AF_MS_SDIO      (GPIO_PORTB | GPIO_AF | 11)
+-#define PB12_PF_SD_CLK       (GPIO_PORTB | GPIO_PF | 12)
+-#define PB12_AF_MS_SCLK0     (GPIO_PORTB | GPIO_AF | 12)
+-#define PB13_PF_SD_CMD       (GPIO_PORTB | GPIO_PF | GPIO_PUEN | 13)
+-#define PB13_AF_MS_BS        (GPIO_PORTB | GPIO_AF | 13)
+-#define PB14_AF_SSI_RXFS     (GPIO_PORTB | GPIO_AF | 14)
+-#define PB15_AF_SSI_RXCLK    (GPIO_PORTB | GPIO_AF | 15)
+-#define PB16_AF_SSI_RXDAT    (GPIO_PORTB | GPIO_IN | GPIO_AF | 16)
+-#define PB17_AF_SSI_TXDAT    (GPIO_PORTB | GPIO_OUT | GPIO_AF | 17)
+-#define PB18_AF_SSI_TXFS     (GPIO_PORTB | GPIO_AF | 18)
+-#define PB19_AF_SSI_TXCLK    (GPIO_PORTB | GPIO_AF | 19)
+-#define PB20_PF_USBD_AFE     (GPIO_PORTB | GPIO_PF | 20)
+-#define PB21_PF_USBD_OE      (GPIO_PORTB | GPIO_PF | 21)
+-#define PB22_PFUSBD_RCV      (GPIO_PORTB | GPIO_PF | 22)
+-#define PB23_PF_USBD_SUSPND  (GPIO_PORTB | GPIO_PF | 23)
+-#define PB24_PF_USBD_VP      (GPIO_PORTB | GPIO_PF | 24)
+-#define PB25_PF_USBD_VM      (GPIO_PORTB | GPIO_PF | 25)
+-#define PB26_PF_USBD_VPO     (GPIO_PORTB | GPIO_PF | 26)
+-#define PB27_PF_USBD_VMO     (GPIO_PORTB | GPIO_PF | 27)
+-#define PB28_PF_UART2_CTS    (GPIO_PORTB | GPIO_OUT | GPIO_PF | 28)
+-#define PB29_PF_UART2_RTS    (GPIO_PORTB | GPIO_IN | GPIO_PF | 29)
+-#define PB30_PF_UART2_TXD    (GPIO_PORTB | GPIO_OUT | GPIO_PF | 30)
+-#define PB31_PF_UART2_RXD    (GPIO_PORTB | GPIO_IN | GPIO_PF | 31)
+-#define PC3_PF_SSI_RXFS      (GPIO_PORTC | GPIO_PF | 3)
+-#define PC4_PF_SSI_RXCLK     (GPIO_PORTC | GPIO_PF | 4)
+-#define PC5_PF_SSI_RXDAT     (GPIO_PORTC | GPIO_IN | GPIO_PF | 5)
+-#define PC6_PF_SSI_TXDAT     (GPIO_PORTC | GPIO_OUT | GPIO_PF | 6)
+-#define PC7_PF_SSI_TXFS      (GPIO_PORTC | GPIO_PF | 7)
+-#define PC8_PF_SSI_TXCLK     (GPIO_PORTC | GPIO_PF | 8)
+-#define PC9_PF_UART1_CTS     (GPIO_PORTC | GPIO_OUT | GPIO_PF | 9)
+-#define PC10_PF_UART1_RTS    (GPIO_PORTC | GPIO_IN | GPIO_PF | 10)
+-#define PC11_PF_UART1_TXD    (GPIO_PORTC | GPIO_OUT | GPIO_PF | 11)
+-#define PC12_PF_UART1_RXD    (GPIO_PORTC | GPIO_IN | GPIO_PF | 12)
+-#define PC13_PF_SPI1_SPI_RDY (GPIO_PORTC | GPIO_PF | 13)
+-#define PC14_PF_SPI1_SCLK    (GPIO_PORTC | GPIO_PF | 14)
+-#define PC15_PF_SPI1_SS      (GPIO_PORTC | GPIO_PF | 15)
+-#define PC16_PF_SPI1_MISO    (GPIO_PORTC | GPIO_PF | 16)
+-#define PC17_PF_SPI1_MOSI    (GPIO_PORTC | GPIO_PF | 17)
+-#define PC24_BIN_UART3_RI    (GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 24)
+-#define PC25_BIN_UART3_DSR   (GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 25)
+-#define PC26_AOUT_UART3_DTR  (GPIO_GIUS | GPIO_PORTC | GPIO_IN | 26)
+-#define PC27_BIN_UART3_DCD   (GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 27)
+-#define PC28_BIN_UART3_CTS   (GPIO_GIUS | GPIO_PORTC | GPIO_OUT | GPIO_BIN | 28)
+-#define PC29_AOUT_UART3_RTS  (GPIO_GIUS | GPIO_PORTC | GPIO_IN | 29)
+-#define PC30_BIN_UART3_TX    (GPIO_GIUS | GPIO_PORTC | GPIO_BIN | 30)
+-#define PC31_AOUT_UART3_RX   (GPIO_GIUS | GPIO_PORTC | GPIO_IN | 31)
+-#define PD6_PF_LSCLK         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 6)
+-#define PD7_PF_REV           (GPIO_PORTD | GPIO_PF | 7)
+-#define PD7_AF_UART2_DTR     (GPIO_GIUS | GPIO_PORTD | GPIO_IN | GPIO_AF | 7)
+-#define PD7_AIN_SPI2_SCLK    (GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 7)
+-#define PD8_PF_CLS           (GPIO_PORTD | GPIO_PF | 8)
+-#define PD8_AF_UART2_DCD     (GPIO_PORTD | GPIO_OUT | GPIO_AF | 8)
+-#define PD8_AIN_SPI2_SS      (GPIO_GIUS | GPIO_PORTD | GPIO_AIN | 8)
+-#define PD9_PF_PS            (GPIO_PORTD | GPIO_PF | 9)
+-#define PD9_AF_UART2_RI      (GPIO_PORTD | GPIO_OUT | GPIO_AF | 9)
+-#define PD9_AOUT_SPI2_RXD    (GPIO_GIUS | GPIO_PORTD | GPIO_IN | 9)
+-#define PD10_PF_SPL_SPR      (GPIO_PORTD | GPIO_OUT | GPIO_PF | 10)
+-#define PD10_AF_UART2_DSR    (GPIO_PORTD | GPIO_OUT | GPIO_AF | 10)
+-#define PD10_AIN_SPI2_TXD    (GPIO_GIUS | GPIO_PORTD | GPIO_OUT | 10)
+-#define PD11_PF_CONTRAST     (GPIO_PORTD | GPIO_OUT | GPIO_PF | 11)
+-#define PD12_PF_ACD_OE       (GPIO_PORTD | GPIO_OUT | GPIO_PF | 12)
+-#define PD13_PF_LP_HSYNC     (GPIO_PORTD | GPIO_OUT | GPIO_PF | 13)
+-#define PD14_PF_FLM_VSYNC    (GPIO_PORTD | GPIO_OUT | GPIO_PF | 14)
+-#define PD15_PF_LD0          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 15)
+-#define PD16_PF_LD1          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 16)
+-#define PD17_PF_LD2          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 17)
+-#define PD18_PF_LD3          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 18)
+-#define PD19_PF_LD4          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 19)
+-#define PD20_PF_LD5          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 20)
+-#define PD21_PF_LD6          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 21)
+-#define PD22_PF_LD7          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 22)
+-#define PD23_PF_LD8          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 23)
+-#define PD24_PF_LD9          (GPIO_PORTD | GPIO_OUT | GPIO_PF | 24)
+-#define PD25_PF_LD10         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 25)
+-#define PD26_PF_LD11         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 26)
+-#define PD27_PF_LD12         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 27)
+-#define PD28_PF_LD13         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 28)
+-#define PD29_PF_LD14         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 29)
+-#define PD30_PF_LD15         (GPIO_PORTD | GPIO_OUT | GPIO_PF | 30)
+-#define PD31_PF_TMR2OUT      (GPIO_PORTD | GPIO_PF | 31)
+-#define PD31_BIN_SPI2_TXD    (GPIO_GIUS | GPIO_PORTD | GPIO_BIN | 31)
+-#endif
+-
+-#ifdef CONFIG_ARCH_MX2
+-#define PA0_PF_USBH2_CLK      (GPIO_PORTA | GPIO_PF | 0)
+-#define PA1_PF_USBH2_DIR      (GPIO_PORTA | GPIO_PF | 1)
+-#define PA2_PF_USBH2_DATA7    (GPIO_PORTA | GPIO_PF | 2)
+-#define PA3_PF_USBH2_NXT      (GPIO_PORTA | GPIO_PF | 3)
+-#define PA4_PF_USBH2_STP      (GPIO_PORTA | GPIO_PF | 4)
+-#define PA5_PF_LSCLK          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 5)
+-#define PA6_PF_LD0            (GPIO_PORTA | GPIO_OUT | GPIO_PF | 6)
+-#define PA7_PF_LD1            (GPIO_PORTA | GPIO_OUT | GPIO_PF | 7)
+-#define PA8_PF_LD2            (GPIO_PORTA | GPIO_OUT | GPIO_PF | 8)
+-#define PA9_PF_LD3            (GPIO_PORTA | GPIO_OUT | GPIO_PF | 9)
+-#define PA10_PF_LD4           (GPIO_PORTA | GPIO_OUT | GPIO_PF | 10)
+-#define PA11_PF_LD5           (GPIO_PORTA | GPIO_OUT | GPIO_PF | 11)
+-#define PA12_PF_LD6           (GPIO_PORTA | GPIO_OUT | GPIO_PF | 12)
+-#define PA13_PF_LD7           (GPIO_PORTA | GPIO_OUT | GPIO_PF | 13)
+-#define PA14_PF_LD8           (GPIO_PORTA | GPIO_OUT | GPIO_PF | 14)
+-#define PA15_PF_LD9           (GPIO_PORTA | GPIO_OUT | GPIO_PF | 15)
+-#define PA16_PF_LD10          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 16)
+-#define PA17_PF_LD11          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 17)
+-#define PA18_PF_LD12          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 18)
+-#define PA19_PF_LD13          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 19)
+-#define PA20_PF_LD14          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 20)
+-#define PA21_PF_LD15          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 21)
+-#define PA22_PF_LD16          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 22)
+-#define PA23_PF_LD17          (GPIO_PORTA | GPIO_OUT | GPIO_PF | 23)
+-#define PA24_PF_REV           (GPIO_PORTA | GPIO_OUT | GPIO_PF | 24)
+-#define PA25_PF_CLS           (GPIO_PORTA | GPIO_OUT | GPIO_PF | 25)
+-#define PA26_PF_PS            (GPIO_PORTA | GPIO_OUT | GPIO_PF | 26)
+-#define PA27_PF_SPL_SPR               (GPIO_PORTA | GPIO_OUT | GPIO_PF | 27)
+-#define PA28_PF_HSYNC         (GPIO_PORTA | GPIO_OUT | GPIO_PF | 28)
+-#define PA29_PF_VSYNC         (GPIO_PORTA | GPIO_OUT | GPIO_PF | 29)
+-#define PA30_PF_CONTRAST      (GPIO_PORTA | GPIO_OUT | GPIO_PF | 30)
+-#define PA31_PF_OE_ACD                (GPIO_PORTA | GPIO_OUT | GPIO_PF | 31)
+-#define PB10_PF_CSI_D0                (GPIO_PORTB | GPIO_OUT | GPIO_PF | 10)
+-#define PB10_AF_UART6_TXD     (GPIO_PORTB | GPIO_OUT | GPIO_AF | 10)
+-#define PB11_PF_CSI_D1                (GPIO_PORTB | GPIO_OUT | GPIO_PF | 11)
+-#define PB11_AF_UART6_RXD     (GPIO_PORTB | GPIO_IN  | GPIO_AF | 11)
+-#define PB12_PF_CSI_D2                (GPIO_PORTB | GPIO_OUT | GPIO_PF | 12)
+-#define PB12_AF_UART6_CTS     (GPIO_PORTB | GPIO_OUT | GPIO_AF | 12)
+-#define PB13_PF_CSI_D3                (GPIO_PORTB | GPIO_OUT | GPIO_PF | 13)
+-#define PB13_AF_UART6_RTS     (GPIO_PORTB | GPIO_IN  | GPIO_AF | 13)
+-#define PB14_PF_CSI_D4                (GPIO_PORTB | GPIO_OUT | GPIO_PF | 14)
+-#define PB15_PF_CSI_MCLK      (GPIO_PORTB | GPIO_OUT | GPIO_PF | 15)
+-#define PB16_PF_CSI_PIXCLK    (GPIO_PORTB | GPIO_OUT | GPIO_PF | 16)
+-#define PB17_PF_CSI_D5                (GPIO_PORTB | GPIO_OUT | GPIO_PF | 17)
+-#define PB18_PF_CSI_D6                (GPIO_PORTB | GPIO_OUT | GPIO_PF | 18)
+-#define PB18_AF_UART5_TXD     (GPIO_PORTB | GPIO_OUT | GPIO_AF | 18)
+-#define PB19_PF_CSI_D7                (GPIO_PORTB | GPIO_OUT | GPIO_PF | 19)
+-#define PB19_AF_UART5_RXD     (GPIO_PORTB | GPIO_IN  | GPIO_AF | 19)
+-#define PB20_PF_CSI_VSYNC     (GPIO_PORTB | GPIO_OUT | GPIO_PF | 20)
+-#define PB20_AF_UART5_CTS     (GPIO_PORTB | GPIO_OUT | GPIO_AF | 20)
+-#define PB21_PF_CSI_HSYNC     (GPIO_PORTB | GPIO_OUT | GPIO_PF | 21)
+-#define PB21_AF_UART5_RTS     (GPIO_PORTB | GPIO_IN  | GPIO_AF | 21)
+-#define PB22_PF_USBH1_SUSP    (GPIO_PORTB | GPIO_PF | 22)
+-#define PB23_PF_USB_PWR               (GPIO_PORTB | GPIO_PF | 23)
+-#define PB24_PF_USB_OC_B      (GPIO_PORTB | GPIO_PF | 24)
+-#define PB25_PF_USBH1_RCV     (GPIO_PORTB | GPIO_PF | 25)
+-#define PB26_PF_USBH1_FS      (GPIO_PORTB | GPIO_PF | 26)
+-#define PB27_PF_USBH1_OE_B    (GPIO_PORTB | GPIO_PF | 27)
+-#define PB28_PF_USBH1_TXDM    (GPIO_PORTB | GPIO_PF | 28)
+-#define PB29_PF_USBH1_TXDP    (GPIO_PORTB | GPIO_PF | 29)
+-#define PB30_PF_USBH1_RXDM    (GPIO_PORTB | GPIO_PF | 30)
+-#define PB31_PF_USBH1_RXDP    (GPIO_PORTB | GPIO_PF | 31)
+-#define PB26_AF_UART4_RTS     (GPIO_PORTB | GPIO_IN  | GPIO_PF | 26)
+-#define PB28_AF_UART4_TXD     (GPIO_PORTB | GPIO_OUT | GPIO_AF | 28)
+-#define PB29_AF_UART4_CTS     (GPIO_PORTB | GPIO_OUT | GPIO_AF | 29)
+-#define PB31_AF_UART4_RXD     (GPIO_PORTB | GPIO_IN  | GPIO_AF | 31)
+-#define PC5_PF_I2C2_SDA               (GPIO_PORTC | GPIO_IN  | GPIO_PF | 5)
+-#define PC6_PF_I2C2_SCL               (GPIO_PORTC | GPIO_IN  | GPIO_PF | 6)
+-#define PC16_PF_SSI4_FS               (GPIO_PORTC | GPIO_IN  | GPIO_PF | 16)
+-#define PC17_PF_SSI4_RXD      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 17)
+-#define PC18_PF_SSI4_TXD      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 18)
+-#define PC19_PF_SSI4_CLK      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 19)
+-#define PC20_PF_SSI1_FS               (GPIO_PORTC | GPIO_IN  | GPIO_PF | 20)
+-#define PC21_PF_SSI1_RXD      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 21)
+-#define PC22_PF_SSI1_TXD      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 22)
+-#define PC23_PF_SSI1_CLK      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 23)
+-#define PC24_PF_SSI2_FS               (GPIO_PORTC | GPIO_IN  | GPIO_PF | 24)
+-#define PC25_PF_SSI2_RXD      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 25)
+-#define PC26_PF_SSI2_TXD      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 26)
+-#define PC27_PF_SSI2_CLK      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 27)
+-#define PC28_PF_SSI3_FS               (GPIO_PORTC | GPIO_IN  | GPIO_PF | 28)
+-#define PC29_PF_SSI3_RXD      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 29)
+-#define PC30_PF_SSI3_TXD      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 30)
+-#define PC31_PF_SSI3_CLK      (GPIO_PORTC | GPIO_IN  | GPIO_PF | 31)
+-#define PD0_AIN_FEC_TXD0      (GPIO_PORTD | GPIO_OUT | GPIO_AIN | 0)
+-#define PD1_AIN_FEC_TXD1      (GPIO_PORTD | GPIO_OUT | GPIO_AIN | 1)
+-#define PD2_AIN_FEC_TXD2      (GPIO_PORTD | GPIO_OUT | GPIO_AIN | 2)
+-#define PD3_AIN_FEC_TXD3      (GPIO_PORTD | GPIO_OUT | GPIO_AIN | 3)
+-#define PD4_AOUT_FEC_RX_ER    (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 4)
+-#define PD5_AOUT_FEC_RXD1     (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 5)
+-#define PD6_AOUT_FEC_RXD2     (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 6)
+-#define PD7_AOUT_FEC_RXD3     (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 7)
+-#define PD8_AF_FEC_MDIO               (GPIO_PORTD | GPIO_IN | GPIO_AF | 8)
+-#define PD9_AIN_FEC_MDC               (GPIO_PORTD | GPIO_OUT | GPIO_AIN | 9)
+-#define PD10_AOUT_FEC_CRS     (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 10)
+-#define PD11_AOUT_FEC_TX_CLK  (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 11)
+-#define PD12_AOUT_FEC_RXD0    (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 12)
+-#define PD13_AOUT_FEC_RX_DV   (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 13)
+-#define PD14_AOUT_FEC_CLR     (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 14)
+-#define PD15_AOUT_FEC_COL     (GPIO_PORTD | GPIO_IN | GPIO_AOUT | 15)
+-#define PD16_AIN_FEC_TX_ER    (GPIO_PORTD | GPIO_OUT | GPIO_AIN | 16)
+-#define PD17_PF_I2C_DATA      (GPIO_PORTD | GPIO_OUT | GPIO_PF | 17)
+-#define PD18_PF_I2C_CLK               (GPIO_PORTD | GPIO_OUT | GPIO_PF | 18)
+-#define PD19_AF_USBH2_DATA4   (GPIO_PORTD | GPIO_AF | 19)
+-#define PD20_AF_USBH2_DATA3   (GPIO_PORTD | GPIO_AF | 20)
+-#define PD21_AF_USBH2_DATA6   (GPIO_PORTD | GPIO_AF | 21)
+-#define PD22_AF_USBH2_DATA0   (GPIO_PORTD | GPIO_AF | 22)
+-#define PD23_AF_USBH2_DATA2   (GPIO_PORTD | GPIO_AF | 23)
+-#define PD24_AF_USBH2_DATA1   (GPIO_PORTD | GPIO_AF | 24)
+-#define PD25_PF_CSPI1_RDY     (GPIO_PORTD | GPIO_OUT | GPIO_PF  | 25)
+-#define PD26_PF_CSPI1_SS2     (GPIO_PORTD | GPIO_OUT | GPIO_PF  | 26)
+-#define PD26_AF_USBH2_DATA5     (GPIO_PORTD | GPIO_AF | 26)
+-#define PD27_PF_CSPI1_SS1     (GPIO_PORTD | GPIO_OUT | GPIO_PF  | 27)
+-#define PD28_PF_CSPI1_SS0     (GPIO_PORTD | GPIO_OUT | GPIO_PF  | 28)
+-#define PD29_PF_CSPI1_SCLK    (GPIO_PORTD | GPIO_OUT | GPIO_PF  | 29)
+-#define PD30_PF_CSPI1_MISO    (GPIO_PORTD | GPIO_IN | GPIO_PF  | 30)
+-#define PD31_PF_CSPI1_MOSI    (GPIO_PORTD | GPIO_OUT | GPIO_PF  | 31)
+-#define PF23_AIN_FEC_TX_EN    (GPIO_PORTF | GPIO_OUT | GPIO_AIN | 23)
+-#define PE3_PF_UART2_CTS      (GPIO_PORTE | GPIO_OUT | GPIO_PF | 3)
+-#define PE4_PF_UART2_RTS      (GPIO_PORTE | GPIO_IN  | GPIO_PF | 4)
+-#define PE6_PF_UART2_TXD      (GPIO_PORTE | GPIO_OUT | GPIO_PF | 6)
+-#define PE7_PF_UART2_RXD      (GPIO_PORTE | GPIO_IN  | GPIO_PF | 7)
+-#define PE8_PF_UART3_TXD      (GPIO_PORTE | GPIO_OUT | GPIO_PF | 8)
+-#define PE9_PF_UART3_RXD      (GPIO_PORTE | GPIO_IN  | GPIO_PF | 9)
+-#define PE10_PF_UART3_CTS     (GPIO_PORTE | GPIO_OUT | GPIO_PF | 10)
+-#define PE11_PF_UART3_RTS     (GPIO_PORTE | GPIO_IN  | GPIO_PF | 11)
+-#define PE12_PF_UART1_TXD     (GPIO_PORTE | GPIO_OUT | GPIO_PF | 12)
+-#define PE13_PF_UART1_RXD     (GPIO_PORTE | GPIO_IN  | GPIO_PF | 13)
+-#define PE14_PF_UART1_CTS     (GPIO_PORTE | GPIO_OUT | GPIO_PF | 14)
+-#define PE15_PF_UART1_RTS     (GPIO_PORTE | GPIO_IN  | GPIO_PF | 15)
+-#define PE16_AF_RTCK          (GPIO_PORTE | GPIO_OUT | GPIO_AF | 16)
+-#define PE16_PF_RTCK          (GPIO_PORTE | GPIO_OUT | GPIO_PF | 16)
+-#define PE18_AF_CSPI3_MISO    (GPIO_PORTE | GPIO_IN  | GPIO_AF | 18)
+-#define PE21_AF_CSPI3_SS      (GPIO_PORTE | GPIO_OUT | GPIO_AF | 21)
+-#define PE22_AF_CSPI3_MOSI    (GPIO_PORTE | GPIO_OUT | GPIO_AF | 22)
+-#define PE23_AF_CSPI3_SCLK    (GPIO_PORTE | GPIO_OUT | GPIO_AF | 23)
+-#endif
++#define MXC_PIN(port,gpio,fn,flags) \
++      (GPIO_PORT##port | GPIO_##fn | (flags) | (gpio))
++#define MXC_DEFINE_PIN(port,gpio,fn,name,flags) \
++      P##port##gpio##_##fn##_##name = MXC_PIN(port,gpio,fn,flags)
+ /* decode irq number to use with IMR(x), ISR(x) and friends */
+-#define IRQ_TO_REG(irq) ((irq - MXC_MAX_INT_LINES) >> 5)
++#define IRQ_TO_REG(irq)       ((irq - MXC_MAX_INT_LINES) >> 5)
+-#define IRQ_GPIOA(x)  (MXC_MAX_INT_LINES + x)
+-#define IRQ_GPIOB(x)  (IRQ_GPIOA(32) + x)
+-#define IRQ_GPIOC(x)  (IRQ_GPIOB(32) + x)
+-#define IRQ_GPIOD(x)  (IRQ_GPIOC(32) + x)
++#define IRQ_GPIOA(x)  (MXC_MAX_INT_LINES + x)
++#define IRQ_GPIOB(x)  (IRQ_GPIOA(32) + x)
++#define IRQ_GPIOC(x)  (IRQ_GPIOB(32) + x)
++#define IRQ_GPIOD(x)  (IRQ_GPIOC(32) + x)
++#define IRQ_GPIOE(x)  (IRQ_GPIOD(32) + x)
+ #endif /* _MXC_GPIO_MX1_MX2_H */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/ipu.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/ipu.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/ipu.h  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/ipu.h     2009-01-05 17:47:15.000000000 +0100
+@@ -0,0 +1,193 @@
++/*
++ * Copyright (C) 2008
++ * Guennadi Liakhovetski, DENX Software Engineering, <lg@denx.de>
++ *
++ * 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 _IPU_H_
++#define _IPU_H_
++
++#include <linux/types.h>
++#include <linux/dmaengine.h>
++
++/* IPU DMA Controller channel definitions. */
++enum ipu_channel {
++      IDMAC_IC_0 = 0,         /* IC (encoding task) to memory */
++      IDMAC_IC_1 = 1,         /* IC (viewfinder task) to memory */
++      IDMAC_ADC_0 = 1,
++      IDMAC_IC_2 = 2,
++      IDMAC_ADC_1 = 2,
++      IDMAC_IC_3 = 3,
++      IDMAC_IC_4 = 4,
++      IDMAC_IC_5 = 5,
++      IDMAC_IC_6 = 6,
++      IDMAC_IC_7 = 7,         /* IC (sensor data) to memory */
++      IDMAC_IC_8 = 8,
++      IDMAC_IC_9 = 9,
++      IDMAC_IC_10 = 10,
++      IDMAC_IC_11 = 11,
++      IDMAC_IC_12 = 12,
++      IDMAC_IC_13 = 13,
++      IDMAC_SDC_0 = 14,       /* Background synchronous display data */
++      IDMAC_SDC_1 = 15,       /* Foreground data (overlay) */
++      IDMAC_SDC_2 = 16,
++      IDMAC_SDC_3 = 17,
++      IDMAC_ADC_2 = 18,
++      IDMAC_ADC_3 = 19,
++      IDMAC_ADC_4 = 20,
++      IDMAC_ADC_5 = 21,
++      IDMAC_ADC_6 = 22,
++      IDMAC_ADC_7 = 23,
++      IDMAC_PF_0 = 24,
++      IDMAC_PF_1 = 25,
++      IDMAC_PF_2 = 26,
++      IDMAC_PF_3 = 27,
++      IDMAC_PF_4 = 28,
++      IDMAC_PF_5 = 29,
++      IDMAC_PF_6 = 30,
++      IDMAC_PF_7 = 31,
++};
++
++/* Order significant! */
++enum ipu_channel_status {
++      IPU_CHANNEL_FREE,
++      IPU_CHANNEL_GRANTED,
++      IPU_CHANNEL_INITIALIZED,
++      IPU_CHANNEL_READY,
++      IPU_CHANNEL_ENABLED,
++};
++
++#define IPU_CHANNELS_NUM 32
++
++enum pixel_fmt {
++      /* 1 byte */
++      IPU_PIX_FMT_GENERIC,
++      IPU_PIX_FMT_RGB332,
++      IPU_PIX_FMT_YUV420P,
++      IPU_PIX_FMT_YUV422P,
++      IPU_PIX_FMT_YUV420P2,
++      IPU_PIX_FMT_YVU422P,
++      /* 2 bytes */
++      IPU_PIX_FMT_RGB565,
++      IPU_PIX_FMT_RGB666,
++      IPU_PIX_FMT_BGR666,
++      IPU_PIX_FMT_YUYV,
++      IPU_PIX_FMT_UYVY,
++      /* 3 bytes */
++      IPU_PIX_FMT_RGB24,
++      IPU_PIX_FMT_BGR24,
++      /* 4 bytes */
++      IPU_PIX_FMT_GENERIC_32,
++      IPU_PIX_FMT_RGB32,
++      IPU_PIX_FMT_BGR32,
++      IPU_PIX_FMT_ABGR32,
++      IPU_PIX_FMT_BGRA32,
++      IPU_PIX_FMT_RGBA32,
++};
++
++enum ipu_color_space {
++      IPU_COLORSPACE_RGB,
++      IPU_COLORSPACE_YCBCR,
++      IPU_COLORSPACE_YUV
++};
++
++/**
++ * Enumeration of IPU rotation modes
++ */
++enum ipu_rotate_mode {
++      /* Note the enum values correspond to BAM value */
++      IPU_ROTATE_NONE = 0,
++      IPU_ROTATE_VERT_FLIP = 1,
++      IPU_ROTATE_HORIZ_FLIP = 2,
++      IPU_ROTATE_180 = 3,
++      IPU_ROTATE_90_RIGHT = 4,
++      IPU_ROTATE_90_RIGHT_VFLIP = 5,
++      IPU_ROTATE_90_RIGHT_HFLIP = 6,
++      IPU_ROTATE_90_LEFT = 7,
++};
++
++struct ipu_platform_data {
++      unsigned int    irq_base;
++};
++
++/**
++ * Enumeration of DI ports for ADC.
++ */
++typedef enum {
++      DISP0,
++      DISP1,
++      DISP2,
++      DISP3
++} display_port_t;
++
++struct idmac_video_param {
++      unsigned short  in_width;
++      unsigned short  in_height;
++      uint32_t        in_pixel_fmt;
++      unsigned short  out_width;
++      unsigned short  out_height;
++      uint32_t        out_pixel_fmt;
++      unsigned short  out_stride;
++      bool            graphics_combine_en;
++      bool            global_alpha_en;
++      bool            key_color_en;
++      display_port_t  disp;
++      unsigned short  out_left;
++      unsigned short  out_top;
++};
++
++/*
++ * Union of initialization parameters for a logical channel. So far only video
++ * parameters are used.
++ */
++union ipu_channel_param {
++      struct idmac_video_param video;
++};
++
++struct idmac_tx_desc {
++      struct dma_async_tx_descriptor  txd;
++      struct scatterlist              *sg;    /* scatterlist for this */
++      unsigned int                    sg_len; /* tx-descriptor. */
++      struct list_head                list;
++};
++
++struct idmac_channel {
++      struct dma_chan         dma_chan;
++      dma_cookie_t            completed;      /* last completed cookie           */
++      union ipu_channel_param params;
++      enum ipu_channel        link;   /* input channel, linked to the output     */
++      enum ipu_channel_status status;
++      struct idmac_client     *iclient;       /* Only one client per channel     */
++      unsigned int            n_tx_desc;
++      struct idmac_tx_desc    *desc;          /* allocated tx-descriptors        */
++      struct scatterlist      *sg[2]; /* scatterlist elements in buffer-0 and -1 */
++      struct list_head        free_list;      /* free tx-descriptors             */
++      struct list_head        queue;          /* queued tx-descriptors           */
++      spinlock_t              lock;           /* protects sg[0,1], queue         */
++      struct mutex            chan_mutex; /* protects status, cookie, free_list  */
++      unsigned int            eof_irq;
++      bool                    sec_chan_en;
++      int                     active_buffer;
++};
++
++struct idmac_channel_rq {
++      enum ipu_channel        channel;
++      struct idmac_channel    *ichannel;
++};
++
++struct idmac_client {
++      int                     n_channels;
++      struct idmac_channel_rq *channels;
++      struct dma_client       dma_client;
++};
++
++extern unsigned long ipu_clk_get_rate(void);
++
++#define to_tx_desc(tx) container_of(tx, struct idmac_tx_desc, txd)
++#define to_idmac_chan(c) container_of(c, struct idmac_channel, dma_chan)
++#define to_idmac_client(i) container_of(i, struct idmac_client, dma_client)
++
++#endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/irqs.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/irqs.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/irqs.h 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/irqs.h    2009-03-11 13:16:24.000000000 +0100
+@@ -14,4 +14,9 @@
+ #include <mach/hardware.h>
+ extern void imx_irq_set_priority(unsigned char irq, unsigned char prio);
++/* all normal IRQs can be FIQs */
++#define FIQ_START     0
++/* switch between IRQ and FIQ */
++extern int mxc_set_irq_fiq(unsigned int irq, unsigned int type);
++
+ #endif /* __ASM_ARCH_MXC_IRQS_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/memory.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/memory.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/memory.h       2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/memory.h  2009-03-11 13:16:24.000000000 +0100
+@@ -26,4 +26,5 @@
+  */
+ #define __bus_to_virt(a)      __phys_to_virt(a)
++#define CONSISTENT_DMA_SIZE (14 * SZ_1M)
+ #endif /* __ASM_ARCH_MXC_MEMORY_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/mmc.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/mmc.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/mmc.h  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/mmc.h     2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,19 @@
++#ifndef ASMARM_ARCH_MMC_H
++#define ASMARM_ARCH_MMC_H
++
++#include <linux/mmc/host.h>
++
++struct device;
++
++struct imxmmc_platform_data {
++      int (*get_ro)(struct device *);
++      int (*init)(struct device *, irq_handler_t, void *);
++      void (*exit)(struct device *, void *);
++      void (*setpower)(struct device *, unsigned int vdd);
++      int (*suspend)(struct device *, pm_message_t state);
++      int (*resume)(struct device *);
++};
++
++extern void imx_set_mmc_info(struct imxmmc_platform_data *info);
++
++#endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/mx27.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/mx27.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/mx27.h 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/mx27.h    2009-03-11 13:16:24.000000000 +0100
+@@ -24,12 +24,20 @@
+ #error "Do not include directly."
+ #endif
++/* the DMA code supports SG list chaining */
++#define ARCH_HAS_SG_CHAIN
++
+ /* IRAM */
+ #define IRAM_BASE_ADDR          0xFFFF4C00    /* internal ram */
+ /* Register offests */
++#ifndef __ASSEMBLY__
++#define AIPI_BASE_ADDR          0x10000000UL
++#define AIPI_BASE_ADDR_VIRT     ((void __iomem *)0xF4000000)
++#else
+ #define AIPI_BASE_ADDR          0x10000000
+ #define AIPI_BASE_ADDR_VIRT     0xF4000000
++#endif
+ #define AIPI_SIZE               SZ_1M
+ #define DMA_BASE_ADDR           (AIPI_BASE_ADDR + 0x01000)
+@@ -72,7 +80,8 @@
+ /* for mx27*/
+ #define OTG_BASE_ADDR           USBOTG_BASE_ADDR
+ #define SAHARA_BASE_ADDR        (AIPI_BASE_ADDR + 0x25000)
+-#define EMMA_BASE_ADDR          (AIPI_BASE_ADDR + 0x26400)
++#define EMMA_PP_BASE_ADDR       (AIPI_BASE_ADDR + 0x26000)
++#define EMMA_PRP_BASE_ADDR      (AIPI_BASE_ADDR + 0x26400)
+ #define CCM_BASE_ADDR           (AIPI_BASE_ADDR + 0x27000)
+ #define SYSCTRL_BASE_ADDR       (AIPI_BASE_ADDR + 0x27800)
+ #define IIM_BASE_ADDR           (AIPI_BASE_ADDR + 0x28000)
+@@ -91,16 +100,26 @@
+ #define AVIC_BASE_ADDR          0x10040000
++#ifndef __ASSEMBLY__
++#define SAHB1_BASE_ADDR         0x80000000UL
++#define SAHB1_BASE_ADDR_VIRT    ((void __iomem *)0xF4100000UL)
++#else
+ #define SAHB1_BASE_ADDR         0x80000000
+ #define SAHB1_BASE_ADDR_VIRT    0xF4100000
++#endif
+ #define SAHB1_SIZE              SZ_1M
+ #define CSI_BASE_ADDR           (SAHB1_BASE_ADDR + 0x0000)
+ #define ATA_BASE_ADDR           (SAHB1_BASE_ADDR + 0x1000)
+ /* NAND, SDRAM, WEIM, M3IF, EMI controllers */
++#ifndef __ASSEMBLY__
++#define X_MEMC_BASE_ADDR        0xD8000000UL
++#define X_MEMC_BASE_ADDR_VIRT   ((void __iomem *)0xF4200000UL)
++#else
+ #define X_MEMC_BASE_ADDR        0xD8000000
+ #define X_MEMC_BASE_ADDR_VIRT   0xF4200000
++#endif
+ #define X_MEMC_SIZE             SZ_1M
+ #define NFC_BASE_ADDR           (X_MEMC_BASE_ADDR)
+@@ -127,14 +146,24 @@
+  * and returning the virtual address. If the physical address is not mapped,
+  * it returns 0xDEADBEEF
+  */
+-#define IO_ADDRESS(x)   \
+-      (void __iomem *) \
+-      (((x >= AIPI_BASE_ADDR) && (x < (AIPI_BASE_ADDR + AIPI_SIZE))) ? \
+-              AIPI_IO_ADDRESS(x) : \
+-      ((x >= SAHB1_BASE_ADDR) && (x < (SAHB1_BASE_ADDR + SAHB1_SIZE))) ? \
+-              SAHB1_IO_ADDRESS(x) : \
+-      ((x >= X_MEMC_BASE_ADDR) && (x < (X_MEMC_BASE_ADDR + X_MEMC_SIZE))) ? \
+-              X_MEMC_IO_ADDRESS(x) : 0xDEADBEEF)
++#define IO_ADDRESS(x)                                                                 \
++      ((((x) >= AIPI_BASE_ADDR) && ((x) < (AIPI_BASE_ADDR + AIPI_SIZE))) ?            \
++              AIPI_IO_ADDRESS(x) :                                                    \
++      (((x) >= SAHB1_BASE_ADDR) && ((x) < (SAHB1_BASE_ADDR + SAHB1_SIZE))) ?          \
++              SAHB1_IO_ADDRESS(x) :                                                   \
++      (((x) >= X_MEMC_BASE_ADDR) && ((x) < (X_MEMC_BASE_ADDR + X_MEMC_SIZE))) ?       \
++              X_MEMC_IO_ADDRESS(x) : NULL)
++
++#define MXC_VADDR_RANGE(v,n)                          \
++      (((v)) >= n##_BASE_ADDR_VIRT) &&                \
++      (((v)) < n##_BASE_ADDR_VIRT + n##_SIZE) ?       \
++      ((v)-n##_BASE_ADDR_VIRT + n##_BASE_ADDR) :
++
++#define MXC_PHYS_ADDRESS(v)                   \
++      (unsigned long)(MXC_VADDR_RANGE(v,AIPI) \
++      MXC_VADDR_RANGE(v,SAHB1)                \
++      MXC_VADDR_RANGE(v,X_MEMC)               \
++      0UL)
+ /* define the address mapping macros: in physical address order */
+ #define AIPI_IO_ADDRESS(x)  \
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/mxc_ehci.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/mxc_ehci.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/mxc_ehci.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/mxc_ehci.h        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,9 @@
++#ifndef __INCLUDE_ASM_ARCH_MXC_EHCI_H
++#define __INCLUDE_ASM_ARCH_MXC_EHCI_H
++
++struct mxc_usbh_platform_data {
++      int (*init)(struct platform_device *pdev);
++      int (*exit)(struct platform_device *pdev);
++};
++#endif /* __INCLUDE_ASM_ARCH_MXC_EHCI_H */
++
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/mxc_timer.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/mxc_timer.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/mxc_timer.h    2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/mxc_timer.h       2009-03-11 13:16:24.000000000 +0100
+@@ -26,7 +26,7 @@
+ #include <linux/clk.h>
+ #include <mach/hardware.h>
+-#ifdef CONFIG_ARCH_IMX
++#ifdef CONFIG_ARCH_MX1
+ #define TIMER_BASE            IO_ADDRESS(TIM1_BASE_ADDR)
+ #define TIMER_INTERRUPT               TIM1_INT
+@@ -65,7 +65,7 @@ static void gpt_irq_acknowledge(void)
+ {
+       __raw_writel(0, TIMER_BASE + MXC_TSTAT);
+ }
+-#endif /* CONFIG_ARCH_IMX */
++#endif /* CONFIG_ARCH_MX1 */
+ #ifdef CONFIG_ARCH_MX2
+ #define TIMER_BASE            IO_ADDRESS(GPT1_BASE_ADDR)
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/system.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/system.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/system.h       2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/system.h  2009-03-11 13:16:24.000000000 +0100
+@@ -21,14 +21,7 @@
+ #ifndef __ASM_ARCH_MXC_SYSTEM_H__
+ #define __ASM_ARCH_MXC_SYSTEM_H__
+-static inline void arch_idle(void)
+-{
+-      cpu_do_idle();
+-}
+-
+-static inline void arch_reset(char mode)
+-{
+-      cpu_reset(0);
+-}
++extern void arch_idle(void);
++extern void arch_reset(char mode);
+ #endif /* __ASM_ARCH_MXC_SYSTEM_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/include/mach/ulpi.h linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/ulpi.h
+--- linux-2.6.28/arch/arm/plat-mxc/include/mach/ulpi.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/include/mach/ulpi.h    2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,31 @@
++#ifndef __MACH_ULPI_H
++#define __MACH_ULPI_H
++
++int ulpi_set(u8 bits, int reg, void __iomem *view);
++int ulpi_clear(u8 bits, int reg, void __iomem *view);
++int ulpi_read(int reg, void __iomem *view);
++
++/* ISP 1504 register addresses */
++#define ISP1504_VID_LOW               0x00    /* Vendor ID low */
++#define ISP1504_VID_HIGH      0x01    /* Vendor ID high */
++#define ISP1504_PID_LOW               0x02    /* Product ID low */
++#define ISP1504_PID_HIGH      0x03    /* Product ID high */
++#define ISP1504_ITFCTL                0x07    /* Interface Control */
++#define ISP1504_OTGCTL                0x0A    /* OTG Control */
++
++/* add to above register address to access Set/Clear functions */
++#define ISP1504_REG_SET               0x01
++#define ISP1504_REG_CLEAR     0x02
++
++/* 1504 OTG Control Register bits */
++#define USE_EXT_VBUS_IND      (1 << 7)        /* Use ext. Vbus indicator */
++#define DRV_VBUS_EXT          (1 << 6)        /* Drive Vbus external */
++#define DRV_VBUS              (1 << 5)        /* Drive Vbus */
++#define CHRG_VBUS             (1 << 4)        /* Charge Vbus */
++#define DISCHRG_VBUS          (1 << 3)        /* Discharge Vbus */
++#define DM_PULL_DOWN          (1 << 2)        /* enable DM Pull Down */
++#define DP_PULL_DOWN          (1 << 1)        /* enable DP Pull Down */
++#define ID_PULL_UP            (1 << 0)        /* enable ID Pull Up */
++
++#endif /* __MACH_ULPI_H */
++
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/iomux-mx1-mx2.c linux-2.6.28-karo/arch/arm/plat-mxc/iomux-mx1-mx2.c
+--- linux-2.6.28/arch/arm/plat-mxc/iomux-mx1-mx2.c     2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/iomux-mx1-mx2.c        2009-03-11 13:16:24.000000000 +0100
+@@ -1,9 +1,10 @@
+ /*
+- *  arch/arm/mach-mxc/generic.c
++ *  arch/arm/plat-mxc/iomux-mx1-mx2.c
+  *
+- *  author: Sascha Hauer
+- *  Created: april 20th, 2004
++ *  Author: Sascha Hauer
++ *  Created: April 20th, 2004
+  *  Copyright: Synertronixx GmbH
++// FIXME: This is most likely as incorrect as the filename comment above
+  *
+  *  Common code for i.MX machines
+  *
+@@ -32,7 +33,7 @@
+ #include <mach/hardware.h>
+ #include <asm/mach/map.h>
+-#include <mach/iomux-mx1-mx2.h>
++#include <mach/iomux.h>
+ void mxc_gpio_mode(int gpio_mode)
+ {
+@@ -40,6 +41,31 @@ void mxc_gpio_mode(int gpio_mode)
+       unsigned int port = (gpio_mode & GPIO_PORT_MASK) >> GPIO_PORT_SHIFT;
+       unsigned int ocr = (gpio_mode & GPIO_OCR_MASK) >> GPIO_OCR_SHIFT;
+       unsigned int tmp;
++      unsigned long flags;
++      char buf[64];
++
++      local_irq_save(flags);
++
++      if (gpio_mode & GPIO_OUT) {
++              switch (gpio_mode & (GPIO_DFLT_LOW | GPIO_DFLT_HIGH)) {
++              case 0:
++                      break;
++              case GPIO_DFLT_LOW:
++                      tmp = __raw_readl(VA_GPIO_BASE + MXC_DR(port));
++                      tmp &= ~(1 << pin);
++                      __raw_writel(tmp, VA_GPIO_BASE + MXC_DR(port));
++                      break;
++              case GPIO_DFLT_HIGH:
++                      tmp = __raw_readl(VA_GPIO_BASE + MXC_DR(port));
++                      tmp |= (1 << pin);
++                      __raw_writel(tmp, VA_GPIO_BASE + MXC_DR(port));
++                      break;
++              default:
++                      printk(KERN_ERR
++                             "GPIO_DFLT_LOW and GPIO_DFLT_HIGH both set for P%c%d\n",
++                             port + 'A', pin);
++              }
++      }
+       /* Pullup enable */
+       tmp = __raw_readl(VA_GPIO_BASE + MXC_PUEN(port));
+@@ -106,51 +132,50 @@ void mxc_gpio_mode(int gpio_mode)
+               tmp |= ((gpio_mode >> GPIO_BOUT_SHIFT) & 3) << (pin * 2);
+               __raw_writel(tmp, VA_GPIO_BASE + MXC_ICONFB2(port));
+       }
++      local_irq_restore(flags);
+ }
+ EXPORT_SYMBOL(mxc_gpio_mode);
+ int mxc_gpio_setup_multiple_pins(const int *pin_list, unsigned count,
+-                              int alloc_mode, const char *label)
++              const char *label)
+ {
+-      const int *p = pin_list;
++      const int *p;
+       int i;
+-      unsigned gpio;
+-      unsigned mode;
++      int ret = -EINVAL;
+-      for (i = 0; i < count; i++) {
+-              gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
+-              mode = *p & ~(GPIO_PIN_MASK | GPIO_PORT_MASK);
++      /* Try to obtain all requested GPIOs */
++      for (i = 0, p = pin_list; i < count; i++, p++) {
++              unsigned gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
+               if (gpio >= (GPIO_PORT_MAX + 1) * 32)
+                       goto setup_error;
+-              if (alloc_mode & MXC_GPIO_ALLOC_MODE_RELEASE)
+-                      gpio_free(gpio);
+-              else if (!(alloc_mode & MXC_GPIO_ALLOC_MODE_NO_ALLOC))
+-                      if (gpio_request(gpio, label)
+-                         && !(alloc_mode & MXC_GPIO_ALLOC_MODE_TRY_ALLOC))
+-                              goto setup_error;
+-
+-              if (!(alloc_mode & (MXC_GPIO_ALLOC_MODE_ALLOC_ONLY |
+-                                  MXC_GPIO_ALLOC_MODE_RELEASE)))
+-                      mxc_gpio_mode(gpio | mode);
+-
+-              p++;
++              ret = gpio_request(gpio, label);
++              if (ret)
++                      goto setup_error;
++      }
++      /* Reconfigure all requested pins */
++      for (i = 0, p = pin_list; i < count; i++, p++) {
++              mxc_gpio_mode(*p);
+       }
+       return 0;
+ setup_error:
+-      if (alloc_mode & (MXC_GPIO_ALLOC_MODE_NO_ALLOC |
+-          MXC_GPIO_ALLOC_MODE_TRY_ALLOC))
+-              return -EINVAL;
+-
+-      while (p != pin_list) {
+-              p--;
+-              gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
++      mxc_gpio_release_multiple_pins(pin_list, i);
++      return ret;
++}
++EXPORT_SYMBOL(mxc_gpio_setup_multiple_pins);
++
++void mxc_gpio_release_multiple_pins(const int *pin_list, int count)
++{
++      const int *p;
++      int i;
++
++      for (i = 0, p = pin_list; i < count; i++, p++) {
++              unsigned gpio = *p & (GPIO_PIN_MASK | GPIO_PORT_MASK);
+               gpio_free(gpio);
+       }
+-      return -EINVAL;
+ }
+-EXPORT_SYMBOL(mxc_gpio_setup_multiple_pins);
++EXPORT_SYMBOL(mxc_gpio_release_multiple_pins);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/irq.c linux-2.6.28-karo/arch/arm/plat-mxc/irq.c
+--- linux-2.6.28/arch/arm/plat-mxc/irq.c       2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/irq.c  2009-03-11 18:48:21.000000000 +0100
+@@ -17,9 +17,13 @@
+  * MA  02110-1301, USA.
+  */
++#include <linux/module.h>
++#include <linux/sysdev.h>
+ #include <linux/irq.h>
+ #include <linux/io.h>
++#include <linux/pm.h>
+ #include <mach/common.h>
++#include <asm/mach/irq.h>
+ #define AVIC_BASE             IO_ADDRESS(AVIC_BASE_ADDR)
+ #define AVIC_INTCNTL          (AVIC_BASE + 0x00)      /* int control reg */
+@@ -65,6 +69,28 @@ void imx_irq_set_priority(unsigned char 
+ EXPORT_SYMBOL(imx_irq_set_priority);
+ #endif
++#ifdef CONFIG_FIQ
++int mxc_set_irq_fiq(unsigned int irq, unsigned int type)
++{
++      unsigned int irqt;
++
++      if (irq >= MXC_MAX_INT_LINES)
++              return -EINVAL;
++
++      if (irq < MXC_MAX_INT_LINES / 2) {
++              irqt = __raw_readl(AVIC_INTTYPEL) & ~(1 << irq);
++              __raw_writel(irqt | (!!type << irq), AVIC_INTTYPEL);
++      } else {
++              irq -= MXC_MAX_INT_LINES / 2;
++              irqt = __raw_readl(AVIC_INTTYPEH) & ~(1 << irq);
++              __raw_writel(irqt | (!!type << irq), AVIC_INTTYPEH);
++      }
++
++      return 0;
++}
++EXPORT_SYMBOL(mxc_set_irq_fiq);
++#endif /* CONFIG_FIQ */
++
+ /* Disable interrupt number "irq" in the AVIC */
+ static void mxc_mask_irq(unsigned int irq)
+ {
+@@ -77,12 +103,94 @@ static void mxc_unmask_irq(unsigned int 
+       __raw_writel(irq, AVIC_INTENNUM);
+ }
++static u32 saved_wakeup_low, saved_wakeup_high;
++static u32 suspend_wakeup_low, suspend_wakeup_high;
++
++/* Set interrupt number "irq" in the AVIC as a wake-up source */
++static int mxc_set_wake_irq(unsigned int irq, unsigned int enable)
++{
++      uint32_t *wakeup_intr;
++      uint32_t irq_bit;
++
++      if (irq < 32) {
++              wakeup_intr = &suspend_wakeup_low;
++              irq_bit = 1 << irq;
++      } else {
++              wakeup_intr = &suspend_wakeup_high;
++              irq_bit = 1 << (irq - 32);
++      }
++
++      if (enable) {
++              *wakeup_intr |= irq_bit;
++      } else {
++              *wakeup_intr &= ~irq_bit;
++      }
++
++      return 0;
++}
++
+ static struct irq_chip mxc_avic_chip = {
+       .ack = mxc_mask_irq,
+       .mask = mxc_mask_irq,
+       .unmask = mxc_unmask_irq,
++      .set_wake = mxc_set_wake_irq,
++};
++
++#ifdef CONFIG_PM
++/* This function puts the AVIC in low-power mode/state.
++ * All interrupts that are enabled are first saved.
++ * Only those interrupts which are registered as a wake source by calling
++ * enable_irq_wake are enabled. All other interrupts are disabled.
++ */
++static int mxc_avic_suspend(struct sys_device *dev, pm_message_t mesg)
++{
++      saved_wakeup_high = __raw_readl(AVIC_INTENABLEH);
++      saved_wakeup_low = __raw_readl(AVIC_INTENABLEL);
++
++      __raw_writel(suspend_wakeup_high, AVIC_INTENABLEH);
++      __raw_writel(suspend_wakeup_low, AVIC_INTENABLEL);
++
++      return 0;
++}
++
++/* This function brings the AVIC back from low-power state.
++ * All interrupts that were enabled prior to suspend are re-enabled.
++ */
++static int mxc_avic_resume(struct sys_device *dev)
++{
++      __raw_writel(saved_wakeup_high, AVIC_INTENABLEH);
++      __raw_writel(saved_wakeup_low, AVIC_INTENABLEL);
++
++      return 0;
++}
++
++#else
++#define mxc_avic_suspend  NULL
++#define mxc_avic_resume   NULL
++#endif                                /* CONFIG_PM */
++
++/*!
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct sysdev_class mxc_avic_sysclass = {
++      .name = "mxc_irq",
++      .suspend = mxc_avic_suspend,
++      .resume = mxc_avic_resume,
++};
++
++/*!
++ * This structure represents AVIC as a system device.
++ * System devices follow a slightly different driver model. 
++ * They don't need to do dynammic driver binding, can't be probed, 
++ * and don't reside on any type of peripheral bus. 
++ * So, it is represented and treated a little differently.
++ */
++struct sys_device mxc_avic_device = {
++      .cls = &mxc_avic_sysclass,
+ };
++static int __init mxc_avic_sysinit(void);
++
+ /*
+  * This function initializes the AVIC hardware and disables all the
+  * interrupts. It registers the interrupt enable and disable functions
+@@ -91,7 +199,6 @@ static struct irq_chip mxc_avic_chip = {
+ void __init mxc_init_irq(void)
+ {
+       int i;
+-      u32 reg;
+       /* put the AVIC into the reset value with
+        * all interrupts disabled
+@@ -119,5 +226,30 @@ void __init mxc_init_irq(void)
+       /* init architectures chained interrupt handler */
+       mxc_register_gpios();
++#ifdef CONFIG_FIQ
++      /* Initialize FIQ */
++      init_FIQ();
++#endif
++
+       printk(KERN_INFO "MXC IRQ initialized\n");
+ }
++
++extern int __init mxc_gpio_sys_init(void);
++
++/* This function registers AVIC hardware as a system device */
++static int __init mxc_avic_sysinit(void)
++{
++      int ret;
++
++      ret = sysdev_class_register(&mxc_avic_sysclass);
++      if (ret)
++              return ret;
++      ret = sysdev_register(&mxc_avic_device);
++      if (ret)
++              return ret;
++
++      ret = mxc_gpio_sys_init();
++
++      return ret;
++}
++arch_initcall(mxc_avic_sysinit);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/arch/arm/plat-mxc/ulpi.c linux-2.6.28-karo/arch/arm/plat-mxc/ulpi.c
+--- linux-2.6.28/arch/arm/plat-mxc/ulpi.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/arch/arm/plat-mxc/ulpi.c 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,120 @@
++/*
++ * Copyright 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston,
++ * MA  02110-1301, USA.
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++
++#include <mach/ulpi.h>
++
++/* ULPIVIEW register bits */
++#define ULPIVW_WU             (1 << 31)       /* Wakeup */
++#define ULPIVW_RUN            (1 << 30)       /* read/write run */
++#define ULPIVW_WRITE          (1 << 29)       /* 0 = read  1 = write */
++#define ULPIVW_SS             (1 << 27)       /* SyncState */
++#define ULPIVW_PORT_MASK      0x07    /* Port field */
++#define ULPIVW_PORT_SHIFT     24
++#define ULPIVW_ADDR_MASK      0xFF    /* data address field */
++#define ULPIVW_ADDR_SHIFT     16
++#define ULPIVW_RDATA_MASK     0xFF    /* read data field */
++#define ULPIVW_RDATA_SHIFT    8
++#define ULPIVW_WDATA_MASK     0xFF    /* write data field */
++#define ULPIVW_WDATA_SHIFT    0
++
++static int ulpi_poll(void __iomem *view, uint32_t bit)
++{
++      uint32_t data;
++      int timeout = 10000;
++
++      data = __raw_readl(view);
++      while (data & bit) {
++              if (!timeout--)
++                      return -ETIMEDOUT;
++
++              udelay(1);
++              data = __raw_readl(view);
++      }
++      return (data >> ULPIVW_RDATA_SHIFT) & ULPIVW_RDATA_MASK;
++}
++
++int ulpi_read(int reg, void __iomem *view)
++{
++      int ret;
++
++      /* make sure interface is running */
++      if (!(__raw_readl(view) && ULPIVW_SS)) {
++              __raw_writel(ULPIVW_WU, view);
++
++              /* wait for wakeup */
++              ret = ulpi_poll(view, ULPIVW_WU);
++              if (ret < 0)
++                      return ret;
++      }
++
++      /* read the register */
++      __raw_writel((ULPIVW_RUN | (reg << ULPIVW_ADDR_SHIFT)), view);
++
++      /* wait for completion */
++      return ulpi_poll(view, ULPIVW_RUN);
++}
++EXPORT_SYMBOL(ulpi_read);
++
++int ulpi_set(u8 bits, int reg, void __iomem *view)
++{
++      int ret;
++
++      /* make sure the interface is running */
++      if (!(__raw_readl(view) && ULPIVW_SS)) {
++              __raw_writel(ULPIVW_WU, view);
++              /* wait for wakeup */
++              ret = ulpi_poll(view, ULPIVW_WU);
++              if (ret < 0)
++                      return ret;
++      }
++
++      __raw_writel((ULPIVW_RUN | ULPIVW_WRITE |
++                    ((reg + ISP1504_REG_SET) << ULPIVW_ADDR_SHIFT) |
++                    ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)),
++                   view);
++
++      /* wait for completion */
++      ret = ulpi_poll(view, ULPIVW_RUN);
++      if (ret < 0)
++              return ret;
++      return 0;
++}
++EXPORT_SYMBOL(ulpi_set);
++
++int ulpi_clear(u8 bits, int reg, void __iomem *view)
++{
++      int ret;
++
++      __raw_writel((ULPIVW_RUN | ULPIVW_WRITE |
++                    ((reg + ISP1504_REG_CLEAR) << ULPIVW_ADDR_SHIFT) |
++                    ((bits & ULPIVW_WDATA_MASK) << ULPIVW_WDATA_SHIFT)),
++                   view);
++
++      /* wait for completion */
++      ret = ulpi_poll(view, ULPIVW_RUN);
++      if (ret < 0)
++              return ret;
++      return 0;
++}
++EXPORT_SYMBOL(ulpi_clear);
++
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/Makefile linux-2.6.28-karo/drivers/Makefile
+--- linux-2.6.28/drivers/Makefile      2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/Makefile 2009-03-11 13:16:24.000000000 +0100
+@@ -102,3 +102,4 @@ obj-$(CONFIG_SSB)          += ssb/
+ obj-$(CONFIG_VIRTIO)          += virtio/
+ obj-$(CONFIG_REGULATOR)               += regulator/
+ obj-$(CONFIG_STAGING)         += staging/
++obj-$(CONFIG_DRIVERS_MXC)     += mxc/
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/dma/dmaengine.c linux-2.6.28-karo/drivers/dma/dmaengine.c
+--- linux-2.6.28/drivers/dma/dmaengine.c       2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/dma/dmaengine.c  2009-03-11 13:16:24.000000000 +0100
+@@ -322,7 +322,12 @@ void dma_async_client_unregister(struct 
+       mutex_lock(&dma_list_mutex);
+       /* free all channels the client is holding */
+-      list_for_each_entry(device, &dma_device_list, global_node)
++      list_for_each_entry(device, &dma_device_list, global_node) {
++              /* Client only can have channels from one DMA controller */
++              if (client->slave && client->slave->dma_dev &&
++                  client->slave->dma_dev != device->dev)
++                      continue;
++
+               list_for_each_entry(chan, &device->channels, device_node) {
+                       ack = client->event_callback(client, chan,
+                               DMA_RESOURCE_REMOVED);
+@@ -332,6 +337,7 @@ void dma_async_client_unregister(struct 
+                               chan->client_count--;
+                       }
+               }
++      }
+       list_del(&client->global_node);
+       mutex_unlock(&dma_list_mutex);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/gpio/gpiolib.c linux-2.6.28-karo/drivers/gpio/gpiolib.c
+--- linux-2.6.28/drivers/gpio/gpiolib.c        2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/gpio/gpiolib.c   2009-03-11 13:16:24.000000000 +0100
+@@ -789,6 +789,7 @@ int gpio_request(unsigned gpio, const ch
+       } else {
+               status = -EBUSY;
+               module_put(chip->owner);
++              goto done;
+       }
+       if (chip->request) {
+@@ -842,9 +843,14 @@ void gpio_free(unsigned gpio)
+               desc_set_label(desc, NULL);
+               module_put(desc->chip->owner);
+               clear_bit(FLAG_REQUESTED, &desc->flags);
+-      } else
++      } else {
++              if (!chip) {
++                      printk(KERN_ERR "%s: No chip for GPIO%d\n", __FUNCTION__, gpio);
++              } else {
++                      printk(KERN_ERR "%s: GPIO%d not requested\n", __FUNCTION__, gpio);
++              }
+               WARN_ON(extra_checks);
+-
++      }
+       spin_unlock_irqrestore(&gpio_lock, flags);
+ }
+ EXPORT_SYMBOL_GPL(gpio_free);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/i2c/busses/Kconfig linux-2.6.28-karo/drivers/i2c/busses/Kconfig
+--- linux-2.6.28/drivers/i2c/busses/Kconfig    2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/i2c/busses/Kconfig       2009-03-11 13:16:24.000000000 +0100
+@@ -355,6 +355,16 @@ config I2C_IBM_IIC
+         This driver can also be built as a module.  If so, the module
+         will be called i2c-ibm_iic.
++config I2C_MXC
++      tristate "MXC I2C support"
++      depends on I2C && ARCH_MXC
++      help
++        Say Y here if you want to use the IIC bus controller on Freescale
++        i.MX2 family of processors (like i.MX21 and i.MX27).
++
++        This driver can also be built as a module.  If so, the module
++        will be called i2c-mxc.
++
+ config I2C_IOP3XX
+       tristate "Intel IOPx3xx and IXP4xx on-chip I2C interface"
+       depends on ARCH_IOP32X || ARCH_IOP33X || ARCH_IXP4XX || ARCH_IOP13XX
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/i2c/busses/Makefile linux-2.6.28-karo/drivers/i2c/busses/Makefile
+--- linux-2.6.28/drivers/i2c/busses/Makefile   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/i2c/busses/Makefile      2009-03-11 13:16:24.000000000 +0100
+@@ -11,6 +11,7 @@ obj-$(CONFIG_I2C_AMD756_S4882)       += i2c-am
+ obj-$(CONFIG_I2C_AMD8111)     += i2c-amd8111.o
+ obj-$(CONFIG_I2C_I801)                += i2c-i801.o
+ obj-$(CONFIG_I2C_ISCH)                += i2c-isch.o
++obj-$(CONFIG_I2C_MXC)         += i2c-mxc.o
+ obj-$(CONFIG_I2C_NFORCE2)     += i2c-nforce2.o
+ obj-$(CONFIG_I2C_NFORCE2_S4985)       += i2c-nforce2-s4985.o
+ obj-$(CONFIG_I2C_PIIX4)               += i2c-piix4.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/i2c/busses/i2c-mxc.c linux-2.6.28-karo/drivers/i2c/busses/i2c-mxc.c
+--- linux-2.6.28/drivers/i2c/busses/i2c-mxc.c  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/i2c/busses/i2c-mxc.c     2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,667 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Juergen Beisert, kernel@pengutronix.de
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++/*
++ * Driver for the Freescale Semiconductor MXC I2C buses.
++ * Based on i2c driver algorithm for PCF8584 adapters
++ */
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/err.h>
++#include <linux/i2c.h>
++#include <linux/clk.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <mach/clock.h>
++#include <mach/imx_i2c.h>
++
++#define DRV_NAME "imx_i2c"
++
++typedef struct {
++      struct i2c_adapter adap;
++      wait_queue_head_t wq;
++      void __iomem *membase;  /* FIXME iomem? */
++      int irq;
++      unsigned int clkdiv;
++      struct clk *clk;
++      bool low_power;
++      struct imx_i2c_platform_data *pdata;
++      bool transfer_done;
++      bool tx_success;
++} imx_i2c_device;
++
++struct clk_div_table {
++      int reg_value;
++      int div;
++};
++
++static const struct clk_div_table i2c_clk_table[] = {
++      {0x20, 22}, {0x21, 24}, {0x22, 26}, {0x23, 28},
++      {0, 30}, {1, 32}, {0x24, 32}, {2, 36},
++      {0x25, 36}, {0x26, 40}, {3, 42}, {0x27, 44},
++      {4, 48}, {0x28, 48}, {5, 52}, {0x29, 56},
++      {6, 60}, {0x2A, 64}, {7, 72}, {0x2B, 72},
++      {8, 80}, {0x2C, 80}, {9, 88}, {0x2D, 96},
++      {0xA, 104}, {0x2E, 112}, {0xB, 128}, {0x2F, 128},
++      {0xC, 144}, {0xD, 160}, {0x30, 160}, {0xE, 192},
++      {0x31, 192}, {0x32, 224}, {0xF, 240}, {0x33, 256},
++      {0x10, 288}, {0x11, 320}, {0x34, 320}, {0x12, 384},
++      {0x35, 384}, {0x36, 448}, {0x13, 480}, {0x37, 512},
++      {0x14, 576}, {0x15, 640}, {0x38, 640}, {0x16, 768},
++      {0x39, 768}, {0x3A, 896}, {0x17, 960}, {0x3B, 1024},
++      {0x18, 1152}, {0x19, 1280}, {0x3C, 1280}, {0x1A, 1536},
++      {0x3D, 1536}, {0x3E, 1792}, {0x1B, 1920}, {0x3F, 2048},
++      {0x1C, 2304}, {0x1D, 2560}, {0x1E, 3072}, {0x1F, 3840},
++      {0, 0}
++};
++
++/* Transmit a STOP signal to the slave device */
++static void imx_i2c_stop(imx_i2c_device * dev)
++{
++      unsigned int cr;
++      int retry = 16;
++
++      cr = __raw_readw(dev->membase + MXC_I2CR);
++      cr &= ~(MXC_I2CR_MSTA | MXC_I2CR_MTX);
++      __raw_writew(cr, dev->membase + MXC_I2CR);
++
++      /*
++       * Make sure STOP meets setup requirement.
++       */
++      for (;;) {
++              unsigned int sr = __raw_readw(dev->membase + MXC_I2SR);
++              if ((sr & MXC_I2SR_IBB) == 0) break;
++              if (retry-- <= 0) {
++                      printk(KERN_DEBUG "Bus busy\n");
++                      break;
++              }
++              udelay(3);
++      }
++}
++
++/*
++ * Wait for the transmission of the data byte to complete. This function waits
++ * till we get a signal from the interrupt service routine indicating completion
++ * of the address cycle or we time out.
++ * The function returns 0 on success or -1 if an ack was not received
++ */
++static int imx_i2c_wait_for_tc(imx_i2c_device * dev, int trans_flag)
++{
++      int retry = 16;
++
++      while (retry-- && !dev->transfer_done) {
++              wait_event_interruptible_timeout(dev->wq,
++                                               dev->transfer_done,
++                                               dev->adap.timeout);
++      }
++      dev->transfer_done = false;
++
++      if (retry <= 0) {
++              /* Unable to send data */
++              printk(KERN_DEBUG "Data not transmitted\n");
++              return -1;
++      } else if (!(trans_flag & I2C_M_RD)) {
++              if (!dev->tx_success) {
++                      /*
++                       * An ACK was not received for a transmitted byte. Don't
++                       * print a message here as slow devices might cause this
++                       * condition quite often. This is not an error as
++                       * routines may try to look if a device is ready.
++                       */
++                      return -1;
++              }
++      }
++
++      return 0;
++}
++
++/* Transmit a START signal to the slave device */
++static void imx_i2c_start(imx_i2c_device * dev, struct i2c_msg *msg)
++{
++      unsigned int cr, sr;
++      unsigned int addr_trans;
++      int retry = 16;
++
++      /*
++       * Set the slave address and the requested transfer mode
++       * in the data register
++       */
++      addr_trans = msg->addr << 1;
++      if (msg->flags & I2C_M_RD) {
++              addr_trans |= 0x01;
++      }
++
++      /* Set the Master bit */
++      cr = __raw_readw(dev->membase + MXC_I2CR);
++      cr |= MXC_I2CR_MSTA;
++      __raw_writew(cr, dev->membase + MXC_I2CR);
++
++      /* Wait till the Bus Busy bit is set */
++      sr = __raw_readw(dev->membase + MXC_I2SR);
++      while (retry-- && (!(sr & MXC_I2SR_IBB))) {
++              udelay(3);
++              sr = __raw_readw(dev->membase + MXC_I2SR);
++      }
++      if (retry <= 0) {
++              printk(KERN_DEBUG "Could not grab Bus ownership\n");
++      }
++
++      /* Set the Transmit bit */
++      cr = __raw_readw(dev->membase + MXC_I2CR);
++      cr |= MXC_I2CR_MTX;
++      __raw_writew(cr, dev->membase + MXC_I2CR);
++
++      __raw_writew(addr_trans, dev->membase + MXC_I2DR);
++}
++
++/* Transmit a REPEAT START to the slave device */
++static void imx_i2c_repstart(imx_i2c_device * dev, struct i2c_msg *msg)
++{
++      unsigned int cr;
++      unsigned int addr_trans;
++
++      /*
++       * Set the slave address and the requested transfer mode
++       * in the data register
++       */
++      addr_trans = msg->addr << 1;
++      if (msg->flags & I2C_M_RD) {
++              addr_trans |= 0x01;
++      }
++      cr = __raw_readw(dev->membase + MXC_I2CR);
++      cr |= MXC_I2CR_RSTA;
++      __raw_writew(cr, dev->membase + MXC_I2CR);
++      udelay(3);
++      __raw_writew(addr_trans, dev->membase + MXC_I2DR);
++}
++
++/*
++ * Read the received data. The function waits till data is available or times
++ * out. Generates a stop signal if this is the last message to be received.
++ * Sends an ack for all the bytes received except the last byte.
++ * The function returns the number of bytes read or -1 on time out.
++ */
++static int imx_i2c_readbytes(imx_i2c_device * dev, struct i2c_msg *msg,
++                           int last, int addr_comp)
++{
++      int i;
++      char *buf = msg->buf;
++      int len = msg->len;
++      unsigned int cr;
++
++      cr = __raw_readw(dev->membase + MXC_I2CR);
++
++      /* switch to receive mode */
++      cr &= ~MXC_I2CR_MTX;
++      /*
++       * Clear the TXAK bit to gen an ack when receiving only one byte.
++       */
++      if (len == 1)
++              cr |= MXC_I2CR_TXAK;
++      else
++              cr &= ~MXC_I2CR_TXAK;
++
++      __raw_writew(cr, dev->membase + MXC_I2CR);
++      /*
++       * Dummy read only at the end of an address cycle
++       */
++      if (addr_comp > 0)
++              __raw_readw(dev->membase + MXC_I2DR);
++
++      for (i = 0; i < len; i++) {
++              /* Wait for data transmission to complete */
++              if (imx_i2c_wait_for_tc(dev, msg->flags)) {
++                      imx_i2c_stop(dev);
++                      return -1;
++              }
++              /* Do not generate an ACK for the last byte */
++              if (i == (len - 2)) {
++                      cr = __raw_readw(dev->membase + MXC_I2CR);
++                      cr |= MXC_I2CR_TXAK;
++                      __raw_writew(cr, dev->membase + MXC_I2CR);
++              } else if (i == (len - 1)) {
++                      if (last)
++                              imx_i2c_stop(dev);
++              }
++              /* Read the data */
++              *buf++ = __raw_readw(dev->membase + MXC_I2DR);
++      }
++
++      return i;
++}
++
++/*
++ * Write the data to the data register. Generates a stop signal if this is
++ * the last message to be sent or if no ack was received for the data sent.
++ * The function returns the number of bytes written or -1 on time out
++ * or if no ack was received for the data that was sent.
++ */
++static int imx_i2c_writebytes(imx_i2c_device * dev, struct i2c_msg *msg,
++                              int last)
++{
++      int i;
++      char *buf = msg->buf;
++      int len = msg->len;
++      unsigned int cr;
++
++      cr = __raw_readw(dev->membase + MXC_I2CR);
++      /* switch to transmit mode */
++      cr |= MXC_I2CR_MTX;
++      __raw_writew(cr, dev->membase + MXC_I2CR);
++
++      for (i = 0; i < len; i++) {
++              /* Write the data */
++              __raw_writew(*buf++, dev->membase + MXC_I2DR);
++              if (imx_i2c_wait_for_tc(dev, msg->flags)) {
++                      imx_i2c_stop(dev);
++                      return -1;
++              }
++      }
++      if (last > 0) {
++              imx_i2c_stop(dev);
++      }
++
++      return i;
++}
++
++/* Function enables the I2C module and initializes the registers */
++static void imx_i2c_module_en(imx_i2c_device * dev, int trans_flag)
++{
++      clk_enable(dev->clk);
++      /* Set the frequency divider */
++      __raw_writew(dev->clkdiv, dev->membase + MXC_IFDR);
++      /* Clear the status register */
++      __raw_writew(0x0, dev->membase + MXC_I2SR);
++      /* Enable I2C and its interrupts */
++      __raw_writew(MXC_I2CR_IEN, dev->membase + MXC_I2CR);
++      __raw_writew(MXC_I2CR_IEN | MXC_I2CR_IIEN, dev->membase + MXC_I2CR);
++}
++
++/* Disables the I2C module */
++static void imx_i2c_module_dis(imx_i2c_device * dev)
++{
++      __raw_writew(0x0, dev->membase + MXC_I2CR);
++      clk_disable(dev->clk);
++}
++
++/*
++ * The function is registered in the adapter structure. It is called when an MXC
++ * driver wishes to transfer data to a device connected to the I2C device.
++ * The function returns the number of messages transferred, -EREMOTEIO on I2C
++ * failure and a 0 if the num argument is less than 0.
++ */
++static int imx_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[],
++                      int num)
++{
++      imx_i2c_device *dev = (imx_i2c_device *) (i2c_get_adapdata(adap));
++      int i, ret = 0, addr_comp = 0;
++      unsigned int sr;
++
++      if (dev->low_power) {
++              printk(KERN_ERR "I2C Device in low power mode\n");
++              return -EREMOTEIO;
++      }
++
++      if (num < 1)
++              return 0;
++
++      imx_i2c_module_en(dev, msgs[0].flags);
++      sr = __raw_readw(dev->membase + MXC_I2SR);
++
++      /* Check bus state */
++      if (sr & MXC_I2SR_IBB) {
++              imx_i2c_module_dis(dev);
++              printk(KERN_DEBUG "Bus busy\n");
++              return -EREMOTEIO;
++      }
++
++      dev->transfer_done = false;
++      dev->tx_success = false;
++      for (i = 0; i < num && ret >= 0; i++) {
++              addr_comp = 0;
++              /*
++               * Send the slave address and transfer direction in the
++               * address cycle
++               */
++              if (i == 0) {
++                      /* Send a start or repeat start signal */
++                      imx_i2c_start(dev, &msgs[0]);
++                      /* Wait for the address cycle to complete */
++                      if (imx_i2c_wait_for_tc(dev, msgs[0].flags)) {
++                              imx_i2c_stop(dev);
++                              imx_i2c_module_dis(dev);
++                              return -EREMOTEIO;
++                      }
++                      addr_comp = 1;
++              } else {
++                      /*
++                       * Generate repeat start only if required i.e the address
++                       * changed or the transfer direction changed
++                       */
++                      if ((msgs[i].addr != msgs[i - 1].addr) ||
++                          ((msgs[i].flags & I2C_M_RD) !=
++                           (msgs[i - 1].flags & I2C_M_RD))) {
++                              imx_i2c_repstart(dev, &msgs[i]);
++                              /* Wait for the address cycle to complete */
++                              if (imx_i2c_wait_for_tc(dev, msgs[i].flags)) {
++                                      imx_i2c_stop(dev);
++                                      imx_i2c_module_dis(dev);
++                                      return -EREMOTEIO;
++                              }
++                              addr_comp = 1;
++                      }
++              }
++
++              /* Transfer the data */
++              if (msgs[i].flags & I2C_M_RD) {
++                      /* Read the data */
++                      ret = imx_i2c_readbytes(dev, &msgs[i], (i + 1 == num),
++                                              addr_comp);
++                      if (ret < 0) {
++                              printk(KERN_ERR "imx_i2c_readbytes: fail.\n");
++                              break;
++                      }
++              } else {
++                      /* Write the data */
++                      ret = imx_i2c_writebytes(dev, &msgs[i], (i + 1 == num));
++                      if (ret < 0) {
++                              printk(KERN_ERR "imx_i2c_writebytes: fail.\n");
++                              break;
++                      }
++              }
++      }
++
++      imx_i2c_module_dis(dev);
++      return i;
++}
++
++/*
++ * Returns the i2c functionality supported by this driver.
++ * Returns the functionality that is supported.
++ */
++static u32 imx_i2c_func(struct i2c_adapter *adap)
++{
++      return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
++}
++
++/*
++ * Stores the pointers for the i2c algorithm functions. The algorithm functions
++ * is used by the i2c bus driver to talk to the i2c bus
++ */
++static struct i2c_algorithm imx_i2c_algorithm = {
++      .master_xfer = imx_i2c_xfer,
++      .functionality = imx_i2c_func
++};
++
++/*
++ * Interrupt Service Routine. It signals to the process about the data transfer
++ * completion. Also sets a flag if bus arbitration is lost.
++ * The function returns IRQ_HANDLED.
++ */
++static irqreturn_t imx_i2c_handler(int irq, void *dev_id)
++{
++      imx_i2c_device *dev = dev_id;
++      unsigned int sr, cr;
++
++      sr = __raw_readw(dev->membase + MXC_I2SR);
++      cr = __raw_readw(dev->membase + MXC_I2CR);
++
++      /*
++       * Clear the interrupt bit
++       */
++      __raw_writew(0x0, dev->membase + MXC_I2SR);
++
++      if (sr & MXC_I2SR_IAL) {
++              printk(KERN_DEBUG "Bus Arbitration lost\n");
++      } else {
++              /* Interrupt due byte transfer completion */
++              dev->tx_success = false;
++              /* Check if RXAK is received in Transmit mode */
++              if ((cr & MXC_I2CR_MTX) && (!(sr & MXC_I2SR_RXAK))) {
++                      dev->tx_success = true;
++              }
++              dev->transfer_done = true;
++              wake_up_interruptible(&dev->wq);
++      }
++
++      return IRQ_HANDLED;
++}
++
++/*
++ * This function is called to put the I2C adapter in a low power state. Refer to the
++ * document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ * The function returns 0 on success and -1 on failure.
++ */
++static int mxci2c_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      imx_i2c_device *mxcdev = platform_get_drvdata(pdev);
++      unsigned int sr;
++
++      if (mxcdev == NULL)
++              return -1;
++
++      /* Prevent further calls to be processed */
++      mxcdev->low_power = true;
++      /* Wait till we finish the current transfer */
++      sr = __raw_readw(mxcdev->membase + MXC_I2SR);
++      while (sr & MXC_I2SR_IBB) {
++              msleep(10);
++              sr = __raw_readw(mxcdev->membase + MXC_I2SR);
++      }
++
++      mxcdev->pdata->exit(pdev);
++
++      return 0;
++}
++
++/*
++ * This function is called to bring the I2C adapter back from a low power state. Refer
++ * to the document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ * The function returns 0 on success and -1 on failure
++ */
++static int mxci2c_resume(struct platform_device *pdev)
++{
++      imx_i2c_device *mxcdev = platform_get_drvdata(pdev);
++
++      if (mxcdev == NULL)
++              return -1;
++
++      mxcdev->low_power = false;
++      mxcdev->pdata->init(pdev);
++
++      return 0;
++}
++
++/*
++ * This function is called during the driver binding process.
++ * The function always returns 0.
++ */
++static int mxci2c_probe(struct platform_device *pdev)
++{
++      imx_i2c_device *imx_i2c;
++      struct imx_i2c_platform_data *i2c_plat_data = pdev->dev.platform_data;
++      struct resource *res;
++      int id = pdev->id;
++      u32 clk_freq;
++      int ret;
++      int i;
++
++      imx_i2c = kzalloc(sizeof(imx_i2c_device), GFP_KERNEL);
++      if (!imx_i2c) {
++              return -ENOMEM;
++      }
++
++      if (i2c_plat_data == NULL) {
++              dev_err(&pdev->dev, "No platform data for device!\n");
++              return -ENODEV;
++      }
++      imx_i2c->pdata = i2c_plat_data;
++      /* claim the region we will work on */
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res == NULL) {
++              ret = -ENODEV;
++              goto err1;
++      }
++      if (!request_mem_region(res->start, resource_size(res), DRV_NAME)) {
++              dev_err(&pdev->dev, "request_mem_region failed for IMX I2C %d\n", id);
++                   ret = -EBUSY;
++              goto err1;
++      }
++
++      imx_i2c->membase = ioremap(res->start, resource_size(res));
++      if (imx_i2c->membase == NULL) {
++              ret = -ENOMEM;
++              goto err2;
++      }
++      /* Claim the I2C irq line */
++      imx_i2c->irq = platform_get_irq(pdev, 0);
++      if (imx_i2c->irq < 0) {
++              dev_err(&pdev->dev, "No interrupt defined for IMX I2C %d\n", id);
++              ret = imx_i2c->irq;
++              goto err3;
++      }
++      ret = request_irq(imx_i2c->irq, imx_i2c_handler,
++                        0, DRV_NAME, imx_i2c);
++      if (ret < 0) {
++              dev_err(&pdev->dev, "Cannot claim interrupt %d for IMX I2C %d\n",
++                      imx_i2c->irq, id);
++              goto err3;
++      }
++
++      init_waitqueue_head(&imx_i2c->wq);
++
++      imx_i2c->low_power = false;
++      imx_i2c->tx_success = false;
++      imx_i2c->transfer_done = false;
++
++      imx_i2c->pdata->init(pdev);
++
++      imx_i2c->clk = clk_get(&pdev->dev, "i2c_clk");
++      if (IS_ERR(imx_i2c->clk)) {
++              ret = PTR_ERR(imx_i2c->clk);
++              dev_err(&pdev->dev, "Cannot get clock for for IMX I2C %d: %d\n", id, ret);
++              goto err4;
++      }
++
++      clk_freq = clk_get_rate(imx_i2c->clk);
++      imx_i2c->clkdiv = -1;
++      if (i2c_plat_data->max_clk) {
++              /* Calculate divider and round up any fractional part */
++              int div = (clk_freq + i2c_plat_data->max_clk - 1) /
++                      i2c_plat_data->max_clk;
++              for (i = 0; i2c_clk_table[i].div != 0; i++) {
++                      if (i2c_clk_table[i].div >= div) {
++                              imx_i2c->clkdiv = i2c_clk_table[i].reg_value;
++                              break;
++                      }
++              }
++      }
++      if (imx_i2c->clkdiv == -1) {
++              i = ARRAY_SIZE(i2c_clk_table) - 2;
++              imx_i2c->clkdiv = i2c_clk_table[i].reg_value;
++      }
++      dev_dbg(&pdev->dev, "i2c speed is %d/%d = %d bps, reg val = 0x%02X\n",
++              clk_freq, i2c_clk_table[i].div,
++              clk_freq / i2c_clk_table[i].div, imx_i2c->clkdiv);
++
++      /*
++       * Set the adapter information
++       */
++      strcpy(imx_i2c->adap.name, MXC_ADAPTER_NAME);
++      imx_i2c->adap.id = id;
++      imx_i2c->adap.nr = id;
++      imx_i2c->adap.algo = &imx_i2c_algorithm;
++      imx_i2c->adap.timeout = 1;
++      platform_set_drvdata(pdev, imx_i2c);
++      i2c_set_adapdata(&imx_i2c->adap, imx_i2c);
++      if ((ret = i2c_add_numbered_adapter(&imx_i2c->adap)) < 0) {
++              dev_err(&pdev->dev, "Cannot register the IMX I2C %d master\n", id);
++              goto err5;
++      }
++
++      return 0;
++err5:
++      clk_put(imx_i2c->clk);
++err4:
++      imx_i2c->pdata->exit(pdev);
++      free_irq(imx_i2c->irq, imx_i2c);
++err3:
++      iounmap(imx_i2c->membase);
++err2:
++      release_mem_region(res->start, resource_size(res));
++err1:
++      dev_err(&pdev->dev, "failed to probe i2c adapter\n");
++      kfree(imx_i2c);
++      return ret;
++}
++
++/*
++ * Dissociates the driver from the I2C device.
++ */
++static int mxci2c_remove(struct platform_device *pdev)
++{
++      imx_i2c_device *imx_i2c = platform_get_drvdata(pdev);
++      struct resource *res;
++
++      free_irq(imx_i2c->irq, imx_i2c);
++      i2c_del_adapter(&imx_i2c->adap);
++      imx_i2c->pdata->exit(pdev);
++      clk_put(imx_i2c->clk);
++      iounmap(imx_i2c->membase);
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      release_mem_region(res->start, resource_size(res));
++      platform_set_drvdata(pdev, NULL);
++      return 0;
++}
++
++/*
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct platform_driver mxci2c_driver = {
++      .driver = {
++              .name = DRV_NAME,
++              .owner = THIS_MODULE,
++      },
++      .probe = mxci2c_probe,
++      .remove = mxci2c_remove,
++      .suspend = mxci2c_suspend,
++      .resume = mxci2c_resume,
++};
++
++static int __init imx_i2c_init(void)
++{
++      return platform_driver_register(&mxci2c_driver);
++}
++
++static void __exit imx_i2c_exit(void)
++{
++      platform_driver_unregister(&mxci2c_driver);
++}
++
++subsys_initcall(imx_i2c_init);
++module_exit(imx_i2c_exit);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MXC I2C driver");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/Kconfig linux-2.6.28-karo/drivers/media/video/Kconfig
+--- linux-2.6.28/drivers/media/video/Kconfig   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/Kconfig      2009-03-11 13:16:24.000000000 +0100
+@@ -531,6 +531,33 @@ config VIDEO_W9966
+         Check out <file:Documentation/video4linux/w9966.txt> for more
+         information.
++config VIDEO_MXC_CAMERA
++      tristate "MXC Video For Linux Camera"
++      depends on VIDEO_DEV && ARCH_MXC
++      default y
++      ---help---
++        This is the video4linux2 capture driver based on MXC IPU/eMMA module.
++
++source "drivers/media/video/mxc/capture/Kconfig"
++
++config VIDEO_MXC_OUTPUT
++      tristate "MXC Video For Linux Video Output"
++      depends on VIDEO_DEV && ARCH_MXC
++      default y
++      ---help---
++        This is the video4linux2 output driver based on MXC IPU/eMMA module.
++
++source "drivers/media/video/mxc/output/Kconfig"
++
++config VIDEO_MXC_OPL
++      tristate
++      depends on VIDEO_DEV && ARCH_MXC
++      default n
++      ---help---
++        This is the ARM9-optimized OPL (Open Primitives Library) software
++        rotation/mirroring implementation. It may be used by eMMA video
++        capture or output device.
++
+ config VIDEO_CPIA
+       tristate "CPiA Video For Linux"
+       depends on VIDEO_V4L1
+@@ -893,4 +920,12 @@ config USB_S2255
+ endif # V4L_USB_DRIVERS
++config VIDEO_MX27
++      tristate "i.MX27 Quick Capture Interface driver"
++      depends on VIDEO_DEV && MACH_MX27
++      select SOC_CAMERA
++      select VIDEOBUF_DMA_CONTIG
++      ---help---
++        This is a v4l2 driver for the i.MX27 Capture Interface
++
+ endif # VIDEO_CAPTURE_DRIVERS
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/Makefile linux-2.6.28-karo/drivers/media/video/Makefile
+--- linux-2.6.28/drivers/media/video/Makefile  2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/Makefile     2009-03-11 13:16:24.000000000 +0100
+@@ -57,6 +57,11 @@ obj-$(CONFIG_VIDEO_ZORAN) += zoran/
+ obj-$(CONFIG_VIDEO_PMS) += pms.o
+ obj-$(CONFIG_VIDEO_VINO) += vino.o indycam.o
+ obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
++obj-$(CONFIG_VIDEO_MXC_IPU_CAMERA) += mxc/capture/
++obj-$(CONFIG_VIDEO_MXC_EMMA_CAMERA) += mxc/capture/
++obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT) += mxc/output/
++obj-$(CONFIG_VIDEO_MXC_EMMA_OUTPUT) += mxc/output/
++obj-$(CONFIG_VIDEO_MXC_OPL) += mxc/opl/
+ obj-$(CONFIG_VIDEO_CPIA) += cpia.o
+ obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
+ obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
+@@ -128,6 +133,7 @@ obj-$(CONFIG_VIDEO_VIVI) += vivi.o
+ obj-$(CONFIG_VIDEO_CX23885) += cx23885/
+ obj-$(CONFIG_VIDEO_PXA27x)    += pxa_camera.o
++obj-$(CONFIG_VIDEO_MX27)      += mx27_camera.o
+ obj-$(CONFIG_VIDEO_SH_MOBILE_CEU)     += sh_mobile_ceu_camera.o
+ obj-$(CONFIG_SOC_CAMERA)      += soc_camera.o
+ obj-$(CONFIG_SOC_CAMERA_MT9M001)      += mt9m001.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mx27_camera.c linux-2.6.28-karo/drivers/media/video/mx27_camera.c
+--- linux-2.6.28/drivers/media/video/mx27_camera.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mx27_camera.c        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,1185 @@
++/*
++ * V4L2 Driver for MX27 camera host
++ *
++ * Copyright (C) 2008, Sascha Hauer, Pengutronix
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/errno.h>
++#include <linux/fs.h>
++#include <linux/interrupt.h>
++#include <linux/kernel.h>
++#include <linux/mm.h>
++#include <linux/moduleparam.h>
++#include <linux/time.h>
++#include <linux/version.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/mutex.h>
++#include <linux/clk.h>
++
++#include <media/v4l2-common.h>
++#include <media/v4l2-dev.h>
++#include <media/videobuf-dma-contig.h>
++#include <media/soc_camera.h>
++
++#include <linux/videodev2.h>
++
++#include <mach/imx_cam.h>
++#include <asm/dma.h>
++#include <mach/dma-mx1-mx2.h>
++
++#include <asm/dma.h>
++
++#define MX27_CAM_DRV_NAME "mx27-camera"
++#define MX27_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5) /* FIXME: Whats this? */
++
++static const char *mx27_cam_driver_description = "i.MX27_Camera";
++
++/* reset values */
++#define CSICR1_RESET_VAL      0x40000800
++#define CSICR2_RESET_VAL      0x0
++#define CSICR3_RESET_VAL      0x0
++
++/* csi control reg 1 */
++#define CSICR1_SWAP16_EN      (1 << 31)
++#define CSICR1_EXT_VSYNC      (1 << 30)
++#define CSICR1_EOF_INTEN      (1 << 29)
++#define CSICR1_PRP_IF_EN      (1 << 28)
++#define CSICR1_CCIR_MODE      (1 << 27)
++#define CSICR1_COF_INTEN      (1 << 26)
++#define CSICR1_SF_OR_INTEN    (1 << 25)
++#define CSICR1_RF_OR_INTEN    (1 << 24)
++#define CSICR1_STATFF_LEVEL   (3 << 22)
++#define CSICR1_STATFF_INTEN   (1 << 21)
++#define CSICR1_RXFF_LEVEL(l)  (((l) & 3) << 19)
++#define CSICR1_RXFF_INTEN     (1 << 18)
++#define CSICR1_SOF_POL                (1 << 17)
++#define CSICR1_SOF_INTEN      (1 << 16)
++#define CSICR1_MCLKDIV(d)     (((d) & 0xF) << 12)
++#define CSICR1_HSYNC_POL      (1 << 11)
++#define CSICR1_CCIR_EN                (1 << 10)
++#define CSICR1_MCLKEN         (1 << 9)
++#define CSICR1_FCC            (1 << 8)
++#define CSICR1_PACK_DIR               (1 << 7)
++#define CSICR1_CLR_STATFIFO   (1 << 6)
++#define CSICR1_CLR_RXFIFO     (1 << 5)
++#define CSICR1_GCLK_MODE      (1 << 4)
++#define CSICR1_INV_DATA               (1 << 3)
++#define CSICR1_INV_PCLK               (1 << 2)
++#define CSICR1_REDGE          (1 << 1)
++
++#define SHIFT_STATFF_LEVEL    22
++#define SHIFT_RXFF_LEVEL      19
++#define SHIFT_MCLKDIV         12
++
++/* control reg 3 */
++#define CSICR3_FRMCNT         (0xFFFF << 16)
++#define CSICR3_FRMCNT_RST     (1 << 15)
++#define CSICR3_CSI_SUP                (1 << 3)
++#define CSICR3_ZERO_PACK_EN   (1 << 2)
++#define CSICR3_ECC_INT_EN     (1 << 1)
++#define CSICR3_ECC_AUTO_EN    (1 << 0)
++
++#define SHIFT_FRMCNT          16
++
++/* csi status reg */
++#define CSISR_SFF_OR_INT      (1 << 25)
++#define CSISR_RFF_OR_INT      (1 << 24)
++#define CSISR_STATFF_INT      (1 << 21)
++#define CSISR_RXFF_INT                (1 << 18)
++#define CSISR_EOF_INT         (1 << 17)
++#define CSISR_SOF_INT         (1 << 16)
++#define CSISR_F2_INT          (1 << 15)
++#define CSISR_F1_INT          (1 << 14)
++#define CSISR_COF_INT         (1 << 13)
++#define CSISR_ECC_INT         (1 << 1)
++#define CSISR_DRDY            (1 << 0)
++
++#define CSICR1                0x00
++#define CSICR2                0x04
++#define CSISR         0x08
++#define CSISTATFIFO   0x0c
++#define CSIRFIFO      0x10
++#define CSIRXCNT      0x14
++#define CSICR3                0x1C
++
++/* EMMA PrP */
++#define PRP_CNTL                      0x00
++#define PRP_INTR_CNTL                 0x04
++#define PRP_INTRSTATUS                        0x08
++#define PRP_SOURCE_Y_PTR              0x0c
++#define PRP_SOURCE_CB_PTR             0x10
++#define PRP_SOURCE_CR_PTR             0x14
++#define PRP_DEST_RGB1_PTR             0x18
++#define PRP_DEST_RGB2_PTR             0x1c
++#define PRP_DEST_Y_PTR                        0x20
++#define PRP_DEST_CB_PTR                       0x24
++#define PRP_DEST_CR_PTR                       0x28
++#define PRP_SRC_FRAME_SIZE            0x2c
++#define PRP_DEST_CH1_LINE_STRIDE      0x30
++#define PRP_SRC_PIXEL_FORMAT_CNTL     0x34
++#define PRP_CH1_PIXEL_FORMAT_CNTL     0x38
++#define PRP_CH1_OUT_IMAGE_SIZE                0x3c
++#define PRP_CH2_OUT_IMAGE_SIZE                0x40
++#define PRP_SRC_LINE_STRIDE           0x44
++#define PRP_CSC_COEF_012              0x48
++#define PRP_CSC_COEF_345              0x4c
++#define PRP_CSC_COEF_678              0x50
++#define PRP_CH1_RZ_HORI_COEF1         0x54
++#define PRP_CH1_RZ_HORI_COEF2         0x58
++#define PRP_CH1_RZ_HORI_VALID         0x5c
++#define PRP_CH1_RZ_VERT_COEF1         0x60
++#define PRP_CH1_RZ_VERT_COEF2         0x64
++#define PRP_CH1_RZ_VERT_VALID         0x68
++#define PRP_CH2_RZ_HORI_COEF1         0x6c
++#define PRP_CH2_RZ_HORI_COEF2         0x70
++#define PRP_CH2_RZ_HORI_VALID         0x74
++#define PRP_CH2_RZ_VERT_COEF1         0x78
++#define PRP_CH2_RZ_VERT_COEF2         0x7c
++#define PRP_CH2_RZ_VERT_VALID         0x80
++
++#define PRP_CNTL_CH1EN                (1 << 0)
++#define PRP_CNTL_CH2EN                (1 << 1)
++#define PRP_CNTL_CSIEN                (1 << 2)
++#define PRP_CNTL_DATA_IN_YUV420       (0 << 3)
++#define PRP_CNTL_DATA_IN_YUV422       (1 << 3)
++#define PRP_CNTL_DATA_IN_RGB16        (2 << 3)
++#define PRP_CNTL_DATA_IN_RGB32        (3 << 3)
++#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5)
++#define PRP_CNTL_CH1_OUT_RGB16        (1 << 5)
++#define PRP_CNTL_CH1_OUT_RGB32        (2 << 5)
++#define PRP_CNTL_CH1_OUT_YUV422       (3 << 5)
++#define PRP_CNTL_CH2_OUT_YUV420       (0 << 7)
++#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
++#define PRP_CNTL_CH2_OUT_YUV444       (2 << 7)
++#define PRP_CNTL_CH1_LEN      (1 << 9)
++#define PRP_CNTL_CH2_LEN      (1 << 10)
++#define PRP_CNTL_SKIP_FRAME   (1 << 11)
++#define PRP_CNTL_SWRST                (1 << 12)
++#define PRP_CNTL_CLKEN                (1 << 13)
++#define PRP_CNTL_WEN          (1 << 14)
++#define PRP_CNTL_CH1BYP               (1 << 15)
++#define PRP_CNTL_IN_TSKIP(x)  ((x) << 16)
++#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19)
++#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22)
++#define PRP_CNTL_INPUT_FIFO_LEVEL(x)  ((x) << 25)
++#define PRP_CNTL_RZ_FIFO_LEVEL(x)     ((x) << 27)
++#define PRP_CNTL_CH2B1EN      (1 << 29)
++#define PRP_CNTL_CH2B2EN      (1 << 30)
++#define PRP_CNTL_CH2FEN               (1 << 31)
++
++/* IRQ Enable and status register */
++#define PRP_INTR_RDERR                (1 << 0)
++#define PRP_INTR_CH1WERR      (1 << 1)
++#define PRP_INTR_CH2WERR      (1 << 2)
++#define PRP_INTR_CH1FC                (1 << 3)
++#define PRP_INTR_CH2FC                (1 << 5)
++#define PRP_INTR_LBOVF                (1 << 7)
++#define PRP_INTR_CH2OVF               (1 << 8)
++
++#define mx27_camera_emma(pcdev)       (pcdev->use_emma)
++
++/* Currently we do not need irqs. All we need is DMA callback
++ * Leave it here for reference for some time.
++ */
++#undef MX27_CAMERA_USE_IRQ
++
++struct mx27_camera_dev {
++      struct device           *dev;
++      struct soc_camera_device *icd;
++      struct clk              *clk_csi, *clk_emma;
++
++      unsigned int            irq_csi, irq_emma;
++      void __iomem            *base_csi, *base_emma;
++
++      struct mx27_camera_platform_data *pdata;
++      struct resource         *res_csi, *res_emma;
++      unsigned long           platform_flags;
++
++      struct list_head        capture;
++      struct list_head        active_bufs;
++
++      spinlock_t              lock;
++
++      int                     dma;
++      struct mx27_buffer      *active;
++
++      int                     use_emma;
++
++      unsigned int            csicr1;
++
++      void __iomem            *discard_buffer;
++      dma_addr_t              discard_buffer_dma;
++      size_t                  discard_size;
++};
++
++/* buffer for one video frame */
++struct mx27_buffer {
++      /* common v4l buffer stuff -- must be first */
++      struct videobuf_buffer vb;
++
++      const struct soc_camera_data_format        *fmt;
++
++      int bufnum;
++};
++
++static DEFINE_MUTEX(camera_lock);
++
++static int mclk_get_divisor(struct mx27_camera_dev *pcdev)
++{
++      dev_info(pcdev->dev, "%s not implemented. Running at max speed\n",
++                      __func__);
++
++#if 0
++      unsigned int mclk = pcdev->pdata->clk_csi;
++      unsigned int pclk = clk_get_rate(pcdev->clk_csi);
++      int i;
++
++      dev_dbg(pcdev->dev, "%s: %ld %ld\n", __func__, mclk, pclk);
++
++      for (i = 0; i < 0xf; i++)
++              if ((i + 1) * 2 * mclk <= pclk)
++                      break;
++      return i;
++#endif
++      return 0;
++}
++
++static void mx27_camera_deactivate(struct mx27_camera_dev *pcdev)
++{
++      clk_disable(pcdev->clk_csi);
++      writel(0, pcdev->base_csi + CSICR1);
++      if (mx27_camera_emma(pcdev))
++              writel(0, pcdev->base_emma + PRP_CNTL);
++}
++
++/* The following two functions absolutely depend on the fact, that
++ * there can be only one camera on mx27 quick capture interface */
++static int mx27_camera_add_device(struct soc_camera_device *icd)
++{
++      struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++      struct mx27_camera_dev *pcdev = ici->priv;
++      int ret;
++      u32 csicr1;
++
++      mutex_lock(&camera_lock);
++
++      if (pcdev->icd) {
++              ret = -EBUSY;
++              goto ebusy;
++      }
++
++      dev_info(&icd->dev, "Camera driver attached to camera %d\n",
++               icd->devnum);
++
++      clk_enable(pcdev->clk_csi);
++
++      csicr1 = CSICR1_MCLKDIV(mclk_get_divisor(pcdev)) |
++                      CSICR1_MCLKEN;
++      if (mx27_camera_emma(pcdev)) {
++              csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
++                      CSICR1_RXFF_LEVEL(0);
++      } else
++              csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2);
++
++      pcdev->csicr1 = csicr1;
++      writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
++
++      ret = icd->ops->init(icd);
++
++      if (!ret)
++              pcdev->icd = icd;
++
++ebusy:
++      mutex_unlock(&camera_lock);
++
++      return ret;
++}
++
++static void mx27_camera_remove_device(struct soc_camera_device *icd)
++{
++      struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++      struct mx27_camera_dev *pcdev = ici->priv;
++
++      BUG_ON(icd != pcdev->icd);
++
++      dev_info(&icd->dev, "Camera driver detached from camera %d\n",
++               icd->devnum);
++
++      icd->ops->release(icd);
++
++      mx27_camera_deactivate(pcdev);
++
++      if (pcdev->discard_buffer) {
++              dma_free_coherent(NULL, pcdev->discard_size,
++                              pcdev->discard_buffer,
++                              pcdev->discard_buffer_dma);
++      }
++      pcdev->discard_buffer = 0;
++
++      pcdev->icd = NULL;
++}
++
++static void mx27_camera_dma_enable(struct mx27_camera_dev *pcdev)
++{
++      u32 tmp;
++
++      imx_dma_enable(pcdev->dma);
++
++      tmp = readl(pcdev->base_csi + CSICR1);
++      tmp |= CSICR1_RF_OR_INTEN;
++      writel(tmp, pcdev->base_csi + CSICR1);
++}
++
++static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
++{
++      struct mx27_camera_dev *pcdev = data;
++      u32 status = readl(pcdev->base_csi + CSISR);
++
++      if (status & CSISR_SOF_INT && pcdev->active) {
++              u32 tmp;
++
++              tmp = readl(pcdev->base_csi + CSICR1);
++              tmp |= CSICR1_CLR_RXFIFO;
++              writel(tmp, pcdev->base_csi + CSICR1);
++              mx27_camera_dma_enable(pcdev);
++              writel(CSISR_SOF_INT | CSISR_RFF_OR_INT,
++                              pcdev->base_csi + CSISR);
++              status &= ~CSISR_RFF_OR_INT;
++      }
++
++      writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR);
++
++      return IRQ_HANDLED;
++}
++
++static unsigned int vid_limit = 16;   /* Video memory limit, in Mb */
++
++/*
++ *  Videobuf operations
++ */
++static int mx27_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
++                            unsigned int *size)
++{
++      struct soc_camera_device *icd = vq->priv_data;
++
++      dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
++
++      *size = icd->width * icd->height *
++              ((icd->current_fmt->depth + 7) >> 3);
++
++      if (0 == *count)
++              *count = 32;
++      while (*size * *count > vid_limit * 1024 * 1024)
++              (*count)--;
++
++      return 0;
++}
++
++static void free_buffer(struct videobuf_queue *vq, struct mx27_buffer *buf)
++{
++      struct soc_camera_device *icd = vq->priv_data;
++
++      BUG_ON(in_interrupt());
++
++      dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
++              &buf->vb, buf->vb.baddr, buf->vb.bsize);
++
++      /* This waits until this buffer is out of danger, i.e., until it is no
++       * longer in STATE_QUEUED or STATE_ACTIVE */
++      videobuf_waiton(&buf->vb, 0, 0);
++
++      videobuf_dma_contig_free(vq, &buf->vb);
++      dev_dbg(&icd->dev, "%s freed\n", __func__);
++
++      buf->vb.state = VIDEOBUF_NEEDS_INIT;
++}
++
++static int mx27_videobuf_prepare(struct videobuf_queue *vq,
++              struct videobuf_buffer *vb, enum v4l2_field field)
++{
++      struct soc_camera_device *icd = vq->priv_data;
++      struct mx27_buffer *buf = container_of(vb, struct mx27_buffer, vb);
++      int ret = 0;
++
++#ifdef DEBUG
++      /* This can be useful if you want to see if we actually fill
++       * the buffer with something */
++      memset((void *)vb->baddr, 0xaa, vb->bsize);
++#endif
++
++      dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
++              vb, vb->baddr, vb->bsize);
++
++      if (buf->fmt    != icd->current_fmt ||
++          vb->width   != icd->width ||
++          vb->height  != icd->height ||
++          vb->field   != field) {
++              buf->fmt        = icd->current_fmt;
++              vb->width       = icd->width;
++              vb->height      = icd->height;
++              vb->field       = field;
++              vb->state       = VIDEOBUF_NEEDS_INIT;
++      }
++
++      vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3);
++      if (vb->baddr && vb->bsize < vb->size) {
++              ret = -EINVAL;
++              goto out;
++      }
++
++      if (vb->state == VIDEOBUF_NEEDS_INIT) {
++              ret = videobuf_iolock(vq, vb, NULL);
++              if (ret)
++                      goto fail;
++
++              vb->state = VIDEOBUF_PREPARED;
++      }
++
++      return 0;
++
++fail:
++      free_buffer(vq, buf);
++out:
++      return ret;
++}
++
++static void mx27_videobuf_queue(struct videobuf_queue *vq,
++                             struct videobuf_buffer *vb)
++{
++      struct soc_camera_device *icd = vq->priv_data;
++      struct soc_camera_host *ici =
++              to_soc_camera_host(icd->dev.parent);
++      struct mx27_camera_dev *pcdev = ici->priv;
++      struct mx27_buffer *buf = container_of(vb, struct mx27_buffer, vb);
++      unsigned long flags;
++      int ret;
++
++      dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
++              vb, vb->baddr, vb->bsize);
++
++      spin_lock_irqsave(&pcdev->lock, flags);
++
++      if (mx27_camera_emma(pcdev)) {
++              list_add_tail(&vb->queue, &pcdev->capture);
++              vb->state = VIDEOBUF_QUEUED;
++      } else {
++              list_add_tail(&vb->queue, &pcdev->capture);
++              vb->state = VIDEOBUF_ACTIVE;
++
++              if (!pcdev->active) {
++                      ret = imx_dma_setup_single(pcdev->dma,
++                                      videobuf_to_dma_contig(vb), vb->size,
++                                      CSI_BASE_ADDR + 0x10, DMA_MODE_READ);
++                      if (ret) {
++                              vb->state = VIDEOBUF_ERROR;
++                              wake_up(&vb->done);
++                              goto out;
++                      }
++
++                      pcdev->active = buf;
++              }
++      }
++
++out:
++      spin_unlock_irqrestore(&pcdev->lock, flags);
++}
++
++static void mx27_videobuf_release(struct videobuf_queue *vq,
++                               struct videobuf_buffer *vb)
++{
++      struct mx27_buffer *buf = container_of(vb, struct mx27_buffer, vb);
++
++#ifdef DEBUG
++      struct soc_camera_device *icd = vq->priv_data;
++
++      dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
++              vb, vb->baddr, vb->bsize);
++
++      switch (vb->state) {
++      case VIDEOBUF_ACTIVE:
++              dev_info(&icd->dev, "%s (active)\n", __func__);
++              break;
++      case VIDEOBUF_QUEUED:
++              dev_info(&icd->dev, "%s (queued)\n", __func__);
++              break;
++      case VIDEOBUF_PREPARED:
++              dev_info(&icd->dev, "%s (prepared)\n", __func__);
++              break;
++      default:
++              dev_info(&icd->dev, "%s (unknown) %d\n", __func__,
++                              vb->state);
++              break;
++      }
++#endif
++
++      free_buffer(vq, buf);
++}
++
++static struct videobuf_queue_ops mx27_videobuf_ops = {
++      .buf_setup      = mx27_videobuf_setup,
++      .buf_prepare    = mx27_videobuf_prepare,
++      .buf_queue      = mx27_videobuf_queue,
++      .buf_release    = mx27_videobuf_release,
++};
++
++static void mx27_camera_init_videobuf(struct videobuf_queue *q,
++                            struct soc_camera_device *icd)
++{
++      struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
++      struct mx27_camera_dev *pcdev = ici->priv;
++
++      /* We must pass NULL as dev pointer, then all pci_* dma operations
++       * transform to normal dma_* ones. */
++      videobuf_queue_dma_contig_init(q, &mx27_videobuf_ops, NULL,
++                      &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
++                      V4L2_FIELD_NONE, sizeof(struct mx27_buffer), icd);
++}
++
++#define MX27_BUS_FLAGS        (SOCAM_DATAWIDTH_8 | \
++                      SOCAM_MASTER | \
++                      SOCAM_VSYNC_ACTIVE_HIGH | \
++                      SOCAM_HSYNC_ACTIVE_HIGH | \
++                      SOCAM_HSYNC_ACTIVE_LOW | \
++                      SOCAM_PCLK_SAMPLE_RISING | \
++                      SOCAM_PCLK_SAMPLE_FALLING)
++
++static int mx27_camera_emma_prp_reset(struct mx27_camera_dev *pcdev)
++{
++      unsigned int cntl;
++
++      cntl = readl(pcdev->base_emma + PRP_CNTL);
++      writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
++      while (readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST)
++              barrier();
++
++      return 0;
++}
++
++static int mx27_camera_set_bus_param(struct soc_camera_device *icd,
++              __u32 pixfmt)
++{
++      struct soc_camera_host *ici =
++              to_soc_camera_host(icd->dev.parent);
++      struct mx27_camera_dev *pcdev = ici->priv;
++      unsigned long camera_flags, common_flags;
++      int ret = 0;
++      u32 csicr1 = pcdev->csicr1;
++
++      camera_flags = icd->ops->query_bus_param(icd);
++
++      common_flags = soc_camera_bus_param_compatible(camera_flags,
++                              MX27_BUS_FLAGS);
++      if (!common_flags)
++              return -EINVAL;
++
++      if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
++          (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
++              if (pcdev->platform_flags & MX27_CAMERA_HSYNC_HIGH)
++                      common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
++              else
++                      common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
++      }
++
++      if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
++          (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
++              if (pcdev->platform_flags & MX27_CAMERA_PCLK_SAMPLE_RISING)
++                      common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
++              else
++                      common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
++      }
++
++      ret = icd->ops->set_bus_param(icd, common_flags);
++      if (ret < 0)
++              return ret;
++
++      if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
++              csicr1 |= CSICR1_INV_PCLK;
++      if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH)
++              csicr1 |= CSICR1_HSYNC_POL;
++      if (pcdev->platform_flags & MX27_CAMERA_SWAP16)
++              csicr1 |= CSICR1_SWAP16_EN;
++      if (pcdev->platform_flags & MX27_CAMERA_EXT_VSYNC)
++              csicr1 |= CSICR1_EXT_VSYNC;
++      if (pcdev->platform_flags & MX27_CAMERA_CCIR)
++              csicr1 |= CSICR1_CCIR_EN;
++      if (pcdev->platform_flags & MX27_CAMERA_CCIR_INTERLACE)
++              csicr1 |= CSICR1_CCIR_MODE;
++      if (pcdev->platform_flags & MX27_CAMERA_GATED_CLOCK)
++              csicr1 |= CSICR1_GCLK_MODE;
++      if (pcdev->platform_flags & MX27_CAMERA_INV_DATA)
++              csicr1 |= CSICR1_INV_DATA;
++      if (pcdev->platform_flags & MX27_CAMERA_PACK_DIR_MSB)
++              csicr1 |= CSICR1_PACK_DIR;
++
++      if (mx27_camera_emma(pcdev)) {
++              int bytesperline = (icd->width * icd->current_fmt->depth) >> 3;
++
++              if (mx27_camera_emma_prp_reset(pcdev))
++                      return -ENODEV;
++
++              if (pcdev->discard_buffer)
++                      dma_free_coherent(NULL, pcdev->discard_size,
++                              pcdev->discard_buffer,
++                              pcdev->discard_buffer_dma);
++
++              /* I didn't manage to properly enable/disable the prp
++               * on a per frame basis during running transfers,
++               * thus we allocate a buffer here and use it to
++               * discard frames when no buffer is available.
++               * Feel free to work on this ;)
++               */
++              pcdev->discard_size = icd->height * bytesperline;
++              pcdev->discard_buffer = dma_alloc_coherent(NULL,
++                              pcdev->discard_size, &pcdev->discard_buffer_dma,
++                              GFP_KERNEL);
++              if (!pcdev->discard_buffer)
++                      return -ENOMEM;
++
++              writel(pcdev->discard_buffer_dma,
++                              pcdev->base_emma + PRP_DEST_RGB1_PTR);
++              writel(pcdev->discard_buffer_dma,
++                              pcdev->base_emma + PRP_DEST_RGB2_PTR);
++
++              /* We only use the EMMA engine to get rid of the f**king
++               * DMA Engine. No color space consversion at the moment.
++               * We adjust incoming and outgoing pixelformat to rgb16
++               * and adjust the bytesperline accordingly.
++               */
++              writel(PRP_CNTL_CH1EN |
++                      PRP_CNTL_CSIEN |
++                      PRP_CNTL_DATA_IN_RGB16 |
++                      PRP_CNTL_CH1_OUT_RGB16 |
++                      PRP_CNTL_CH1_LEN |
++                      PRP_CNTL_CH1BYP |
++                      PRP_CNTL_CH1_TSKIP(0) |
++                      PRP_CNTL_IN_TSKIP(0),
++                      pcdev->base_emma + PRP_CNTL);
++
++              writel(((bytesperline >> 1) << 16) | icd->height,
++                              pcdev->base_emma + PRP_SRC_FRAME_SIZE);
++              writel(((bytesperline >> 1) << 16) | icd->height,
++                              pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
++              writel(bytesperline,
++                              pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
++              writel(0x2ca00565,
++                              pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
++              writel(0x2ca00565,
++                              pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
++
++              /* Enable interrupts */
++              writel(PRP_INTR_RDERR |
++                      PRP_INTR_CH1WERR |
++                      PRP_INTR_CH2WERR |
++                      PRP_INTR_CH1FC |
++                      PRP_INTR_CH2FC |
++                      PRP_INTR_LBOVF |
++                      PRP_INTR_CH2OVF
++                      , pcdev->base_emma + PRP_INTR_CNTL);
++      }
++
++      pcdev->csicr1 = csicr1;
++
++      writel(csicr1, pcdev->base_csi + CSICR1);
++
++      return 0;
++}
++
++static int mx27_camera_try_bus_param(struct soc_camera_device *icd,
++              __u32 pixfmt)
++{
++      unsigned long bus_flags, camera_flags;
++
++      bus_flags = MX27_BUS_FLAGS;
++
++      camera_flags = icd->ops->query_bus_param(icd);
++
++      return soc_camera_bus_param_compatible(camera_flags, bus_flags) ?
++                              0 : -EINVAL;
++}
++
++static int mx27_camera_set_fmt_cap(struct soc_camera_device *icd,
++                                __u32 pixfmt, struct v4l2_rect *rect)
++{
++      return icd->ops->set_fmt_cap(icd, pixfmt, rect);
++}
++
++static int mx27_camera_try_fmt_cap(struct soc_camera_device *icd,
++                                struct v4l2_format *f)
++{
++      return 0;
++}
++
++static int mx27_camera_querycap(struct soc_camera_host *ici,
++                             struct v4l2_capability *cap)
++{
++      /* cap->name is set by the friendly caller:-> */
++      strlcpy(cap->card, mx27_cam_driver_description, sizeof(cap->card));
++      cap->version = MX27_CAM_VERSION_CODE;
++      cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
++
++      return 0;
++}
++
++static int mx27_camera_reqbufs(struct soc_camera_file *icf,
++                            struct v4l2_requestbuffers *p)
++{
++      int i;
++
++      for (i = 0; i < p->count; i++) {
++              struct mx27_buffer *buf = container_of(icf->vb_vidq.bufs[i],
++                                                    struct mx27_buffer, vb);
++              INIT_LIST_HEAD(&buf->vb.queue);
++      }
++
++      return 0;
++}
++
++static void mx27_camera_frame_done(struct mx27_camera_dev *pcdev, int state)
++{
++      struct videobuf_buffer *vb;
++      struct mx27_buffer *buf;
++      int ret;
++
++      if (!pcdev->active) {
++              dev_err(pcdev->dev, "%s called with no active buffer!\n",
++                              __func__);
++              return;
++      }
++
++      vb = &pcdev->active->vb;
++      buf = container_of(vb, struct mx27_buffer, vb);
++      WARN_ON(list_empty(&vb->queue));
++      dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
++              vb, vb->baddr, vb->bsize);
++
++      /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
++      list_del_init(&vb->queue);
++      vb->state = state;
++      do_gettimeofday(&vb->ts);
++      vb->field_count++;
++
++      wake_up(&vb->done);
++
++      if (list_empty(&pcdev->capture)) {
++              pcdev->active = NULL;
++              return;
++      }
++
++      pcdev->active = list_entry(pcdev->capture.next,
++                      struct mx27_buffer, vb.queue);
++
++      vb = &pcdev->active->vb;
++      vb->state = VIDEOBUF_ACTIVE;
++
++      ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb),
++                      vb->size, CSI_BASE_ADDR + 0x10, DMA_MODE_READ);
++      if (ret) {
++              vb->state = VIDEOBUF_ERROR;
++              wake_up(&vb->done);
++              return;
++      }
++}
++
++static void mx27_camera_dma_err_callback(int channel, void *data, int err)
++{
++      struct mx27_camera_dev *pcdev = data;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pcdev->lock, flags);
++
++      mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR);
++
++      spin_unlock_irqrestore(&pcdev->lock, flags);
++}
++
++static void mx27_camera_dma_callback(int channel, void *data)
++{
++      struct mx27_camera_dev *pcdev = data;
++      unsigned long flags;
++
++      spin_lock_irqsave(&pcdev->lock, flags);
++
++      mx27_camera_frame_done(pcdev, VIDEOBUF_DONE);
++
++      spin_unlock_irqrestore(&pcdev->lock, flags);
++}
++
++static unsigned int mx27_camera_poll(struct file *file, poll_table *pt)
++{
++      struct soc_camera_file *icf = file->private_data;
++      struct mx27_buffer *buf;
++
++      buf = list_entry(icf->vb_vidq.stream.next, struct mx27_buffer,
++                       vb.stream);
++
++      poll_wait(file, &buf->vb.done, pt);
++
++      if (buf->vb.state == VIDEOBUF_DONE ||
++          buf->vb.state == VIDEOBUF_ERROR)
++              return POLLIN | POLLRDNORM;
++
++      return 0;
++}
++
++/* Should beallocated dynamically too, but we have only one. */
++static struct soc_camera_host_ops mx27_soc_camera_host_ops = {
++      .owner          = THIS_MODULE,
++      .add            = mx27_camera_add_device,
++      .remove         = mx27_camera_remove_device,
++      .set_fmt_cap    = mx27_camera_set_fmt_cap,
++      .try_fmt_cap    = mx27_camera_try_fmt_cap,
++      .init_videobuf  = mx27_camera_init_videobuf,
++      .reqbufs        = mx27_camera_reqbufs,
++      .poll           = mx27_camera_poll,
++      .querycap       = mx27_camera_querycap,
++      .try_bus_param  = mx27_camera_try_bus_param,
++      .set_bus_param  = mx27_camera_set_bus_param,
++};
++
++static void mx27_camera_frame_done_emma(struct mx27_camera_dev *pcdev,
++              int bufnum, int state)
++{
++      struct mx27_buffer *buf;
++      struct videobuf_buffer *vb;
++      unsigned long phys;
++
++      if (!list_empty(&pcdev->active_bufs)) {
++              buf = list_entry(pcdev->active_bufs.next,
++                      struct mx27_buffer, vb.queue);
++
++              if (buf->bufnum == bufnum) {
++                      vb = &buf->vb;
++#ifdef DEBUG
++                      phys = videobuf_to_dma_contig(vb);
++                      if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR +
++                                              4 * bufnum) != phys) {
++                              dev_err(pcdev->dev, "%p != %p\n", phys,
++                                              readl(pcdev->base_emma +
++                                              PRP_DEST_RGB1_PTR +
++                                              4 * bufnum));
++                      }
++#endif
++                      dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n",
++                                      __func__, vb, vb->baddr, vb->bsize);
++
++                      list_del(&vb->queue);
++                      vb->state = state;
++                      do_gettimeofday(&vb->ts);
++                      vb->field_count++;
++
++                      wake_up(&vb->done);
++              }
++      }
++
++      if (list_empty(&pcdev->capture)) {
++              writel(pcdev->discard_buffer_dma, pcdev->base_emma +
++                              PRP_DEST_RGB1_PTR + 4 * bufnum);
++              return;
++      }
++
++      buf = list_entry(pcdev->capture.next,
++                      struct mx27_buffer, vb.queue);
++
++      buf->bufnum = bufnum;
++
++      list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
++
++      vb = &buf->vb;
++      vb->state = VIDEOBUF_ACTIVE;
++
++      phys = videobuf_to_dma_contig(vb);
++      writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
++}
++
++static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
++{
++      struct mx27_camera_dev *pcdev = data;
++      unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS);
++
++      if (status & (1 << 6))
++              mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
++      if (status & (1 << 5))
++              mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
++      if (status & (1 << 7)) {
++              uint32_t cntl;
++              cntl = readl(pcdev->base_emma + PRP_CNTL);
++              writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL);
++              writel(cntl, pcdev->base_emma + PRP_CNTL);
++      }
++
++      writel(status, pcdev->base_emma + PRP_INTRSTATUS);
++
++      return IRQ_HANDLED;
++}
++
++/* Should be allocated dynamically too, but we have only one. */
++static struct soc_camera_host mx27_soc_camera_host = {
++      .drv_name               = MX27_CAM_DRV_NAME,
++      .ops                    = &mx27_soc_camera_host_ops,
++};
++
++int mx27_camera_emma_init(struct mx27_camera_dev *pcdev)
++{
++      struct resource *res_emma = pcdev->res_emma;
++      int err = 0;
++
++      if (!request_mem_region(res_emma->start, resource_size(res_emma),
++                              MX27_CAM_DRV_NAME)) {
++              err = -EBUSY;
++              goto out;
++      }
++
++      pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma));
++      if (!pcdev->base_emma) {
++              err = -ENOMEM;
++              goto exit_release;
++      }
++
++      err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0,
++                      MX27_CAM_DRV_NAME, pcdev);
++      if (err) {
++              dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n");
++              goto exit_iounmap;
++      }
++
++      pcdev->clk_emma = clk_get(pcdev->dev, "emma_clk");
++      if (IS_ERR(pcdev->clk_emma)) {
++              err = PTR_ERR(pcdev->clk_emma);
++              goto exit_free_irq;
++      }
++
++      clk_enable(pcdev->clk_emma);
++
++      err = mx27_camera_emma_prp_reset(pcdev);
++      if (err)
++              goto exit_clk_emma_put;
++
++      return err;
++
++exit_clk_emma_put:
++      clk_disable(pcdev->clk_emma);
++      clk_put(pcdev->clk_emma);
++exit_free_irq:
++      free_irq(pcdev->irq_emma, pcdev);
++exit_iounmap:
++      iounmap(pcdev->base_emma);
++exit_release:
++      release_mem_region(res_emma->start, resource_size(res_emma));
++out:
++      return err;
++}
++
++static int mx27_camera_probe(struct platform_device *pdev)
++{
++      struct mx27_camera_dev *pcdev;
++      struct resource *res_csi, *res_emma;
++      void __iomem *base_csi;
++      unsigned int irq_csi, irq_emma;
++      int err = 0;
++
++      dev_info(&pdev->dev, "initialising\n");
++
++      res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      irq_csi = platform_get_irq(pdev, 0);
++      if (!res_csi || !irq_csi) {
++              dev_err(&pdev->dev, "No platform irq\n");
++              err = -ENODEV;
++              goto exit;
++      }
++
++      pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
++      if (!pcdev) {
++              dev_err(&pdev->dev, "Could not allocate pcdev\n");
++              err = -ENOMEM;
++              goto exit;
++      }
++
++      pcdev->clk_csi = clk_get(&pdev->dev, "csi_perclk");
++      if (IS_ERR(pcdev->clk_csi)) {
++              err = PTR_ERR(pcdev->clk_csi);
++              goto exit_kfree;
++      }
++
++      dev_info(&pdev->dev, "Camera clock frequency: %ld\n",
++                      clk_get_rate(pcdev->clk_csi));
++
++      /* Initialize DMA */
++      pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH);
++      if (pcdev->dma < 0) {
++              dev_err(&pdev->dev,
++                      "mxc_v4l_read failed to request DMA channel\n");
++              err = -EIO;
++              goto exit_clk_put;
++      }
++
++      err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback,
++                                      mx27_camera_dma_err_callback, pcdev);
++      if (err != 0) {
++              dev_err(&pdev->dev,
++                              "mxc_v4l_read failed to set DMA callback\n");
++              err = -EIO;
++              goto exit_dma_free;
++      }
++
++      imx_dma_config_channel(pcdev->dma,
++                      IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
++                      IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
++                      DMA_REQ_CSI_RX, 1);
++
++      imx_dma_config_burstlen(pcdev->dma, 64);
++
++      dev_set_drvdata(&pdev->dev, pcdev);
++      pcdev->res_csi = res_csi;
++
++      pcdev->pdata = pdev->dev.platform_data;
++      pcdev->platform_flags = pcdev->pdata->flags;
++
++      clk_set_rate(pcdev->clk_csi, pcdev->pdata->clk * 2);
++
++      INIT_LIST_HEAD(&pcdev->capture);
++      INIT_LIST_HEAD(&pcdev->active_bufs);
++      spin_lock_init(&pcdev->lock);
++
++      /*
++       * Request the regions.
++       */
++      if (!request_mem_region(res_csi->start, resource_size(res_csi),
++                              MX27_CAM_DRV_NAME)) {
++              err = -EBUSY;
++              goto exit_dma_free;
++      }
++
++      base_csi = ioremap(res_csi->start, resource_size(res_csi));
++      if (!base_csi) {
++              err = -ENOMEM;
++              goto exit_release;
++      }
++      pcdev->irq_csi = irq_csi;
++      pcdev->base_csi = base_csi;
++      pcdev->dev = &pdev->dev;
++
++      pcdev->pdata->init(pdev);
++
++      err = request_irq(pcdev->irq_csi, mx27_camera_irq, 0, MX27_CAM_DRV_NAME,
++                        pcdev);
++      if (err) {
++              dev_err(pcdev->dev, "Camera interrupt register failed \n");
++              goto exit_iounmap;
++      }
++
++      mx27_soc_camera_host.priv       = pcdev;
++      mx27_soc_camera_host.dev.parent = &pdev->dev;
++      mx27_soc_camera_host.nr         = pdev->id;
++
++      /* EMMA support */
++      res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++      irq_emma = platform_get_irq(pdev, 1);
++
++      if (res_emma && irq_emma) {
++              dev_info(&pdev->dev, "Using EMMA\n");
++              pcdev->use_emma = 1;
++              pcdev->res_emma = res_emma;
++              pcdev->irq_emma = irq_emma;
++              if (mx27_camera_emma_init(pcdev))
++                      goto exit_free_irq;
++      }
++
++      err = soc_camera_host_register(&mx27_soc_camera_host);
++      if (err)
++              goto exit_free_emma;
++
++      return 0;
++
++exit_free_emma:
++      free_irq(pcdev->irq_emma, pcdev);
++      clk_disable(pcdev->clk_emma);
++      clk_put(pcdev->clk_emma);
++      iounmap(pcdev->base_emma);
++      release_mem_region(res_emma->start, resource_size(res_emma));
++exit_free_irq:
++      free_irq(pcdev->irq_csi, pcdev);
++exit_iounmap:
++      iounmap(base_csi);
++exit_release:
++      release_mem_region(res_csi->start, resource_size(res_csi));
++exit_dma_free:
++      imx_dma_free(pcdev->dma);
++exit_clk_put:
++      clk_put(pcdev->clk_csi);
++exit_kfree:
++      kfree(pcdev);
++exit:
++      return err;
++}
++
++static int __devexit mx27_camera_remove(struct platform_device *pdev)
++{
++      struct mx27_camera_dev *pcdev = platform_get_drvdata(pdev);
++      struct resource *res;
++
++      clk_put(pcdev->clk_csi);
++      imx_dma_free(pcdev->dma);
++      free_irq(pcdev->irq_csi, pcdev);
++      if (mx27_camera_emma(pcdev))
++              free_irq(pcdev->irq_emma, pcdev);
++
++      soc_camera_host_unregister(&mx27_soc_camera_host);
++
++      iounmap(pcdev->base_csi);
++
++      if (mx27_camera_emma(pcdev)) {
++              clk_disable(pcdev->clk_emma);
++              clk_put(pcdev->clk_emma);
++              iounmap(pcdev->base_emma);
++              res = pcdev->res_emma;
++              release_mem_region(res->start, resource_size(res));
++      }
++
++      pcdev->pdata->exit(pdev);
++
++      res = pcdev->res_csi;
++      release_mem_region(res->start, resource_size(res));
++
++      kfree(pcdev);
++
++      dev_info(&pdev->dev, "MX27 Camera driver unloaded\n");
++
++      return 0;
++}
++
++static struct platform_driver mx27_camera_driver = {
++      .driver         = {
++              .name   = MX27_CAM_DRV_NAME,
++      },
++      .probe          = mx27_camera_probe,
++      .remove         = __exit_p(mx27_camera_remove),
++};
++
++
++static int __devinit mx27_camera_init(void)
++{
++      return platform_driver_register(&mx27_camera_driver);
++}
++
++static void __exit mx27_camera_exit(void)
++{
++      return platform_driver_unregister(&mx27_camera_driver);
++}
++
++module_init(mx27_camera_init);
++module_exit(mx27_camera_exit);
++
++MODULE_DESCRIPTION("i.MX27 SoC Camera Host driver");
++MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/Kconfig linux-2.6.28-karo/drivers/media/video/mxc/capture/Kconfig
+--- linux-2.6.28/drivers/media/video/mxc/capture/Kconfig       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/Kconfig  2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,80 @@
++if VIDEO_MXC_CAMERA
++
++menu "MXC Camera/V4L2 PRP Features support"
++config VIDEO_MXC_IPU_CAMERA
++      bool
++      depends on VIDEO_MXC_CAMERA && MXC_IPU
++      default y
++
++config VIDEO_MXC_EMMA_CAMERA
++      bool "MX27 eMMA support"
++      depends on VIDEO_MXC_CAMERA && MXC_EMMA && FB_MXC_SYNC_PANEL && (MXC_CAMERA_MICRON111 || MXC_CAMERA_MC521DA || MXC_CAMERA_OV2640)
++      select VIDEO_MXC_OPL
++      default y
++
++config VIDEO_MXC_CSI_DMA
++      bool "CSI-DMA Still Image Capture support"
++      depends on VIDEO_MXC_EMMA_CAMERA
++      default n
++      ---help---
++        Use CSI-DMA method instead of CSI-PrP link to capture still image. This allows
++        to use less physical contiguous memory to capture big resolution still image. But
++        with this method the CSC (Color Space Conversion) and resize are not supported.
++        If unsure, say N.
++
++choice
++      prompt "Select Camera"
++      default MXC_CAMERA_MICRON111
++      depends on (VIDEO_MXC_CAMERA && I2C_MXC)
++
++config MXC_CAMERA_MICRON111
++      tristate "Micron mt9v111 camera support"
++      ---help---
++        If you plan to use the mt9v111 Camera with your MXC system, say Y here.
++
++config MXC_CAMERA_MC521DA
++      tristate "Magnachip mc521da camera support"
++      ---help---
++        If you plan to use the mc521da Camera with your MXC system, say Y here.
++
++config MXC_CAMERA_OV2640
++      tristate "OmniVision ov2640 camera support"
++      ---help---
++        If you plan to use the ov2640 Camera with your MXC system, say Y here.
++endchoice
++
++config MXC_IPU_PRP_VF_SDC
++      tristate "Pre-Processor VF SDC library"
++      depends on (VIDEO_MXC_IPU_CAMERA && FB_MXC_SYNC_PANEL && (MXC_CAMERA_MICRON111 || MXC_CAMERA_MC521DA || MXC_CAMERA_OV2640))
++      default y
++      ---help---
++        Use case PRP_VF_SDC:
++              Preprocessing image from smart sensor for viewfinder and
++              displaying it on synchronous display with SDC use case.
++              If SDC BG is selected, Rotation will not be supported.
++              CSI -> IC (PRP VF) -> MEM
++              MEM -> IC (ROT) -> MEM
++              MEM -> SDC (FG/BG)
++
++config MXC_IPU_PRP_VF_ADC
++      tristate "Pre-Processor VF ADC library"
++      depends on (VIDEO_MXC_IPU_CAMERA && FB_MXC_ASYNC_PANEL && (MXC_CAMERA_MICRON111 || MXC_CAMERA_MC521DA || MXC_CAMERA_OV2640))
++      default y
++      ---help---
++        Use case PRP_VF_ADC:
++              Preprocessing image from smart sensor for viewfinder and
++              displaying it on asynchronous display.
++              CSI -> IC (PRP VF) -> ADC2
++
++config MXC_IPU_PRP_ENC
++      tristate "Pre-processor Encoder library"
++      depends on (VIDEO_MXC_IPU_CAMERA && (MXC_CAMERA_MICRON111 || MXC_CAMERA_MC521DA || MXC_CAMERA_OV2640))
++      default y
++      ---help---
++        Use case PRP_ENC:
++              Preprocessing image from smart sensor for encoder.
++              CSI -> IC (PRP ENC) -> MEM
++
++endmenu
++
++endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/Makefile linux-2.6.28-karo/drivers/media/video/mxc/capture/Makefile
+--- linux-2.6.28/drivers/media/video/mxc/capture/Makefile      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/Makefile 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,18 @@
++ifeq ($(CONFIG_VIDEO_MXC_IPU_CAMERA),y)
++      obj-$(CONFIG_VIDEO_MXC_CAMERA) += mxc_v4l2_capture.o
++      obj-$(CONFIG_MXC_IPU_PRP_VF_ADC) += ipu_prp_vf_adc.o
++      obj-$(CONFIG_MXC_IPU_PRP_VF_SDC) += ipu_prp_vf_sdc.o ipu_prp_vf_sdc_bg.o
++      obj-$(CONFIG_MXC_IPU_PRP_ENC) += ipu_prp_enc.o ipu_still.o
++endif
++
++mx27_capture-objs := mx27_prphw.o mx27_prpsw.o mx27_v4l2_capture.o
++obj-$(CONFIG_VIDEO_MXC_EMMA_CAMERA) += mx27_csi.o mx27_capture.o 
++
++mc521da_camera-objs := mc521da.o sensor_clock.o
++obj-$(CONFIG_MXC_CAMERA_MC521DA) += mc521da_camera.o
++
++mt9v111_camera-objs := mt9v111.o sensor_clock.o
++obj-$(CONFIG_MXC_CAMERA_MICRON111) += mt9v111_camera.o 
++
++ov2640_camera-objs := ov2640.o sensor_clock.o
++obj-$(CONFIG_MXC_CAMERA_OV2640) += ov2640_camera.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mc521da.c linux-2.6.28-karo/drivers/media/video/mxc/capture/mc521da.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/mc521da.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mc521da.c        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,702 @@
++/*
++ * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mc521da.c
++ *
++ * @brief MC521DA camera driver functions
++ *
++ * @ingroup Camera
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <linux/clk.h>
++#include <asm/arch/mxc_i2c.h>
++#include "mxc_v4l2_capture.h"
++
++#define MC521DA_I2C_ADDRESS   0x22
++#define MC521DA_TERM          0xFF
++
++typedef struct {
++      u16 width;
++      u16 height;
++} mc521da_image_format;
++
++struct mc521da_reg {
++      u8 reg;
++      u8 val;
++};
++
++static sensor_interface *interface_param = NULL;
++
++static mc521da_image_format format[2] = {
++      {
++       .width = 1600,
++       .height = 1200,
++       },
++      {
++       .width = 640,
++       .height = 480,
++       },
++};
++
++const static struct mc521da_reg mc521da_initial[] = {
++      /*----------------------------------------------------------
++       * Sensor Setting Start
++       *----------------------------------------------------------
++       */
++      {0xff, 0x01},           /* Sensor setting start */
++      {0x01, 0x10},           /* Wavetable script, generated by waveman */
++      {0x10, 0x64},
++      {0x03, 0x00}, {0x04, 0x06}, {0x05, 0x30}, {0x06, 0x02}, {0x08, 0x00},
++      {0x03, 0x01}, {0x04, 0x41}, {0x05, 0x70}, {0x06, 0x03}, {0x08, 0x00},
++      {0x03, 0x02}, {0x04, 0x55}, {0x05, 0x30}, {0x06, 0x03}, {0x08, 0x00},
++      {0x03, 0x03}, {0x04, 0x5A}, {0x05, 0x30}, {0x06, 0x02}, {0x08, 0x00},
++      {0x03, 0x04}, {0x04, 0x7A}, {0x05, 0x30}, {0x06, 0x06}, {0x08, 0x00},
++      {0x03, 0x05}, {0x04, 0x9C}, {0x05, 0x30}, {0x06, 0x0F}, {0x08, 0x00},
++      {0x03, 0x06}, {0x04, 0x73}, {0x05, 0x31}, {0x06, 0x06}, {0x08, 0x00},
++      {0x03, 0x07}, {0x04, 0x2D}, {0x05, 0x3B}, {0x06, 0x06}, {0x08, 0x00},
++      {0x03, 0x08}, {0x04, 0x32}, {0x05, 0x33}, {0x06, 0x06}, {0x08, 0x00},
++      {0x03, 0x09}, {0x04, 0x67}, {0x05, 0x63}, {0x06, 0x06}, {0x08, 0x00},
++      {0x03, 0x0a}, {0x04, 0x6C}, {0x05, 0x23}, {0x06, 0x0E}, {0x08, 0x00},
++      {0x03, 0x0b}, {0x04, 0x71}, {0x05, 0x23}, {0x06, 0x06}, {0x08, 0x00},
++      {0x03, 0x0c}, {0x04, 0x30}, {0x05, 0x2F}, {0x06, 0x06}, {0x08, 0x00},
++      {0x03, 0x0d}, {0x04, 0x00}, {0x05, 0x00}, {0x06, 0x06}, {0x08, 0x00},
++      {0x07, 0x0e},
++
++      /* Start Address */
++      {0x10, 0x64}, {0x14, 0x10}, {0x15, 0x00},
++
++      /* SYNC */
++      {0x18, 0x40}, {0x19, 0x00}, {0x1A, 0x03}, {0x1B, 0x00},
++
++      /* X-Y Mirror */
++      {0x11, 0x00}, {0xda, 0x00},     /* X mirror OFF, Y Mirror OFF */
++
++      /* Frame height */
++      {0x1c, 0x13}, {0x1d, 0x04}, {0x0e, 0x4b}, {0x0f, 0x05},
++      {0x9e, 0x04}, {0x9d, 0xc6}, {0xcc, 0x14}, {0xcd, 0x05},
++
++      /* Frame width */
++      {0x0c, 0x35}, {0x0d, 0x07}, {0x9b, 0x10}, {0x9c, 0x07},
++      {0x93, 0x21},
++
++      {0x01, 0x01}, {0x40, 0x00}, {0x41, 0x00}, {0x42, 0xf0},
++      {0x43, 0x03}, {0x44, 0x0a}, {0x45, 0x00}, {0x3b, 0x40},
++      {0x38, 0x18}, {0x3c, 0x00}, {0x20, 0x00}, {0x21, 0x01},
++      {0x22, 0x00}, {0x23, 0x01}, {0x24, 0x00}, {0x25, 0x01},
++      {0x26, 0x00}, {0x27, 0x01}, {0xb9, 0x04}, {0xb8, 0xc3},
++      {0xbb, 0x04}, {0xba, 0xc3}, {0xbf, 0x04}, {0xbe, 0xc3},
++
++      /* Ramp */
++      {0x57, 0x07}, {0x56, 0xd6}, {0x55, 0x03}, {0x54, 0x74},
++      {0x9f, 0x99}, {0x94, 0x80}, {0x91, 0x78}, {0x92, 0x8b},
++
++      /* Output Mode */
++      {0x52, 0x10}, {0x51, 0x00},
++
++      /* Analog Gain and Output driver */
++      {0x28, 0x00}, {0xdd, 0x82}, {0xdb, 0x00}, {0xdc, 0x00},
++
++      /* Update */
++      {0x00, 0x84},
++
++      /* PLL  ADC clock = 75 MHz */
++      {0xb5, 0x60}, {0xb4, 0x02}, {0xb5, 0x20},
++
++      /*----------------------------------------------*/
++      /*      ISP Setting Start                       */
++      /*----------------------------------------------*/
++      {0xff, 0x02},
++      {0x01, 0xbd}, {0x02, 0xf8}, {0x03, 0x3a}, {0x04, 0x00}, {0x0e, 0x00},
++
++      /* Output mode */
++      {0x88, 0x00}, {0x87, 0x11},
++
++      /* Threshold */
++      {0xb6, 0x1b}, {0x0d, 0xc0}, {0x24, 0x00}, {0x25, 0x00}, {0x26, 0x00},
++
++      /* Image Effect */
++      {0x3f, 0x80}, {0x40, 0x00}, {0x41, 0x00}, {0x42, 0x80}, {0x43, 0x00},
++      {0x44, 0x00}, {0x45, 0x00}, {0x46, 0x00}, {0x56, 0x80}, {0x57, 0x20},
++      {0x58, 0x20}, {0x59, 0x02}, {0x5a, 0x00}, {0x5b, 0x78}, {0x5c, 0x7c},
++      {0x5d, 0x84}, {0x5e, 0x85}, {0x5f, 0x78}, {0x60, 0x7e}, {0x61, 0x82},
++      {0x62, 0x85}, {0x63, 0x00}, {0x64, 0x80}, {0x65, 0x00}, {0x66, 0x80},
++      {0x67, 0x80}, {0x68, 0x80},
++
++      /* Auto Focus */
++      {0x6e, 0x02}, {0x6f, 0xe5}, {0x70, 0x08}, {0x71, 0x01}, {0x72, 0x00},
++
++      /* Decimator */
++      {0x78, 0xff}, {0x79, 0xff}, {0x7a, 0x70}, {0x7b, 0x00}, {0x7c, 0x00},
++      {0x7d, 0x00}, {0x7e, 0xc8}, {0x7f, 0xc8}, {0x80, 0x96}, {0x81, 0x96},
++      {0x82, 0x00}, {0x83, 0x00}, {0x84, 0x00}, {0x85, 0x00}, {0x86, 0x00},
++
++      /* Luminance Info */
++      {0xf9, 0x20}, {0xb7, 0x7f}, {0xb8, 0x28}, {0xb9, 0x08},
++      {0xf9, 0xa0}, {0xb7, 0x10}, {0xb9, 0x00},
++      {0xf9, 0x40}, {0xb7, 0x7f}, {0xb8, 0x28}, {0xb9, 0x08},
++      {0xf9, 0xc0}, {0xb7, 0x08}, {0xb9, 0x00},
++      {0xf9, 0x60}, {0xb7, 0x7f}, {0xb8, 0x28}, {0xb9, 0x08},
++      {0xf9, 0xe0}, {0xb7, 0x05}, {0xb9, 0x00},
++      {0xf9, 0x00}, {0xb7, 0x03}, {0xb8, 0x2d}, {0xb9, 0xcd},
++      {0xf9, 0x80}, {0xb7, 0x02}, {0xb9, 0x00},
++
++      /* AE */
++      {0x8a, 0x00}, {0x89, 0xc0}, {0x8c, 0x32}, {0x8d, 0x96}, {0x8e, 0x25},
++      {0x8f, 0x70}, {0x90, 0x12}, {0x91, 0x41}, {0x9e, 0x2e}, {0x9f, 0x2e},
++      {0xa0, 0x0b}, {0xa1, 0x71}, {0xa2, 0xb0}, {0xa3, 0x09}, {0xa4, 0x89},
++      {0xa5, 0x68}, {0xa6, 0x1a}, {0xa7, 0xb3}, {0xa8, 0xf0}, {0xa9, 0x19},
++      {0xaa, 0x6a}, {0xab, 0x6b}, {0xac, 0x01}, {0xad, 0xe8}, {0xae, 0x48},
++      {0xaf, 0x01}, {0xb0, 0x96}, {0xb1, 0xe6}, {0xb2, 0x03}, {0xb3, 0x00},
++      {0xb4, 0x10}, {0xb5, 0x00}, {0xb6, 0x04}, {0xba, 0x44}, {0xbb, 0x3a},
++      {0xbc, 0x01}, {0xbd, 0x08}, {0xbe, 0xa0}, {0xbf, 0x01}, {0xc0, 0x82},
++      {0x8a, 0xe1}, {0x8b, 0x8c},
++
++      /* AWB */
++      {0xc8, 0x00}, {0xc9, 0x00}, {0xca, 0x40}, {0xcb, 0xB0}, {0xcc, 0x40},
++      {0xcd, 0xff}, {0xce, 0x19}, {0xcf, 0x40}, {0xd0, 0x01}, {0xd1, 0x43},
++      {0xd2, 0x80}, {0xd3, 0x80}, {0xd4, 0xf1}, {0xdf, 0x00}, {0xe0, 0x8f},
++      {0xe1, 0x8f}, {0xe2, 0x53}, {0xe3, 0x97}, {0xe4, 0x1f}, {0xe5, 0x3b},
++      {0xe6, 0x9c}, {0xe7, 0x2e}, {0xe8, 0x03}, {0xe9, 0x02},
++
++      /* Neutral CCM */
++      {0xfa, 0x00}, {0xd5, 0x3f}, {0xd6, 0x8c}, {0xd7, 0x43}, {0xd8, 0x08},
++      {0xd9, 0x27}, {0xda, 0x7e}, {0xdb, 0x17}, {0xdc, 0x1a}, {0xdd, 0x47},
++      {0xde, 0xa1},
++
++      /* Blue CCM */
++      {0xfa, 0x01}, {0xd5, 0x3f}, {0xd6, 0x77}, {0xd7, 0x34}, {0xd8, 0x03},
++      {0xd9, 0x18}, {0xda, 0x6e}, {0xdb, 0x16}, {0xdc, 0x0f}, {0xdd, 0x29},
++      {0xde, 0x77},
++
++      /* Red CCM */
++      {0xfa, 0x02}, {0xd5, 0x3f}, {0xd6, 0x7d}, {0xd7, 0x2f}, {0xd8, 0x0e},
++      {0xd9, 0x1e}, {0xda, 0x76}, {0xdb, 0x18}, {0xdc, 0x29}, {0xdd, 0x51},
++      {0xde, 0xba},
++
++      /* AWB */
++      {0xea, 0x00}, {0xeb, 0x1a}, {0xc8, 0x33}, {0xc9, 0xc2},
++
++      {0xed, 0x02}, {0xee, 0x02},
++
++      /* AFD */
++      {0xf0, 0x11}, {0xf1, 0x03}, {0xf2, 0x05}, {0xf5, 0x05}, {0xf6, 0x32},
++      {0xf7, 0x32},
++
++      /* Lens Shading */
++      {0xf9, 0x00}, {0x05, 0x04}, {0x06, 0xff}, {0x07, 0xf2}, {0x08, 0x00},
++      {0x09, 0x00}, {0x0a, 0xf2}, {0x0b, 0xff}, {0x0c, 0xff},
++      {0xf9, 0x01}, {0x05, 0x04}, {0x06, 0xff}, {0x07, 0x8b}, {0x08, 0x16},
++      {0x09, 0x16}, {0x0a, 0x8b}, {0x0b, 0xff}, {0x0c, 0xe0},
++      {0xf9, 0x02}, {0x05, 0x04}, {0x06, 0xff}, {0x07, 0x8b}, {0x08, 0x16},
++      {0x09, 0x16}, {0x0a, 0x8b}, {0x0b, 0xff}, {0x0c, 0xe0},
++      {0xf9, 0x03}, {0x05, 0x04}, {0x06, 0xff}, {0x07, 0x7c}, {0x08, 0x26},
++      {0x09, 0x26}, {0x0a, 0x7c}, {0x0b, 0xd0}, {0x0c, 0xe0},
++      {0xf9, 0x04}, {0x05, 0x0d}, {0x06, 0x40}, {0x07, 0xa0}, {0x08, 0x00},
++      {0x09, 0x00}, {0x0a, 0xa0}, {0x0b, 0x40}, {0x0c, 0xe0},
++      {0xf9, 0x05}, {0x05, 0x0d}, {0x06, 0x40}, {0x07, 0xa0}, {0x08, 0x00},
++      {0x09, 0x00}, {0x0a, 0xa0}, {0x0b, 0x40}, {0x0c, 0xa0},
++      {0xf9, 0x06}, {0x05, 0x0d}, {0x06, 0x40}, {0x07, 0xa0}, {0x08, 0x00},
++      {0x09, 0x00}, {0x0a, 0xa0}, {0x0b, 0x40}, {0x0c, 0xa0},
++      {0xf9, 0x07}, {0x05, 0x0d}, {0x06, 0x40}, {0x07, 0xa0}, {0x08, 0x00},
++      {0x09, 0x00}, {0x0a, 0xa0}, {0x0b, 0x40}, {0x0c, 0xa0},
++
++      /* Edge setting */
++      {0x73, 0x68}, {0x74, 0x40}, {0x75, 0x00}, {0x76, 0xff}, {0x77, 0x80},
++      {0x4f, 0x80}, {0x50, 0x82}, {0x51, 0x82}, {0x52, 0x08},
++
++      /* Interpolation Setting */
++      {0x23, 0x7f}, {0x22, 0x08}, {0x18, 0xff}, {0x19, 0x00},
++      {0x40, 0x00}, {0x53, 0xff}, {0x54, 0x0a}, {0x55, 0xc2},
++      {0x1b, 0x18},
++
++      {0xfa, 0x00}, {0x15, 0x0c}, {0x22, 0x00}, {0x0e, 0xef}, {0x1f, 0x1d},
++      {0x20, 0x2d}, {0x1c, 0x01}, {0x1d, 0x02}, {0x1e, 0x03}, {0x0e, 0xee},
++      {0x12, 0x10}, {0x16, 0x10}, {0x17, 0x02}, {0x1a, 0x01},
++      {0xfa, 0x04}, {0x0e, 0xef}, {0x1c, 0x01}, {0x1d, 0x02}, {0x1e, 0x03},
++      {0x1f, 0x11}, {0x20, 0x11}, {0x0e, 0xee}, {0x12, 0x03}, {0x16, 0x10},
++      {0x17, 0x02}, {0x1a, 0xee},
++      {0xfa, 0x08}, {0x0e, 0xef}, {0x1c, 0x01}, {0x1d, 0x02}, {0x1e, 0x03},
++      {0x1f, 0x00}, {0x20, 0x00}, {0x0e, 0xee}, {0x12, 0x03}, {0x16, 0x10},
++      {0x17, 0x02}, {0x1a, 0x22},
++
++      /* Gamma Correction */
++      {0x27, 0x62}, {0x28, 0x00}, {0x27, 0x62}, {0x28, 0x00}, {0x29, 0x00},
++      {0x2a, 0x00}, {0x2f, 0x03}, {0x30, 0x10}, {0x31, 0x2b}, {0x32, 0x50},
++      {0x33, 0x70}, {0x34, 0x90}, {0x35, 0xB0}, {0x36, 0xD0}, {0x37, 0x00},
++      {0x38, 0x18}, {0x39, 0x57}, {0x3a, 0x89}, {0x3b, 0xac}, {0x3c, 0xc9},
++      {0x3d, 0xde}, {0x3e, 0xef}, {0x2b, 0x00}, {0x2c, 0x00}, {0x2d, 0x40},
++      {0x2e, 0xab},
++
++      /* Contrast */
++      {0x47, 0x10}, {0x48, 0x1f}, {0x49, 0xe3}, {0x4a, 0xf0}, {0x4b, 0x08},
++      {0x4c, 0x14}, {0x4d, 0xe9}, {0x4e, 0xf5}, {0x98, 0x8a},
++
++      {0xfa, 0x00},
++      {MC521DA_TERM, MC521DA_TERM}
++};
++
++static int mc521da_attach(struct i2c_adapter *adapter);
++static int mc521da_detach(struct i2c_client *client);
++
++static struct i2c_driver mc521da_i2c_driver = {
++      .driver = {
++                 .owner = THIS_MODULE,
++                 .name = "MC521DA Client",
++                 },
++      .attach_adapter = mc521da_attach,
++      .detach_client = mc521da_detach,
++};
++
++static struct i2c_client mc521da_i2c_client = {
++      .name = "MC521DA I2C dev",
++      .addr = MC521DA_I2C_ADDRESS,
++      .driver = &mc521da_i2c_driver,
++};
++
++/*
++ * Function definitions
++ */
++static int mc521da_i2c_client_xfer(unsigned int addr, char *reg,
++                                 int reg_len, char *buf, int num,
++                                 int tran_flag)
++{
++      struct i2c_msg msg[2];
++      int ret;
++
++      msg[0].addr = addr;
++      msg[0].len = reg_len;
++      msg[0].buf = reg;
++      msg[0].flags = tran_flag;
++      msg[0].flags &= ~I2C_M_RD;
++
++      msg[1].addr = addr;
++      msg[1].len = num;
++      msg[1].buf = buf;
++      msg[1].flags = tran_flag;
++
++      if (tran_flag & MXC_I2C_FLAG_READ) {
++              msg[1].flags |= I2C_M_RD;
++      } else {
++              msg[1].flags &= ~I2C_M_RD;
++      }
++
++      ret = i2c_transfer(mc521da_i2c_client.adapter, msg, 2);
++      if (ret >= 0)
++              return 0;
++
++      return ret;
++}
++
++static int mc521da_read_reg(u8 * reg, u8 * val)
++{
++      return mc521da_i2c_client_xfer(MC521DA_I2C_ADDRESS, reg, 1, val, 1,
++                                     MXC_I2C_FLAG_READ);
++}
++
++static int mc521da_write_reg(u8 reg, u8 val)
++{
++      u8 temp1, temp2;
++      temp1 = reg;
++      temp2 = val;
++      return mc521da_i2c_client_xfer(MC521DA_I2C_ADDRESS, &temp1, 1, &temp2,
++                                     1, 0);
++}
++
++static int mc521da_write_regs(const struct mc521da_reg reglist[])
++{
++      int err;
++      const struct mc521da_reg *next = reglist;
++
++      while (!((next->reg == MC521DA_TERM) && (next->val == MC521DA_TERM))) {
++              err = mc521da_write_reg(next->reg, next->val);
++              if (err) {
++                      return err;
++              }
++              next++;
++      }
++      return 0;
++}
++
++/*!
++ * mc521da sensor downscale function
++ * @param downscale            bool
++ * @return  Error code indicating success or failure
++ */
++static u8 mc521da_sensor_downscale(bool downscale)
++{
++      u8 reg[1], data;
++      u32 i = 0;
++
++      if (downscale == true) {
++              // VGA
++              mc521da_write_reg(0xff, 0x01);
++
++              mc521da_write_reg(0x52, 0x30);
++              mc521da_write_reg(0x51, 0x00);
++
++              mc521da_write_reg(0xda, 0x01);
++              mc521da_write_reg(0x00, 0x8C);
++
++              /* Wait for changes to take effect */
++              reg[0] = 0x00;
++              while (i < 256) {
++                      i++;
++                      mc521da_read_reg(reg, &data);
++                      if ((data & 0x80) == 0)
++                              break;
++                      msleep(5);
++              }
++
++              /* ISP */
++              mc521da_write_reg(0xff, 0x02);
++
++              mc521da_write_reg(0x03, 0x3b);  /* Enable Decimator */
++
++              mc521da_write_reg(0x7a, 0x74);
++              mc521da_write_reg(0x7b, 0x01);
++              mc521da_write_reg(0x7e, 0x50);
++              mc521da_write_reg(0x7f, 0x50);
++              mc521da_write_reg(0x80, 0x3c);
++              mc521da_write_reg(0x81, 0x3c);
++      } else {
++              //UXGA
++              mc521da_write_reg(0xff, 0x01);
++              mc521da_write_reg(0x52, 0x10);
++              mc521da_write_reg(0x51, 0x00);
++              mc521da_write_reg(0xda, 0x00);
++
++              /* update */
++              mc521da_write_reg(0x00, 0x84);
++
++              /* Wait for changes to take effect */
++              reg[0] = 0x00;
++              while (i < 256) {
++                      i++;
++                      mc521da_read_reg(reg, &data);
++                      if ((data & 0x80) == 0)
++                              break;
++                      msleep(5);
++              }
++
++              /* ISP */
++              mc521da_write_reg(0xff, 0x02);
++
++              mc521da_write_reg(0x03, 0x3a);
++
++              mc521da_write_reg(0x7a, 0x70);
++              mc521da_write_reg(0x7b, 0x00);
++              mc521da_write_reg(0x7e, 0xc8);
++              mc521da_write_reg(0x7f, 0xc8);
++              mc521da_write_reg(0x80, 0x96);
++              mc521da_write_reg(0x81, 0x96);
++      }
++
++      return 0;
++}
++
++/*!
++ * mc521da sensor interface Initialization
++ * @param param            sensor_interface *
++ * @param width            u32
++ * @param height           u32
++ * @return  None
++ */
++static void mc521da_interface(sensor_interface * param, u32 width, u32 height)
++{
++      param->clk_mode = 0x0;  //gated
++      param->pixclk_pol = 0x0;
++      param->data_width = 0x1;
++      param->data_pol = 0x0;
++      param->ext_vsync = 0x0;
++      param->Vsync_pol = 0x0;
++      param->Hsync_pol = 0x0;
++      param->width = width - 1;
++      param->height = height - 1;
++      param->pixel_fmt = IPU_PIX_FMT_UYVY;
++}
++
++extern void gpio_sensor_reset(bool flag);
++
++/*!
++ * mc521da Reset function
++ *
++ * @return  None
++ */
++static sensor_interface *mc521da_reset(void)
++{
++      if (interface_param == NULL)
++              return NULL;
++
++      mc521da_interface(interface_param, format[1].width, format[1].height);
++      set_mclk_rate(&interface_param->mclk);
++
++      gpio_sensor_reset(true);
++      msleep(10);
++      gpio_sensor_reset(false);
++      msleep(50);
++
++      return interface_param;
++}
++
++/*!
++ * mc521da sensor configuration
++ *
++ * @param frame_rate       int        *
++ * @param high_quality     int
++ * @return  sensor_interface *
++ */
++static sensor_interface *mc521da_config(int *frame_rate, int high_quality)
++{
++      int num_clock_per_row, err;
++      int max_rate = 0;
++      int index = 1;
++      u16 frame_height;
++
++      if (high_quality == 1)
++              index = 0;
++
++      err = mc521da_write_regs(mc521da_initial);
++      if (err) {
++              /* Reduce the MCLK */
++              interface_param->mclk = 20000000;
++              mc521da_reset();
++
++              printk(KERN_INFO "mc521da: mclk reduced\n");
++              mc521da_write_regs(mc521da_initial);
++      }
++
++      mc521da_interface(interface_param, format[index].width,
++                        format[index].height);
++
++      if (index == 0) {
++              mc521da_sensor_downscale(false);
++      } else {
++              mc521da_sensor_downscale(true);
++      }
++
++      num_clock_per_row = 1845;
++      max_rate = interface_param->mclk * 3 * (index + 1)
++          / (2 * num_clock_per_row * 1300);
++
++      if ((*frame_rate > max_rate) || (*frame_rate == 0)) {
++              *frame_rate = max_rate;
++      }
++
++      frame_height = 1300 * max_rate / (*frame_rate);
++
++      *frame_rate = interface_param->mclk * 3 * (index + 1)
++          / (2 * num_clock_per_row * frame_height);
++
++      mc521da_write_reg(0xff, 0x01);
++      mc521da_write_reg(0xE, frame_height & 0xFF);
++      mc521da_write_reg(0xF, (frame_height & 0xFF00) >> 8);
++      mc521da_write_reg(0xCC, frame_height & 0xFF);
++      mc521da_write_reg(0xCD, (frame_height & 0xFF00) >> 8);
++
++      return interface_param;
++}
++
++/*!
++ * mc521da sensor set color configuration
++ *
++ * @param bright       int
++ * @param saturation   int
++ * @param red          int
++ * @param green        int
++ * @param blue         int
++ * @return  None
++ */
++static void
++mc521da_set_color(int bright, int saturation, int red, int green, int blue)
++{
++      /* Select ISP */
++      mc521da_write_reg(0xff, 0x02);
++
++      mc521da_write_reg(0x41, bright);
++      mc521da_write_reg(0xca, red);
++      mc521da_write_reg(0xcb, green);
++      mc521da_write_reg(0xcc, blue);
++}
++
++/*!
++ * mc521da sensor get color configuration
++ *
++ * @param bright       int *
++ * @param saturation   int *
++ * @param red          int *
++ * @param green        int *
++ * @param blue         int *
++ * @return  None
++ */
++static void
++mc521da_get_color(int *bright, int *saturation, int *red, int *green, int *blue)
++{
++      u8 reg[1];
++      u8 *pdata;
++
++      *saturation = 0;
++
++      /* Select ISP */
++      mc521da_write_reg(0xff, 0x02);
++
++      reg[0] = 0x41;
++      pdata = (u8 *) bright;
++      mc521da_read_reg(reg, pdata);
++
++      reg[0] = 0xCA;
++      pdata = (u8 *) red;
++      mc521da_read_reg(reg, pdata);
++
++      reg[0] = 0xCB;
++      pdata = (u8 *) green;
++      mc521da_read_reg(reg, pdata);
++
++      reg[0] = 0xCC;
++      pdata = (u8 *) blue;
++      mc521da_read_reg(reg, pdata);
++}
++
++struct camera_sensor camera_sensor_if = {
++      set_color:mc521da_set_color,
++      get_color:mc521da_get_color,
++      config:mc521da_config,
++      reset:mc521da_reset,
++};
++
++/*!
++ * mc521da I2C detect_client function
++ *
++ * @param adapter            struct i2c_adapter *
++ * @param address            int
++ * @param kind               int
++ * 
++ * @return  Error code indicating success or failure
++ */
++static int mc521da_detect_client(struct i2c_adapter *adapter, int address,
++                               int kind)
++{
++      mc521da_i2c_client.adapter = adapter;
++      if (i2c_attach_client(&mc521da_i2c_client)) {
++              mc521da_i2c_client.adapter = NULL;
++              printk(KERN_ERR "mc521da_attach: i2c_attach_client failed\n");
++              return -1;
++      }
++
++      interface_param = (sensor_interface *)
++          kmalloc(sizeof(sensor_interface), GFP_KERNEL);
++      if (!interface_param) {
++              printk(KERN_ERR "mc521da_attach: kmalloc failed \n");
++              return -1;
++      }
++
++      interface_param->mclk = 25000000;
++
++      printk(KERN_INFO "mc521da Detected\n");
++
++      return 0;
++}
++
++static unsigned short normal_i2c[] = { MC521DA_I2C_ADDRESS, I2C_CLIENT_END };
++
++/* Magic definition of all other variables and things */
++I2C_CLIENT_INSMOD;
++
++static int mc521da_attach(struct i2c_adapter *adap)
++{
++      uint32_t mclk = 25000000;
++      struct clk *clk;
++      int err;
++
++      clk = clk_get(NULL, "csi_clk");
++      clk_enable(clk);
++      set_mclk_rate(&mclk);
++
++      gpio_sensor_reset(true);
++      msleep(10);
++      gpio_sensor_reset(false);
++      msleep(100);
++
++      err = i2c_probe(adap, &addr_data, &mc521da_detect_client);
++
++      clk_disable(clk);
++      clk_put(clk);
++
++      return err;
++}
++
++/*!
++ * mc521da I2C detach function
++ *
++ * @param client            struct i2c_client *
++ * @return  Error code indicating success or failure
++ */
++static int mc521da_detach(struct i2c_client *client)
++{
++      int err;
++
++      if (!mc521da_i2c_client.adapter)
++              return -1;
++
++      err = i2c_detach_client(&mc521da_i2c_client);
++      mc521da_i2c_client.adapter = NULL;
++
++      if (interface_param)
++              kfree(interface_param);
++      interface_param = NULL;
++
++      return err;
++}
++
++extern void gpio_sensor_active(void);
++extern void gpio_sensor_inactive(void);
++
++/*!
++ * mc521da init function
++ *
++ * @return  Error code indicating success or failure
++ */
++static __init int mc521da_init(void)
++{
++      gpio_sensor_active();
++      return i2c_add_driver(&mc521da_i2c_driver);
++}
++
++/*!
++ * mc521da cleanup function
++ *
++ * @return  Error code indicating success or failure
++ */
++static void __exit mc521da_clean(void)
++{
++      i2c_del_driver(&mc521da_i2c_driver);
++      gpio_sensor_inactive();
++}
++
++module_init(mc521da_init);
++module_exit(mc521da_clean);
++
++/* Exported symbols for modules. */
++EXPORT_SYMBOL(camera_sensor_if);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MC521DA Camera Driver");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mt9v111.c linux-2.6.28-karo/drivers/media/video/mxc/capture/mt9v111.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/mt9v111.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mt9v111.c        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,932 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mt9v111.c
++ *
++ * @brief mt9v111 camera driver functions
++ *
++ * @ingroup Camera
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <linux/clk.h>
++#include <asm/arch/mxc_i2c.h>
++#include "mxc_v4l2_capture.h"
++#include "mt9v111.h"
++
++#ifdef MT9V111_DEBUG
++static u16 testpattern = 0;
++#endif
++
++static sensor_interface *interface_param = NULL;
++static mt9v111_conf mt9v111_device;
++static int reset_frame_rate = 30;
++
++#define MT9V111_FRAME_RATE_NUM    20
++
++static mt9v111_image_format format[2] = {
++      {
++       .index = 0,
++       .width = 640,
++       .height = 480,
++       },
++      {
++       .index = 1,
++       .width = 352,
++       .height = 288,
++       },
++};
++
++static int mt9v111_attach(struct i2c_adapter *adapter);
++static int mt9v111_detach(struct i2c_client *client);
++
++static struct i2c_driver mt9v111_i2c_driver = {
++      .driver = {
++                 .owner = THIS_MODULE,
++                 .name = "MT9V111 Client",
++                 },
++      .attach_adapter = mt9v111_attach,
++      .detach_client = mt9v111_detach,
++};
++
++static struct i2c_client mt9v111_i2c_client = {
++      .name = "mt9v111 I2C dev",
++      .addr = MT9V111_I2C_ADDRESS,
++      .driver = &mt9v111_i2c_driver,
++};
++
++/*
++ * Function definitions
++ */
++
++static u16 mt9v111_endian_swap16(u16 data)
++{
++      u16 temp;
++
++      temp = data;
++      temp = ((data >> 8) & 0xff) | ((data << 8) & 0xff00);
++
++      return temp;
++}
++
++static int mt9v111_i2c_client_xfer(unsigned int addr, char *reg, int reg_len,
++                                 char *buf, int num, int tran_flag)
++{
++      struct i2c_msg msg[2];
++      int ret;
++
++      msg[0].addr = addr;
++      msg[0].len = reg_len;
++      msg[0].buf = reg;
++      msg[0].flags = tran_flag;
++      msg[0].flags &= ~I2C_M_RD;
++
++      msg[1].addr = addr;
++      msg[1].len = num;
++      msg[1].buf = buf;
++      msg[1].flags = tran_flag;
++
++      if (tran_flag & MXC_I2C_FLAG_READ) {
++              msg[1].flags |= I2C_M_RD;
++      } else {
++              msg[1].flags &= ~I2C_M_RD;
++      }
++
++      ret = i2c_transfer(mt9v111_i2c_client.adapter, msg, 2);
++      if (ret >= 0)
++              return 0;
++
++      return ret;
++}
++
++static int mt9v111_read_reg(u8 * reg, u16 * val)
++{
++      return mt9v111_i2c_client_xfer(MT9V111_I2C_ADDRESS, reg, 1,
++                                     (u8 *) val, 2, MXC_I2C_FLAG_READ);
++}
++
++static int mt9v111_write_reg(u8 reg, u16 val)
++{
++      u8 temp1;
++      u16 temp2;
++      temp1 = reg;
++      temp2 = mt9v111_endian_swap16(val);
++      pr_debug("write reg %x val %x.\n", reg, val);
++      return mt9v111_i2c_client_xfer(MT9V111_I2C_ADDRESS, &temp1, 1,
++                                     (u8 *) & temp2, 2, 0);
++}
++
++/*!
++ * Initialize mt9v111_sensor_lib
++ * Libarary for Sensor configuration through I2C
++ *
++ * @param       coreReg       Core Registers
++ * @param       ifpReg        IFP Register
++ *
++ * @return status
++ */
++static u8 mt9v111_sensor_lib(mt9v111_coreReg * coreReg, mt9v111_IFPReg * ifpReg)
++{
++      u8 reg;
++      u16 data;
++      u8 error = 0;
++
++      /*
++       * setup to IFP registers
++       */
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = ifpReg->addrSpaceSel;
++      mt9v111_write_reg(reg, data);
++
++      // Operation Mode Control
++      reg = MT9V111I_MODE_CONTROL;
++      data = ifpReg->modeControl;
++      mt9v111_write_reg(reg, data);
++
++      // Output format
++      reg = MT9V111I_FORMAT_CONTROL;
++      data = ifpReg->formatControl;   // Set bit 12
++      mt9v111_write_reg(reg, data);
++
++      // Flicker Control
++      reg = MT9V111I_FLICKER_CONTROL;
++      data = ifpReg->flickerCtrl;
++      mt9v111_write_reg(reg, data);
++
++      // AE limit 4
++      reg = MT9V111I_SHUTTER_WIDTH_LIMIT_AE;
++      data = ifpReg->gainLimitAE;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111I_OUTPUT_FORMAT_CTRL2;
++      data = ifpReg->outputFormatCtrl2;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111I_AE_SPEED;
++      data = ifpReg->AESpeed;
++      mt9v111_write_reg(reg, data);
++
++      /* output image size */
++      reg = MT9V111i_H_PAN;
++      data = 0x8000 | ifpReg->HPan;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111i_H_ZOOM;
++      data = 0x8000 | ifpReg->HZoom;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111i_H_SIZE;
++      data = 0x8000 | ifpReg->HSize;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111i_V_PAN;
++      data = 0x8000 | ifpReg->VPan;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111i_V_ZOOM;
++      data = 0x8000 | ifpReg->VZoom;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111i_V_SIZE;
++      data = 0x8000 | ifpReg->VSize;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111i_H_PAN;
++      data = ~0x8000 & ifpReg->HPan;
++      mt9v111_write_reg(reg, data);
++#if 0
++      reg = MT9V111I_UPPER_SHUTTER_DELAY_LIM;
++      data = ifpReg->upperShutterDelayLi;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111I_SHUTTER_60;
++      data = ifpReg->shutter_width_60;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111I_SEARCH_FLICK_60;
++      data = ifpReg->search_flicker_60;
++      mt9v111_write_reg(reg, data);
++#endif
++
++      /*
++       * setup to sensor core registers
++       */
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = coreReg->addressSelect;
++      mt9v111_write_reg(reg, data);
++
++      // enable changes and put the Sync bit on
++      reg = MT9V111S_OUTPUT_CTRL;
++      data = MT9V111S_OUTCTRL_SYNC | MT9V111S_OUTCTRL_CHIP_ENABLE | 0x3000;
++      mt9v111_write_reg(reg, data);
++
++      // min PIXCLK - Default
++      reg = MT9V111S_PIXEL_CLOCK_SPEED;
++      data = coreReg->pixelClockSpeed;
++      mt9v111_write_reg(reg, data);
++
++      //Setup image flipping / Dark rows / row/column skip
++      reg = MT9V111S_READ_MODE;
++      data = coreReg->readMode;
++      mt9v111_write_reg(reg, data);
++
++      //zoom 0
++      reg = MT9V111S_DIGITAL_ZOOM;
++      data = coreReg->digitalZoom;
++      mt9v111_write_reg(reg, data);
++
++      // min H-blank
++      reg = MT9V111S_HOR_BLANKING;
++      data = coreReg->horizontalBlanking;
++      mt9v111_write_reg(reg, data);
++
++      // min V-blank
++      reg = MT9V111S_VER_BLANKING;
++      data = coreReg->verticalBlanking;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111S_SHUTTER_WIDTH;
++      data = coreReg->shutterWidth;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111S_SHUTTER_DELAY;
++      data = ifpReg->upperShutterDelayLi;
++      mt9v111_write_reg(reg, data);
++
++      // changes become effective
++      reg = MT9V111S_OUTPUT_CTRL;
++      data = MT9V111S_OUTCTRL_CHIP_ENABLE | 0x3000;
++      mt9v111_write_reg(reg, data);
++
++      return error;
++}
++
++/*!
++ * mt9v111 sensor interface Initialization
++ * @param param            sensor_interface *
++ * @param width            u32
++ * @param height           u32
++ * @return  None
++ */
++static void mt9v111_interface(sensor_interface * param, u32 width, u32 height)
++{
++      param->Vsync_pol = 0x0;
++      param->clk_mode = 0x0;  //gated
++      param->pixclk_pol = 0x0;
++      param->data_width = 0x1;
++      param->data_pol = 0x0;
++      param->ext_vsync = 0x0;
++      param->Vsync_pol = 0x0;
++      param->Hsync_pol = 0x0;
++      param->width = width - 1;
++      param->height = height - 1;
++      param->pixel_fmt = IPU_PIX_FMT_UYVY;
++      param->mclk = 27000000;
++}
++
++/*!
++ * MT9V111 frame rate calculate
++ *
++ * @param frame_rate       int *
++ * @param mclk             int
++ * @return  None
++ */
++static void mt9v111_rate_cal(int *frame_rate, int mclk)
++{
++      int num_clock_per_row;
++      int max_rate = 0;
++
++      mt9v111_device.coreReg->horizontalBlanking = MT9V111_HORZBLANK_MIN;
++
++      num_clock_per_row = (format[0].width + 114 + MT9V111_HORZBLANK_MIN) * 2;
++      max_rate = mclk / (num_clock_per_row *
++                         (format[0].height + MT9V111_VERTBLANK_DEFAULT));
++
++      if ((*frame_rate > max_rate) || (*frame_rate == 0)) {
++              *frame_rate = max_rate;
++      }
++
++      mt9v111_device.coreReg->verticalBlanking
++          = mclk / (*frame_rate * num_clock_per_row) - format[0].height;
++
++      reset_frame_rate = *frame_rate;
++}
++
++/*!
++ * MT9V111 sensor configuration
++ *
++ * @param frame_rate       int *
++ * @param high_quality     int
++ * @return  sensor_interface *
++ */
++sensor_interface *mt9v111_config(int *frame_rate, int high_quality)
++{
++      u32 out_width, out_height;
++
++      if (interface_param == NULL)
++              return NULL;
++
++      mt9v111_device.coreReg->addressSelect = MT9V111I_SEL_SCA;
++      mt9v111_device.ifpReg->addrSpaceSel = MT9V111I_SEL_IFP;
++
++      mt9v111_device.coreReg->windowHeight = MT9V111_WINHEIGHT;
++      mt9v111_device.coreReg->windowWidth = MT9V111_WINWIDTH;
++      mt9v111_device.coreReg->zoomColStart = 0;
++      mt9v111_device.coreReg->zomRowStart = 0;
++      mt9v111_device.coreReg->digitalZoom = 0x0;
++
++      mt9v111_device.coreReg->verticalBlanking = MT9V111_VERTBLANK_DEFAULT;
++      mt9v111_device.coreReg->horizontalBlanking = MT9V111_HORZBLANK_MIN;
++      mt9v111_device.coreReg->pixelClockSpeed = 0;
++      mt9v111_device.coreReg->readMode = 0xd0a1;
++
++      mt9v111_device.ifpReg->outputFormatCtrl2 = 0;
++      mt9v111_device.ifpReg->gainLimitAE = 0x300;
++      mt9v111_device.ifpReg->AESpeed = 0x80;
++
++      // here is the default value
++      mt9v111_device.ifpReg->formatControl = 0xc800;
++      mt9v111_device.ifpReg->modeControl = 0x708e;
++      mt9v111_device.ifpReg->awbSpeed = 0x4514;
++      mt9v111_device.ifpReg->flickerCtrl = 0x02;
++      mt9v111_device.coreReg->shutterWidth = 0xf8;
++
++      out_width = 640;
++      out_height = 480;
++
++      /*output size */
++      mt9v111_device.ifpReg->HPan = 0;
++      mt9v111_device.ifpReg->HZoom = 640;
++      mt9v111_device.ifpReg->HSize = out_width;
++      mt9v111_device.ifpReg->VPan = 0;
++      mt9v111_device.ifpReg->VZoom = 480;
++      mt9v111_device.ifpReg->VSize = out_height;
++
++      mt9v111_interface(interface_param, out_width, out_height);
++      set_mclk_rate(&interface_param->mclk);
++      mt9v111_rate_cal(frame_rate, interface_param->mclk);
++      mt9v111_sensor_lib(mt9v111_device.coreReg, mt9v111_device.ifpReg);
++
++      return interface_param;
++}
++
++/*!
++ * mt9v111 sensor set color configuration
++ *
++ * @param bright       int
++ * @param saturation   int
++ * @param red          int
++ * @param green        int
++ * @param blue         int
++ * @return  None
++ */
++static void
++mt9v111_set_color(int bright, int saturation, int red, int green, int blue)
++{
++      u8 reg;
++      u16 data;
++
++      switch (saturation) {
++      case 100:
++              mt9v111_device.ifpReg->awbSpeed = 0x4514;
++              break;
++      case 150:
++              mt9v111_device.ifpReg->awbSpeed = 0x6D14;
++              break;
++      case 75:
++              mt9v111_device.ifpReg->awbSpeed = 0x4D14;
++              break;
++      case 50:
++              mt9v111_device.ifpReg->awbSpeed = 0x5514;
++              break;
++      case 37:
++              mt9v111_device.ifpReg->awbSpeed = 0x5D14;
++              break;
++      case 25:
++              mt9v111_device.ifpReg->awbSpeed = 0x6514;
++              break;
++      default:
++              mt9v111_device.ifpReg->awbSpeed = 0x4514;
++              break;
++      }
++
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = mt9v111_device.ifpReg->addrSpaceSel;
++      mt9v111_write_reg(reg, data);
++
++      // Operation Mode Control
++      reg = MT9V111I_AWB_SPEED;
++      data = mt9v111_device.ifpReg->awbSpeed;
++      mt9v111_write_reg(reg, data);
++}
++
++/*!
++ * mt9v111 sensor get color configuration
++ *
++ * @param bright       int *
++ * @param saturation   int *
++ * @param red          int *
++ * @param green        int *
++ * @param blue         int *
++ * @return  None
++ */
++static void
++mt9v111_get_color(int *bright, int *saturation, int *red, int *green, int *blue)
++{
++      *saturation = (mt9v111_device.ifpReg->awbSpeed & 0x3800) >> 11;
++      switch (*saturation) {
++      case 0:
++              *saturation = 100;
++              break;
++      case 1:
++              *saturation = 75;
++              break;
++      case 2:
++              *saturation = 50;
++              break;
++      case 3:
++              *saturation = 37;
++              break;
++      case 4:
++              *saturation = 25;
++              break;
++      case 5:
++              *saturation = 150;
++              break;
++      case 6:
++              *saturation = 0;
++              break;
++      default:
++              *saturation = 0;
++              break;
++      }
++}
++
++/*!
++ * mt9v111 sensor set AE measurement window mode configuration
++ *
++ * @param ae_mode      int
++ * @return  None
++ */
++static void mt9v111_set_ae_mode(int ae_mode)
++{
++      u8 reg;
++      u16 data;
++
++      mt9v111_device.ifpReg->modeControl &= 0xfff3;
++      mt9v111_device.ifpReg->modeControl |= (ae_mode & 0x03) << 2;
++
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = mt9v111_device.ifpReg->addrSpaceSel;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111I_MODE_CONTROL;
++      data = mt9v111_device.ifpReg->modeControl;
++      mt9v111_write_reg(reg, data);
++}
++
++/*!
++ * mt9v111 sensor get AE measurement window mode configuration
++ *
++ * @param ae_mode      int *
++ * @return  None
++ */
++static void mt9v111_get_ae_mode(int *ae_mode)
++{
++      if (ae_mode != NULL) {
++              *ae_mode = (mt9v111_device.ifpReg->modeControl & 0xc) >> 2;
++      }
++}
++
++/*!
++ * mt9v111 sensor enable/disable AE 
++ *
++ * @param active      int
++ * @return  None
++ */
++static void mt9v111_set_ae(int active)
++{
++      u8 reg;
++      u16 data;
++
++      mt9v111_device.ifpReg->modeControl &= 0xBFFF; 
++      mt9v111_device.ifpReg->modeControl |= (active & 0x01) << 14;
++
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = mt9v111_device.ifpReg->addrSpaceSel;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111I_MODE_CONTROL;
++      data = mt9v111_device.ifpReg->modeControl;
++      mt9v111_write_reg(reg, data);
++}
++
++ /*!
++ * mt9v111 sensor set AE gain
++ *
++ * @param active      int
++ * @return  None
++ */
++static void mt9v111_set_ae_limit(int limit)
++{
++       u8 reg;
++       u16 data;
++
++       mt9v111_device.ifpReg->gainLimitAE = (limit & 0x1F) << 5;
++
++       reg = MT9V111I_ADDR_SPACE_SEL;
++       data = mt9v111_device.ifpReg->addrSpaceSel;
++       mt9v111_write_reg(reg, data);
++
++       reg = MT9V111I_SHUTTER_WIDTH_LIMIT_AE;
++       data = mt9v111_device.ifpReg->gainLimitAE;
++       mt9v111_write_reg(reg, data);
++}
++
++
++/*!
++ * mt9v111 sensor enable/disable auto white balance
++ *
++ * @param active      int
++ * @return  None
++ */
++static void mt9v111_set_awb(int active)
++{
++      u8 reg;
++      u16 data;
++
++      mt9v111_device.ifpReg->modeControl &= 0xFFFD;
++      mt9v111_device.ifpReg->modeControl |= (active & 0x01) << 1;
++
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = mt9v111_device.ifpReg->addrSpaceSel;
++      mt9v111_write_reg(reg, data);
++
++      reg = MT9V111I_MODE_CONTROL;
++      data = mt9v111_device.ifpReg->modeControl;
++      mt9v111_write_reg(reg, data);
++}
++
++/*!
++ * mt9v111 sensor set the flicker control 
++ *
++ * @param control      int
++ * @return  None
++ */
++static void mt9v111_flicker_control(int control)
++{
++      u8 reg;
++      u16 data;
++
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = mt9v111_device.ifpReg->addrSpaceSel;
++      mt9v111_write_reg(reg, data);
++
++      switch (control) {
++      case V4L2_MXC_FLICKER_DISABLE:
++              mt9v111_device.ifpReg->formatControl &= ~(0x01 << 11);
++
++              reg = MT9V111I_FORMAT_CONTROL;
++              data = mt9v111_device.ifpReg->formatControl;
++              mt9v111_write_reg(reg, data);
++              break;
++
++      case V4L2_MXC_FLICKER_50HZ:
++              if (!(mt9v111_device.ifpReg->formatControl & (0x01 << 11))) {
++                      mt9v111_device.ifpReg->formatControl |= (0x01 << 11);
++                      reg = MT9V111I_FORMAT_CONTROL;
++                      data = mt9v111_device.ifpReg->formatControl;
++                      mt9v111_write_reg(reg, data);
++              }
++              mt9v111_device.ifpReg->flickerCtrl = 0x01;
++              reg = MT9V111I_FLICKER_CONTROL;
++              data = mt9v111_device.ifpReg->flickerCtrl;
++              mt9v111_write_reg(reg, data);
++              break;
++
++      case V4L2_MXC_FLICKER_60HZ:
++              if (!(mt9v111_device.ifpReg->formatControl & (0x01 << 11))) {
++                      mt9v111_device.ifpReg->formatControl |= (0x01 << 11);
++                      reg = MT9V111I_FORMAT_CONTROL;
++                      data = mt9v111_device.ifpReg->formatControl;
++                      mt9v111_write_reg(reg, data);
++              }
++              mt9v111_device.ifpReg->flickerCtrl = 0x03;
++              reg = MT9V111I_FLICKER_CONTROL;
++              data = mt9v111_device.ifpReg->flickerCtrl;
++              mt9v111_write_reg(reg, data);
++              break;
++
++      case V4L2_MXC_FLICKER_AUTO:
++              if (!(mt9v111_device.ifpReg->formatControl & (0x01 << 11))) {
++                      mt9v111_device.ifpReg->formatControl |= (0x01 << 11);
++                      reg = MT9V111I_FORMAT_CONTROL;
++                      data = mt9v111_device.ifpReg->formatControl;
++                      mt9v111_write_reg(reg, data);
++              }
++              mt9v111_device.ifpReg->flickerCtrl = 0x10;
++              reg = MT9V111I_FLICKER_CONTROL;
++              data = mt9v111_device.ifpReg->flickerCtrl;
++              mt9v111_write_reg(reg, data);
++              break;
++      }
++      return;
++
++}
++
++/*!
++ * mt9v111 Get mode&flicker control parameters 
++ *
++ * @return  None
++ */
++static void mt9v111_get_control_params(int *ae, int *awb, int *flicker)
++{
++      if ((ae != NULL) && (awb != NULL) && (flicker != NULL)) {
++              *ae = (mt9v111_device.ifpReg->modeControl & 0x4000) >> 14;
++              *awb = (mt9v111_device.ifpReg->modeControl & 0x02) >> 1;
++              *flicker = (mt9v111_device.ifpReg->formatControl & 0x800) >> 9;
++              if (*flicker) {
++                      *flicker = (mt9v111_device.ifpReg->flickerCtrl & 0x03);
++                      switch (*flicker) {
++                      case 1:
++                              *flicker = V4L2_MXC_FLICKER_50HZ;
++                              break;
++                      case 3:
++                              *flicker = V4L2_MXC_FLICKER_60HZ;
++                              break;
++                      default:
++                              *flicker = V4L2_MXC_FLICKER_AUTO;
++                              break;
++                      }
++              } else
++                      *flicker = V4L2_MXC_FLICKER_DISABLE;
++      }
++      return;
++}
++
++/*!
++ * mt9v111 Reset function
++ *
++ * @return  None
++ */
++static sensor_interface *mt9v111_reset(void)
++{
++      return mt9v111_config(&reset_frame_rate, 0);
++}
++
++/*!
++ * mt9v111 get_status function
++ *
++ * @return  int
++ */
++static int mt9v111_get_status(void)
++{
++      int retval = 0;
++      u8 reg;
++      u16 data = 0;
++
++      if (!interface_param)
++              return -ENODEV;
++
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = MT9V111I_SEL_SCA;
++      retval = mt9v111_write_reg(reg, data);
++
++      reg = MT9V111S_SENSOR_CORE_VERSION;
++      retval = mt9v111_read_reg(&reg, &data);
++      data = mt9v111_endian_swap16(data);
++      if (MT9V111_CHIP_VERSION != data)
++              retval = -ENODEV;
++
++      return retval;
++}
++
++struct camera_sensor camera_sensor_if = {
++      .set_color = mt9v111_set_color,
++      .get_color = mt9v111_get_color,
++      .set_ae_mode = mt9v111_set_ae_mode,
++      .get_ae_mode = mt9v111_get_ae_mode,
++      .set_ae = mt9v111_set_ae,
++      .set_ae_limit = mt9v111_set_ae_limit,
++      .set_awb = mt9v111_set_awb,
++      .flicker_control = mt9v111_flicker_control,
++      .get_control_params = mt9v111_get_control_params,
++      .config = mt9v111_config,
++      .reset = mt9v111_reset,
++      .get_status = mt9v111_get_status,
++};
++
++#ifdef MT9V111_DEBUG
++/*!
++ * Set sensor to test mode, which will generate test pattern.
++ *
++ * @return none
++ */
++static void mt9v111_test_pattern(bool flag)
++{
++      u8 reg;
++      u16 data;
++
++      // switch to sensor registers
++      reg = MT9V111I_ADDR_SPACE_SEL;
++      data = MT9V111I_SEL_SCA;
++      mt9v111_write_reg(reg, data);
++
++      if (flag == true) {
++              testpattern = MT9V111S_OUTCTRL_TEST_MODE;
++
++              reg = MT9V111S_ROW_NOISE_CTRL;
++              data = mt9v111_read_reg(&reg, &data) & 0xBF;
++              data = mt9v111_endian_swap16(data);
++              mt9v111_write_reg(reg, data);
++
++              reg = MT9V111S_TEST_DATA;
++              data = 0;
++              mt9v111_write_reg(reg, data);
++
++              reg = MT9V111S_OUTPUT_CTRL;
++              // changes take effect
++              data = MT9V111S_OUTCTRL_CHIP_ENABLE | testpattern | 0x3000;
++              mt9v111_write_reg(reg, data);
++      } else {
++              testpattern = 0;
++
++              reg = MT9V111S_ROW_NOISE_CTRL;
++              data = mt9v111_read_reg(&reg, &data) | 0x40;
++              data = mt9v111_endian_swap16(data);
++              mt9v111_write_reg(reg, data);
++
++              reg = MT9V111S_OUTPUT_CTRL;
++              // changes take effect
++              data = MT9V111S_OUTCTRL_CHIP_ENABLE | testpattern | 0x3000;
++              mt9v111_write_reg(reg, data);
++      }
++}
++#endif
++
++/*!
++ * mt9v111 I2C detect_client function
++ *
++ * @param adapter            struct i2c_adapter *
++ * @param address            int
++ * @param kind               int
++ * 
++ * @return  Error code indicating success or failure
++ */
++static int mt9v111_detect_client(struct i2c_adapter *adapter, int address,
++                               int kind)
++{
++      mt9v111_i2c_client.adapter = adapter;
++      if (i2c_attach_client(&mt9v111_i2c_client)) {
++              mt9v111_i2c_client.adapter = NULL;
++              printk(KERN_ERR "mt9v111_attach: i2c_attach_client failed\n");
++              return -1;
++      }
++
++      interface_param = (sensor_interface *)
++          kmalloc(sizeof(sensor_interface), GFP_KERNEL);
++      if (!interface_param) {
++              printk(KERN_ERR "mt9v111_attach: kmalloc failed \n");
++              return -1;
++      }
++
++      printk(KERN_INFO "MT9V111 Detected\n");
++
++      return 0;
++}
++
++static unsigned short normal_i2c[] = { MT9V111_I2C_ADDRESS, I2C_CLIENT_END };
++
++/* Magic definition of all other variables and things */
++I2C_CLIENT_INSMOD;
++
++/*!
++ * mt9v111 I2C attach function
++ *
++ * @param adapter            struct i2c_adapter *
++ * @return  Error code indicating success or failure
++ */
++static int mt9v111_attach(struct i2c_adapter *adap)
++{
++      uint32_t mclk = 27000000;
++      struct clk *clk;
++      int err;
++
++      clk = clk_get(NULL, "csi_clk");
++      clk_enable(clk);
++      set_mclk_rate(&mclk);
++
++      err = i2c_probe(adap, &addr_data, &mt9v111_detect_client);
++      clk_disable(clk);
++      clk_put(clk);
++
++      return err;
++}
++
++/*!
++ * mt9v111 I2C detach function
++ *
++ * @param client            struct i2c_client *
++ * @return  Error code indicating success or failure
++ */
++static int mt9v111_detach(struct i2c_client *client)
++{
++      int err;
++
++      if (!mt9v111_i2c_client.adapter)
++              return -1;
++
++      err = i2c_detach_client(&mt9v111_i2c_client);
++      mt9v111_i2c_client.adapter = NULL;
++
++      if (interface_param)
++              kfree(interface_param);
++      interface_param = NULL;
++
++      return err;
++}
++
++extern void gpio_sensor_active(void);
++
++/*!
++ * MT9V111 init function
++ *
++ * @return  Error code indicating success or failure
++ */
++static __init int mt9v111_init(void)
++{
++      u8 err;
++
++      gpio_sensor_active();
++
++      mt9v111_device.coreReg = (mt9v111_coreReg *)
++          kmalloc(sizeof(mt9v111_coreReg), GFP_KERNEL);
++      if (!mt9v111_device.coreReg)
++              return -1;
++
++      memset(mt9v111_device.coreReg, 0, sizeof(mt9v111_coreReg));
++
++      mt9v111_device.ifpReg = (mt9v111_IFPReg *)
++          kmalloc(sizeof(mt9v111_IFPReg), GFP_KERNEL);
++      if (!mt9v111_device.ifpReg) {
++              kfree(mt9v111_device.coreReg);
++              mt9v111_device.coreReg = NULL;
++              return -1;
++      }
++
++      memset(mt9v111_device.ifpReg, 0, sizeof(mt9v111_IFPReg));
++
++      err = i2c_add_driver(&mt9v111_i2c_driver);
++      return err;
++}
++
++extern void gpio_sensor_inactive(void);
++/*!
++ * MT9V111 cleanup function
++ *
++ * @return  Error code indicating success or failure
++ */
++static void __exit mt9v111_clean(void)
++{
++      if (mt9v111_device.coreReg) {
++              kfree(mt9v111_device.coreReg);
++              mt9v111_device.coreReg = NULL;
++      }
++
++      if (mt9v111_device.ifpReg) {
++              kfree(mt9v111_device.ifpReg);
++              mt9v111_device.ifpReg = NULL;
++      }
++
++      i2c_del_driver(&mt9v111_i2c_driver);
++
++      gpio_sensor_inactive();
++}
++
++module_init(mt9v111_init);
++module_exit(mt9v111_clean);
++
++/* Exported symbols for modules. */
++EXPORT_SYMBOL(camera_sensor_if);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("Mt9v111 Camera Driver");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mt9v111.h linux-2.6.28-karo/drivers/media/video/mxc/capture/mt9v111.h
+--- linux-2.6.28/drivers/media/video/mxc/capture/mt9v111.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mt9v111.h        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,435 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup Camera Sensor Drivers
++ */
++
++/*!
++ * @file mt9v111.h
++ *
++ * @brief MT9V111 Camera Header file
++ *
++ * It include all the defines for bitmaps operations, also two main structure
++ * one for IFP interface structure, other for sensor core registers.
++ *
++ * @ingroup Camera
++ */
++
++#ifndef MT9V111_H_
++#define MT9V111_H_
++
++/*!
++ * mt9v111 CHIP VERSION 
++ */
++#define MT9V111_CHIP_VERSION  0x823A
++
++/*!
++ * mt9v111 IFP REGISTER BANK MAP
++ */
++#define MT9V111I_ADDR_SPACE_SEL           0x1
++#define MT9V111I_BASE_MAXTRIX_SIGN        0x2
++#define MT9V111I_BASE_MAXTRIX_SCALE15     0x3
++#define MT9V111I_BASE_MAXTRIX_SCALE69     0x4
++#define MT9V111I_APERTURE_GAIN            0x5
++#define MT9V111I_MODE_CONTROL             0x6
++#define MT9V111I_SOFT_RESET               0x7
++#define MT9V111I_FORMAT_CONTROL           0x8
++#define MT9V111I_BASE_MATRIX_CFK1         0x9
++#define MT9V111I_BASE_MATRIX_CFK2         0xa
++#define MT9V111I_BASE_MATRIX_CFK3         0xb
++#define MT9V111I_BASE_MATRIX_CFK4         0xc
++#define MT9V111I_BASE_MATRIX_CFK5         0xd
++#define MT9V111I_BASE_MATRIX_CFK6         0xe
++#define MT9V111I_BASE_MATRIX_CFK7         0xf
++#define MT9V111I_BASE_MATRIX_CFK8         0x10
++#define MT9V111I_BASE_MATRIX_CFK9         0x11
++#define MT9V111I_AWB_POSITION             0x12
++#define MT9V111I_AWB_RED_GAIN             0x13
++#define MT9V111I_AWB_BLUE_GAIN            0x14
++#define MT9V111I_DELTA_MATRIX_CF_SIGN     0x15
++#define MT9V111I_DELTA_MATRIX_CF_D1       0x16
++#define MT9V111I_DELTA_MATRIX_CF_D2       0x17
++#define MT9V111I_DELTA_MATRIX_CF_D3       0x18
++#define MT9V111I_DELTA_MATRIX_CF_D4       0x19
++#define MT9V111I_DELTA_MATRIX_CF_D5       0x1a
++#define MT9V111I_DELTA_MATRIX_CF_D6       0x1b
++#define MT9V111I_DELTA_MATRIX_CF_D7       0x1c
++#define MT9V111I_DELTA_MATRIX_CF_D8       0x1d
++#define MT9V111I_DELTA_MATRIX_CF_D9       0x1e
++#define MT9V111I_LUMINANCE_LIMIT_WB       0x20
++#define MT9V111I_RBG_MANUUAL_WB           0x21
++#define MT9V111I_AWB_RED_LIMIT            0x22
++#define MT9V111I_AWB_BLUE_LIMIT           0x23
++#define MT9V111I_MATRIX_ADJUST_LIMIT      0x24
++#define MT9V111I_AWB_SPEED                0x25
++#define MT9V111I_H_BOUND_AE               0x26
++#define MT9V111I_V_BOUND_AE               0x27
++#define MT9V111I_H_BOUND_AE_CEN_WIN       0x2b
++#define MT9V111I_V_BOUND_AE_CEN_WIN       0x2c
++#define MT9V111I_BOUND_AWB_WIN            0x2d
++#define MT9V111I_AE_PRECISION_TARGET      0x2e
++#define MT9V111I_AE_SPEED                 0x2f
++#define MT9V111I_RED_AWB_MEASURE          0x30
++#define MT9V111I_LUMA_AWB_MEASURE         0x31
++#define MT9V111I_BLUE_AWB_MEASURE         0x32
++#define MT9V111I_LIMIT_SHARP_SATU_CTRL    0x33
++#define MT9V111I_LUMA_OFFSET              0x34
++#define MT9V111I_CLIP_LIMIT_OUTPUT_LUMI   0x35
++#define MT9V111I_GAIN_LIMIT_AE            0x36
++#define MT9V111I_SHUTTER_WIDTH_LIMIT_AE   0x37
++#define MT9V111I_UPPER_SHUTTER_DELAY_LIM  0x39
++#define MT9V111I_OUTPUT_FORMAT_CTRL2      0x3a
++#define MT9V111I_IPF_BLACK_LEVEL_SUB      0x3b
++#define MT9V111I_IPF_BLACK_LEVEL_ADD      0x3c
++#define MT9V111I_ADC_LIMIT_AE_ADJ         0x3d
++#define MT9V111I_GAIN_THRE_CCAM_ADJ       0x3e
++#define MT9V111I_LINEAR_AE                0x3f
++#define MT9V111I_THRESHOLD_EDGE_DEFECT    0x47
++#define MT9V111I_LUMA_SUM_MEASURE         0x4c
++#define MT9V111I_TIME_ADV_SUM_LUMA        0x4d
++#define MT9V111I_MOTION                   0x52
++#define MT9V111I_GAMMA_KNEE_Y12           0x53
++#define MT9V111I_GAMMA_KNEE_Y34           0x54
++#define MT9V111I_GAMMA_KNEE_Y56           0x55
++#define MT9V111I_GAMMA_KNEE_Y78           0x56
++#define MT9V111I_GAMMA_KNEE_Y90           0x57
++#define MT9V111I_GAMMA_VALUE_Y0           0x58
++#define MT9V111I_SHUTTER_60               0x59
++#define MT9V111I_FLICKER_CONTROL        0x5B
++#define MT9V111I_SEARCH_FLICK_60          0x5c
++#define MT9V111I_RATIO_IMAGE_GAIN_BASE    0x5e
++#define MT9V111I_RATIO_IMAGE_GAIN_DELTA   0x5f
++#define MT9V111I_SIGN_VALUE_REG5F         0x60
++#define MT9V111I_AE_GAIN                  0x62
++#define MT9V111I_MAX_GAIN_AE              0x67
++#define MT9V111I_LENS_CORRECT_CTRL        0x80
++#define MT9V111I_SHADING_PARAMETER1       0x81
++#define MT9V111I_SHADING_PARAMETER2       0x82
++#define MT9V111I_SHADING_PARAMETER3       0x83
++#define MT9V111I_SHADING_PARAMETER4       0x84
++#define MT9V111I_SHADING_PARAMETER5       0x85
++#define MT9V111I_SHADING_PARAMETER6       0x86
++#define MT9V111I_SHADING_PARAMETER7       0x87
++#define MT9V111I_SHADING_PARAMETER8       0x88
++#define MT9V111I_SHADING_PARAMETER9       0x89
++#define MT9V111I_SHADING_PARAMETER10      0x8A
++#define MT9V111I_SHADING_PARAMETER11      0x8B
++#define MT9V111I_SHADING_PARAMETER12      0x8C
++#define MT9V111I_SHADING_PARAMETER13      0x8D
++#define MT9V111I_SHADING_PARAMETER14      0x8E
++#define MT9V111I_SHADING_PARAMETER15      0x8F
++#define MT9V111I_SHADING_PARAMETER16      0x90
++#define MT9V111I_SHADING_PARAMETER17      0x91
++#define MT9V111I_SHADING_PARAMETER18      0x92
++#define MT9V111I_SHADING_PARAMETER19      0x93
++#define MT9V111I_SHADING_PARAMETER20      0x94
++#define MT9V111I_SHADING_PARAMETER21      0x95
++#define MT9V111i_FLASH_CTRL               0x98
++#define MT9V111i_LINE_COUNTER             0x99
++#define MT9V111i_FRAME_COUNTER            0x9A
++#define MT9V111i_H_PAN                    0xA5
++#define MT9V111i_H_ZOOM                   0xA6
++#define MT9V111i_H_SIZE                   0xA7
++#define MT9V111i_V_PAN                    0xA8
++#define MT9V111i_V_ZOOM                   0xA9
++#define MT9V111i_V_SIZE                   0xAA
++
++#define MT9V111I_SEL_IFP                  0x1
++#define MT9V111I_SEL_SCA                  0x4
++#define MT9V111I_FC_RGB_OR_YUV            0x1000
++
++/*!
++ * Mt9v111 SENSOR CORE REGISTER BANK MAP
++ */
++#define MT9V111S_ADDR_SPACE_SEL           0x1
++#define MT9V111S_COLUMN_START             0x2
++#define MT9V111S_WIN_HEIGHT               0x3
++#define MT9V111S_WIN_WIDTH                0x4
++#define MT9V111S_HOR_BLANKING             0x5
++#define MT9V111S_VER_BLANKING             0x6
++#define MT9V111S_OUTPUT_CTRL              0x7
++#define MT9V111S_ROW_START                0x8
++#define MT9V111S_SHUTTER_WIDTH            0x9
++#define MT9V111S_PIXEL_CLOCK_SPEED        0xa
++#define MT9V111S_RESTART                  0xb
++#define MT9V111S_SHUTTER_DELAY            0xc
++#define MT9V111S_RESET                    0xd
++#define MT9V111S_COLUMN_START_IN_ZOOM     0x12
++#define MT9V111S_ROW_START_IN_ZOOM        0x13
++#define MT9V111S_DIGITAL_ZOOM             0x1e
++#define MT9V111S_READ_MODE                0x20
++#define MT9V111S_DAC_CTRL                 0x27
++#define MT9V111S_GREEN1_GAIN              0x2b
++#define MT9V111S_BLUE_GAIN                0x2c
++#define MT9V111S_READ_GAIN                0x2d
++#define MT9V111S_GREEN2_GAIN              0x2e
++#define MT9V111S_ROW_NOISE_CTRL           0x30
++#define MT9V111S_DARK_TARGET_W            0x31
++#define MT9V111S_TEST_DATA                0x32
++#define MT9V111S_GLOBAL_GAIN              0x35
++#define MT9V111S_SENSOR_CORE_VERSION      0x36
++#define MT9V111S_DARK_TARGET_WO           0x37
++#define MT9V111S_VERF_DAC                 0x41
++#define MT9V111S_VCM_VCL                  0x42
++#define MT9V111S_DISABLE_BYPASS           0x58
++#define MT9V111S_CALIB_MEAN_TEST          0x59
++#define MT9V111S_DARK_G1_AVE              0x5B
++#define MT9V111S_DARK_G2_AVE              0x5C
++#define MT9V111S_DARK_R_AVE               0x5D
++#define MT9V111S_DARK_B_AVE               0x5E
++#define MT9V111S_CAL_THRESHOLD            0x5f
++#define MT9V111S_CAL_G1                   0x60
++#define MT9V111S_CAL_G2                   0x61
++#define MT9V111S_CAL_CTRL                 0x62
++#define MT9V111S_CAL_R                    0x63
++#define MT9V111S_CAL_B                    0x64
++#define MT9V111S_CHIP_ENABLE              0xF1
++#define MT9V111S_CHIP_VERSION             0xFF
++
++// OUTPUT_CTRL
++#define MT9V111S_OUTCTRL_SYNC             0x1
++#define MT9V111S_OUTCTRL_CHIP_ENABLE      0x2
++#define MT9V111S_OUTCTRL_TEST_MODE        0x40
++
++// READ_MODE
++#define MT9V111S_RM_NOBADFRAME            0x1
++#define MT9V111S_RM_NODESTRUCT            0x2
++#define MT9V111S_RM_COLUMNSKIP            0x4
++#define MT9V111S_RM_ROWSKIP               0x8
++#define MT9V111S_RM_BOOSTEDRESET          0x1000
++#define MT9V111S_RM_COLUMN_LATE           0x10
++#define MT9V111S_RM_ROW_LATE              0x80
++#define MT9V111S_RM_RIGTH_TO_LEFT         0x4000
++#define MT9V111S_RM_BOTTOM_TO_TOP         0x8000
++
++/*! I2C Slave Address */
++#define MT9V111_I2C_ADDRESS   0x48
++
++/*!
++ * The image resolution enum for the mt9v111 sensor
++ */
++typedef enum {
++      MT9V111_OutputResolution_VGA = 0,       /*!< VGA size */
++      MT9V111_OutputResolution_QVGA,  /*!< QVGA size */
++      MT9V111_OutputResolution_CIF,   /*!< CIF size */
++      MT9V111_OutputResolution_QCIF,  /*!< QCIF size */
++      MT9V111_OutputResolution_QQVGA, /*!< QQVGA size */
++      MT9V111_OutputResolution_SXGA   /*!< SXGA size */
++} MT9V111_OutputResolution;
++
++enum {
++      MT9V111_WINWIDTH = 0x287,
++      MT9V111_WINWIDTH_DEFAULT = 0x287,
++      MT9V111_WINWIDTH_MIN = 0x9,
++
++      MT9V111_WINHEIGHT = 0x1E7,
++      MT9V111_WINHEIGHT_DEFAULT = 0x1E7,
++
++      MT9V111_HORZBLANK_DEFAULT = 0x26,
++      MT9V111_HORZBLANK_MIN = 0x9,
++      MT9V111_HORZBLANK_MAX = 0x3FF,
++
++      MT9V111_VERTBLANK_DEFAULT = 0x4,
++      MT9V111_VERTBLANK_MIN = 0x3,
++      MT9V111_VERTBLANK_MAX = 0xFFF,
++};
++
++/*!
++ * Mt9v111 Core Register structure.
++ */
++typedef struct {
++      u32 addressSelect;      /*!< select address bank for Core Register 0x4 */
++      u32 columnStart;        /*!< Starting Column */
++      u32 windowHeight;       /*!< Window Height */
++      u32 windowWidth;        /*!< Window Width */
++      u32 horizontalBlanking; /*!< Horizontal Blank time, in pixels */
++      u32 verticalBlanking;   /*!< Vertical Blank time, in pixels */
++      u32 outputControl;      /*!< Register to control sensor output */
++      u32 rowStart;           /*!< Starting Row */
++      u32 shutterWidth;
++      u32 pixelClockSpeed;    /*!< pixel date rate */
++      u32 restart;            /*!< Abandon the readout of current frame */
++      u32 shutterDelay;
++      u32 reset;              /*!< reset the sensor to the default mode */
++      u32 zoomColStart;       /*!< Column start in the Zoom mode */
++      u32 zomRowStart;        /*!< Row start in the Zoom mode */
++      u32 digitalZoom;        /*!< 1 means zoom by 2 */
++      u32 readMode;           /*!< Readmode: aspects of the readout of the sensor */
++      u32 dACStandbyControl;
++      u32 green1Gain;         /*!< Gain Settings */
++      u32 blueGain;
++      u32 redGain;
++      u32 green2Gain;
++      u32 rowNoiseControl;
++      u32 darkTargetwNC;
++      u32 testData;           /*!< test mode */
++      u32 globalGain;
++      u32 chipVersion;
++      u32 darkTargetwoNC;
++      u32 vREFDACs;
++      u32 vCMandVCL;
++      u32 disableBypass;
++      u32 calibMeanTest;
++      u32 darkG1average;
++      u32 darkG2average;
++      u32 darkRaverage;
++      u32 darkBaverage;
++      u32 calibThreshold;
++      u32 calibGreen1;
++      u32 calibGreen2;
++      u32 calibControl;
++      u32 calibRed;
++      u32 calibBlue;
++      u32 chipEnable;         /*!< Image core Registers written by image flow processor */
++} mt9v111_coreReg;
++
++/*!
++ * Mt9v111 IFP Register structure.
++ */
++typedef struct {
++      u32 addrSpaceSel;       /*!< select address bank for Core Register 0x1 */
++      u32 baseMaxtrixSign;    /*!< sign of coefficient for base color correction matrix */
++      u32 baseMaxtrixScale15; /*!< scaling of color correction coefficient K1-5 */
++      u32 baseMaxtrixScale69; /*!< scaling of color correction coefficient K6-9 */
++      u32 apertureGain;       /*!< sharpening */
++      u32 modeControl;        /*!< bit 7 CCIR656 sync codes are embedded in the image */
++      u32 softReset;          /*!< Image processing mode: 1 reset mode, 0 operational mode */
++      u32 formatControl;      /*!< bit12 1 for RGB565, 0 for YcrCb */
++      u32 baseMatrixCfk1;     /*!< K1 Color correction coefficient */
++      u32 baseMatrixCfk2;     /*!< K2 Color correction coefficient */
++      u32 baseMatrixCfk3;     /*!< K3 Color correction coefficient */
++      u32 baseMatrixCfk4;     /*!< K4 Color correction coefficient */
++      u32 baseMatrixCfk5;     /*!< K5 Color correction coefficient */
++      u32 baseMatrixCfk6;     /*!< K6 Color correction coefficient */
++      u32 baseMatrixCfk7;     /*!< K7 Color correction coefficient */
++      u32 baseMatrixCfk8;     /*!< K8 Color correction coefficient */
++      u32 baseMatrixCfk9;     /*!< K9 Color correction coefficient */
++      u32 awbPosition;        /*!< Current position of AWB color correction matrix */
++      u32 awbRedGain;         /*!< Current value of AWB red channel gain */
++      u32 awbBlueGain;        /*!< Current value of AWB blue channel gain */
++      u32 deltaMatrixCFSign;  /*!< Sign of coefficients of delta color correction matrix register */
++      u32 deltaMatrixCFD1;    /*!< D1 Delta coefficient */
++      u32 deltaMatrixCFD2;    /*!< D2 Delta coefficient */
++      u32 deltaMatrixCFD3;    /*!< D3 Delta coefficient */
++      u32 deltaMatrixCFD4;    /*!< D4 Delta coefficient */
++      u32 deltaMatrixCFD5;    /*!< D5 Delta coefficient */
++      u32 deltaMatrixCFD6;    /*!< D6 Delta coefficient */
++      u32 deltaMatrixCFD7;    /*!< D7 Delta coefficient */
++      u32 deltaMatrixCFD8;    /*!< D8 Delta coefficient */
++      u32 deltaMatrixCFD9;    /*!< D9 Delta coefficient */
++      u32 lumLimitWB;         /*!< Luminance range of pixels considered in WB statistics */
++      u32 RBGManualWB;        /*!< Red and Blue color channel gains for manual white balance */
++      u32 awbRedLimit;        /*!< Limits on Red channel gain adjustment through AWB */
++      u32 awbBlueLimit;       /*!< Limits on Blue channel gain adjustment through AWB */
++      u32 matrixAdjLimit;     /*!< Limits on color correction matrix adjustment through AWB */
++      u32 awbSpeed;           /*!< AWB speed and color saturation control */
++      u32 HBoundAE;           /*!< Horizontal boundaries of AWB measurement window */
++      u32 VBoundAE;           /*!< Vertical boundaries of AWB measurement window */
++      u32 HBoundAECenWin;     /*!< Horizontal boundaries of AE measurement window for backlight compensation */
++      u32 VBoundAECenWin;     /*!< Vertical boundaries of AE measurement window for backlight compensation */
++      u32 boundAwbWin;        /*!< Boundaries of AWB measurement window */
++      u32 AEPrecisionTarget;  /*!< Auto exposure target and precision control */
++      u32 AESpeed;            /*!< AE speed and sensitivity control register */
++      u32 redAWBMeasure;      /*!< Measure of the red channel value used by AWB */
++      u32 lumaAWBMeasure;     /*!< Measure of the luminance channel value used by AWB */
++      u32 blueAWBMeasure;     /*!< Measure of the blue channel value used by AWB */
++      u32 limitSharpSatuCtrl; /*!< Automatic control of sharpness and color saturation */
++      u32 lumaOffset;         /*!< Luminance offset control (brightness control) */
++      u32 clipLimitOutputLumi;        /*!< Clipping limits for output luminance */
++      u32 gainLimitAE;        /*!< Imager gain limits for AE adjustment */
++      u32 shutterWidthLimitAE;        /*!< Shutter width (exposure time) limits for AE adjustment */
++      u32 upperShutterDelayLi;        /*!< Upper Shutter Delay Limit */
++      u32 outputFormatCtrl2;  /*!< Output Format Control 2
++                                 00 = 16-bit RGB565.
++                                 01 = 15-bit RGB555.
++                                 10 = 12-bit RGB444x.
++                                 11 = 12-bit RGBx444.       */
++      u32 ipfBlackLevelSub;   /*!< IFP black level subtraction */
++      u32 ipfBlackLevelAdd;   /*!< IFP black level addition */
++      u32 adcLimitAEAdj;      /*!< ADC limits for AE adjustment */
++      u32 agimnThreCamAdj;    /*!< Gain threshold for CCM adjustment */
++      u32 linearAE;
++      u32 thresholdEdgeDefect;        /*!< Edge threshold for interpolation and defect correction */
++      u32 lumaSumMeasure;     /*!< Luma measured by AE engine */
++      u32 timeAdvSumLuma;     /*!< Time-averaged luminance value tracked by auto exposure */
++      u32 motion;             /*!< 1 when motion is detected */
++      u32 gammaKneeY12;       /*!< Gamma knee points Y1 and Y2 */
++      u32 gammaKneeY34;       /*!< Gamma knee points Y3 and Y4 */
++      u32 gammaKneeY56;       /*!< Gamma knee points Y5 and Y6 */
++      u32 gammaKneeY78;       /*!< Gamma knee points Y7 and Y8 */
++      u32 gammaKneeY90;       /*!< Gamma knee points Y9 and Y10 */
++      u32 gammaKneeY0;        /*!< Gamma knee point Y0 */
++      u32 shutter_width_60;
++      u32 flickerCtrl;
++      u32 search_flicker_60;
++      u32 ratioImageGainBase;
++      u32 ratioImageGainDelta;
++      u32 signValueReg5F;
++      u32 aeGain;
++      u32 maxGainAE;
++      u32 lensCorrectCtrl;
++      u32 shadingParameter1;  /*!< Shade Parameters */
++      u32 shadingParameter2;
++      u32 shadingParameter3;
++      u32 shadingParameter4;
++      u32 shadingParameter5;
++      u32 shadingParameter6;
++      u32 shadingParameter7;
++      u32 shadingParameter8;
++      u32 shadingParameter9;
++      u32 shadingParameter10;
++      u32 shadingParameter11;
++      u32 shadingParameter12;
++      u32 shadingParameter13;
++      u32 shadingParameter14;
++      u32 shadingParameter15;
++      u32 shadingParameter16;
++      u32 shadingParameter17;
++      u32 shadingParameter18;
++      u32 shadingParameter19;
++      u32 shadingParameter20;
++      u32 shadingParameter21;
++      u32 flashCtrl;          /*!< Flash control */
++      u32 lineCounter;        /*!< Line counter */
++      u32 frameCounter;       /*!< Frame counter */
++      u32 HPan;               /*!< Horizontal pan in decimation */
++      u32 HZoom;              /*!< Horizontal zoom in decimation */
++      u32 HSize;              /*!< Horizontal output size iIn decimation */
++      u32 VPan;               /*!< Vertical pan in decimation */
++      u32 VZoom;              /*!< Vertical zoom in decimation */
++      u32 VSize;              /*!< Vertical output size in decimation */
++} mt9v111_IFPReg;
++
++/*!
++ * mt9v111 Config structure
++ */
++typedef struct {
++      mt9v111_coreReg *coreReg;       /*!< Sensor Core Register Bank */
++      mt9v111_IFPReg *ifpReg; /*!< IFP Register Bank */
++} mt9v111_conf;
++
++typedef struct {
++      u8 index;
++      u16 width;
++      u16 height;
++} mt9v111_image_format;
++
++typedef struct {
++      u16 ae;
++      u16 awb;
++      u16 flicker;
++      u16 reserved;
++} mt9v111_ctrl_params;
++
++#endif                                // MT9V111_H_
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mx27_csi.c linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_csi.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/mx27_csi.c    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_csi.c       2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,332 @@
++/*
++ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_csi.c
++ *
++ * @brief CMOS Sensor interface functions
++ *
++ * @ingroup CSI
++ */
++#include <linux/types.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/err.h>
++#include <linux/interrupt.h>
++#include <linux/spinlock.h>
++#include <linux/delay.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <asm/arch/clock.h>
++#include <asm/arch/hardware.h>
++
++#include "mx27_csi.h"
++
++static csi_config_t g_csi_cfg;        /* csi hardware configuration */
++static bool gcsi_mclk_on = false;
++static csi_irq_callback_t g_callback = 0;
++static void *g_callback_data = 0;
++static struct clk csi_mclk;
++
++static irqreturn_t csi_irq_handler(int irq, void *data)
++{
++      unsigned long status = __raw_readl(CSI_CSISR);
++
++      __raw_writel(status, CSI_CSISR);
++      if (g_callback)
++              g_callback(g_callback_data, status);
++
++      pr_debug("CSI status = 0x%08lX\n", status);
++
++      return IRQ_HANDLED;
++}
++
++static void csihw_set_config(csi_config_t * cfg)
++{
++      unsigned val = 0;
++
++      /* control reg 1 */
++      val |= cfg->swap16_en ? BIT_SWAP16_EN : 0;
++      val |= cfg->ext_vsync ? BIT_EXT_VSYNC : 0;
++      val |= cfg->eof_int_en ? BIT_EOF_INT_EN : 0;
++      val |= cfg->prp_if_en ? BIT_PRP_IF_EN : 0;
++      val |= cfg->ccir_mode ? BIT_CCIR_MODE : 0;
++      val |= cfg->cof_int_en ? BIT_COF_INT_EN : 0;
++      val |= cfg->sf_or_inten ? BIT_SF_OR_INTEN : 0;
++      val |= cfg->rf_or_inten ? BIT_RF_OR_INTEN : 0;
++      val |= cfg->statff_level << SHIFT_STATFF_LEVEL;
++      val |= cfg->staff_inten ? BIT_STATFF_INTEN : 0;
++      val |= cfg->rxff_level << SHIFT_RXFF_LEVEL;
++      val |= cfg->rxff_inten ? BIT_RXFF_INTEN : 0;
++      val |= cfg->sof_pol ? BIT_SOF_POL : 0;
++      val |= cfg->sof_inten ? BIT_SOF_INTEN : 0;
++      val |= cfg->mclkdiv << SHIFT_MCLKDIV;
++      val |= cfg->hsync_pol ? BIT_HSYNC_POL : 0;
++      val |= cfg->ccir_en ? BIT_CCIR_EN : 0;
++      val |= cfg->mclken ? BIT_MCLKEN : 0;
++      val |= cfg->fcc ? BIT_FCC : 0;
++      val |= cfg->pack_dir ? BIT_PACK_DIR : 0;
++      val |= cfg->gclk_mode ? BIT_GCLK_MODE : 0;
++      val |= cfg->inv_data ? BIT_INV_DATA : 0;
++      val |= cfg->inv_pclk ? BIT_INV_PCLK : 0;
++      val |= cfg->redge ? BIT_REDGE : 0;
++
++      __raw_writel(val, CSI_CSICR1);
++
++      /* control reg 3 */
++      val = 0x0;
++      val |= cfg->csi_sup ? BIT_CSI_SUP : 0;
++      val |= cfg->zero_pack_en ? BIT_ZERO_PACK_EN : 0;
++      val |= cfg->ecc_int_en ? BIT_ECC_INT_EN : 0;
++      val |= cfg->ecc_auto_en ? BIT_ECC_AUTO_EN : 0;
++
++      __raw_writel(val, CSI_CSICR3);
++
++      /* rxfifo counter */
++      __raw_writel(cfg->rxcnt, CSI_CSIRXCNT);
++
++      /* update global config */
++      memcpy(&g_csi_cfg, cfg, sizeof(csi_config_t));
++}
++
++static void csihw_reset_frame_count(void)
++{
++      __raw_writel(__raw_readl(CSI_CSICR3) | BIT_FRMCNT_RST, CSI_CSICR3);
++}
++
++static void csihw_reset(void)
++{
++      csihw_reset_frame_count();
++      __raw_writel(CSICR1_RESET_VAL, CSI_CSICR1);
++      __raw_writel(CSICR2_RESET_VAL, CSI_CSICR2);
++      __raw_writel(CSICR3_RESET_VAL, CSI_CSICR3);
++}
++
++/*!
++ * csi_init_interface
++ *    Sets initial values for the CSI registers.
++ *    The width and height of the sensor and the actual frame size will be
++ *    set to the same values.
++ * @param       width        Sensor width
++ * @param       height       Sensor height
++ * @param       pixel_fmt    pixel format
++ * @param       sig          csi_signal_cfg_t
++ *
++ * @return      0 for success, -EINVAL for error
++ */
++int32_t csi_init_interface(uint16_t width, uint16_t height,
++                         uint32_t pixel_fmt, csi_signal_cfg_t sig)
++{
++      csi_config_t cfg;
++
++      /* Set the CSI_SENS_CONF register remaining fields */
++      cfg.swap16_en = 1;
++      cfg.ext_vsync = sig.ext_vsync;
++      cfg.eof_int_en = 0;
++      cfg.prp_if_en = 1;
++      cfg.ccir_mode = 0;
++      cfg.cof_int_en = 0;
++      cfg.sf_or_inten = 0;
++      cfg.rf_or_inten = 0;
++      cfg.statff_level = 0;
++      cfg.staff_inten = 0;
++      cfg.rxff_level = 2;
++      cfg.rxff_inten = 0;
++      cfg.sof_pol = 1;
++      cfg.sof_inten = 0;
++      cfg.mclkdiv = 0;
++      cfg.hsync_pol = 1;
++      cfg.ccir_en = 0;
++      cfg.mclken = gcsi_mclk_on ? 1 : 0;
++      cfg.fcc = 1;
++      cfg.pack_dir = 0;
++      cfg.gclk_mode = 1;
++      cfg.inv_data = sig.data_pol;
++      cfg.inv_pclk = sig.pixclk_pol;
++      cfg.redge = 1;
++      cfg.csicnt1_rsv = 0;
++
++      /* control reg 3 */
++      cfg.frmcnt = 0;
++      cfg.frame_reset = 0;
++      cfg.csi_sup = 0;
++      cfg.zero_pack_en = 0;
++      cfg.ecc_int_en = 0;
++      cfg.ecc_auto_en = 0;
++
++      csihw_set_config(&cfg);
++
++      return 0;
++}
++
++/*!
++ * csi_enable_prpif
++ *    Enable or disable CSI-PrP interface
++ * @param       enable        Non-zero to enable, zero to disable
++ */
++void csi_enable_prpif(uint32_t enable)
++{
++      if (enable) {
++              g_csi_cfg.prp_if_en = 1;
++              g_csi_cfg.sof_inten = 0;
++              g_csi_cfg.pack_dir = 0;
++      } else {
++              g_csi_cfg.prp_if_en = 0;
++              g_csi_cfg.sof_inten = 1;
++              g_csi_cfg.pack_dir = 1;
++      }
++
++      csihw_set_config(&g_csi_cfg);
++}
++
++/*!
++ * csi_enable_mclk
++ *
++ * @param       src         enum define which source to control the clk
++ *                          CSI_MCLK_VF CSI_MCLK_ENC CSI_MCLK_RAW CSI_MCLK_I2C
++ * @param       flag        true to enable mclk, false to disable mclk
++ * @param       wait        true to wait 100ms make clock stable, false not wait
++ *
++ * @return      0 for success
++ */
++int32_t csi_enable_mclk(int src, bool flag, bool wait)
++{
++      if (flag == true) {
++              clk_enable(&csi_mclk);
++              if (wait == true)
++                      msleep(10);
++              pr_debug("Enable csi clock from source %d\n", src);
++              gcsi_mclk_on = true;
++      } else {
++              clk_disable(&csi_mclk);
++              pr_debug("Disable csi clock from source %d\n", src);
++              gcsi_mclk_on = false;
++      }
++
++      return 0;
++}
++
++/*!
++ * csi_read_mclk_flag
++ *
++ * @return  gcsi_mclk_source
++ */
++int csi_read_mclk_flag(void)
++{
++      return 0;
++}
++
++void csi_set_callback(csi_irq_callback_t callback, void *data)
++{
++      g_callback = callback;
++      g_callback_data = data;
++}
++
++static void _mclk_recalc(struct clk *clk)
++{
++      u32 div;
++
++      div = (__raw_readl(CSI_CSICR1) & BIT_MCLKDIV) >> SHIFT_MCLKDIV;
++      div = (div + 1) * 2;
++
++      clk->rate = clk->parent->rate / div;
++}
++
++static unsigned long _mclk_round_rate(struct clk *clk, unsigned long rate)
++{
++      /* Keep CSI divider and change parent clock */
++      if (clk->parent->round_rate) {
++              return clk->parent->round_rate(clk->parent, rate * 2);
++      }
++      return 0;
++}
++
++static int _mclk_set_rate(struct clk *clk, unsigned long rate)
++{
++      int ret = -EINVAL;
++
++      /* Keep CSI divider and change parent clock */
++      if (clk->parent->set_rate) {
++              ret = clk->parent->set_rate(clk->parent, rate * 2);
++              if (ret == 0) {
++                      clk->rate = clk->parent->rate / 2;
++              }
++      }
++
++      return ret;
++}
++
++static int _mclk_enable(struct clk *clk)
++{
++      __raw_writel(__raw_readl(CSI_CSICR1) | BIT_MCLKEN, CSI_CSICR1);
++      return 0;
++}
++
++static void _mclk_disable(struct clk *clk)
++{
++      __raw_writel(__raw_readl(CSI_CSICR1) & ~BIT_MCLKEN, CSI_CSICR1);
++}
++
++static struct clk csi_mclk = {
++      .name = "csi_clk",
++      .recalc = _mclk_recalc,
++      .round_rate = _mclk_round_rate,
++      .set_rate = _mclk_set_rate,
++      .enable = _mclk_enable,
++      .disable = _mclk_disable,
++};
++
++int32_t __init csi_init_module(void)
++{
++      int ret = 0;
++      struct clk *per_clk;
++
++      per_clk = clk_get(NULL, "csi_perclk");
++      if (IS_ERR(per_clk))
++              return PTR_ERR(per_clk);
++      clk_put(per_clk);
++      csi_mclk.parent = per_clk;
++      clk_register(&csi_mclk);
++      clk_enable(per_clk);
++      csi_mclk.recalc(&csi_mclk);
++
++      csihw_reset();
++
++      /* interrupt enable */
++      ret = request_irq(INT_CSI, csi_irq_handler, 0, "csi", 0);
++      if (ret)
++              pr_debug("CSI error: irq request fail\n");
++
++      return ret;
++}
++
++void __exit csi_cleanup_module(void)
++{
++      /* free irq */
++      free_irq(INT_CSI, 0);
++
++      clk_disable(&csi_mclk);
++}
++
++module_init(csi_init_module);
++module_exit(csi_cleanup_module);
++
++EXPORT_SYMBOL(csi_init_interface);
++EXPORT_SYMBOL(csi_enable_mclk);
++EXPORT_SYMBOL(csi_read_mclk_flag);
++EXPORT_SYMBOL(csi_set_callback);
++EXPORT_SYMBOL(csi_enable_prpif);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("MX27 CSI driver");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mx27_csi.h linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_csi.h
+--- linux-2.6.28/drivers/media/video/mxc/capture/mx27_csi.h    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_csi.h       2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,165 @@
++/*
++ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_csi.h
++ *
++ * @brief CMOS Sensor interface functions
++ *
++ * @ingroup CSI
++ */
++
++#ifndef MX27_CSI_H
++#define MX27_CSI_H
++
++/* reset values */
++#define CSICR1_RESET_VAL      0x40000800
++#define CSICR2_RESET_VAL      0x0
++#define CSICR3_RESET_VAL      0x0
++
++/* csi control reg 1 */
++#define BIT_SWAP16_EN         (0x1 << 31)
++#define BIT_EXT_VSYNC         (0x1 << 30)
++#define BIT_EOF_INT_EN                (0x1 << 29)
++#define BIT_PRP_IF_EN         (0x1 << 28)
++#define BIT_CCIR_MODE         (0x1 << 27)
++#define BIT_COF_INT_EN                (0x1 << 26)
++#define BIT_SF_OR_INTEN               (0x1 << 25)
++#define BIT_RF_OR_INTEN               (0x1 << 24)
++#define BIT_STATFF_LEVEL      (0x3 << 22)
++#define BIT_STATFF_INTEN      (0x1 << 21)
++#define BIT_RXFF_LEVEL                (0x3 << 19)
++#define BIT_RXFF_INTEN                (0x1 << 18)
++#define BIT_SOF_POL           (0x1 << 17)
++#define BIT_SOF_INTEN         (0x1 << 16)
++#define BIT_MCLKDIV           (0xF << 12)
++#define BIT_HSYNC_POL         (0x1 << 11)
++#define BIT_CCIR_EN           (0x1 << 10)
++#define BIT_MCLKEN            (0x1 << 9)
++#define BIT_FCC                       (0x1 << 8)
++#define BIT_PACK_DIR          (0x1 << 7)
++#define BIT_CLR_STATFIFO      (0x1 << 6)
++#define BIT_CLR_RXFIFO                (0x1 << 5)
++#define BIT_GCLK_MODE         (0x1 << 4)
++#define BIT_INV_DATA          (0x1 << 3)
++#define BIT_INV_PCLK          (0x1 << 2)
++#define BIT_REDGE             (0x1 << 1)
++
++#define SHIFT_STATFF_LEVEL    22
++#define SHIFT_RXFF_LEVEL      19
++#define SHIFT_MCLKDIV         12
++
++/* control reg 3 */
++#define BIT_FRMCNT            (0xFFFF << 16)
++#define BIT_FRMCNT_RST                (0x1 << 15)
++#define BIT_CSI_SUP           (0x1 << 3)
++#define BIT_ZERO_PACK_EN      (0x1 << 2)
++#define BIT_ECC_INT_EN                (0x1 << 1)
++#define BIT_ECC_AUTO_EN               (0x1)
++
++#define SHIFT_FRMCNT          16
++
++/* csi status reg */
++#define BIT_SFF_OR_INT                (0x1 << 25)
++#define BIT_RFF_OR_INT                (0x1 << 24)
++#define BIT_STATFF_INT                (0x1 << 21)
++#define BIT_RXFF_INT          (0x1 << 18)
++#define BIT_EOF_INT           (0x1 << 17)
++#define BIT_SOF_INT           (0x1 << 16)
++#define BIT_F2_INT            (0x1 << 15)
++#define BIT_F1_INT            (0x1 << 14)
++#define BIT_COF_INT           (0x1 << 13)
++#define BIT_ECC_INT           (0x1 << 1)
++#define BIT_DRDY              (0x1 << 0)
++
++#define CSI_MCLK_VF           1
++#define CSI_MCLK_ENC          2
++#define CSI_MCLK_RAW          4
++#define CSI_MCLK_I2C          8
++
++#define CSI_CSICR1            (IO_ADDRESS(CSI_BASE_ADDR))
++#define CSI_CSICR2            (IO_ADDRESS(CSI_BASE_ADDR + 0x4))
++#define CSI_CSISR             (IO_ADDRESS(CSI_BASE_ADDR + 0x8))
++#define CSI_STATFIFO          (IO_ADDRESS(CSI_BASE_ADDR + 0xC))
++#define CSI_CSIRXFIFO         (IO_ADDRESS(CSI_BASE_ADDR + 0x10))
++#define CSI_CSIRXCNT          (IO_ADDRESS(CSI_BASE_ADDR + 0x14))
++#define CSI_CSICR3            (IO_ADDRESS(CSI_BASE_ADDR + 0x1C))
++
++#define CSI_CSIRXFIFO_PHYADDR (CSI_BASE_ADDR + 0x10)
++
++static __inline void csi_clear_status(unsigned long status)
++{
++      __raw_writel(status, CSI_CSISR);
++}
++
++typedef struct {
++      unsigned data_width:3;
++      unsigned clk_mode:2;
++      unsigned ext_vsync:1;
++      unsigned Vsync_pol:1;
++      unsigned Hsync_pol:1;
++      unsigned pixclk_pol:1;
++      unsigned data_pol:1;
++      unsigned sens_clksrc:1;
++} csi_signal_cfg_t;
++
++typedef struct {
++      /* control reg 1 */
++      unsigned int swap16_en:1;
++      unsigned int ext_vsync:1;
++      unsigned int eof_int_en:1;
++      unsigned int prp_if_en:1;
++      unsigned int ccir_mode:1;
++      unsigned int cof_int_en:1;
++      unsigned int sf_or_inten:1;
++      unsigned int rf_or_inten:1;
++      unsigned int statff_level:2;
++      unsigned int staff_inten:1;
++      unsigned int rxff_level:2;
++      unsigned int rxff_inten:1;
++      unsigned int sof_pol:1;
++      unsigned int sof_inten:1;
++      unsigned int mclkdiv:4;
++      unsigned int hsync_pol:1;
++      unsigned int ccir_en:1;
++      unsigned int mclken:1;
++      unsigned int fcc:1;
++      unsigned int pack_dir:1;
++      unsigned int gclk_mode:1;
++      unsigned int inv_data:1;
++      unsigned int inv_pclk:1;
++      unsigned int redge:1;
++      unsigned int csicnt1_rsv:1;
++
++      /* control reg 3 */
++      unsigned int frmcnt:16;
++      unsigned int frame_reset:1;
++      unsigned int csi_sup:1;
++      unsigned int zero_pack_en:1;
++      unsigned int ecc_int_en:1;
++      unsigned int ecc_auto_en:1;
++
++      /* fifo counter */
++      unsigned int rxcnt;
++} csi_config_t;
++
++typedef void (*csi_irq_callback_t) (void *data, unsigned long status);
++
++int32_t csi_enable_mclk(int src, bool flag, bool wait);
++int32_t csi_init_interface(uint16_t width, uint16_t height,
++                         uint32_t pixel_fmt, csi_signal_cfg_t sig);
++int csi_read_mclk_flag(void);
++void csi_set_callback(csi_irq_callback_t callback, void *data);
++void csi_enable_prpif(uint32_t enable);
++
++#endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mx27_prp.h linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_prp.h
+--- linux-2.6.28/drivers/media/video/mxc/capture/mx27_prp.h    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_prp.h       2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,308 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_prp.h
++ *
++ * @brief Header file for MX27 V4L2 capture driver
++ *
++ * @ingroup MXC_V4L2_CAPTURE
++ */
++#ifndef __MX27_PRP_H__
++#define __MX27_PRP_H__
++
++#define PRP_REG(ofs)  (IO_ADDRESS(EMMA_BASE_ADDR) + ofs)
++
++/* Register definitions of PrP */
++#define PRP_CNTL                      PRP_REG(0x00)
++#define PRP_INTRCNTL                  PRP_REG(0x04)
++#define PRP_INTRSTATUS                        PRP_REG(0x08)
++#define PRP_SOURCE_Y_PTR              PRP_REG(0x0C)
++#define PRP_SOURCE_CB_PTR             PRP_REG(0x10)
++#define PRP_SOURCE_CR_PTR             PRP_REG(0x14)
++#define PRP_DEST_RGB1_PTR             PRP_REG(0x18)
++#define PRP_DEST_RGB2_PTR             PRP_REG(0x1C)
++#define PRP_DEST_Y_PTR                        PRP_REG(0x20)
++#define PRP_DEST_CB_PTR                       PRP_REG(0x24)
++#define PRP_DEST_CR_PTR                       PRP_REG(0x28)
++#define PRP_SOURCE_FRAME_SIZE                 PRP_REG(0x2C)
++#define PRP_CH1_LINE_STRIDE           PRP_REG(0x30)
++#define PRP_SRC_PIXEL_FORMAT_CNTL     PRP_REG(0x34)
++#define PRP_CH1_PIXEL_FORMAT_CNTL     PRP_REG(0x38)
++#define PRP_CH1_OUT_IMAGE_SIZE                PRP_REG(0x3C)
++#define PRP_CH2_OUT_IMAGE_SIZE                PRP_REG(0x40)
++#define PRP_SOURCE_LINE_STRIDE                PRP_REG(0x44)
++#define PRP_CSC_COEF_012              PRP_REG(0x48)
++#define PRP_CSC_COEF_345              PRP_REG(0x4C)
++#define PRP_CSC_COEF_678              PRP_REG(0x50)
++#define PRP_CH1_RZ_HORI_COEF1         PRP_REG(0x54)
++#define PRP_CH1_RZ_HORI_COEF2         PRP_REG(0x58)
++#define PRP_CH1_RZ_HORI_VALID         PRP_REG(0x5C)
++#define PRP_CH1_RZ_VERT_COEF1         PRP_REG(0x60)
++#define PRP_CH1_RZ_VERT_COEF2         PRP_REG(0x64)
++#define PRP_CH1_RZ_VERT_VALID         PRP_REG(0x68)
++#define PRP_CH2_RZ_HORI_COEF1         PRP_REG(0x6C)
++#define PRP_CH2_RZ_HORI_COEF2         PRP_REG(0x70)
++#define PRP_CH2_RZ_HORI_VALID         PRP_REG(0x74)
++#define PRP_CH2_RZ_VERT_COEF1         PRP_REG(0x78)
++#define PRP_CH2_RZ_VERT_COEF2         PRP_REG(0x7C)
++#define PRP_CH2_RZ_VERT_VALID         PRP_REG(0x80)
++
++#define B_SET(b)                      (1 << (b))
++
++/* Bit definitions for PrP control register */
++#define PRP_CNTL_RSTVAL                       0x28
++#define PRP_CNTL_CH1EN                        B_SET(0)
++#define PRP_CNTL_CH2EN                        B_SET(1)
++#define PRP_CNTL_CSI                  B_SET(2)
++#define PRP_CNTL_IN_32                        B_SET(3)
++#define PRP_CNTL_IN_RGB                       B_SET(4)
++#define PRP_CNTL_IN_YUV420            0
++#define PRP_CNTL_IN_YUV422            PRP_CNTL_IN_32
++#define PRP_CNTL_IN_RGB16             PRP_CNTL_IN_RGB
++#define PRP_CNTL_IN_RGB32             (PRP_CNTL_IN_RGB | PRP_CNTL_IN_32)
++#define PRP_CNTL_CH1_RGB8             0
++#define PRP_CNTL_CH1_RGB16            B_SET(5)
++#define PRP_CNTL_CH1_RGB32            B_SET(6)
++#define PRP_CNTL_CH1_YUV422           (B_SET(5) | B_SET(6))
++#define PRP_CNTL_CH2_YUV420           0
++#define PRP_CNTL_CH2_YUV422           B_SET(7)
++#define PRP_CNTL_CH2_YUV444           B_SET(8)
++#define PRP_CNTL_CH1_LOOP             B_SET(9)
++#define PRP_CNTL_CH2_LOOP             B_SET(10)
++#define PRP_CNTL_AUTODROP             B_SET(11)
++#define PRP_CNTL_RST                  B_SET(12)
++#define PRP_CNTL_CNTREN                       B_SET(13)
++#define PRP_CNTL_WINEN                        B_SET(14)
++#define PRP_CNTL_UNCHAIN              B_SET(15)
++#define PRP_CNTL_IN_SKIP_NONE         0
++#define PRP_CNTL_IN_SKIP_1_2          B_SET(16)
++#define PRP_CNTL_IN_SKIP_1_3          B_SET(17)
++#define PRP_CNTL_IN_SKIP_2_3          (B_SET(16) | B_SET(17))
++#define PRP_CNTL_IN_SKIP_1_4          B_SET(18)
++#define PRP_CNTL_IN_SKIP_3_4          (B_SET(16) | B_SET(18))
++#define PRP_CNTL_IN_SKIP_2_5          (B_SET(17) | B_SET(18))
++#define PRP_CNTL_IN_SKIP_3_5          (B_SET(16) | B_SET(17) | B_SET(18))
++#define PRP_CNTL_CH1_SKIP_NONE                0
++#define PRP_CNTL_CH1_SKIP_1_2         B_SET(19)
++#define PRP_CNTL_CH1_SKIP_1_3         B_SET(20)
++#define PRP_CNTL_CH1_SKIP_2_3         (B_SET(19) | B_SET(20))
++#define PRP_CNTL_CH1_SKIP_1_4         B_SET(21)
++#define PRP_CNTL_CH1_SKIP_3_4         (B_SET(19) | B_SET(21))
++#define PRP_CNTL_CH1_SKIP_2_5         (B_SET(20) | B_SET(21))
++#define PRP_CNTL_CH1_SKIP_3_5         (B_SET(19) | B_SET(20) | B_SET(21))
++#define PRP_CNTL_CH2_SKIP_NONE                0
++#define PRP_CNTL_CH2_SKIP_1_2         B_SET(22)
++#define PRP_CNTL_CH2_SKIP_1_3         B_SET(23)
++#define PRP_CNTL_CH2_SKIP_2_3         (B_SET(22) | B_SET(23))
++#define PRP_CNTL_CH2_SKIP_1_4         B_SET(24)
++#define PRP_CNTL_CH2_SKIP_3_4         (B_SET(22) | B_SET(24))
++#define PRP_CNTL_CH2_SKIP_2_5         (B_SET(23) | B_SET(24))
++#define PRP_CNTL_CH2_SKIP_3_5         (B_SET(22) | B_SET(23) | B_SET(24))
++#define PRP_CNTL_FIFO_I128            0
++#define PRP_CNTL_FIFO_I96             B_SET(25)
++#define PRP_CNTL_FIFO_I64             B_SET(26)
++#define PRP_CNTL_FIFO_I32             (B_SET(25) | B_SET(26))
++#define PRP_CNTL_FIFO_O64             0
++#define PRP_CNTL_FIFO_O48             B_SET(27)
++#define PRP_CNTL_FIFO_O32             B_SET(28)
++#define PRP_CNTL_FIFO_O16             (B_SET(27) | B_SET(28))
++#define PRP_CNTL_CH2B1                        B_SET(29)
++#define PRP_CNTL_CH2B2                        B_SET(30)
++#define PRP_CNTL_CH2_FLOWEN           B_SET(31)
++
++/* Bit definitions for PrP interrupt control register */
++#define PRP_INTRCNTL_RDERR            B_SET(0)
++#define PRP_INTRCNTL_CH1WERR          B_SET(1)
++#define PRP_INTRCNTL_CH2WERR          B_SET(2)
++#define PRP_INTRCNTL_CH1FC            B_SET(3)
++#define PRP_INTRCNTL_CH2FC            B_SET(5)
++#define PRP_INTRCNTL_LBOVF            B_SET(7)
++#define PRP_INTRCNTL_CH2OVF           B_SET(8)
++
++/* Bit definitions for PrP interrupt status register */
++#define PRP_INTRSTAT_RDERR            B_SET(0)
++#define PRP_INTRSTAT_CH1WERR          B_SET(1)
++#define PRP_INTRSTAT_CH2WERR          B_SET(2)
++#define PRP_INTRSTAT_CH2BUF2          B_SET(3)
++#define PRP_INTRSTAT_CH2BUF1          B_SET(4)
++#define PRP_INTRSTAT_CH1BUF2          B_SET(5)
++#define PRP_INTRSTAT_CH1BUF1          B_SET(6)
++#define PRP_INTRSTAT_LBOVF            B_SET(7)
++#define PRP_INTRSTAT_CH2OVF           B_SET(8)
++
++#define PRP_CHANNEL_1         0x1
++#define PRP_CHANNEL_2         0x2
++
++/* PRP-CSI config */
++#define PRP_CSI_EN            0x80
++#define PRP_CSI_LOOP          (0x40 | PRP_CSI_EN)
++#define PRP_CSI_IRQ_FRM               (0x08 | PRP_CSI_LOOP)
++#define PRP_CSI_IRQ_CH1ERR    (0x10 | PRP_CSI_LOOP)
++#define PRP_CSI_IRQ_CH2ERR    (0x20 | PRP_CSI_LOOP)
++#define PRP_CSI_IRQ_ALL               (0x38 | PRP_CSI_LOOP)
++#define PRP_CSI_SKIP_NONE     0
++#define PRP_CSI_SKIP_1OF2     1
++#define PRP_CSI_SKIP_1OF3     2
++#define PRP_CSI_SKIP_2OF3     3
++#define PRP_CSI_SKIP_1OF4     4
++#define PRP_CSI_SKIP_3OF4     5
++#define PRP_CSI_SKIP_2OF5     6
++#define PRP_CSI_SKIP_4OF5     7
++
++#define PRP_PIXIN_RGB565      0x2CA00565
++#define PRP_PIXIN_RGB888      0x41000888
++#define PRP_PIXIN_YUV420      0
++#define PRP_PIXIN_YUYV                0x22000888
++#define PRP_PIXIN_YVYU                0x20100888
++#define PRP_PIXIN_UYVY                0x03080888
++#define PRP_PIXIN_VYUY                0x01180888
++#define PRP_PIXIN_YUV422      0x62080888
++
++#define PRP_PIX1_RGB332               0x14400322
++#define PRP_PIX1_RGB565               0x2CA00565
++#define PRP_PIX1_RGB888               0x41000888
++#define PRP_PIX1_YUYV         0x62000888
++#define PRP_PIX1_YVYU         0x60100888
++#define PRP_PIX1_UYVY         0x43080888
++#define PRP_PIX1_VYUY         0x41180888
++#define PRP_PIX1_UNUSED               0
++
++#define PRP_PIX2_YUV420               0
++#define PRP_PIX2_YUV422               1
++#define PRP_PIX2_YUV444               4
++#define PRP_PIX2_UNUSED               8
++
++#define PRP_ALGO_WIDTH_ANY    0
++#define PRP_ALGO_HEIGHT_ANY   0
++#define PRP_ALGO_WIDTH_BIL    1
++#define PRP_ALGO_WIDTH_AVG    2
++#define PRP_ALGO_HEIGHT_BIL   4
++#define PRP_ALGO_HEIGHT_AVG   8
++#define PRP_ALGO_BYPASS               0x10
++
++typedef struct _emma_prp_ratio {
++      unsigned short num;
++      unsigned short den;
++} emma_prp_ratio;
++
++/*
++ * The following definitions are for resizing. Definition values must not
++ * be changed otherwise decision logic will be wrong.
++ */
++#define BC_COEF               3
++#define MAX_TBL               20
++#define SZ_COEF               (1 << BC_COEF)
++
++#define ALGO_AUTO     0
++#define ALGO_BIL      1
++#define ALGO_AVG      2
++
++typedef struct {
++      char tbl[20];           /* table entries */
++      char len;               /* table length used */
++      char algo;              /* ALGO_xxx */
++      char ratio[20];         /* ratios used */
++} scale_t;
++
++/*
++ * structure for prp scaling.
++ * algorithm - bilinear or averaging for each axis
++ * PRP_ALGO_WIDTH_x | PRP_ALGO_HEIGHT_x | PRP_ALGO_BYPASS 
++ * PRP_ALGO_BYPASS - Ch1 will not use Ch2 scaling with this flag
++ */
++typedef struct _emma_prp_scale {
++      unsigned char algo;
++      emma_prp_ratio width;
++      emma_prp_ratio height;
++} emma_prp_scale;
++
++typedef struct emma_prp_cfg {
++      unsigned int in_pix;    /* PRP_PIXIN_xxx */
++      unsigned short in_width;        /* image width, 32 - 2044 */
++      unsigned short in_height;       /* image height, 32 - 2044 */
++      unsigned char in_csi;   /* PRP_CSI_SKIP_x | PRP_CSI_LOOP */
++      unsigned short in_line_stride;  /* in_line_stride and in_line_skip */
++      unsigned short in_line_skip;    /* allow cropping from CSI */
++      unsigned int in_ptr;    /* bus address */
++      /*
++       * in_csc[9] = 1 -> Y-16
++       * if in_csc[1..9] == 0
++       *      in_csc[0] represents YUV range 0-3 = A0,A1,B0,B1;
++       * else
++       *      in_csc[0..9] represents either format
++       */
++      unsigned short in_csc[10];
++
++      unsigned char ch2_pix;  /* PRP_PIX2_xxx */
++      emma_prp_scale ch2_scale;       /* resizing paramters */
++      unsigned short ch2_width;       /* 4-2044, 0 = scaled */
++      unsigned short ch2_height;      /* 4-2044, 0 = scaled */
++      unsigned int ch2_ptr;   /* bus addr */
++      unsigned int ch2_ptr2;  /* bus addr for 2nd buf (loop mode) */
++      unsigned char ch2_csi;  /* PRP_CSI_SKIP_x | PRP_CSI_LOOP */
++
++      unsigned int ch1_pix;   /* PRP_PIX1_xxx */
++      emma_prp_scale ch1_scale;       /* resizing parameters */
++      unsigned short ch1_width;       /* 4-2044, 0 = scaled */
++      unsigned short ch1_height;      /* 4-2044, 0 = scaled */
++      unsigned short ch1_stride;      /* 4-4088, 0 = ch1_width */
++      unsigned int ch1_ptr;   /* bus addr */
++      unsigned int ch1_ptr2;  /* bus addr for 2nd buf (loop mode) */
++      unsigned char ch1_csi;  /* PRP_CSI_SKIP_x | PRP_CSI_LOOP */
++
++      /*
++       * channel resizing coefficients
++       * scale[0] for channel 1 width
++       * scale[1] for channel 1 height
++       * scale[2] for channel 2 width
++       * scale[3] for channel 2 height
++       */
++      scale_t scale[4];
++} emma_prp_cfg;
++
++int prphw_reset(void);
++int prphw_enable(int channel);
++int prphw_disable(int channel);
++int prphw_inptr(emma_prp_cfg *);
++int prphw_ch1ptr(emma_prp_cfg *);
++int prphw_ch1ptr2(emma_prp_cfg *);
++int prphw_ch2ptr(emma_prp_cfg *);
++int prphw_ch2ptr2(emma_prp_cfg *);
++int prphw_cfg(emma_prp_cfg *);
++int prphw_isr(void);
++void prphw_init(void);
++void prphw_exit(void);
++
++/*
++ * scale      out     coefficient table
++ * din                in      scale numerator
++ * dout               in      scale denominator
++ * inv                in      pre-scale dimension
++ * vout               in/out  post-scale output dimension
++ * pout               out     post-scale internal dimension [opt]
++ * retry      in      retry times (round the output length) when need
++ */
++int prp_scale(scale_t * pscale, int din, int dout, int inv,
++            unsigned short *vout, unsigned short *pout, int ch);
++
++int prp_init(void *dev_id);
++void prp_exit(void *dev_id);
++int prp_enc_select(void *data);
++int prp_enc_deselect(void *data);
++int prp_vf_select(void *data);
++int prp_vf_deselect(void *data);
++int prp_still_select(void *data);
++int prp_still_deselect(void *data);
++
++#endif                                /* __MX27_PRP_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mx27_prphw.c linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_prphw.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/mx27_prphw.c  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_prphw.c     2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,1230 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_prphw.c
++ *
++ * @brief MX27 Video For Linux 2 capture driver
++ *
++ * @ingroup MXC_V4L2_CAPTURE
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/clk.h>
++#include <asm/io.h>
++#include <linux/delay.h>
++
++#include "mx27_prp.h"
++
++#define PRP_MIN_IN_WIDTH      32
++#define PRP_MAX_IN_WIDTH      2044
++#define PRP_MIN_IN_HEIGHT     32
++#define PRP_MAX_IN_HEIGHT     2044
++
++typedef struct _coeff_t {
++      unsigned long coeff[2];
++      unsigned long cntl;
++} coeff_t[2][2];
++
++static coeff_t *PRP_RSZ_COEFF = (coeff_t *) PRP_CH1_RZ_HORI_COEF1;
++
++static unsigned char scale_get(scale_t * t,
++                             unsigned char *i, unsigned char *out);
++static int gcd(int x, int y);
++static int ratio(int x, int y, int *den);
++static int prp_scale_bilinear(scale_t * t, int coeff, int base, int nxt);
++static int prp_scale_ave(scale_t * t, unsigned char base);
++static int ave_scale(scale_t * t, int inv, int outv);
++static int scale(scale_t * t, int inv, int outv);
++
++/*!
++ * @param t   table
++ * @param i   table index
++ * @param out bilinear        # input pixels to advance
++ *            average         whether result is ready for output
++ * @return    coefficient
++*/
++static unsigned char scale_get(scale_t * t, unsigned char *i,
++                             unsigned char *out)
++{
++      unsigned char c;
++
++      c = t->tbl[*i];
++      (*i)++;
++      *i %= t->len;
++
++      if (out) {
++              if (t->algo == ALGO_BIL) {
++                      for ((*out) = 1;
++                           (*i) && ((*i) < t->len) && !t->tbl[(*i)]; (*i)++) {
++                              (*out)++;
++                      }
++                      if ((*i) == t->len)
++                              (*i) = 0;
++              } else
++                      *out = c >> BC_COEF;
++      }
++
++      c &= SZ_COEF - 1;
++
++      if (c == SZ_COEF - 1)
++              c = SZ_COEF;
++
++      return c;
++}
++
++/*!
++ * @brief Get maximum common divisor.
++ * @param x   First input value
++ * @param y   Second input value
++ * @return    Maximum common divisor of x and y
++ */
++static int gcd(int x, int y)
++{
++      int k;
++
++      if (x < y) {
++              k = x;
++              x = y;
++              y = k;
++      }
++
++      while ((k = x % y)) {
++              x = y;
++              y = k;
++      }
++
++      return y;
++}
++
++/*!
++ * @brief Get ratio.
++ * @param x   First input value
++ * @param y   Second input value
++ * @param den Denominator of the ratio (corresponding to y)
++ * @return    Numerator of the ratio (corresponding to x)
++ */
++static int ratio(int x, int y, int *den)
++{
++      int g;
++
++      if (!x || !y)
++              return 0;
++
++      g = gcd(x, y);
++      *den = y / g;
++
++      return x / g;
++}
++
++/*!
++ * @brief Build PrP coefficient entry based on bilinear algorithm
++ *
++ * @param t   The pointer to scale_t structure
++ * @param coeff       The weighting coefficient
++ * @param base        The base of the coefficient
++ * @param nxt Number of pixels to be read
++ *
++ * @return    The length of current coefficient table on success
++ *            -1 on failure
++ */
++static int prp_scale_bilinear(scale_t * t, int coeff, int base, int nxt)
++{
++      int i;
++
++      if (t->len >= sizeof(t->tbl))
++              return -1;
++
++      coeff = ((coeff << BC_COEF) + (base >> 1)) / base;
++      if (coeff >= SZ_COEF - 1)
++              coeff--;
++
++      coeff |= SZ_COEF;
++      t->tbl[(int)t->len++] = (unsigned char)coeff;
++
++      for (i = 1; i < nxt; i++) {
++              if (t->len >= MAX_TBL)
++                      return -1;
++
++              t->tbl[(int)t->len++] = 0;
++      }
++
++      return t->len;
++}
++
++#define _bary(name)   static const unsigned char name[]
++
++_bary(c1) = {
++7};
++
++_bary(c2) = {
++4, 4};
++
++_bary(c3) = {
++2, 4, 2};
++
++_bary(c4) = {
++2, 2, 2, 2};
++
++_bary(c5) = {
++1, 2, 2, 2, 1};
++
++_bary(c6) = {
++1, 1, 2, 2, 1, 1};
++
++_bary(c7) = {
++1, 1, 1, 2, 1, 1, 1};
++
++_bary(c8) = {
++1, 1, 1, 1, 1, 1, 1, 1};
++
++_bary(c9) = {
++1, 1, 1, 1, 1, 1, 1, 1, 0};
++
++_bary(c10) = {
++0, 1, 1, 1, 1, 1, 1, 1, 1, 0};
++
++_bary(c11) = {
++0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0};
++
++_bary(c12) = {
++0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0};
++
++_bary(c13) = {
++0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0};
++
++_bary(c14) = {
++0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0};
++
++_bary(c15) = {
++0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0};
++
++_bary(c16) = {
++1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
++
++_bary(c17) = {
++0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
++
++_bary(c18) = {
++0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0};
++
++_bary(c19) = {
++0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0};
++
++_bary(c20) = {
++0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0};
++
++static const unsigned char *ave_coeff[] = {
++      c1, c2, c3, c4, c5, c6, c7, c8, c9, c10,
++      c11, c12, c13, c14, c15, c16, c17, c18, c19, c20
++};
++
++static const unsigned char coeftab[] = {
++      1, 1,
++      19, 20,
++      18, 19,
++      17, 18,
++      16, 17,
++      15, 16,
++      14, 15,
++      13, 14,
++      12, 13,
++      11, 12,
++      10, 11,
++      9, 10,
++      17, 19,
++      8, 9,
++      15, 17,
++      7, 8,
++      13, 15,
++      6, 7,
++      17, 20,
++      11, 13,
++      16, 19,
++      5, 6,
++      14, 17,
++      9, 11,
++      13, 16,
++      4, 5,
++      15, 19,
++      11, 14,
++      7, 9,
++      10, 13,
++      13, 17,
++      3, 4,
++      14, 19,
++      11, 15,
++      8, 11,
++      13, 18,
++      5, 7,
++      12, 17,
++      7, 10,
++      9, 13,
++      11, 16,
++      13, 19,
++      2, 3,
++      13, 20,
++      11, 17,
++      9, 14,
++      7, 11,
++      12, 19,
++      5, 8,
++      8, 13,
++      11, 18,
++      3, 5,
++      10, 17,
++      7, 12,
++      11, 19,
++      4, 7,
++      9, 16,
++      5, 9,
++      11, 20,
++      6, 11,
++      7, 13,
++      8, 15,
++      9, 17,
++      10, 19,
++      1, 2,
++      9, 19,
++      8, 17,
++      7, 15,
++      6, 13,
++      5, 11,
++      9, 20,
++      4, 9,
++      7, 16,
++      3, 7,
++      8, 19,
++      5, 12,
++      7, 17,
++      2, 5,
++      7, 18,
++      5, 13,
++      3, 8,
++      7, 19,
++      4, 11,
++      5, 14,
++      6, 17,
++      7, 20,
++      1, 3,
++      6, 19,
++      5, 16,
++      4, 13,
++      3, 10,
++      5, 17,
++      2, 7,
++      5, 18,
++      3, 11,
++      4, 15,
++      5, 19,
++      1, 4,
++      4, 17,
++      3, 13,
++      2, 9,
++      3, 14,
++      4, 19,
++      1, 5,
++      3, 16,
++      2, 11,
++      3, 17,
++      1, 6,
++      3, 19,
++      2, 13,
++      3, 20,
++      1, 7,
++      2, 15,
++      1, 8,
++      2, 17,
++      1, 9,
++      2, 19,
++      1, 10,
++      1, 11,
++      1, 12,
++      1, 13,
++      1, 14,
++      1, 15,
++      1, 16,
++      1, 17,
++      1, 18,
++      1, 19,
++      1, 20
++};
++
++/*!
++ * @brief Build PrP coefficient table based on average algorithm
++ *
++ * @param t   The pointer to scale_t structure
++ * @param base        The base of the coefficient
++ *
++ * @return    The length of current coefficient table on success
++ *            -1 on failure
++ */
++static int prp_scale_ave(scale_t * t, unsigned char base)
++{
++      if (t->len + base > sizeof(t->tbl))
++              return -1;
++
++      memcpy(&t->tbl[(int)t->len], ave_coeff[(int)base - 1], base);
++      t->len = (unsigned char)(t->len + base);
++      t->tbl[t->len - 1] |= SZ_COEF;
++
++      return t->len;
++}
++
++/*!
++ * @brief Build PrP coefficient table based on average algorithm
++ *
++ * @param t   The pointer to scale_t structure
++ * @param inv Input resolution
++ * @param outv        Output resolution
++ *
++ * @return    The length of current coefficient table on success
++ *            -1 on failure
++ */
++static int ave_scale(scale_t * t, int inv, int outv)
++{
++      int ratio_count;
++
++      ratio_count = 0;
++      if (outv != 1) {
++              unsigned char a[20];
++              int v;
++
++              /* split n:m into multiple n[i]:1 */
++              for (v = 0; v < outv; v++)
++                      a[v] = (unsigned char)(inv / outv);
++
++              inv %= outv;
++              if (inv) {
++                      /* find start of next layer */
++                      v = (outv - inv) >> 1;
++                      inv += v;
++                      for (; v < inv; v++)
++                              a[v]++;
++              }
++
++              for (v = 0; v < outv; v++) {
++                      if (prp_scale_ave(t, a[v]) < 0)
++                              return -1;
++
++                      t->ratio[ratio_count] = a[v];
++                      ratio_count++;
++              }
++      } else if (prp_scale_ave(t, inv) < 0) {
++              return -1;
++      } else {
++              t->ratio[ratio_count++] = (char)inv;
++              ratio_count++;
++      }
++
++      return t->len;
++}
++
++/*!
++ * @brief Build PrP coefficient table
++ *
++ * @param t   The pointer to scale_t structure
++ * @param inv input resolution reduced ratio
++ * @param outv        output resolution reduced ratio
++ *
++ * @return    The length of current coefficient table on success
++ *            -1 on failure
++ */
++static int scale(scale_t * t, int inv, int outv)
++{
++      int v;                  /* overflow counter */
++      int coeff, nxt;         /* table output */
++
++      t->len = 0;
++      if (t->algo == ALGO_AUTO) {
++              /* automatic choice - bilinear for shrinking less than 2:1 */
++              t->algo = ((outv != inv) && ((2 * outv) > inv)) ?
++                  ALGO_BIL : ALGO_AVG;
++      }
++
++      /* 1:1 resize must use averaging, bilinear will hang */
++      if ((inv == outv) && (t->algo == ALGO_BIL)) {
++              pr_debug("Warning: 1:1 resize must use averaging algo\n");
++              t->algo = ALGO_AVG;
++      }
++
++      memset(t->tbl, 0, sizeof(t->tbl));
++      if (t->algo == ALGO_BIL) {
++              t->ratio[0] = (char)inv;
++              t->ratio[1] = (char)outv;
++      } else
++              memset(t->ratio, 0, sizeof(t->ratio));
++
++      if (inv == outv) {
++              /* force scaling */
++              t->ratio[0] = 1;
++              if (t->algo == ALGO_BIL)
++                      t->ratio[1] = 1;
++
++              return prp_scale_ave(t, 1);
++      }
++
++      if (inv < outv) {
++              pr_debug("Upscaling not supported %d:%d\n", inv, outv);
++              return -1;
++      }
++
++      if (t->algo != ALGO_BIL)
++              return ave_scale(t, inv, outv);
++
++      v = 0;
++      if (inv >= 2 * outv) {
++              /* downscale: >=2:1 bilinear approximation */
++              coeff = inv - 2 * outv;
++              v = 0;
++              nxt = 0;
++              do {
++                      v += coeff;
++                      nxt = 2;
++                      while (v >= outv) {
++                              v -= outv;
++                              nxt++;
++                      }
++
++                      if (prp_scale_bilinear(t, 1, 2, nxt) < 0)
++                              return -1;
++              } while (v);
++      } else {
++              /* downscale: bilinear */
++              int in_pos_inc = 2 * outv;
++              int out_pos = inv;
++              int out_pos_inc = 2 * inv;
++              int init_carry = inv - outv;
++              int carry = init_carry;
++
++              v = outv + in_pos_inc;
++              do {
++                      coeff = v - out_pos;
++                      out_pos += out_pos_inc;
++                      carry += out_pos_inc;
++                      for (nxt = 0; v < out_pos; nxt++) {
++                              v += in_pos_inc;
++                              carry -= in_pos_inc;
++                      }
++                      if (prp_scale_bilinear(t, coeff, in_pos_inc, nxt) < 0)
++                              return -1;
++              } while (carry != init_carry);
++      }
++      return t->len;
++}
++
++/*!
++ * @brief Get approximate ratio
++ *
++ * @param pscale      The pointer to scale_t structure which holdes
++ *                    coefficient tables
++ * @param mt          Scale ratio numerator
++ * @param nt          Scale ratio denominator
++ * @param *n          denominator of approximate ratio
++ * @return            numerator of approximate ratio
++ */
++
++static int approx_ratio(int mt, int nt, int *n)
++{
++      int index = sizeof(coeftab) / sizeof(coeftab[0]) / 2;
++      int left = 0;
++      int right = index - 1;
++      int nom, den;
++      while (index > 0) {
++              nom = coeftab[(((right + left) >> 1) << 1) + 1];
++              den = coeftab[(((right + left) >> 1) << 1)];
++              if ((nom * nt - mt * den) < 0) {
++                      left = (right + left) >> 1;
++              } else {
++                      right = (right + left) >> 1;
++              }
++              index = index >> 1;
++      }
++      *n = coeftab[left * 2];
++      nom = coeftab[left * 2 + 1];
++      return nom;
++}
++
++/*!
++ * @brief Build PrP coefficient table
++ *
++ * @param pscale      The pointer to scale_t structure which holdes
++ *                    coefficient tables
++ * @param din         Scale ratio numerator
++ * @param dout                Scale ratio denominator
++ * @param inv         Input resolution
++ * @param vout                Output resolution
++ * @param pout                Internal output resolution
++ * @param retry               Retry times (round the output length) when need
++ *
++ * @return            Zero on success, others on failure
++ */
++int prp_scale(scale_t * pscale, int din, int dout, int inv,
++            unsigned short *vout, unsigned short *pout, int ch)
++{
++      int num, new_num;
++      int den, new_den;
++      unsigned short outv;
++
++      /* auto-generation of values */
++      if (!(dout && din)) {
++              if (!*vout)
++                      dout = din = 1;
++              else {
++                      din = inv;
++                      dout = *vout;
++              }
++      }
++
++      if (din < dout) {
++              pr_debug("Scale err, unsupported ratio %d : %d\n", din, dout);
++              return -1;
++      }
++
++      num = ratio(din, dout, &den);
++      if (!num) {
++              pr_debug("Scale err, unsupported ratio %d : %d\n", din, dout);
++              return -1;
++      }
++
++      if (num > MAX_TBL) {
++              if (num / den <= MAX_TBL) {
++                      new_num = approx_ratio(num, den, &new_den);
++                      num = new_num;
++                      den = new_den;
++              } else if (ch == PRP_CHANNEL_2) {
++                      pr_debug("Unsupported ch_2 resize ratio %d : %d\n", num,
++                               den);
++                      return -1;
++              } else if (num / den > MAX_TBL * MAX_TBL) {
++                      pr_debug("Unsupported ch_1 resize ratio %d : %d\n", num,
++                               den);
++                      return -1;
++              }
++      }
++
++      if ((num > MAX_TBL * MAX_TBL) || scale(pscale, num, den) < 0) {
++              pr_debug("Scale err, unsupported ratio %d : %d\n", num, den);
++              return -1;
++      }
++
++      if (pscale->algo == ALGO_BIL) {
++              unsigned char i, j, k;
++
++              outv =
++                  (unsigned short)(inv / pscale->ratio[0] * pscale->ratio[1]);
++              inv %= pscale->ratio[0];
++              for (i = j = 0; inv > 0; j++) {
++                      unsigned char nxt;
++
++                      k = scale_get(pscale, &i, &nxt);
++                      if (inv == 1 && k < SZ_COEF) {
++                              /* needs 2 pixels for this output */
++                              break;
++                      }
++                      inv -= nxt;
++              }
++              outv = outv + j;
++      } else {
++              unsigned char i, tot;
++
++              for (tot = i = 0; pscale->ratio[i]; i++)
++                      tot = tot + pscale->ratio[i];
++
++              outv = (unsigned short)(inv / tot) * i;
++              inv %= tot;
++              for (i = 0; inv > 0; i++, outv++)
++                      inv -= pscale->ratio[i];
++      }
++
++      if (!(*vout) || ((*vout) > outv))
++              *vout = outv;
++
++      if (pout)
++              *pout = outv;
++
++      return 0;
++}
++
++/*!
++ * @brief Reset PrP block
++ */
++int prphw_reset(void)
++{
++      unsigned long val;
++      unsigned long flag;
++      int i;
++
++      flag = PRP_CNTL_RST;
++      val = PRP_CNTL_RSTVAL;
++
++      __raw_writel(flag, PRP_CNTL);
++
++      /* timeout */
++      for (i = 0; i < 1000; i++) {
++              if (!(__raw_readl(PRP_CNTL) & flag)) {
++                      pr_debug("PrP reset over\n");
++                      break;
++              }
++              msleep(1);
++      }
++
++      /* verify reset value */
++      if (__raw_readl(PRP_CNTL) != val) {
++              pr_info("PrP reset err, val = 0x%08X\n", __raw_readl(PRP_CNTL));
++              return -1;
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Enable PrP channel.
++ * @param channel     Channel number to be enabled
++ * @return            Zero on success, others on failure
++ */
++int prphw_enable(int channel)
++{
++      unsigned long val;
++
++      val = __raw_readl(PRP_CNTL);
++      if (channel & PRP_CHANNEL_1)
++              val |= PRP_CNTL_CH1EN;
++      if (channel & PRP_CHANNEL_2)
++              val |=
++                  (PRP_CNTL_CH2EN | PRP_CNTL_CH2_FLOWEN | PRP_CNTL_AUTODROP);
++
++      __raw_writel(val, PRP_CNTL);
++
++      return 0;
++}
++
++/*!
++ * @brief Disable PrP channel.
++ * @param channel     Channel number to be disable
++ * @return            Zero on success, others on failure
++ */
++int prphw_disable(int channel)
++{
++      unsigned long val;
++
++      val = __raw_readl(PRP_CNTL);
++      if (channel & PRP_CHANNEL_1)
++              val &= ~PRP_CNTL_CH1EN;
++      if (channel & PRP_CHANNEL_2)
++              val &= ~(PRP_CNTL_CH2EN | PRP_CNTL_CH2_FLOWEN);
++
++      __raw_writel(val, PRP_CNTL);
++
++      return 0;
++}
++
++/*!
++ * @brief Set PrP input buffer address.
++ * @param cfg Pointer to PrP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++int prphw_inptr(emma_prp_cfg * cfg)
++{
++      if (cfg->in_csi & PRP_CSI_EN)
++              return -1;
++
++      __raw_writel(cfg->in_ptr, PRP_SOURCE_Y_PTR);
++      if (cfg->in_pix == PRP_PIXIN_YUV420) {
++              u32 size;
++
++              size = cfg->in_line_stride * cfg->in_height;
++              __raw_writel(cfg->in_ptr + size, PRP_SOURCE_CB_PTR);
++              __raw_writel(cfg->in_ptr + size + (size >> 2),
++                           PRP_SOURCE_CR_PTR);
++      }
++      return 0;
++}
++
++/*!
++ * @brief Set PrP channel 1 output buffer 1 address.
++ * @param cfg Pointer to PrP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++int prphw_ch1ptr(emma_prp_cfg * cfg)
++{
++      if (cfg->ch1_pix == PRP_PIX1_UNUSED)
++              return -1;
++
++      __raw_writel(cfg->ch1_ptr, PRP_DEST_RGB1_PTR);
++
++      /* support double buffer in loop mode only */
++      if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) {
++              if (cfg->ch1_ptr2)
++                      __raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR);
++              else
++                      __raw_writel(cfg->ch1_ptr, PRP_DEST_RGB2_PTR);
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Set PrP channel 1 output buffer 2 address.
++ * @param cfg Pointer to PrP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++int prphw_ch1ptr2(emma_prp_cfg * cfg)
++{
++      if (cfg->ch1_pix == PRP_PIX1_UNUSED ||
++          (cfg->in_csi & PRP_CSI_LOOP) != PRP_CSI_LOOP)
++              return -1;
++
++      if (cfg->ch1_ptr2)
++              __raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR);
++      else
++              return -1;
++
++      return 0;
++}
++
++/*!
++ * @brief Set PrP channel 2 output buffer 1 address.
++ * @param cfg Pointer to PrP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++int prphw_ch2ptr(emma_prp_cfg * cfg)
++{
++      u32 size;
++
++      if (cfg->ch2_pix == PRP_PIX2_UNUSED)
++              return -1;
++
++      __raw_writel(cfg->ch2_ptr, PRP_DEST_Y_PTR);
++
++      if (cfg->ch2_pix == PRP_PIX2_YUV420) {
++              size = cfg->ch2_width * cfg->ch2_height;
++              __raw_writel(cfg->ch2_ptr + size, PRP_DEST_CB_PTR);
++              __raw_writel(cfg->ch2_ptr + size + (size >> 2),
++                           PRP_DEST_CR_PTR);
++      }
++
++      __raw_writel(__raw_readl(PRP_CNTL) | PRP_CNTL_CH2B1, PRP_CNTL);
++      return 0;
++}
++
++/*!
++ * @brief Set PrP channel 2 output buffer 2 address.
++ * @param cfg Pointer to PrP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++int prphw_ch2ptr2(emma_prp_cfg * cfg)
++{
++      u32 size;
++
++      if (cfg->ch2_pix == PRP_PIX2_UNUSED ||
++          (cfg->in_csi & PRP_CSI_LOOP) != PRP_CSI_LOOP)
++              return -1;
++
++      __raw_writel(cfg->ch2_ptr2, PRP_SOURCE_Y_PTR);
++      if (cfg->ch2_pix == PRP_PIX2_YUV420) {
++              size = cfg->ch2_width * cfg->ch2_height;
++              __raw_writel(cfg->ch2_ptr2 + size, PRP_SOURCE_CB_PTR);
++              __raw_writel(cfg->ch2_ptr2 + size + (size >> 2),
++                           PRP_SOURCE_CR_PTR);
++      }
++
++      __raw_writel(__raw_readl(PRP_CNTL) | PRP_CNTL_CH2B2, PRP_CNTL);
++      return 0;
++}
++
++/*!
++ * @brief Build CSC table
++ * @param csc CSC table
++ *            in      csc[0]=index            0..3 : A.1 A.0 B.1 B.0
++ *                    csc[1]=direction        0 : YUV2RGB  1 : RGB2YUV
++ *            out     csc[0..4] are coefficients c[9] is offset
++ *                    csc[0..8] are coefficients c[9] is offset
++ */
++void csc_tbl(short csc[10])
++{
++      static const unsigned short _r2y[][9] = {
++              {0x4D, 0x4B, 0x3A, 0x57, 0x55, 0x40, 0x40, 0x6B, 0x29},
++              {0x42, 0x41, 0x32, 0x4C, 0x4A, 0x38, 0x38, 0x5E, 0x24},
++              {0x36, 0x5C, 0x25, 0x3B, 0x63, 0x40, 0x40, 0x74, 0x18},
++              {0x2F, 0x4F, 0x20, 0x34, 0x57, 0x38, 0x38, 0x66, 0x15},
++      };
++      static const unsigned short _y2r[][5] = {
++              {0x80, 0xb4, 0x2c, 0x5b, 0x0e4},
++              {0x95, 0xcc, 0x32, 0x68, 0x104},
++              {0x80, 0xca, 0x18, 0x3c, 0x0ec},
++              {0x95, 0xe5, 0x1b, 0x44, 0x1e0},
++      };
++      unsigned short *_csc;
++      int _csclen;
++
++      csc[9] = csc[0] & 1;
++      _csclen = csc[0] & 3;
++
++      if (csc[1]) {
++              _csc = (unsigned short *)_r2y[_csclen];
++              _csclen = sizeof(_r2y[0]);
++      } else {
++              _csc = (unsigned short *)_y2r[_csclen];
++              _csclen = sizeof(_y2r[0]);
++              memset(csc + 5, 0, sizeof(short) * 4);
++      }
++      memcpy(csc, _csc, _csclen);
++}
++
++/*!
++ * @brief Setup PrP resize coefficient registers
++ *
++ * @param ch  PrP channel number
++ * @param dir Direction, 0 - horizontal, 1 - vertical
++ * @param scale       The pointer to scale_t structure
++ */
++static void prp_set_scaler(int ch, int dir, scale_t * scale)
++{
++      int i;
++      unsigned int coeff[2];
++      unsigned int valid;
++
++      for (coeff[0] = coeff[1] = valid = 0, i = 19; i >= 0; i--) {
++              int j;
++
++              j = i > 9 ? 1 : 0;
++              coeff[j] = (coeff[j] << BC_COEF) |
++                  (scale->tbl[i] & (SZ_COEF - 1));
++
++              if (i == 5 || i == 15)
++                      coeff[j] <<= 1;
++
++              valid = (valid << 1) | (scale->tbl[i] >> BC_COEF);
++      }
++
++      valid |= (scale->len << 24) | ((2 - scale->algo) << 31);
++
++      for (i = 0; i < 2; i++)
++              (*PRP_RSZ_COEFF)[1 - ch][dir].coeff[i] = coeff[i];
++
++      (*PRP_RSZ_COEFF)[1 - ch][dir].cntl = valid;
++}
++
++/*!
++ * @brief Setup PrP registers relevant to input.
++ * @param cfg         Pointer to PrP configuration parameter
++ * @param prp_cntl    Holds the value for PrP control register
++ * @return            Zero on success, others on failure
++ */
++static int prphw_input_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl)
++{
++      unsigned long mask;
++
++      switch (cfg->in_pix) {
++      case PRP_PIXIN_YUV420:
++              *prp_cntl |= PRP_CNTL_IN_YUV420;
++              mask = 0x7;
++              break;
++      case PRP_PIXIN_YUYV:
++      case PRP_PIXIN_YVYU:
++      case PRP_PIXIN_UYVY:
++      case PRP_PIXIN_VYUY:
++              *prp_cntl |= PRP_CNTL_IN_YUV422;
++              mask = 0x1;
++              break;
++      case PRP_PIXIN_RGB565:
++              *prp_cntl |= PRP_CNTL_IN_RGB16;
++              mask = 0x1;
++              break;
++      case PRP_PIXIN_RGB888:
++              *prp_cntl |= PRP_CNTL_IN_RGB32;
++              mask = 0;
++              break;
++      default:
++              pr_debug("Unsupported input pix format 0x%08X\n", cfg->in_pix);
++              return -1;
++      }
++
++      /* align the input image width */
++      if (cfg->in_width & mask) {
++              pr_debug("in_width misaligned. in_width=%d\n", cfg->in_width);
++              return -1;
++      }
++
++      if ((cfg->in_width < PRP_MIN_IN_WIDTH)
++          || (cfg->in_width > PRP_MAX_IN_WIDTH)) {
++              pr_debug("Unsupported input width %d\n", cfg->in_width);
++              return -1;
++      }
++
++      cfg->in_height &= ~1;   /* truncate to make even */
++
++      if ((cfg->in_height < PRP_MIN_IN_HEIGHT)
++          || (cfg->in_height > PRP_MAX_IN_HEIGHT)) {
++              pr_debug("Unsupported input height %d\n", cfg->in_height);
++              return -1;
++      }
++
++      if (!(cfg->in_csi & PRP_CSI_EN))
++              if (!cfg->in_line_stride)
++                      cfg->in_line_stride = cfg->in_width;
++
++      __raw_writel(cfg->in_pix, PRP_SRC_PIXEL_FORMAT_CNTL);
++      __raw_writel((cfg->in_width << 16) | cfg->in_height,
++                   PRP_SOURCE_FRAME_SIZE);
++      __raw_writel((cfg->in_line_skip << 16) | cfg->in_line_stride,
++                   PRP_SOURCE_LINE_STRIDE);
++
++      if (!(cfg->in_csi & PRP_CSI_EN)) {
++              __raw_writel(cfg->in_ptr, PRP_SOURCE_Y_PTR);
++              if (cfg->in_pix == PRP_PIXIN_YUV420) {
++                      unsigned int size;
++
++                      size = cfg->in_line_stride * cfg->in_height;
++                      __raw_writel(cfg->in_ptr + size, PRP_SOURCE_CB_PTR);
++                      __raw_writel(cfg->in_ptr + size + (size >> 2),
++                                   PRP_SOURCE_CR_PTR);
++              }
++      }
++
++      /* always cropping */
++      *prp_cntl |= PRP_CNTL_WINEN;
++
++      /* color space conversion */
++      if (!cfg->in_csc[1]) {
++              if (cfg->in_csc[0] > 3) {
++                      pr_debug("in_csc invalid 0x%X\n", cfg->in_csc[0]);
++                      return -1;
++              }
++              if ((cfg->in_pix == PRP_PIXIN_RGB565)
++                  || (cfg->in_pix == PRP_PIXIN_RGB888))
++                      cfg->in_csc[1] = 1;
++              else
++                      cfg->in_csc[0] = 0;
++              csc_tbl(cfg->in_csc);
++      }
++
++      __raw_writel((cfg->in_csc[0] << 21) | (cfg->in_csc[1] << 11)
++                   | cfg->in_csc[2], PRP_CSC_COEF_012);
++      __raw_writel((cfg->in_csc[3] << 21) | (cfg->in_csc[4] << 11)
++                   | cfg->in_csc[5], PRP_CSC_COEF_345);
++      __raw_writel((cfg->in_csc[6] << 21) | (cfg->in_csc[7] << 11)
++                   | cfg->in_csc[8] | (cfg->in_csc[9] << 31),
++                   PRP_CSC_COEF_678);
++
++      if (cfg->in_csi & PRP_CSI_EN) {
++              *prp_cntl |= PRP_CNTL_CSI;
++
++              /* loop mode enable, ch1 ch2 together */
++              if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP)
++                      *prp_cntl |= (PRP_CNTL_CH1_LOOP | PRP_CNTL_CH2_LOOP);
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Setup PrP registers relevant to channel 2.
++ * @param cfg         Pointer to PrP configuration parameter
++ * @param prp_cntl    Holds the value for PrP control register
++ * @return            Zero on success, others on failure
++ */
++static int prphw_ch2_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl)
++{
++      switch (cfg->ch2_pix) {
++      case PRP_PIX2_YUV420:
++              *prp_cntl |= PRP_CNTL_CH2_YUV420;
++              break;
++      case PRP_PIX2_YUV422:
++              *prp_cntl |= PRP_CNTL_CH2_YUV422;
++              break;
++      case PRP_PIX2_YUV444:
++              *prp_cntl |= PRP_CNTL_CH2_YUV444;
++              break;
++      case PRP_PIX2_UNUSED:
++              return 0;
++      default:
++              pr_debug("Unsupported channel 2 pix format 0x%08X\n",
++                       cfg->ch2_pix);
++              return -1;
++      }
++
++      if (cfg->ch2_pix == PRP_PIX2_YUV420) {
++              cfg->ch2_height &= ~1;  /* ensure U/V presence */
++              cfg->ch2_width &= ~7;   /* ensure U/V word aligned */
++      } else if (cfg->ch2_pix == PRP_PIX2_YUV422) {
++              cfg->ch2_width &= ~1;   /* word aligned */
++      }
++
++      __raw_writel((cfg->ch2_width << 16) | cfg->ch2_height,
++                   PRP_CH2_OUT_IMAGE_SIZE);
++
++      return 0;
++}
++
++/*!
++ * @brief Setup PrP registers relevant to channel 1.
++ * @param cfg         Pointer to PrP configuration parameter
++ * @param prp_cntl    Holds the value for PrP control register
++ * @return            Zero on success, others on failure
++ */
++static int prphw_ch1_cfg(emma_prp_cfg * cfg, unsigned long *prp_cntl)
++{
++      int ch1_bpp = 0;
++
++      switch (cfg->ch1_pix) {
++      case PRP_PIX1_RGB332:
++              *prp_cntl |= PRP_CNTL_CH1_RGB8;
++              ch1_bpp = 1;
++              break;
++      case PRP_PIX1_RGB565:
++              *prp_cntl |= PRP_CNTL_CH1_RGB16;
++              ch1_bpp = 2;
++              break;
++      case PRP_PIX1_RGB888:
++              *prp_cntl |= PRP_CNTL_CH1_RGB32;
++              ch1_bpp = 4;
++              break;
++      case PRP_PIX1_YUYV:
++      case PRP_PIX1_YVYU:
++      case PRP_PIX1_UYVY:
++      case PRP_PIX1_VYUY:
++              *prp_cntl |= PRP_CNTL_CH1_YUV422;
++              ch1_bpp = 2;
++              break;
++      case PRP_PIX1_UNUSED:
++              return 0;
++      default:
++              pr_debug("Unsupported channel 1 pix format 0x%08X\n",
++                       cfg->ch1_pix);
++              return -1;
++      }
++
++      /* parallel or cascade resize */
++      if (cfg->ch1_scale.algo & PRP_ALGO_BYPASS)
++              *prp_cntl |= PRP_CNTL_UNCHAIN;
++
++      /* word align */
++      if (ch1_bpp == 2)
++              cfg->ch1_width &= ~1;
++      else if (ch1_bpp == 1)
++              cfg->ch1_width &= ~3;
++
++      if (!cfg->ch1_stride)
++              cfg->ch1_stride = cfg->ch1_width;
++
++      __raw_writel(cfg->ch1_pix, PRP_CH1_PIXEL_FORMAT_CNTL);
++      __raw_writel((cfg->ch1_width << 16) | cfg->ch1_height,
++                   PRP_CH1_OUT_IMAGE_SIZE);
++      __raw_writel(cfg->ch1_stride * ch1_bpp, PRP_CH1_LINE_STRIDE);
++      __raw_writel(cfg->ch1_ptr, PRP_DEST_RGB1_PTR);
++
++      /* double buffer for loop mode */
++      if ((cfg->in_csi & PRP_CSI_LOOP) == PRP_CSI_LOOP) {
++              if (cfg->ch1_ptr2)
++                      __raw_writel(cfg->ch1_ptr2, PRP_DEST_RGB2_PTR);
++              else
++                      __raw_writel(cfg->ch1_ptr, PRP_DEST_RGB2_PTR);
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Setup PrP registers.
++ * @param cfg Pointer to PrP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++int prphw_cfg(emma_prp_cfg * cfg)
++{
++      unsigned long prp_cntl = 0;
++      unsigned long val;
++
++      /* input pixel format checking */
++      if (prphw_input_cfg(cfg, &prp_cntl))
++              return -1;
++
++      if (prphw_ch2_cfg(cfg, &prp_cntl))
++              return -1;
++
++      if (prphw_ch1_cfg(cfg, &prp_cntl))
++              return -1;
++
++      /* register setting */
++      __raw_writel(prp_cntl, PRP_CNTL);
++
++      /* interrupt configuration */
++      val = PRP_INTRCNTL_RDERR | PRP_INTRCNTL_LBOVF;
++      if (cfg->ch1_pix != PRP_PIX1_UNUSED)
++              val |= PRP_INTRCNTL_CH1FC | PRP_INTRCNTL_CH1WERR;
++      if (cfg->ch2_pix != PRP_PIX2_UNUSED)
++              val |=
++                  PRP_INTRCNTL_CH2FC | PRP_INTRCNTL_CH2WERR |
++                  PRP_INTRCNTL_CH2OVF;
++      __raw_writel(val, PRP_INTRCNTL);
++
++      prp_set_scaler(1, 0, &cfg->scale[0]);   /* Channel 1 width */
++      prp_set_scaler(1, 1, &cfg->scale[1]);   /* Channel 1 height */
++      prp_set_scaler(0, 0, &cfg->scale[2]);   /* Channel 2 width */
++      prp_set_scaler(0, 1, &cfg->scale[3]);   /* Channel 2 height */
++
++      return 0;
++}
++
++/*!
++ * @brief Check PrP interrupt status.
++ * @return    PrP interrupt status
++ */
++int prphw_isr(void)
++{
++      int status;
++
++      status = __raw_readl(PRP_INTRSTATUS) & 0x1FF;
++
++      if (status & (PRP_INTRSTAT_RDERR | PRP_INTRSTAT_CH1WERR |
++                    PRP_INTRSTAT_CH2WERR))
++              pr_debug("isr bus error. status= 0x%08X\n", status);
++      else if (status & PRP_INTRSTAT_CH2OVF)
++              pr_debug("isr ch 2 buffer overflow. status= 0x%08X\n", status);
++      else if (status & PRP_INTRSTAT_LBOVF)
++              pr_debug("isr line buffer overflow. status= 0x%08X\n", status);
++
++      /* silicon bug?? enable bit does not self clear? */
++      if (!(__raw_readl(PRP_CNTL) & PRP_CNTL_CH1_LOOP))
++              __raw_writel(__raw_readl(PRP_CNTL) & (~PRP_CNTL_CH1EN),
++                           PRP_CNTL);
++      if (!(__raw_readl(PRP_CNTL) & PRP_CNTL_CH2_LOOP))
++              __raw_writel(__raw_readl(PRP_CNTL) & (~PRP_CNTL_CH2EN),
++                           PRP_CNTL);
++
++      __raw_writel(status, PRP_INTRSTATUS);   /* clr irq */
++
++      return status;
++}
++
++static struct clk *emma_clk;
++
++/*!
++ * @brief  PrP module clock enable
++ */
++void prphw_init(void)
++{
++      emma_clk = clk_get(NULL, "emma_clk");
++      clk_enable(emma_clk);
++}
++
++/*!
++ * @brief PrP module clock disable
++ */
++void prphw_exit(void)
++{
++      clk_disable(emma_clk);
++      clk_put(emma_clk);
++}
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mx27_prpsw.c linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_prpsw.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/mx27_prpsw.c  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_prpsw.c     2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,1050 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_prpsw.c
++ *
++ * @brief MX27 Video For Linux 2 capture driver
++ *
++ * @ingroup MXC_V4L2_CAPTURE
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/string.h>
++#include <linux/fb.h>
++#include <linux/pci.h>
++#include <asm/cacheflush.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include "mxc_v4l2_capture.h"
++#include "mx27_prp.h"
++#include "mx27_csi.h"
++#include "../drivers/video/mxc/mx2fb.h"
++#include "../opl/opl.h"
++
++#define MEAN_COEF     (SZ_COEF >> 1)
++
++static char prp_dev[] = "emma_prp";
++static int g_still_on = 0;
++static emma_prp_cfg g_prp_cfg;
++static int g_vfbuf, g_rotbuf;
++static struct tasklet_struct prp_vf_tasklet;
++
++/*
++ * The following variables represents the virtual address for the cacheable
++ * buffers accessed by SW rotation/mirroring. The rotation/mirroring in
++ * cacheable buffers has significant performance improvement than it in
++ * non-cacheable buffers.
++ */
++static char *g_vaddr_vfbuf[2] = { 0, 0 };
++static char *g_vaddr_rotbuf[2] = { 0, 0 };
++static char *g_vaddr_fb = 0;
++
++static int set_ch1_addr(emma_prp_cfg * cfg, cam_data * cam);
++static int prp_v4l2_cfg(emma_prp_cfg * cfg, cam_data * cam);
++static int prp_vf_mem_alloc(cam_data * cam);
++static void prp_vf_mem_free(cam_data * cam);
++static int prp_rot_mem_alloc(cam_data * cam);
++static void prp_rot_mem_free(cam_data * cam);
++static int prp_enc_update_eba(u32 eba, int *buffer_num);
++static int prp_enc_enable(void *private);
++static int prp_enc_disable(void *private);
++static int prp_vf_start(void *private);
++static int prp_vf_stop(void *private);
++static int prp_still_start(void *private);
++static int prp_still_stop(void *private);
++static irqreturn_t prp_isr(int irq, void *dev_id);
++static void rotation(unsigned long private);
++static int prp_resize_check_ch1(emma_prp_cfg * cfg);
++static int prp_resize_check_ch2(emma_prp_cfg * cfg);
++
++#define PRP_DUMP(val) pr_debug("%s\t = 0x%08X\t%d\n", #val, val, val)
++
++/*!
++ * @brief Dump PrP configuration parameters.
++ * @param cfg The pointer to PrP configuration parameter
++ */
++static void prp_cfg_dump(emma_prp_cfg * cfg)
++{
++      PRP_DUMP(cfg->in_pix);
++      PRP_DUMP(cfg->in_width);
++      PRP_DUMP(cfg->in_height);
++      PRP_DUMP(cfg->in_csi);
++      PRP_DUMP(cfg->in_line_stride);
++      PRP_DUMP(cfg->in_line_skip);
++      PRP_DUMP(cfg->in_ptr);
++
++      PRP_DUMP(cfg->ch1_pix);
++      PRP_DUMP(cfg->ch1_width);
++      PRP_DUMP(cfg->ch1_height);
++      PRP_DUMP(cfg->ch1_scale.algo);
++      PRP_DUMP(cfg->ch1_scale.width.num);
++      PRP_DUMP(cfg->ch1_scale.width.den);
++      PRP_DUMP(cfg->ch1_scale.height.num);
++      PRP_DUMP(cfg->ch1_scale.height.den);
++      PRP_DUMP(cfg->ch1_stride);
++      PRP_DUMP(cfg->ch1_ptr);
++      PRP_DUMP(cfg->ch1_ptr2);
++      PRP_DUMP(cfg->ch1_csi);
++
++      PRP_DUMP(cfg->ch2_pix);
++      PRP_DUMP(cfg->ch2_width);
++      PRP_DUMP(cfg->ch2_height);
++      PRP_DUMP(cfg->ch2_scale.algo);
++      PRP_DUMP(cfg->ch2_scale.width.num);
++      PRP_DUMP(cfg->ch2_scale.width.den);
++      PRP_DUMP(cfg->ch2_scale.height.num);
++      PRP_DUMP(cfg->ch2_scale.height.den);
++      PRP_DUMP(cfg->ch2_ptr);
++      PRP_DUMP(cfg->ch2_ptr2);
++      PRP_DUMP(cfg->ch2_csi);
++}
++
++/*!
++ * @brief Set PrP channel 1 output address.
++ * @param cfg Pointer to emma_prp_cfg structure
++ * @param cam Pointer to cam_data structure
++ * @return    Zero on success, others on failure
++ */
++static int set_ch1_addr(emma_prp_cfg * cfg, cam_data * cam)
++{
++      if (cam->rotation != V4L2_MXC_ROTATE_NONE) {
++              cfg->ch1_ptr = (unsigned int)cam->rot_vf_bufs[0];
++              cfg->ch1_ptr2 = (unsigned int)cam->rot_vf_bufs[1];
++              if ((cam->rotation == V4L2_MXC_ROTATE_90_RIGHT)
++                  || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_VFLIP)
++                  || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_HFLIP)
++                  || (cam->rotation == V4L2_MXC_ROTATE_90_LEFT))
++                      cfg->ch1_stride = cam->win.w.height;
++              else
++                      cfg->ch1_stride = cam->win.w.width;
++
++              if (cam->v4l2_fb.flags != V4L2_FBUF_FLAG_OVERLAY) {
++                      struct fb_info *fb = cam->overlay_fb;
++                      if (!fb)
++                              return -1;
++                      if (g_vaddr_fb)
++                              iounmap(g_vaddr_fb);
++                      g_vaddr_fb = ioremap_cached(fb->fix.smem_start,
++                                                  fb->fix.smem_len);
++                      if (!g_vaddr_fb)
++                              return -1;
++              }
++      } else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              cfg->ch1_ptr = (unsigned int)cam->vf_bufs[0];
++              cfg->ch1_ptr2 = (unsigned int)cam->vf_bufs[1];
++              cfg->ch1_stride = cam->win.w.width;
++      } else {
++              struct fb_info *fb = cam->overlay_fb;
++
++              if (!fb)
++                      return -1;
++
++              cfg->ch1_ptr = fb->fix.smem_start;
++              cfg->ch1_ptr += cam->win.w.top * fb->var.xres_virtual
++                  * (fb->var.bits_per_pixel >> 3)
++                  + cam->win.w.left * (fb->var.bits_per_pixel >> 3);
++              cfg->ch1_ptr2 = cfg->ch1_ptr;
++              cfg->ch1_stride = fb->var.xres_virtual;
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Setup PrP configuration parameters.
++ * @param cfg Pointer to emma_prp_cfg structure
++ * @param cam Pointer to cam_data structure
++ * @return    Zero on success, others on failure
++ */
++static int prp_v4l2_cfg(emma_prp_cfg * cfg, cam_data * cam)
++{
++      cfg->in_pix = PRP_PIXIN_YUYV;
++      cfg->in_width = cam->crop_current.width;
++      cfg->in_height = cam->crop_current.height;
++      cfg->in_line_stride = cam->crop_current.left;
++      cfg->in_line_skip = cam->crop_current.top;
++      cfg->in_ptr = 0;
++      cfg->in_csi = PRP_CSI_LOOP;
++      memset(cfg->in_csc, 0, sizeof(cfg->in_csc));
++
++      if (cam->overlay_on) {
++              /* Convert V4L2 pixel format to PrP pixel format */
++              switch (cam->v4l2_fb.fmt.pixelformat) {
++              case V4L2_PIX_FMT_RGB332:
++                      cfg->ch1_pix = PRP_PIX1_RGB332;
++                      break;
++              case V4L2_PIX_FMT_RGB32:
++              case V4L2_PIX_FMT_BGR32:
++                      cfg->ch1_pix = PRP_PIX1_RGB888;
++                      break;
++              case V4L2_PIX_FMT_YUYV:
++                      cfg->ch1_pix = PRP_PIX1_YUYV;
++                      break;
++              case V4L2_PIX_FMT_UYVY:
++                      cfg->ch1_pix = PRP_PIX1_UYVY;
++                      break;
++              case V4L2_PIX_FMT_RGB565:
++              default:
++                      cfg->ch1_pix = PRP_PIX1_RGB565;
++                      break;
++              }
++              if ((cam->rotation == V4L2_MXC_ROTATE_90_RIGHT)
++                  || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_VFLIP)
++                  || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_HFLIP)
++                  || (cam->rotation == V4L2_MXC_ROTATE_90_LEFT)) {
++                      cfg->ch1_width = cam->win.w.height;
++                      cfg->ch1_height = cam->win.w.width;
++              } else {
++                      cfg->ch1_width = cam->win.w.width;
++                      cfg->ch1_height = cam->win.w.height;
++              }
++
++              if (set_ch1_addr(cfg, cam))
++                      return -1;
++      } else {
++              cfg->ch1_pix = PRP_PIX1_UNUSED;
++              cfg->ch1_width = cfg->in_width;
++              cfg->ch1_height = cfg->in_height;
++      }
++      cfg->ch1_scale.algo = 0;
++      cfg->ch1_scale.width.num = cfg->in_width;
++      cfg->ch1_scale.width.den = cfg->ch1_width;
++      cfg->ch1_scale.height.num = cfg->in_height;
++      cfg->ch1_scale.height.den = cfg->ch1_height;
++      cfg->ch1_csi = PRP_CSI_EN;
++
++      if (cam->capture_on || g_still_on) {
++              switch (cam->v2f.fmt.pix.pixelformat) {
++              case V4L2_PIX_FMT_YUYV:
++                      cfg->ch2_pix = PRP_PIX2_YUV422;
++                      break;
++              case V4L2_PIX_FMT_YUV420:
++                      cfg->ch2_pix = PRP_PIX2_YUV420;
++                      break;
++                      /*
++                       * YUV444 is not defined by V4L2.
++                       * We support it in default case.
++                       */
++              default:
++                      cfg->ch2_pix = PRP_PIX2_YUV444;
++                      break;
++              }
++              cfg->ch2_width = cam->v2f.fmt.pix.width;
++              cfg->ch2_height = cam->v2f.fmt.pix.height;
++      } else {
++              cfg->ch2_pix = PRP_PIX2_UNUSED;
++              cfg->ch2_width = cfg->in_width;
++              cfg->ch2_height = cfg->in_height;
++      }
++      cfg->ch2_scale.algo = 0;
++      cfg->ch2_scale.width.num = cfg->in_width;
++      cfg->ch2_scale.width.den = cfg->ch2_width;
++      cfg->ch2_scale.height.num = cfg->in_height;
++      cfg->ch2_scale.height.den = cfg->ch2_height;
++      cfg->ch2_csi = PRP_CSI_EN;
++
++      memset(cfg->scale, 0, sizeof(cfg->scale));
++      cfg->scale[0].algo = cfg->ch1_scale.algo & 3;
++      cfg->scale[1].algo = (cfg->ch1_scale.algo >> 2) & 3;
++      cfg->scale[2].algo = cfg->ch2_scale.algo & 3;
++      cfg->scale[3].algo = (cfg->ch2_scale.algo >> 2) & 3;
++
++      prp_cfg_dump(cfg);
++
++      if (prp_resize_check_ch2(cfg))
++              return -1;
++
++      if (prp_resize_check_ch1(cfg))
++              return -1;
++
++      return 0;
++}
++
++/*!
++ * @brief PrP interrupt handler
++ */
++static irqreturn_t prp_isr(int irq, void *dev_id)
++{
++      int status;
++      cam_data *cam = (cam_data *) dev_id;
++
++      status = prphw_isr();
++
++      if (g_still_on && (status & PRP_INTRSTAT_CH2BUF1)) {
++              prp_still_stop(cam);
++              cam->still_counter++;
++              wake_up_interruptible(&cam->still_queue);
++              /*
++               * Still & video capture use the same PrP channel 2.
++               * They are execlusive.
++               */
++      } else if (cam->capture_on) {
++              if (status & PRP_INTRSTAT_CH2OVF) {
++                      prphw_disable(PRP_CHANNEL_2);
++                      cam->enc_callback(1, cam);
++              } else if (status &
++                         (PRP_INTRSTAT_CH2BUF1 | PRP_INTRSTAT_CH2BUF2)) {
++                      if (cam->overflow != 1)
++                              cam->enc_callback(0, cam);
++              }
++      }
++      if (cam->overlay_on
++          && (status & (PRP_INTRSTAT_CH1BUF1 | PRP_INTRSTAT_CH1BUF2))) {
++              if (cam->rotation != V4L2_MXC_ROTATE_NONE) {
++                      g_rotbuf = (status & PRP_INTRSTAT_CH1BUF1) ? 0 : 1;
++                      tasklet_schedule(&prp_vf_tasklet);
++              } else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++                      struct fb_gwinfo gwinfo;
++
++                      gwinfo.enabled = 1;
++                      gwinfo.alpha_value = 255;
++                      gwinfo.ck_enabled = 0;
++                      gwinfo.xpos = cam->win.w.left;
++                      gwinfo.ypos = cam->win.w.top;
++                      gwinfo.xres = cam->win.w.width;
++                      gwinfo.yres = cam->win.w.height;
++                      gwinfo.xres_virtual = cam->win.w.width;
++                      gwinfo.vs_reversed = 0;
++                      if (status & PRP_INTRSTAT_CH1BUF1)
++                              gwinfo.base = (unsigned long)cam->vf_bufs[0];
++                      else
++                              gwinfo.base = (unsigned long)cam->vf_bufs[1];
++
++                      mx2_gw_set(&gwinfo);
++              }
++      }
++
++      return IRQ_HANDLED;
++}
++
++/*!
++ * @brief PrP initialization.
++ * @param dev_id      Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++int prp_init(void *dev_id)
++{
++      enable_irq(INT_EMMAPRP);
++      if (request_irq(INT_EMMAPRP, prp_isr, 0, prp_dev, dev_id))
++              return -1;
++      prphw_init();
++
++      return 0;
++}
++
++/*!
++ * @brief PrP initialization.
++ * @param dev_id      Pointer to cam_data structure
++ */
++void prp_exit(void *dev_id)
++{
++      prphw_exit();
++      disable_irq(INT_EMMAPRP);
++      free_irq(INT_EMMAPRP, dev_id);
++}
++
++/*!
++ * @brief Update PrP channel 2 output buffer address.
++ * @param eba         Physical address for PrP output buffer
++ * @param buffer_num  The PrP channel 2 buffer number to be updated
++ * @return            Zero on success, others on failure
++ */
++static int prp_enc_update_eba(u32 eba, int *buffer_num)
++{
++      if (*buffer_num) {
++              g_prp_cfg.ch2_ptr2 = eba;
++              prphw_ch2ptr2(&g_prp_cfg);
++              *buffer_num = 0;
++      } else {
++              g_prp_cfg.ch2_ptr = eba;
++              prphw_ch2ptr(&g_prp_cfg);
++              *buffer_num = 1;
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Enable PrP for encoding.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++static int prp_enc_enable(void *private)
++{
++      cam_data *cam = (cam_data *) private;
++
++      if (prp_v4l2_cfg(&g_prp_cfg, cam))
++              return -1;
++
++      csi_enable_mclk(CSI_MCLK_ENC, true, true);
++      prphw_reset();
++
++      if (prphw_cfg(&g_prp_cfg))
++              return -1;
++
++      prphw_enable(cam->overlay_on ? (PRP_CHANNEL_1 | PRP_CHANNEL_2)
++                   : PRP_CHANNEL_2);
++
++      return 0;
++}
++
++/*!
++ * @brief Disable PrP for encoding.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++static int prp_enc_disable(void *private)
++{
++      prphw_disable(PRP_CHANNEL_2);
++      csi_enable_mclk(CSI_MCLK_ENC, false, false);
++
++      return 0;
++}
++
++/*!
++ * @brief Setup encoding functions.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++int prp_enc_select(void *private)
++{
++      int ret = 0;
++      cam_data *cam = (cam_data *) private;
++
++      if (cam) {
++              cam->enc_update_eba = prp_enc_update_eba;
++              cam->enc_enable = prp_enc_enable;
++              cam->enc_disable = prp_enc_disable;
++      } else
++              ret = -EIO;
++
++      return ret;
++}
++
++/*!
++ * @brief Uninstall encoding functions.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++int prp_enc_deselect(void *private)
++{
++      int ret = 0;
++      cam_data *cam = (cam_data *) private;
++
++      ret = prp_enc_disable(private);
++
++      if (cam) {
++              cam->enc_update_eba = NULL;
++              cam->enc_enable = NULL;
++              cam->enc_disable = NULL;
++      }
++
++      return ret;
++}
++
++/*!
++ * @brief Allocate memory for overlay.
++ * @param cam Pointer to cam_data structure
++ * @return    Zero on success, others on failure
++ */
++static int prp_vf_mem_alloc(cam_data * cam)
++{
++      int i;
++
++      for (i = 0; i < 2; i++) {
++              cam->vf_bufs_size[i] = cam->win.w.width * cam->win.w.height * 2;
++              cam->vf_bufs_vaddr[i] = dma_alloc_coherent(0,
++                                                         cam->vf_bufs_size[i],
++                                                         &cam->vf_bufs[i],
++                                                         GFP_DMA |
++                                                         GFP_KERNEL);
++              if (!cam->vf_bufs_vaddr[i]) {
++                      pr_debug("Failed to alloc memory for vf.\n");
++                      prp_vf_mem_free(cam);
++                      return -1;
++              }
++
++              g_vaddr_vfbuf[i] =
++                  ioremap_cached(cam->vf_bufs[i], cam->vf_bufs_size[i]);
++              if (!g_vaddr_vfbuf[i]) {
++                      pr_debug("Failed to ioremap_cached() for vf.\n");
++                      prp_vf_mem_free(cam);
++                      return -1;
++              }
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Free memory for overlay.
++ * @param cam Pointer to cam_data structure
++ * @return    Zero on success, others on failure
++ */
++static void prp_vf_mem_free(cam_data * cam)
++{
++      int i;
++
++      for (i = 0; i < 2; i++) {
++              if (cam->vf_bufs_vaddr[i]) {
++                      dma_free_coherent(0,
++                                        cam->vf_bufs_size[i],
++                                        cam->vf_bufs_vaddr[i],
++                                        cam->vf_bufs[i]);
++              }
++              cam->vf_bufs[i] = 0;
++              cam->vf_bufs_vaddr[i] = 0;
++              cam->vf_bufs_size[i] = 0;
++              if (g_vaddr_vfbuf[i]) {
++                      iounmap(g_vaddr_vfbuf[i]);
++                      g_vaddr_vfbuf[i] = 0;
++              }
++      }
++}
++
++/*!
++ * @brief Allocate intermediate memory for overlay rotation/mirroring.
++ * @param cam Pointer to cam_data structure
++ * @return    Zero on success, others on failure
++ */
++static int prp_rot_mem_alloc(cam_data * cam)
++{
++      int i;
++
++      for (i = 0; i < 2; i++) {
++              cam->rot_vf_buf_size[i] =
++                  cam->win.w.width * cam->win.w.height * 2;
++              cam->rot_vf_bufs_vaddr[i] =
++                  dma_alloc_coherent(0, cam->rot_vf_buf_size[i],
++                                     &cam->rot_vf_bufs[i],
++                                     GFP_DMA | GFP_KERNEL);
++              if (!cam->rot_vf_bufs_vaddr[i]) {
++                      pr_debug("Failed to alloc memory for vf rotation.\n");
++                      prp_rot_mem_free(cam);
++                      return -1;
++              }
++
++              g_vaddr_rotbuf[i] =
++                  ioremap_cached(cam->rot_vf_bufs[i],
++                                 cam->rot_vf_buf_size[i]);
++              if (!g_vaddr_rotbuf[i]) {
++                      pr_debug
++                          ("Failed to ioremap_cached() for rotation buffer.\n");
++                      prp_rot_mem_free(cam);
++                      return -1;
++              }
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Free intermedaite memory for overlay rotation/mirroring.
++ * @param cam Pointer to cam_data structure
++ * @return    Zero on success, others on failure
++ */
++static void prp_rot_mem_free(cam_data * cam)
++{
++      int i;
++
++      for (i = 0; i < 2; i++) {
++              if (cam->rot_vf_bufs_vaddr[i]) {
++                      dma_free_coherent(0,
++                                        cam->rot_vf_buf_size[i],
++                                        cam->rot_vf_bufs_vaddr[i],
++                                        cam->rot_vf_bufs[i]);
++              }
++              cam->rot_vf_bufs[i] = 0;
++              cam->rot_vf_bufs_vaddr[i] = 0;
++              cam->rot_vf_buf_size[i] = 0;
++              if (g_vaddr_rotbuf[i]) {
++                      iounmap(g_vaddr_rotbuf[i]);
++                      g_vaddr_rotbuf[i] = 0;
++              }
++      }
++}
++
++/*!
++ * @brief Start overlay (view finder).
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++static int prp_vf_start(void *private)
++{
++      cam_data *cam = (cam_data *) private;
++
++      if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              prp_vf_mem_free(cam);
++              if (prp_vf_mem_alloc(cam)) {
++                      pr_info("Error to allocate vf buffer\n");
++                      return -ENOMEM;
++              }
++      }
++
++      if (cam->rotation != V4L2_MXC_ROTATE_NONE) {
++              prp_rot_mem_free(cam);
++              if (prp_rot_mem_alloc(cam)) {
++                      pr_info("Error to allocate rotation buffer\n");
++                      prp_vf_mem_free(cam);
++                      return -ENOMEM;
++              }
++      }
++
++      if (prp_v4l2_cfg(&g_prp_cfg, cam)) {
++              prp_vf_mem_free(cam);
++              prp_rot_mem_free(cam);
++              return -1;
++      }
++
++      csi_enable_mclk(CSI_MCLK_VF, true, true);
++      prphw_reset();
++
++      if (prphw_cfg(&g_prp_cfg)) {
++              prp_vf_mem_free(cam);
++              prp_rot_mem_free(cam);
++              return -1;
++      }
++      g_vfbuf = g_rotbuf = 0;
++      tasklet_init(&prp_vf_tasklet, rotation, (unsigned long)private);
++
++      prphw_enable(cam->capture_on ? (PRP_CHANNEL_1 | PRP_CHANNEL_2)
++                   : PRP_CHANNEL_1);
++
++      return 0;
++}
++
++/*!
++ * @brief Stop overlay (view finder).
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++static int prp_vf_stop(void *private)
++{
++      cam_data *cam = (cam_data *) private;
++
++      prphw_disable(PRP_CHANNEL_1);
++
++      csi_enable_mclk(CSI_MCLK_VF, false, false);
++      tasklet_kill(&prp_vf_tasklet);
++
++      if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              struct fb_gwinfo gwinfo;
++
++              /* Disable graphic window */
++              gwinfo.enabled = 0;
++              mx2_gw_set(&gwinfo);
++
++              prp_vf_mem_free(cam);
++      }
++      prp_rot_mem_free(cam);
++      if (g_vaddr_fb) {
++              iounmap(g_vaddr_fb);
++              g_vaddr_fb = 0;
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Setup overlay functions.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++int prp_vf_select(void *private)
++{
++      int ret = 0;
++      cam_data *cam = (cam_data *) private;
++
++      if (cam) {
++              cam->vf_start_sdc = prp_vf_start;
++              cam->vf_stop_sdc = prp_vf_stop;
++              cam->overlay_active = false;
++      } else
++              ret = -EIO;
++
++      return ret;
++}
++
++/*!
++ * @brief Uninstall overlay functions.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++int prp_vf_deselect(void *private)
++{
++      int ret = 0;
++      cam_data *cam = (cam_data *) private;
++
++      ret = prp_vf_stop(private);
++
++      if (cam) {
++              cam->vf_start_sdc = NULL;
++              cam->vf_stop_sdc = NULL;
++      }
++
++      return ret;
++}
++
++/*!
++ * @brief Start still picture capture.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++static int prp_still_start(void *private)
++{
++      cam_data *cam = (cam_data *) private;
++
++      g_still_on = 1;
++      g_prp_cfg.ch2_ptr = (unsigned int)cam->still_buf;
++      g_prp_cfg.ch2_ptr2 = 0;
++
++      if (prp_v4l2_cfg(&g_prp_cfg, cam))
++              return -1;
++
++      csi_enable_mclk(CSI_MCLK_RAW, true, true);
++      prphw_reset();
++
++      if (prphw_cfg(&g_prp_cfg)) {
++              g_still_on = 0;
++              return -1;
++      }
++
++      prphw_enable(cam->overlay_on ? (PRP_CHANNEL_1 | PRP_CHANNEL_2)
++                   : PRP_CHANNEL_2);
++
++      return 0;
++}
++
++/*!
++ * @brief Stop still picture capture.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++static int prp_still_stop(void *private)
++{
++      prphw_disable(PRP_CHANNEL_2);
++
++      csi_enable_mclk(CSI_MCLK_RAW, false, false);
++
++      g_still_on = 0;
++
++      return 0;
++}
++
++/*!
++ * @brief Setup functions for still picture capture.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++int prp_still_select(void *private)
++{
++      cam_data *cam = (cam_data *) private;
++
++      if (cam) {
++              cam->csi_start = prp_still_start;
++              cam->csi_stop = prp_still_stop;
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Uninstall functions for still picture capture.
++ * @param private     Pointer to cam_data structure
++ * @return            Zero on success, others on failure
++ */
++int prp_still_deselect(void *private)
++{
++      cam_data *cam = (cam_data *) private;
++      int err = 0;
++
++      err = prp_still_stop(cam);
++
++      if (cam) {
++              cam->csi_start = NULL;
++              cam->csi_stop = NULL;
++      }
++
++      return err;
++}
++
++/*!
++ * @brief Perform software rotation or mirroring
++ * @param private     Argument passed to the tasklet
++ */
++static void rotation(unsigned long private)
++{
++      char *src, *dst;
++      int width, height, s_stride, d_stride;
++      int size;
++      cam_data *cam = (cam_data *) private;
++
++      src = g_vaddr_rotbuf[g_rotbuf];
++      size = cam->rot_vf_buf_size[g_rotbuf];
++
++      if ((cam->rotation == V4L2_MXC_ROTATE_90_RIGHT)
++          || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_VFLIP)
++          || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_HFLIP)
++          || (cam->rotation == V4L2_MXC_ROTATE_90_LEFT)) {
++              width = cam->win.w.height;
++              height = cam->win.w.width;
++              s_stride = cam->win.w.height << 1;
++      } else {
++              width = cam->win.w.width;
++              height = cam->win.w.height;
++              s_stride = cam->win.w.width << 1;
++      }
++
++      if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              dst = g_vaddr_vfbuf[g_vfbuf];
++              d_stride = cam->win.w.width << 1;
++      } else {                /* The destination is the framebuffer */
++              struct fb_info *fb = cam->overlay_fb;
++              if (!fb)
++                      return;
++              dst = g_vaddr_fb;
++              dst += cam->win.w.top * fb->var.xres_virtual
++                  * (fb->var.bits_per_pixel >> 3)
++                  + cam->win.w.left * (fb->var.bits_per_pixel >> 3);
++              d_stride = fb->var.xres_virtual << 1;
++      }
++
++      /*
++       * Invalidate the data in cache before performing the SW rotaion
++       * or mirroring in case the image size is less than QVGA. For image
++       * larger than QVGA it is not invalidated becase the invalidation
++       * will consume much time while we don't see any artifacts on the
++       * output if we don't perform invalidation for them.
++       * Similarly we don't flush the data after SW rotation/mirroring.
++       */
++      if (size < 320 * 240 * 2)
++              dmac_inv_range(src, src + size);
++      switch (cam->rotation) {
++      case V4L2_MXC_ROTATE_VERT_FLIP:
++              opl_vmirror_u16(src, s_stride, width, height, dst, d_stride);
++              break;
++      case V4L2_MXC_ROTATE_HORIZ_FLIP:
++              opl_hmirror_u16(src, s_stride, width, height, dst, d_stride);
++              break;
++      case V4L2_MXC_ROTATE_180:
++              opl_rotate180_u16(src, s_stride, width, height, dst, d_stride);
++              break;
++      case V4L2_MXC_ROTATE_90_RIGHT:
++              opl_rotate90_u16(src, s_stride, width, height, dst, d_stride);
++              break;
++      case V4L2_MXC_ROTATE_90_RIGHT_VFLIP:
++              opl_rotate90_vmirror_u16(src, s_stride, width, height, dst,
++                                       d_stride);
++              break;
++      case V4L2_MXC_ROTATE_90_RIGHT_HFLIP:
++              /* ROTATE_90_RIGHT_HFLIP = ROTATE_270_RIGHT_VFLIP */
++              opl_rotate270_vmirror_u16(src, s_stride, width, height, dst,
++                                        d_stride);
++              break;
++      case V4L2_MXC_ROTATE_90_LEFT:
++              opl_rotate270_u16(src, s_stride, width, height, dst, d_stride);
++              break;
++      default:
++              return;
++      }
++
++      /* Config and display the graphic window */
++      if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              struct fb_gwinfo gwinfo;
++
++              gwinfo.enabled = 1;
++              gwinfo.alpha_value = 255;
++              gwinfo.ck_enabled = 0;
++              gwinfo.xpos = cam->win.w.left;
++              gwinfo.ypos = cam->win.w.top;
++              gwinfo.xres = cam->win.w.width;
++              gwinfo.yres = cam->win.w.height;
++              gwinfo.xres_virtual = cam->win.w.width;
++              gwinfo.vs_reversed = 0;
++              gwinfo.base = (unsigned long)cam->vf_bufs[g_vfbuf];
++              mx2_gw_set(&gwinfo);
++
++              g_vfbuf = g_vfbuf ? 0 : 1;
++      }
++}
++
++/*
++ * @brief Check if the resize ratio is supported based on the input and output
++ *        dimension
++ * @param     input   input dimension
++ * @param     output  output dimension
++ * @return    output dimension (should equal the parameter *output*)
++ *            -1 on failure
++ */
++static int check_simple(scale_t * scale, int input, int output, int ch)
++{
++      unsigned short int_out; /* PrP internel width or height */
++      unsigned short orig_out = output;
++
++      if (prp_scale(scale, input, output, input, &orig_out, &int_out, ch))
++              return -1;      /* resize failed */
++      else
++              return int_out;
++}
++
++/*!
++ * @brief Check if the resize ratio is supported by PrP channel 1
++ * @param cfg Pointer to emma_prp_cfg structure
++ * @return    Zero on success, others on failure
++ */
++static int prp_resize_check_ch1(emma_prp_cfg * cfg)
++{
++      int in_w, in_h, ch1_w, ch1_h, ch2_w, ch2_h, w, h;
++      scale_t *pscale = &cfg->scale[0];       /* Ch1 width resize coeff */
++
++      if (cfg->ch1_pix == PRP_PIX1_UNUSED)
++              return 0;
++
++      in_w = cfg->in_width;
++      in_h = cfg->in_height;
++      ch1_w = cfg->ch1_width;
++      ch1_h = cfg->ch1_height;
++      ch2_w = cfg->ch2_width;
++      ch2_h = cfg->ch2_height;
++
++      /*
++       * For channel 1, try parallel resize first. If the resize
++       * ratio is not exactly supported, try cascade resize. If it
++       * still fails, use parallel resize but with rounded value.
++       */
++      w = check_simple(pscale, in_w, ch1_w, PRP_CHANNEL_1);
++      h = check_simple(pscale + 1, in_h, ch1_h, PRP_CHANNEL_1);
++
++      if ((in_w <= ch1_w * MAX_TBL) && (in_h <= MAX_TBL * ch1_h))
++              goto exit_parallel;
++
++      if (cfg->ch2_pix != PRP_PIX2_UNUSED) {
++              /*
++               * Channel 2 is already used. The pscale is still pointing
++               * to ch1 resize coeff for temporary use.
++               */
++              if ((ch2_w * MAX_TBL <= ch1_w) && (ch2_h * MAX_TBL <= ch1_h)) {
++                      w = check_simple(pscale, ch2_w, ch1_w, PRP_CHANNEL_1);
++                      h = check_simple(pscale + 1, ch2_h, ch1_h,
++                                       PRP_CHANNEL_1);
++                      goto exit_cascade;
++              }
++      } else {
++              /*
++               * Try cascade resize for width, width is multiple of 2.
++               * Channel 2 is not used. So we have more values to pick
++               * for channel 2 resize.
++               */
++              if (in_w * MAX_TBL > ch1_w) {
++                      for (w = in_w / 2; w > ch1_w; w /= 2) {
++                              /* Ch1 width resize */
++                              if (check_simple
++                                  (pscale, w, ch1_w, PRP_CHANNEL_1) < 0)
++                                      continue;
++                              /* Ch2 width resize */
++                              ch2_w =
++                                  check_simple(pscale + 2, in_w, w,
++                                               PRP_CHANNEL_1);
++                              if (ch2_w < 0) {
++                                      w = in_w / MAX_TBL;
++                                      continue;
++                              }
++                              check_simple(pscale, ch2_w, ch1_w,
++                                           PRP_CHANNEL_1);
++                              break;
++                      }
++              } else {
++                      w = check_simple(pscale, in_w, ch1_w, PRP_CHANNEL_1);
++                      ch2_w = check_simple(pscale + 2, w, w, PRP_CHANNEL_1);
++              }
++              if (ch2_w >= ch1_w) {
++                      if (in_h * MAX_TBL > ch1_h) {
++                              /* try cascade resize for height */
++                              for (h = in_h / 2; h > ch1_h; h /= 2) {
++                                      /* Ch2 height resize */
++                                      if (check_simple
++                                          (pscale + 1, h, ch1_h,
++                                           PRP_CHANNEL_1) < 0)
++                                              continue;
++                                      /* Ch1 height resize */
++                                      ch2_h =
++                                          check_simple(pscale + 3, in_h, h,
++                                                       PRP_CHANNEL_1);
++                                      if (ch2_w < 0) {
++                                              h = in_h / MAX_TBL;
++                                              continue;
++                                      }
++                                      check_simple(pscale + 1, ch2_h, ch1_h,
++                                                   PRP_CHANNEL_1);
++                                      break;
++                              }
++                      } else {
++                              h = check_simple(pscale + 1, in_h, ch1_h,
++                                               PRP_CHANNEL_1);
++                              ch2_h =
++                                  check_simple(pscale + 3, h, h,
++                                               PRP_CHANNEL_1);
++                      }
++
++                      goto exit_cascade;
++              }
++      }
++
++      pr_debug("Ch1 resize error.\n");
++      return -1;
++
++      exit_parallel:
++      cfg->ch1_scale.algo |= PRP_ALGO_BYPASS;
++      pr_debug("ch1 parallel resize.\n");
++      pr_debug("original width = %d internel width = %d\n", ch1_w, w);
++      pr_debug("original height = %d internel height = %d\n", ch1_h, h);
++      return 0;
++
++      exit_cascade:
++      cfg->ch1_scale.algo &= ~PRP_ALGO_BYPASS;
++      pr_debug("ch1 cascade resize.\n");
++      pr_debug("[width] in : ch2 : ch1=%d : %d : %d\n", in_w, ch2_w, ch1_w);
++      pr_debug("[height] in : ch2 : ch1=%d : %d : %d\n", in_h, ch2_h, ch1_h);
++      return 0;
++}
++
++/*!
++ * @brief Check if the resize ratio is supported by PrP channel 2
++ * @param cfg Pointer to emma_prp_cfg structure
++ * @return    Zero on success, others on failure
++ */
++static int prp_resize_check_ch2(emma_prp_cfg * cfg)
++{
++      int w, h;
++      scale_t *pscale = &cfg->scale[2];       /* Ch2 width resize coeff */
++
++      if (cfg->ch2_pix == PRP_PIX2_UNUSED)
++              return 0;
++
++      w = check_simple(pscale, cfg->in_width, cfg->ch2_width, PRP_CHANNEL_2);
++      h = check_simple(pscale + 1, cfg->in_height, cfg->ch2_height,
++                       PRP_CHANNEL_2);
++      if ((w != -1) && (h != -1)) {
++              pr_debug("Ch2 resize.\n");
++              pr_debug("Original width = %d internel width = %d\n",
++                       cfg->ch2_width, w);
++              pr_debug("Original height = %d internel height = %d\n",
++                       cfg->ch2_height, h);
++              return 0;
++      } else {
++              pr_debug("Ch2 resize error.\n");
++              return -1;
++      }
++}
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mx27_v4l2_capture.c linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_v4l2_capture.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/mx27_v4l2_capture.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mx27_v4l2_capture.c      2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,2288 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_v4l2_capture.c
++ *
++ * @brief MX27 Video For Linux 2 driver
++ *
++ * @ingroup MXC_V4L2_CAPTURE
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include <linux/pagemap.h>
++#include <linux/vmalloc.h>
++#include <linux/types.h>
++#include <linux/fb.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <linux/version.h>
++#include <media/v4l2-dev.h>
++#include <asm/io.h>
++#include <asm/semaphore.h>
++
++#include "mxc_v4l2_capture.h"
++#include "mx27_prp.h"
++#include "mx27_csi.h"
++
++static int csi_mclk_flag_backup;
++static int video_nr = -1;
++cam_data *g_cam;
++EXPORT_SYMBOL(g_cam);
++
++static int dq_intr_cnt = 0;
++static int dq_timeout_cnt = 0;
++static int empty_wq_cnt = 0;
++struct workqueue_struct *v4l2_work;
++
++static void prp_reset(struct work_struct *unused)
++{
++      struct mxc_v4l_frame *done_frame, *ready_frame, *temp_frame;
++
++      g_cam->ping_pong_csi = 0;
++      g_cam->enc_enable(g_cam);
++      if (!list_empty(&g_cam->working_q)) {
++              done_frame =
++                  list_entry(g_cam->working_q.next, struct mxc_v4l_frame,
++                             queue);
++              list_del(g_cam->working_q.next);
++              if (!list_empty(&g_cam->working_q)) {
++                      temp_frame =
++                          list_entry(g_cam->working_q.next,
++                                     struct mxc_v4l_frame, queue);
++                      list_del(g_cam->working_q.next);
++                      list_add_tail(&temp_frame->queue, &g_cam->working_q);
++                      g_cam->enc_update_eba(temp_frame->paddress,
++                                            &g_cam->ping_pong_csi);
++              }
++              list_add_tail(&done_frame->queue, &g_cam->working_q);
++              g_cam->enc_update_eba(done_frame->paddress,
++                                    &g_cam->ping_pong_csi);
++              pr_debug("prp_reset - working_q\n");
++      } else if (list_empty(&g_cam->ready_q)) {
++              prphw_disable(PRP_CHANNEL_2);
++              g_cam->skip_frame++;
++      } else {
++              ready_frame =
++                  list_entry(g_cam->ready_q.next, struct mxc_v4l_frame,
++                             queue);
++              list_del(g_cam->ready_q.next);
++              list_add_tail(&ready_frame->queue, &g_cam->working_q);
++              g_cam->enc_update_eba(ready_frame->paddress,
++                                    &g_cam->ping_pong_csi);
++      }
++      g_cam->overflow = 0;
++      wake_up_interruptible(&g_cam->overflow_queue);
++}
++
++DECLARE_WORK(prp_reset_work, prp_reset);
++/*!
++ * Free frame buffers
++ *
++ * @param cam      Structure cam_data *
++ *
++ * @return status  0 success.
++ */
++static int mxc_free_frame_buf(cam_data * cam)
++{
++      int i;
++
++      for (i = 0; i < FRAME_NUM; i++) {
++              if (cam->frame[i].vaddress != 0) {
++                      dma_free_coherent(0,
++                                        cam->frame[i].buffer.length,
++                                        cam->frame[i].vaddress,
++                                        cam->frame[i].paddress);
++                      cam->frame[i].vaddress = 0;
++              }
++      }
++
++      return 0;
++}
++
++/*!
++ * Allocate frame buffers
++ *
++ * @param cam      Structure cam_data *
++ *
++ * @param count    int number of buffer need to allocated
++ *
++ * @return status  -0 Successfully allocated a buffer, -ENOBUFS       failed.
++ */
++static int mxc_allocate_frame_buf(cam_data * cam, int count)
++{
++      int i;
++
++      for (i = 0; i < count; i++) {
++              cam->frame[i].vaddress = dma_alloc_coherent(0,
++                                                          PAGE_ALIGN(cam->v2f.
++                                                                     fmt.pix.
++                                                                     sizeimage),
++                                                          &cam->frame[i].
++                                                          paddress,
++                                                          GFP_DMA |
++                                                          GFP_KERNEL);
++              if (cam->frame[i].vaddress == 0) {
++                      pr_debug("mxc_allocate_frame_buf failed.\n");
++                      mxc_free_frame_buf(cam);
++                      return -ENOBUFS;
++              }
++              cam->frame[i].buffer.index = i;
++              cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
++              cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++              cam->frame[i].buffer.length =
++                  PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
++              cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP;
++              cam->frame[i].buffer.m.offset = cam->frame[i].paddress;
++              cam->frame[i].index = i;
++      }
++
++      return 0;
++}
++
++/*!
++ * Free frame buffers status
++ *
++ * @param cam    Structure cam_data *
++ *
++ * @return none
++ */
++static void mxc_free_frames(cam_data * cam)
++{
++      int i;
++
++      for (i = 0; i < FRAME_NUM; i++) {
++              cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
++      }
++
++      cam->enc_counter = 0;
++      cam->skip_frame = 0;
++      INIT_LIST_HEAD(&cam->ready_q);
++      INIT_LIST_HEAD(&cam->working_q);
++      INIT_LIST_HEAD(&cam->done_q);
++}
++
++/*!
++ * Return the buffer status
++ *
++ * @param cam            Structure cam_data *
++ * @param buf      Structure v4l2_buffer *
++ *
++ * @return status  0 success, EINVAL failed.
++ */
++static int mxc_v4l2_buffer_status(cam_data * cam, struct v4l2_buffer *buf)
++{
++      /* check range */
++      if (buf->index < 0 || buf->index >= FRAME_NUM) {
++              pr_debug("mxc_v4l2_buffer_status buffers not allocated\n");
++              return -EINVAL;
++      }
++
++      memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf));
++      return 0;
++}
++
++/*!
++ * start the encoder job
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static int mxc_streamon(cam_data * cam)
++{
++      struct mxc_v4l_frame *frame;
++      int err = 0;
++
++      if (!cam)
++              return -EIO;
++
++      if (list_empty(&cam->ready_q)) {
++              printk(KERN_ERR "mxc_streamon buffer not been queued yet\n");
++              return -EINVAL;
++      }
++
++      cam->capture_pid = current->pid;
++
++      if (cam->enc_enable) {
++              err = cam->enc_enable(cam);
++              if (err != 0) {
++                      return err;
++              }
++      }
++
++      cam->ping_pong_csi = 0;
++      cam->overflow = 0;
++      if (cam->enc_update_eba) {
++              frame =
++                  list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
++              list_del(cam->ready_q.next);
++              list_add_tail(&frame->queue, &cam->working_q);
++              err = cam->enc_update_eba(frame->paddress, &cam->ping_pong_csi);
++
++              frame =
++                  list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
++              list_del(cam->ready_q.next);
++              list_add_tail(&frame->queue, &cam->working_q);
++              err |=
++                  cam->enc_update_eba(frame->paddress, &cam->ping_pong_csi);
++      } else {
++              return -EINVAL;
++      }
++
++      return err;
++}
++
++/*!
++ * Shut down the encoder job
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static int mxc_streamoff(cam_data * cam)
++{
++      int err = 0;
++
++      if (!cam)
++              return -EIO;
++
++      if (cam->enc_disable) {
++              err = cam->enc_disable(cam);
++      }
++      mxc_free_frames(cam);
++      return err;
++}
++
++/*!
++ * Valid whether the palette is supported
++ *
++ * @param palette pixel format
++ *
++ * @return 0 if failed
++ */
++static inline int valid_mode(u32 palette)
++{
++      /*
++       * MX27 PrP channel 2 supports YUV444, but YUV444 is not
++       * defined by V4L2 :(
++       */
++      return ((palette == V4L2_PIX_FMT_YUYV) ||
++              (palette == V4L2_PIX_FMT_YUV420));
++}
++
++/*!
++ * Valid and adjust the overlay window size, position
++ *
++ * @param cam      structure cam_data *
++ * @param win      struct v4l2_window  *
++ *
++ * @return 0
++ */
++static int verify_preview(cam_data * cam, struct v4l2_window *win)
++{
++      if (cam->output >= num_registered_fb) {
++              pr_debug("verify_preview No matched.\n");
++              return -EINVAL;
++      }
++      cam->overlay_fb = (struct fb_info *)registered_fb[cam->output];
++
++      /* TODO: suppose 16bpp, 4 bytes alignment */
++      win->w.left &= ~0x1;
++
++      if (win->w.width + win->w.left > cam->overlay_fb->var.xres)
++              win->w.width = cam->overlay_fb->var.xres - win->w.left;
++      if (win->w.height + win->w.top > cam->overlay_fb->var.yres)
++              win->w.height = cam->overlay_fb->var.yres - win->w.top;
++
++      /*
++       * TODO: suppose 16bpp. Rounded down to a multiple of 2 pixels for
++       * width according to PrP limitations.
++       */
++      if ((cam->rotation == V4L2_MXC_ROTATE_90_RIGHT)
++          || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_VFLIP)
++          || (cam->rotation == V4L2_MXC_ROTATE_90_RIGHT_HFLIP)
++          || (cam->rotation == V4L2_MXC_ROTATE_90_LEFT))
++              win->w.height &= ~0x1;
++      else
++              win->w.width &= ~0x1;
++
++      return 0;
++}
++
++/*!
++ * start the viewfinder job
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static int start_preview(cam_data * cam)
++{
++      int err = 0;
++
++      err = prp_vf_select(cam);
++      if (err != 0)
++              return err;
++
++      cam->overlay_pid = current->pid;
++      err = cam->vf_start_sdc(cam);
++
++      return err;
++}
++
++/*!
++ * shut down the viewfinder job
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static int stop_preview(cam_data * cam)
++{
++      int err = 0;
++
++      err = prp_vf_deselect(cam);
++      return err;
++}
++
++/*!
++ * V4L2 - mxc_v4l2_g_fmt function
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param f           structure v4l2_format *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2_g_fmt(cam_data * cam, struct v4l2_format *f)
++{
++      int retval = 0;
++
++      switch (f->type) {
++      case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++              f->fmt.pix.width = cam->v2f.fmt.pix.width;
++              f->fmt.pix.height = cam->v2f.fmt.pix.height;
++              f->fmt.pix.sizeimage = cam->v2f.fmt.pix.sizeimage;
++              f->fmt.pix.pixelformat = cam->v2f.fmt.pix.pixelformat;
++              f->fmt.pix.bytesperline = cam->v2f.fmt.pix.bytesperline;
++              f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
++              retval = 0;
++              break;
++      case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++              f->fmt.win = cam->win;
++              break;
++      default:
++              retval = -EINVAL;
++      }
++      return retval;
++}
++
++/*!
++ * V4L2 - mxc_v4l2_s_fmt function
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param f           structure v4l2_format *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2_s_fmt(cam_data * cam, struct v4l2_format *f)
++{
++      int retval = 0;
++      int size = 0;
++      int bytesperline = 0;
++
++      switch (f->type) {
++      case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++              if (!valid_mode(f->fmt.pix.pixelformat)) {
++                      pr_debug("mxc_v4l2_s_fmt: format not supported\n");
++                      retval = -EINVAL;
++              }
++
++              if (cam->rotation != V4L2_MXC_ROTATE_NONE)
++                      pr_debug("mxc_v4l2_s_fmt: capture rotation ignored\n");
++
++              switch (f->fmt.pix.pixelformat) {
++              case V4L2_PIX_FMT_YUYV:
++                      f->fmt.pix.width &= ~0x1;       /* Multiple of 2 */
++                      size = f->fmt.pix.width * f->fmt.pix.height * 2;
++                      bytesperline = f->fmt.pix.width * 2;
++                      break;
++              case V4L2_PIX_FMT_YUV420:
++                      f->fmt.pix.width &= ~0x7;       /* Multiple of 8 */
++                      f->fmt.pix.height &= ~0x1;      /* Multiple of 2 */
++                      size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;
++                      bytesperline = f->fmt.pix.width * 3 / 2;
++                      break;
++              default:
++                      /* Suppose it's YUV444 or 32bpp */
++                      size = f->fmt.pix.width * f->fmt.pix.height * 4;
++                      bytesperline = f->fmt.pix.width * 4;
++                      pr_info("mxc_v4l2_s_fmt: default assume"
++                              " to be YUV444 interleaved.\n");
++                      break;
++              }
++
++              if (f->fmt.pix.bytesperline < bytesperline) {
++                      f->fmt.pix.bytesperline = bytesperline;
++              } else {
++                      bytesperline = f->fmt.pix.bytesperline;
++              }
++
++              if (f->fmt.pix.sizeimage > size) {
++                      pr_debug("mxc_v4l2_s_fmt: sizeimage bigger than"
++                               " needed.\n");
++                      size = f->fmt.pix.sizeimage;
++              }
++              f->fmt.pix.sizeimage = size;
++
++              cam->v2f.fmt.pix.sizeimage = size;
++              cam->v2f.fmt.pix.bytesperline = bytesperline;
++              cam->v2f.fmt.pix.width = f->fmt.pix.width;
++              cam->v2f.fmt.pix.height = f->fmt.pix.height;
++              cam->v2f.fmt.pix.pixelformat = f->fmt.pix.pixelformat;
++              retval = 0;
++              break;
++      case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++              retval = verify_preview(cam, &f->fmt.win);
++              cam->win = f->fmt.win;
++              break;
++      default:
++              retval = -EINVAL;
++      }
++      return retval;
++}
++
++/*!
++ * get control param
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param c           structure v4l2_control *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_get_v42l_control(cam_data * cam, struct v4l2_control *c)
++{
++      int status = 0;
++
++      switch (c->id) {
++      case V4L2_CID_HFLIP:
++              c->value = cam->rotation;
++              break;
++      case V4L2_CID_VFLIP:
++              c->value = cam->rotation;
++              break;
++      case V4L2_CID_MXC_ROT:
++              c->value = cam->rotation;
++              break;
++      case V4L2_CID_BRIGHTNESS:
++              c->value = cam->bright;
++              break;
++      case V4L2_CID_HUE:
++              c->value = cam->hue;
++              break;
++      case V4L2_CID_CONTRAST:
++              c->value = cam->contrast;
++              break;
++      case V4L2_CID_SATURATION:
++              c->value = cam->saturation;
++              break;
++      case V4L2_CID_RED_BALANCE:
++              c->value = cam->red;
++              break;
++      case V4L2_CID_BLUE_BALANCE:
++              c->value = cam->blue;
++              break;
++      case V4L2_CID_BLACK_LEVEL:
++              c->value = cam->ae_mode;
++              break;
++      case V4L2_CID_AUTO_WHITE_BALANCE:
++              c->value = cam->awb_enable;
++              break;
++      case V4L2_CID_AUTOGAIN:
++              c->value = cam->ae_enable;
++              break;
++      case V4L2_CID_MXC_FLICKER:
++              c->value = cam->flicker_ctrl;
++              break;
++      default:
++              status = -EINVAL;
++      }
++      return status;
++}
++
++/*!
++ * V4L2 - set_control function
++ * V4L2_CID_MXC_ROT is the extention for rotation/mirroring.
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param c           structure v4l2_control *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_set_v42l_control(cam_data * cam, struct v4l2_control *c)
++{
++      switch (c->id) {
++      case V4L2_CID_HFLIP:
++              if (c->value == 1) {
++                      if ((cam->rotation != V4L2_MXC_ROTATE_VERT_FLIP) &&
++                          (cam->rotation != V4L2_MXC_ROTATE_180))
++                              cam->rotation = V4L2_MXC_ROTATE_HORIZ_FLIP;
++                      else
++                              cam->rotation = V4L2_MXC_ROTATE_180;
++              } else {
++                      if (cam->rotation == V4L2_MXC_ROTATE_HORIZ_FLIP)
++                              cam->rotation = V4L2_MXC_ROTATE_NONE;
++                      else if (cam->rotation == V4L2_MXC_ROTATE_180)
++                              cam->rotation = V4L2_MXC_ROTATE_VERT_FLIP;
++              }
++              break;
++      case V4L2_CID_VFLIP:
++              if (c->value == 1) {
++                      if ((cam->rotation != V4L2_MXC_ROTATE_HORIZ_FLIP) &&
++                          (cam->rotation != V4L2_MXC_ROTATE_180))
++                              cam->rotation = V4L2_MXC_ROTATE_VERT_FLIP;
++                      else
++                              cam->rotation = V4L2_MXC_ROTATE_180;
++              } else {
++                      if (cam->rotation == V4L2_MXC_ROTATE_VERT_FLIP)
++                              cam->rotation = V4L2_MXC_ROTATE_NONE;
++                      if (cam->rotation == V4L2_MXC_ROTATE_180)
++                              cam->rotation = V4L2_MXC_ROTATE_HORIZ_FLIP;
++              }
++              break;
++      case V4L2_CID_MXC_ROT:
++              switch (c->value) {
++              case V4L2_MXC_ROTATE_NONE:
++              case V4L2_MXC_ROTATE_VERT_FLIP:
++              case V4L2_MXC_ROTATE_HORIZ_FLIP:
++              case V4L2_MXC_ROTATE_180:
++              case V4L2_MXC_ROTATE_90_RIGHT:
++              case V4L2_MXC_ROTATE_90_RIGHT_VFLIP:
++              case V4L2_MXC_ROTATE_90_RIGHT_HFLIP:
++              case V4L2_MXC_ROTATE_90_LEFT:
++                      cam->rotation = c->value;
++                      break;
++              default:
++                      return -EINVAL;
++              }
++              break;
++      case V4L2_CID_HUE:
++              cam->hue = c->value;
++              break;
++      case V4L2_CID_CONTRAST:
++              cam->contrast = c->value;
++              break;
++      case V4L2_CID_BRIGHTNESS:
++              cam->bright = c->value;
++      case V4L2_CID_SATURATION:
++              cam->saturation = c->value;
++      case V4L2_CID_RED_BALANCE:
++              cam->red = c->value;
++      case V4L2_CID_BLUE_BALANCE:
++              cam->blue = c->value;
++              csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              cam->cam_sensor->set_color(cam->bright, cam->saturation,
++                                         cam->red, cam->green, cam->blue);
++              csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              break;
++      case V4L2_CID_BLACK_LEVEL:
++              cam->ae_mode = c->value & 0x03;
++              csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              if (cam->cam_sensor->set_ae_mode)
++                      cam->cam_sensor->set_ae_mode(cam->ae_mode);
++              csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              break;
++      case V4L2_CID_MXC_FLASH:
++              break;
++      case V4L2_CID_AUTOGAIN:
++              cam->ae_enable = c->value;
++              csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              if (cam->cam_sensor->set_ae)
++                      cam->cam_sensor->set_ae(cam->ae_enable);
++              csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              break;
++      case V4L2_CID_MXC_GAIN_LIMIT:
++              cam->ae_limit = c->value;
++              csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              if (cam->cam_sensor->set_ae_limit)
++                     cam->cam_sensor->set_ae_limit(cam->ae_limit);
++              csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              break;
++      case V4L2_CID_AUTO_WHITE_BALANCE:
++              cam->awb_enable = c->value;
++              csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              if (cam->cam_sensor->set_awb)
++                      cam->cam_sensor->set_awb(cam->awb_enable);
++              csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              break;
++      case V4L2_CID_MXC_FLICKER:
++              cam->flicker_ctrl = c->value;
++              csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              if (cam->cam_sensor->flicker_control)
++                      cam->cam_sensor->flicker_control(cam->flicker_ctrl);
++              csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/*!
++ * V4L2 - mxc_v4l2_s_param function
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param parm        structure v4l2_streamparm *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2_s_param(cam_data * cam, struct v4l2_streamparm *parm)
++{
++      sensor_interface *param;
++      csi_signal_cfg_t csi_param;
++
++      if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++              pr_debug("mxc_v4l2_s_param invalid type\n");
++              return -EINVAL;
++      }
++
++      if (parm->parm.capture.timeperframe.denominator >
++          cam->standard.frameperiod.denominator) {
++              pr_debug("mxc_v4l2_s_param frame rate %d larger "
++                       "than standard supported %d\n",
++                       parm->parm.capture.timeperframe.denominator,
++                       cam->standard.frameperiod.denominator);
++              return -EINVAL;
++      }
++
++      cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
++
++      csi_enable_mclk(CSI_MCLK_I2C, true, true);
++      param = cam->cam_sensor->config
++          (&parm->parm.capture.timeperframe.denominator,
++           parm->parm.capture.capturemode);
++      csi_enable_mclk(CSI_MCLK_I2C, false, false);
++
++      cam->streamparm.parm.capture.timeperframe =
++          parm->parm.capture.timeperframe;
++
++      if ((parm->parm.capture.capturemode != 0) &&
++          (parm->parm.capture.capturemode != V4L2_MODE_HIGHQUALITY)) {
++              pr_debug("mxc_v4l2_s_param frame un-supported capture mode\n");
++              return -EINVAL;
++      }
++
++      if (parm->parm.capture.capturemode ==
++          cam->streamparm.parm.capture.capturemode) {
++              return 0;
++      }
++
++      /* resolution changed, so need to re-program the CSI */
++      csi_param.sens_clksrc = 0;
++      csi_param.clk_mode = param->clk_mode;
++      csi_param.pixclk_pol = param->pixclk_pol;
++      csi_param.data_width = param->data_width;
++      csi_param.data_pol = param->data_pol;
++      csi_param.ext_vsync = param->ext_vsync;
++      csi_param.Vsync_pol = param->Vsync_pol;
++      csi_param.Hsync_pol = param->Hsync_pol;
++      csi_init_interface(param->width, param->height, param->pixel_fmt,
++                         csi_param);
++
++      if (parm->parm.capture.capturemode != V4L2_MODE_HIGHQUALITY) {
++              cam->streamparm.parm.capture.capturemode = 0;
++      } else {
++              cam->streamparm.parm.capture.capturemode =
++                  V4L2_MODE_HIGHQUALITY;
++              cam->streamparm.parm.capture.extendedmode =
++                  parm->parm.capture.extendedmode;
++              cam->streamparm.parm.capture.readbuffers = 1;
++      }
++      return 0;
++}
++
++/*!
++ * Dequeue one V4L capture buffer
++ *
++ * @param cam         structure cam_data *
++ * @param buf         structure v4l2_buffer *
++ *
++ * @return  status    0 success, EINVAL invalid frame number,
++ *                    ETIME timeout, ERESTARTSYS interrupted by user
++ */
++static int mxc_v4l_dqueue(cam_data * cam, struct v4l2_buffer *buf)
++{
++      int retval = 0;
++      struct mxc_v4l_frame *frame;
++
++      if (!wait_event_interruptible_timeout(cam->enc_queue,
++                                            cam->enc_counter != 0, 10 * HZ)) {
++              if ((dq_timeout_cnt & 0x1f) == 0)
++                      printk(KERN_ERR
++                             "mxc_v4l_dqueue timeout enc_counter %x\n",
++                             cam->enc_counter);
++              dq_timeout_cnt++;
++              return -ETIME;
++      } else if (signal_pending(current)) {
++              if (dq_intr_cnt == 0)
++                      printk(KERN_ERR
++                             "mxc_v4l_dqueue() interrupt received %d\n",
++                             dq_intr_cnt);
++              dq_intr_cnt++;
++              return -ERESTARTSYS;
++      }
++
++      cam->enc_counter--;
++
++      frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue);
++      list_del(cam->done_q.next);
++      if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) {
++              frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE;
++      } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
++              printk(KERN_ERR "VIDIOC_DQBUF: Buffer not filled.\n");
++              frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
++              retval = -EINVAL;
++      } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) {
++              printk(KERN_ERR "VIDIOC_DQBUF: Buffer not queued.\n");
++              retval = -EINVAL;
++      }
++
++      buf->bytesused = cam->v2f.fmt.pix.sizeimage;
++      buf->index = frame->index;
++      buf->flags = frame->buffer.flags;
++      buf->m = cam->frame[frame->index].buffer.m;
++      return retval;
++}
++
++/*!
++ * Get the current attached camera device
++ *
++ * @param inode      struct i2c_client *
++ *
++ * @param int       int * p_input_index
++ *
++ * @return           0 success, ENODEV for invalid device instance,
++ *                   -1 for other errors.
++ */
++static int mxc_get_video_input(cam_data * cam)
++{
++      int retval = 0;
++      csi_enable_mclk(CSI_MCLK_I2C, true, true);
++      retval = cam->cam_sensor->get_status();
++      csi_enable_mclk(CSI_MCLK_I2C, false, false);
++      return retval;
++}
++
++/*!
++ * V4L interface - open function
++ *
++ * @param inode        structure inode *
++ * @param file         structure file *
++ *
++ * @return  status    0 success, ENODEV invalid device instance,
++ *                    ENODEV timeout, ERESTARTSYS interrupted by user
++ */
++static int mxc_v4l_open(struct inode *inode, struct file *file)
++{
++      sensor_interface *param;
++      csi_signal_cfg_t csi_param;
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++      int err = 0;
++
++      dq_intr_cnt = 0;
++      dq_timeout_cnt = 0;
++      empty_wq_cnt = 0;
++      if (!cam) {
++              pr_info("Internal error, cam_data not found!\n");
++              return -ENODEV;
++      }
++
++      err = mxc_get_video_input(cam);
++      if (0 != err)
++              return -ENODEV;
++
++      if (down_interruptible(&cam->busy_lock))
++              return -EINTR;
++
++      if (signal_pending(current))
++              goto oops;
++
++      if (cam->open_count++ == 0) {
++              wait_event_interruptible(cam->power_queue,
++                                       cam->low_power == false);
++
++              err = prp_enc_select(cam);
++
++              cam->enc_counter = 0;
++              cam->skip_frame = 0;
++              INIT_LIST_HEAD(&cam->ready_q);
++              INIT_LIST_HEAD(&cam->working_q);
++              INIT_LIST_HEAD(&cam->done_q);
++
++              csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              param = cam->cam_sensor->reset();
++              if (param == NULL) {
++                      cam->open_count--;
++                      csi_enable_mclk(CSI_MCLK_I2C, false, false);
++                      err = -ENODEV;
++                      goto oops;
++              }
++              csi_param.sens_clksrc = 0;
++              csi_param.clk_mode = param->clk_mode;
++              csi_param.pixclk_pol = param->pixclk_pol;
++              csi_param.data_width = param->data_width;
++              csi_param.data_pol = param->data_pol;
++              csi_param.ext_vsync = param->ext_vsync;
++              csi_param.Vsync_pol = param->Vsync_pol;
++              csi_param.Hsync_pol = param->Hsync_pol;
++              csi_init_interface(param->width, param->height,
++                                 param->pixel_fmt, csi_param);
++              cam->cam_sensor->get_color(&cam->bright, &cam->saturation,
++                                         &cam->red, &cam->green, &cam->blue);
++              if (cam->cam_sensor->get_ae_mode)
++                      cam->cam_sensor->get_ae_mode(&cam->ae_mode);
++              cam->cam_sensor->get_control_params(&cam->ae_enable,
++                                                  &cam->awb_enable,
++                                                  &cam->flicker_ctrl);
++              csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              prp_init(cam);
++
++      }
++
++      file->private_data = dev;
++      oops:
++      up(&cam->busy_lock);
++      return err;
++}
++
++/*!
++ * V4L interface - close function
++ *
++ * @param inode    struct inode *
++ * @param file     struct file *
++ *
++ * @return         0 success
++ */
++static int mxc_v4l_close(struct inode *inode, struct file *file)
++{
++      struct video_device *dev = video_devdata(file);
++      int err = 0;
++      cam_data *cam = dev->priv;
++
++      /* for the case somebody hit the ctrl C */
++      if (cam->overlay_pid == current->pid) {
++              err = stop_preview(cam);
++              cam->overlay_on = false;
++      }
++      if (cam->capture_pid == current->pid) {
++              err |= mxc_streamoff(cam);
++              cam->capture_on = false;
++              wake_up_interruptible(&cam->enc_queue);
++              wake_up_interruptible(&cam->overflow_queue);
++      }
++
++      if (--cam->open_count == 0) {
++              wait_event_interruptible(cam->power_queue,
++                                       cam->low_power == false);
++              pr_debug("mxc_v4l_close: release resource\n");
++
++              err |= prp_enc_deselect(cam);
++
++              mxc_free_frame_buf(cam);
++              file->private_data = NULL;
++
++              /* capture off */
++              wake_up_interruptible(&cam->enc_queue);
++              wake_up_interruptible(&cam->overflow_queue);
++              mxc_free_frames(cam);
++              cam->enc_counter++;
++              prp_exit(cam);
++      }
++
++      return err;
++}
++
++#ifdef CONFIG_VIDEO_MXC_CSI_DMA
++#include <asm/arch/dma.h>
++
++#define CSI_DMA_STATUS_IDLE   0       /* DMA is not started */
++#define CSI_DMA_STATUS_WORKING        1       /* DMA is transfering the data */
++#define CSI_DMA_STATUS_DONE   2       /* One frame completes successfully */
++#define CSI_DMA_STATUS_ERROR  3       /* Error occurs during the DMA */
++
++/*
++ * Sometimes the start of the DMA is not synchronized with the CSI
++ * SOF (Start of Frame) interrupt which will lead to incorrect
++ * captured image. In this case the driver will re-try capturing
++ * another frame. The following macro defines the maximum re-try
++ * times.
++ */
++#define CSI_DMA_RETRY         8
++
++/*
++ * Size of the physical contiguous memory area used to hold image data
++ * transfered by DMA. It can be less than the size of the image data.
++ */
++#define CSI_MEM_SIZE          (1024 * 600)
++
++/* Number of bytes for one DMA transfer */
++#define CSI_DMA_LENGTH                (1024 * 200)
++
++static int g_dma_channel = 0;
++static int g_dma_status = CSI_DMA_STATUS_DONE;
++static volatile int g_dma_completed;  /* number of completed DMA transfers */
++static volatile int g_dma_copied;     /* number of copied DMA transfers */
++static struct tasklet_struct g_dma_tasklet;
++static char *g_user_buf;      /* represents the buf passed by read() */
++static int g_user_count;      /* represents the count passed by read() */
++
++/*!
++ * @brief setup the DMA to transfer data
++ *      There may be more than one DMA to transfer the whole image. Those
++ *      DMAs work like chain. This function is used to setup the DMA in
++ *      case there is enough space to hold the data.
++ * @param     data    pointer to the cam structure
++ */
++static void mxc_csi_dma_chaining(void *data)
++{
++      cam_data *cam = (cam_data *) data;
++      int count, chained = 0;
++      int max_dma = CSI_MEM_SIZE / CSI_DMA_LENGTH;
++      mxc_dma_requestbuf_t dma_request;
++
++      while (chained * CSI_DMA_LENGTH < g_user_count) {
++              /*
++               * Calculate how many bytes the DMA should transfer. It may
++               * be less than CSI_DMA_LENGTH if the DMA is the last one.
++               */
++              if ((chained + 1) * CSI_DMA_LENGTH > g_user_count)
++                      count = g_user_count - chained * CSI_DMA_LENGTH;
++              else
++                      count = CSI_DMA_LENGTH;
++              pr_debug("%s() DMA chained count = %d\n", __FUNCTION__, count);
++
++              /* Config DMA */
++              memset(&dma_request, 0, sizeof(mxc_dma_requestbuf_t));
++              dma_request.dst_addr = cam->still_buf
++                  + (chained % max_dma) * CSI_DMA_LENGTH;
++              dma_request.src_addr = (dma_addr_t) CSI_CSIRXFIFO_PHYADDR;
++              dma_request.num_of_bytes = count;
++              mxc_dma_config(g_dma_channel, &dma_request, 1,
++                             MXC_DMA_MODE_READ);
++
++              chained++;
++      }
++}
++
++/*!
++ * @brief Copy image data from physical contiguous memory to user space buffer
++ *      Once the data are copied, there will be more spare space in the
++ *      physical contiguous memory to receive data from DMA.
++ * @param     data    pointer to the cam structure
++ */
++static void mxc_csi_dma_task(unsigned long data)
++{
++      cam_data *cam = (cam_data *) data;
++      int count;
++      int max_dma = CSI_MEM_SIZE / CSI_DMA_LENGTH;
++
++      while (g_dma_copied < g_dma_completed) {
++              /*
++               * Calculate how many bytes the DMA has transfered. It may
++               * be less than CSI_DMA_LENGTH if the DMA is the last one.
++               */
++              if ((g_dma_copied + 1) * CSI_DMA_LENGTH > g_user_count)
++                      count = g_user_count - g_dma_copied * CSI_DMA_LENGTH;
++              else
++                      count = CSI_DMA_LENGTH;
++              if (copy_to_user(g_user_buf + g_dma_copied * CSI_DMA_LENGTH,
++                               cam->still_buf_vaddr + (g_dma_copied % max_dma)
++                               * CSI_DMA_LENGTH, count))
++                      pr_debug("Warning: some bytes not copied\n");
++
++              g_dma_copied++;
++      }
++
++      /* If the whole image has been captured */
++      if (g_dma_copied * CSI_DMA_LENGTH >= g_user_count) {
++              cam->still_counter++;
++              wake_up_interruptible(&cam->still_queue);
++      }
++
++      pr_debug("%s() DMA completed = %d copied = %d\n",
++               __FUNCTION__, g_dma_completed, g_dma_copied);
++}
++
++/*!
++ * @brief DMA interrupt callback function
++ * @param     data    pointer to the cam structure
++ * @param     error   DMA error flag
++ * @param     count   number of bytes transfered by the DMA
++ */
++static void mxc_csi_dma_callback(void *data, int error, unsigned int count)
++{
++      cam_data *cam = (cam_data *) data;
++      int max_dma = CSI_MEM_SIZE / CSI_DMA_LENGTH;
++      unsigned long lock_flags;
++
++      spin_lock_irqsave(&cam->int_lock, lock_flags);
++
++      g_dma_completed++;
++
++      if (error != MXC_DMA_DONE) {
++              g_dma_status = CSI_DMA_STATUS_ERROR;
++              pr_debug("%s() DMA error\n", __FUNCTION__);
++      }
++
++      /* If the whole image has been captured */
++      if ((g_dma_status != CSI_DMA_STATUS_ERROR)
++          && (g_dma_completed * CSI_DMA_LENGTH >= g_user_count))
++              g_dma_status = CSI_DMA_STATUS_DONE;
++
++      if ((g_dma_status == CSI_DMA_STATUS_WORKING) &&
++          (g_dma_completed >= g_dma_copied + max_dma)) {
++              g_dma_status = CSI_DMA_STATUS_ERROR;
++              pr_debug("%s() Previous buffer over written\n", __FUNCTION__);
++      }
++
++      /* Schedule the tasklet */
++      tasklet_schedule(&g_dma_tasklet);
++
++      spin_unlock_irqrestore(&cam->int_lock, lock_flags);
++
++      pr_debug("%s() count = %d bytes\n", __FUNCTION__, count);
++}
++
++/*!
++ * @brief CSI interrupt callback function
++ * @param     data    pointer to the cam structure
++ * @param     status  CSI interrupt status
++ */
++static void mxc_csi_irq_callback(void *data, unsigned long status)
++{
++      cam_data *cam = (cam_data *) data;
++      unsigned long lock_flags;
++
++      spin_lock_irqsave(&cam->int_lock, lock_flags);
++
++      /* Wait for SOF (Start of Frame) interrupt to sync the image */
++      if (status & BIT_SOF_INT) {
++              if (g_dma_status == CSI_DMA_STATUS_IDLE) {
++                      /* Start DMA transfer to capture image */
++                      mxc_dma_enable(g_dma_channel);
++                      g_dma_status = CSI_DMA_STATUS_WORKING;
++                      pr_debug("%s() DMA started.\n", __FUNCTION__);
++              } else if (g_dma_status == CSI_DMA_STATUS_WORKING) {
++                      /*
++                       * Another SOF occurs during DMA transfer. In this
++                       * case the image is not synchronized so need to
++                       * report error and probably try again.
++                       */
++                      g_dma_status = CSI_DMA_STATUS_ERROR;
++                      pr_debug("%s() Image is not synchronized with DMA - "
++                               "SOF before DMA completes\n", __FUNCTION__);
++              }
++      }
++
++      spin_unlock_irqrestore(&cam->int_lock, lock_flags);
++
++      pr_debug("%s() g_dma_status = %d\n", __FUNCTION__, g_dma_status);
++}
++
++/*!
++ * V4L interface - read function
++ *
++ * @param file       struct file *
++ * @param read buf   char *
++ * @param count      size_t
++ * @param ppos       structure loff_t *
++ *
++ * @return           bytes read
++ */
++static ssize_t
++mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t * ppos)
++{
++      int err = 0;
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++      int retry = CSI_DMA_RETRY;
++
++      g_user_buf = buf;
++
++      if (down_interruptible(&cam->busy_lock))
++              return -EINTR;
++
++      /* Video capture and still image capture are exclusive */
++      if (cam->capture_on == true) {
++              err = -EBUSY;
++              goto exit0;
++      }
++
++      /* The CSI-DMA can not do CSC */
++      if (cam->v2f.fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV) {
++              pr_info("mxc_v4l_read support YUYV pixel format only\n");
++              err = -EINVAL;
++              goto exit0;
++      }
++
++      /* The CSI-DMA can not do resize or crop */
++      if ((cam->v2f.fmt.pix.width != cam->crop_bounds.width)
++          || (cam->v2f.fmt.pix.height != cam->crop_bounds.height)) {
++              pr_info("mxc_v4l_read resize is not supported\n");
++              pr_info("supported image size width = %d height = %d\n",
++                      cam->crop_bounds.width, cam->crop_bounds.height);
++              err = -EINVAL;
++              goto exit0;
++      }
++      if ((cam->crop_current.left != cam->crop_bounds.left)
++          || (cam->crop_current.width != cam->crop_bounds.width)
++          || (cam->crop_current.top != cam->crop_bounds.top)
++          || (cam->crop_current.height != cam->crop_bounds.height)) {
++              pr_info("mxc_v4l_read cropping is not supported\n");
++              err = -EINVAL;
++              goto exit0;
++      }
++
++      cam->still_buf_vaddr = dma_alloc_coherent(0,
++                                                PAGE_ALIGN(CSI_MEM_SIZE),
++                                                &cam->still_buf,
++                                                GFP_DMA | GFP_KERNEL);
++
++      if (!cam->still_buf_vaddr) {
++              pr_info("mxc_v4l_read failed at allocate still_buf\n");
++              err = -ENOBUFS;
++              goto exit0;
++      }
++
++      /* Initialize DMA */
++      g_dma_channel = mxc_dma_request(MXC_DMA_CSI_RX, "CSI RX DMA");
++      if (g_dma_channel < 0) {
++              pr_debug("mxc_v4l_read failed to request DMA channel\n");
++              err = -EIO;
++              goto exit1;
++      }
++
++      err = mxc_dma_callback_set(g_dma_channel,
++                                 mxc_csi_dma_callback,
++                                 cam);
++      if (err != 0) {
++              pr_debug("mxc_v4l_read failed to set DMA callback\n");
++              err = -EIO;
++              goto exit2;
++      }
++
++      g_user_buf = buf;
++      if (cam->v2f.fmt.pix.sizeimage < count)
++              g_user_count = cam->v2f.fmt.pix.sizeimage;
++      else
++              g_user_count = count & ~0x3;
++
++      tasklet_init(&g_dma_tasklet, mxc_csi_dma_task, (unsigned long)cam);
++      g_dma_status = CSI_DMA_STATUS_DONE;
++      csi_set_callback(mxc_csi_irq_callback, cam);
++      csi_enable_prpif(0);
++
++      /* clear current SOF first */
++      csi_clear_status(BIT_SOF_INT);
++      csi_enable_mclk(CSI_MCLK_RAW, true, true);
++
++      do {
++              g_dma_completed = g_dma_copied = 0;
++              mxc_csi_dma_chaining(cam);
++              cam->still_counter = 0;
++              g_dma_status = CSI_DMA_STATUS_IDLE;
++
++              if (!wait_event_interruptible_timeout(cam->still_queue,
++                                                    cam->still_counter != 0,
++                                                    10 * HZ)) {
++                      pr_info("mxc_v4l_read timeout counter %x\n",
++                              cam->still_counter);
++                      err = -ETIME;
++                      goto exit3;
++              }
++
++              if (g_dma_status == CSI_DMA_STATUS_DONE)
++                      break;
++
++              if (retry-- == 0)
++                      break;
++
++              pr_debug("Now retry image capture\n");
++      } while (1);
++
++      if (g_dma_status != CSI_DMA_STATUS_DONE)
++              err = -EIO;
++
++      exit3:
++      csi_enable_prpif(1);
++      g_dma_status = CSI_DMA_STATUS_DONE;
++      csi_set_callback(0, 0);
++      csi_enable_mclk(CSI_MCLK_RAW, false, false);
++      tasklet_kill(&g_dma_tasklet);
++
++      exit2:
++      mxc_dma_free(g_dma_channel);
++
++      exit1:
++      dma_free_coherent(0, PAGE_ALIGN(CSI_MEM_SIZE),
++                        cam->still_buf_vaddr, cam->still_buf);
++      cam->still_buf = 0;
++
++      exit0:
++      up(&cam->busy_lock);
++      if (err < 0)
++              return err;
++      else
++              return g_user_count;
++}
++#else
++/*!
++ * V4L interface - read function
++ *
++ * @param file       struct file *
++ * @param read buf   char *
++ * @param count      size_t
++ * @param ppos       structure loff_t *
++ *
++ * @return           bytes read
++ */
++static ssize_t
++mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t * ppos)
++{
++      int err = 0;
++      u8 *v_address;
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++
++      if (down_interruptible(&cam->busy_lock))
++              return -EINTR;
++
++      /* Video capture and still image capture are exclusive */
++      if (cam->capture_on == true) {
++              err = -EBUSY;
++              goto exit0;
++      }
++
++      v_address = dma_alloc_coherent(0,
++                                     PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
++                                     &cam->still_buf, GFP_DMA | GFP_KERNEL);
++
++      if (!v_address) {
++              pr_info("mxc_v4l_read failed at allocate still_buf\n");
++              err = -ENOBUFS;
++              goto exit0;
++      }
++
++      if (prp_still_select(cam)) {
++              err = -EIO;
++              goto exit1;
++      }
++
++      cam->still_counter = 0;
++      if (cam->csi_start(cam)) {
++              err = -EIO;
++              goto exit2;
++      }
++
++      if (!wait_event_interruptible_timeout(cam->still_queue,
++                                            cam->still_counter != 0,
++                                            10 * HZ)) {
++              pr_info("mxc_v4l_read timeout counter %x\n",
++                      cam->still_counter);
++              err = -ETIME;
++              goto exit2;
++      }
++      err = copy_to_user(buf, v_address, cam->v2f.fmt.pix.sizeimage);
++
++      exit2:
++      prp_still_deselect(cam);
++
++      exit1:
++      dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address,
++                        cam->still_buf);
++      cam->still_buf = 0;
++
++      exit0:
++      up(&cam->busy_lock);
++      if (err < 0)
++              return err;
++      else
++              return (cam->v2f.fmt.pix.sizeimage - err);
++}
++#endif                                /* CONFIG_VIDEO_MXC_CSI_DMA */
++
++/*!
++ * V4L interface - ioctl function
++ *
++ * @param inode      struct inode *
++ *
++ * @param file       struct file *
++ *
++ * @param ioctlnr    unsigned int
++ *
++ * @param arg        void *
++ *
++ * @return           0 success, ENODEV for invalid device instance,
++ *                   -1 for other errors.
++ */
++static int
++mxc_v4l_do_ioctl(struct inode *inode, struct file *file,
++               unsigned int ioctlnr, void *arg)
++{
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++      int retval = 0;
++      unsigned long lock_flags;
++
++      if (!cam)
++              return -EBADF;
++
++      wait_event_interruptible(cam->power_queue, cam->low_power == false);
++      /* make this _really_ smp-safe */
++      if (down_interruptible(&cam->busy_lock))
++              return -EBUSY;
++
++      switch (ioctlnr) {
++              /*!
++               * V4l2 VIDIOC_QUERYCAP ioctl
++               */
++      case VIDIOC_QUERYCAP:{
++                      struct v4l2_capability *cap = arg;
++                      strcpy(cap->driver, "mxc_v4l2");
++                      cap->version = KERNEL_VERSION(0, 1, 11);
++                      cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
++                          V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_STREAMING
++                          | V4L2_CAP_READWRITE;
++                      cap->card[0] = '\0';
++                      cap->bus_info[0] = '\0';
++                      retval = 0;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_G_FMT ioctl
++               */
++      case VIDIOC_G_FMT:{
++                      struct v4l2_format *gf = arg;
++                      retval = mxc_v4l2_g_fmt(cam, gf);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_S_FMT ioctl
++               */
++      case VIDIOC_S_FMT:{
++                      struct v4l2_format *sf = arg;
++                      retval = mxc_v4l2_s_fmt(cam, sf);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_REQBUFS ioctl
++               */
++      case VIDIOC_REQBUFS:{
++                      struct v4l2_requestbuffers *req = arg;
++                      int i;
++                      if (req->count > FRAME_NUM) {
++                              pr_info("VIDIOC_REQBUFS: not enough buffer\n");
++                              req->count = FRAME_NUM;
++                      }
++
++                      if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
++                          ((req->memory != V4L2_MEMORY_MMAP)
++                           && (req->memory != V4L2_MEMORY_USERPTR))) {
++                              pr_debug("VIDIOC_REQBUFS: wrong buffer type\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      mxc_streamoff(cam);
++                      mxc_free_frame_buf(cam);
++
++                      if (req->memory == V4L2_MEMORY_MMAP)
++                              retval =
++                                  mxc_allocate_frame_buf(cam, req->count);
++                      else if (req->memory == V4L2_MEMORY_USERPTR) {
++                              for (i = 0; i < req->count; i++) {
++                                      cam->frame[i].vaddress = 0;
++                                      cam->frame[i].buffer.index = i;
++                                      cam->frame[i].buffer.type =
++                                          V4L2_BUF_TYPE_VIDEO_CAPTURE;
++                                      cam->frame[i].buffer.flags = 0;
++                                      cam->frame[i].buffer.length = 0;
++                                      cam->frame[i].buffer.memory =
++                                          V4L2_MEMORY_USERPTR;
++                                      cam->frame[i].buffer.m.offset = 0;
++                                      cam->frame[i].index = i;
++                              }
++                      }
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_QUERYBUF ioctl
++               */
++      case VIDIOC_QUERYBUF:{
++                      struct v4l2_buffer *buf = arg;
++                      int index = buf->index;
++
++                      if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++                              pr_debug
++                                  ("VIDIOC_QUERYBUFS: wrong buffer type\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      memset(buf, 0, sizeof(buf));
++                      buf->index = index;
++
++                      down(&cam->param_lock);
++                      retval = mxc_v4l2_buffer_status(cam, buf);
++                      up(&cam->param_lock);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_QBUF ioctl
++               */
++      case VIDIOC_QBUF:{
++                      struct v4l2_buffer *buf = arg;
++                      int index = buf->index;
++
++                      pr_debug("VIDIOC_QBUF: %d\n", buf->index);
++                      wait_event_interruptible(cam->overflow_queue,
++                                               cam->overflow == 0);
++                      spin_lock_irqsave(&cam->int_lock, lock_flags);
++                      if (cam->frame[index].buffer.memory == V4L2_MEMORY_MMAP) {
++                              if ((cam->frame[index].buffer.flags & 0x7) ==
++                                  V4L2_BUF_FLAG_MAPPED) {
++                                      cam->frame[index].buffer.flags |=
++                                          V4L2_BUF_FLAG_QUEUED;
++                                      if (cam->skip_frame > 0) {
++                                              prphw_enable(PRP_CHANNEL_2);
++                                              list_add_tail(&cam->
++                                                            frame[index].
++                                                            queue,
++                                                            &cam->working_q);
++                                              retval =
++                                                  cam->enc_update_eba(cam->
++                                                                      frame
++                                                                      [index].
++                                                                      paddress,
++                                                                      &cam->
++                                                                      ping_pong_csi);
++                                              cam->skip_frame = 0;
++                                      } else {
++                                              list_add_tail(&cam->
++                                                            frame[index].
++                                                            queue,
++                                                            &cam->ready_q);
++                                      }
++                              } else if (cam->frame[index].buffer.flags &
++                                         V4L2_BUF_FLAG_QUEUED) {
++                                      pr_debug
++                                          ("VIDIOC_QBUF: buffer already queued\n");
++                              } else if (cam->frame[index].buffer.
++                                         flags & V4L2_BUF_FLAG_DONE) {
++                                      pr_debug
++                                          ("VIDIOC_QBUF: overwrite done buffer.\n");
++                                      cam->frame[index].buffer.flags &=
++                                          ~V4L2_BUF_FLAG_DONE;
++                                      cam->frame[index].buffer.flags |=
++                                          V4L2_BUF_FLAG_QUEUED;
++                              }
++                      } else {
++                              cam->frame[index].buffer.flags =
++                                  (V4L2_BUF_FLAG_MAPPED |
++                                   V4L2_BUF_FLAG_QUEUED);
++                              cam->frame[index].buffer.m.offset =
++                                  buf->m.offset;
++                              cam->frame[index].paddress = buf->m.offset;
++                              cam->frame[index].buffer.length = buf->length;
++                              if (cam->skip_frame > 0) {
++                                      prphw_enable(PRP_CHANNEL_2);
++                                      list_add_tail(&cam->frame[index].queue,
++                                                    &cam->working_q);
++                                      retval =
++                                          cam->enc_update_eba(cam->
++                                                              frame[index].
++                                                              paddress,
++                                                              &cam->
++                                                              ping_pong_csi);
++                                      cam->skip_frame = 0;
++                              } else {
++                                      list_add_tail(&cam->frame[index].queue,
++                                                    &cam->ready_q);
++                              }
++                      }
++                      buf->flags = cam->frame[index].buffer.flags;
++                      spin_unlock_irqrestore(&cam->int_lock, lock_flags);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_DQBUF ioctl
++               */
++      case VIDIOC_DQBUF:{
++                      struct v4l2_buffer *buf = arg;
++
++                      retval = mxc_v4l_dqueue(cam, buf);
++
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_STREAMON ioctl
++               */
++      case VIDIOC_STREAMON:{
++                      cam->capture_on = true;
++                      retval = mxc_streamon(cam);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_STREAMOFF ioctl
++               */
++      case VIDIOC_STREAMOFF:{
++                      retval = mxc_streamoff(cam);
++                      cam->capture_on = false;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_G_CTRL ioctl
++               */
++      case VIDIOC_G_CTRL:{
++                      retval = mxc_get_v42l_control(cam, arg);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_S_CTRL ioctl
++               */
++      case VIDIOC_S_CTRL:{
++                      retval = mxc_set_v42l_control(cam, arg);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_CROPCAP ioctl
++               */
++      case VIDIOC_CROPCAP:{
++                      struct v4l2_cropcap *cap = arg;
++
++                      if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++                          cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      cap->bounds = cam->crop_bounds;
++                      cap->defrect = cam->crop_defrect;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_G_CROP ioctl
++               */
++      case VIDIOC_G_CROP:{
++                      struct v4l2_crop *crop = arg;
++
++                      if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++                          crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      crop->c = cam->crop_current;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_S_CROP ioctl
++               */
++      case VIDIOC_S_CROP:{
++                      struct v4l2_crop *crop = arg;
++                      struct v4l2_rect *b = &cam->crop_bounds;
++                      int i;
++
++                      if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++                          crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      crop->c.top = (crop->c.top < b->top) ? b->top
++                          : crop->c.top;
++                      if (crop->c.top > b->top + b->height)
++                              crop->c.top = b->top + b->height - 1;
++                      if (crop->c.height > b->top + b->height - crop->c.top)
++                              crop->c.height =
++                                  b->top + b->height - crop->c.top;
++
++                      crop->c.left = (crop->c.left < b->left) ? b->left
++                          : crop->c.left;
++                      if (crop->c.left > b->left + b->width)
++                              crop->c.left = b->left + b->width - 1;
++                      if (crop->c.width > b->left - crop->c.left + b->width)
++                              crop->c.width =
++                                  b->left - crop->c.left + b->width;
++
++                      crop->c.width &= ~0x1;
++
++                      /*
++                       * MX27 PrP limitation:
++                       * The right spare space (CSI_FRAME_X_SIZE
++                       *  - SOURCE_LINE_STRIDE - PICTURE_X_SIZE)) must be
++                       * multiple of 32.
++                       * So we tune the crop->c.left value to the closest
++                       * desired cropping value and meet the PrP requirement.
++                       */
++                      i = ((b->left + b->width)
++                           - (crop->c.left + crop->c.width)) % 32;
++                      if (i <= 16) {
++                              if (crop->c.left + crop->c.width + i
++                                  <= b->left + b->width)
++                                      crop->c.left += i;
++                              else if (crop->c.left - (32 - i) >= b->left)
++                                      crop->c.left -= 32 - i;
++                              else {
++                                      retval = -EINVAL;
++                                      break;
++                              }
++                      } else {
++                              if (crop->c.left - (32 - i) >= b->left)
++                                      crop->c.left -= 32 - i;
++                              else if (crop->c.left + crop->c.width + i
++                                       <= b->left + b->width)
++                                      crop->c.left += i;
++                              else {
++                                      retval = -EINVAL;
++                                      break;
++                              }
++                      }
++
++                      cam->crop_current = crop->c;
++
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_OVERLAY ioctl
++               */
++      case VIDIOC_OVERLAY:{
++                      int *on = arg;
++                      if (*on) {
++                              cam->overlay_on = true;
++                              retval = start_preview(cam);
++                      }
++                      if (!*on) {
++                              retval = stop_preview(cam);
++                              cam->overlay_on = false;
++                      }
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_G_FBUF ioctl
++               */
++      case VIDIOC_G_FBUF:{
++                      struct v4l2_framebuffer *fb = arg;
++                      struct fb_var_screeninfo *var;
++
++                      if (cam->output >= num_registered_fb) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      var = &registered_fb[cam->output]->var;
++                      cam->v4l2_fb.fmt.width = var->xres;
++                      cam->v4l2_fb.fmt.height = var->yres;
++                      cam->v4l2_fb.fmt.bytesperline =
++                          var->xres_virtual * var->bits_per_pixel;
++                      cam->v4l2_fb.fmt.colorspace = V4L2_COLORSPACE_SRGB;
++                      *fb = cam->v4l2_fb;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_S_FBUF ioctl
++               */
++      case VIDIOC_S_FBUF:{
++                      struct v4l2_framebuffer *fb = arg;
++                      cam->v4l2_fb.flags = fb->flags;
++                      cam->v4l2_fb.fmt.pixelformat = fb->fmt.pixelformat;
++                      break;
++              }
++
++      case VIDIOC_G_PARM:{
++                      struct v4l2_streamparm *parm = arg;
++                      if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++                              pr_debug("VIDIOC_G_PARM invalid type\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++                      parm->parm.capture = cam->streamparm.parm.capture;
++                      break;
++              }
++      case VIDIOC_S_PARM:{
++                      struct v4l2_streamparm *parm = arg;
++                      retval = mxc_v4l2_s_param(cam, parm);
++                      break;
++              }
++
++              /* linux v4l2 bug, kernel c0485619 user c0405619 */
++      case VIDIOC_ENUMSTD:{
++                      struct v4l2_standard *e = arg;
++                      *e = cam->standard;
++                      pr_debug("VIDIOC_ENUMSTD call\n");
++                      retval = 0;
++                      break;
++              }
++
++      case VIDIOC_G_STD:{
++                      v4l2_std_id *e = arg;
++                      *e = cam->standard.id;
++                      break;
++              }
++
++      case VIDIOC_S_STD:{
++                      break;
++              }
++
++      case VIDIOC_ENUMOUTPUT:
++              {
++                      struct v4l2_output *output = arg;
++
++                      if (output->index >= num_registered_fb) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      strncpy(output->name,
++                              registered_fb[output->index]->fix.id, 31);
++                      output->type = V4L2_OUTPUT_TYPE_ANALOG;
++                      output->audioset = 0;
++                      output->modulator = 0;
++                      output->std = V4L2_STD_UNKNOWN;
++
++                      break;
++              }
++      case VIDIOC_G_OUTPUT:
++              {
++                      int *p_output_num = arg;
++
++                      *p_output_num = cam->output;
++                      break;
++              }
++      case VIDIOC_S_OUTPUT:
++              {
++                      int *p_output_num = arg;
++
++                      if (*p_output_num >= num_registered_fb) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      cam->output = *p_output_num;
++                      break;
++              }
++
++      case VIDIOC_G_INPUT:
++              {
++                      int *p_input_index = arg;
++
++                      retval = mxc_get_video_input(cam);
++                      if (0 == retval)
++                              *p_input_index = 1;
++                      else
++                              *p_input_index = -ENODEV;
++
++                      break;
++              }
++
++      case VIDIOC_ENUM_FMT:
++      case VIDIOC_TRY_FMT:
++      case VIDIOC_QUERYCTRL:
++      case VIDIOC_ENUMINPUT:
++      case VIDIOC_S_INPUT:
++      case VIDIOC_G_TUNER:
++      case VIDIOC_S_TUNER:
++      case VIDIOC_G_FREQUENCY:
++      case VIDIOC_S_FREQUENCY:
++      default:
++              retval = -EINVAL;
++              break;
++      }
++
++      up(&cam->busy_lock);
++      return retval;
++}
++
++/*
++ * V4L interface - ioctl function
++ *
++ * @return  None
++ */
++static int
++mxc_v4l_ioctl(struct inode *inode, struct file *file,
++            unsigned int cmd, unsigned long arg)
++{
++      return video_usercopy(inode, file, cmd, arg, mxc_v4l_do_ioctl);
++}
++
++/*!
++ * V4L interface - mmap function
++ *
++ * @param file        structure file *
++ *
++ * @param vma         structure vm_area_struct *
++ *
++ * @return status     0 Success, EINTR busy lock error, ENOBUFS remap_page error
++ */
++static int mxc_mmap(struct file *file, struct vm_area_struct *vma)
++{
++      struct video_device *dev = video_devdata(file);
++      unsigned long size;
++      int res = 0;
++      cam_data *cam = dev->priv;
++
++      pr_debug("pgoff=0x%lx, start=0x%lx, end=0x%lx\n",
++               vma->vm_pgoff, vma->vm_start, vma->vm_end);
++
++      /* make this _really_ smp-safe */
++      if (down_interruptible(&cam->busy_lock))
++              return -EINTR;
++
++      size = vma->vm_end - vma->vm_start;
++      vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++      if (remap_pfn_range(vma, vma->vm_start,
++                          vma->vm_pgoff, size, vma->vm_page_prot)) {
++              pr_debug("mxc_mmap: remap_pfn_range failed\n");
++              res = -ENOBUFS;
++              goto mxc_mmap_exit;
++      }
++
++      vma->vm_flags &= ~VM_IO;        /* using shared anonymous pages */
++
++      mxc_mmap_exit:
++      up(&cam->busy_lock);
++      return res;
++}
++
++/*!
++ * V4L interface - poll function
++ *
++ * @param file       structure file *
++ *
++ * @param wait       structure poll_table *
++ *
++ * @return  status   POLLIN | POLLRDNORM
++ */
++static unsigned int mxc_poll(struct file *file, poll_table * wait)
++{
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++      wait_queue_head_t *queue = NULL;
++      int res = POLLIN | POLLRDNORM;
++
++      if (down_interruptible(&cam->busy_lock))
++              return -EINTR;
++
++      queue = &cam->enc_queue;
++      poll_wait(file, queue, wait);
++
++      up(&cam->busy_lock);
++      return res;
++}
++
++static struct
++file_operations mxc_v4l_fops = {
++      .owner = THIS_MODULE,
++      .open = mxc_v4l_open,
++      .release = mxc_v4l_close,
++      .read = mxc_v4l_read,
++      .ioctl = mxc_v4l_ioctl,
++      .mmap = mxc_mmap,
++      .poll = mxc_poll,
++};
++
++static struct video_device mxc_v4l_template = {
++      .owner = THIS_MODULE,
++      .name = "Mxc Camera",
++      .type = 0,
++      .type2 = VID_TYPE_CAPTURE,
++      .hardware = 0,
++      .fops = &mxc_v4l_fops,
++      .release = video_device_release,
++};
++
++static void camera_platform_release(struct device *device)
++{
++}
++
++/*! Device Definition for Mt9v111 devices */
++static struct platform_device mxc_v4l2_devices = {
++      .name = "mxc_v4l2",
++      .dev = {
++              .release = camera_platform_release,
++              },
++      .id = 0,
++};
++
++extern struct camera_sensor camera_sensor_if;
++
++/*!
++* Camera V4l2 callback function.
++*
++* @return status
++*/
++static void camera_callback(u32 mask, void *dev)
++{
++      struct mxc_v4l_frame *done_frame;
++      struct mxc_v4l_frame *ready_frame;
++
++      cam_data *cam = (cam_data *) dev;
++      if (cam == NULL)
++              return;
++
++      if (mask == 1) {
++              if (cam->overflow == 0) {
++                      cam->overflow = 1;
++                      queue_work(v4l2_work, &prp_reset_work);
++              }
++              return;
++      }
++
++      if (list_empty(&cam->working_q)) {
++              if (empty_wq_cnt == 0) {
++                      printk(KERN_ERR
++                             "camera_callback: working queue empty %d\n",
++                             empty_wq_cnt);
++              }
++              empty_wq_cnt++;
++              if (list_empty(&cam->ready_q)) {
++                      prphw_disable(PRP_CHANNEL_2);
++                      cam->skip_frame++;
++              } else {
++                      ready_frame =
++                          list_entry(cam->ready_q.next, struct mxc_v4l_frame,
++                                     queue);
++                      list_del(cam->ready_q.next);
++                      list_add_tail(&ready_frame->queue, &cam->working_q);
++                      cam->enc_update_eba(ready_frame->paddress,
++                                          &cam->ping_pong_csi);
++              }
++              return;
++      }
++
++      done_frame =
++          list_entry(cam->working_q.next, struct mxc_v4l_frame, queue);
++      if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
++              done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE;
++              done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
++
++              list_del(cam->working_q.next);
++              if (list_empty(&cam->ready_q)) {
++                      if (list_empty(&cam->working_q))
++                              prphw_disable(PRP_CHANNEL_2);
++                      cam->skip_frame++;
++              } else {
++                      ready_frame =
++                          list_entry(cam->ready_q.next, struct mxc_v4l_frame,
++                                     queue);
++                      list_del(cam->ready_q.next);
++                      list_add_tail(&ready_frame->queue, &cam->working_q);
++                      cam->enc_update_eba(ready_frame->paddress,
++                                          &cam->ping_pong_csi);
++              }
++
++              /* Added to the done queue */
++              list_add_tail(&done_frame->queue, &cam->done_q);
++
++              /* Wake up the queue */
++              cam->enc_counter++;
++              wake_up_interruptible(&cam->enc_queue);
++      } else {
++              printk(KERN_ERR "camera_callback :buffer not queued\n");
++      }
++}
++
++/*!
++ * initialize cam_data structure
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static void init_camera_struct(cam_data * cam)
++{
++      int i;
++
++      /* Default everything to 0 */
++      memset(cam, 0, sizeof(cam_data));
++
++      init_MUTEX(&cam->param_lock);
++      init_MUTEX(&cam->busy_lock);
++
++      cam->video_dev = video_device_alloc();
++      if (cam->video_dev == NULL)
++              return;
++
++      *(cam->video_dev) = mxc_v4l_template;
++
++      video_set_drvdata(cam->video_dev, cam);
++      dev_set_drvdata(&mxc_v4l2_devices.dev, cam);
++      cam->video_dev->minor = -1;
++
++      for (i = 0; i < FRAME_NUM; i++) {
++              cam->frame[i].width = 0;
++              cam->frame[i].height = 0;
++              cam->frame[i].paddress = 0;
++      }
++
++      init_waitqueue_head(&cam->enc_queue);
++      init_waitqueue_head(&cam->still_queue);
++      init_waitqueue_head(&cam->overflow_queue);
++      cam->overflow = 0;
++
++      /* setup cropping */
++      cam->crop_bounds.left = 0;
++      cam->crop_bounds.width = 640;
++      cam->crop_bounds.top = 0;
++      cam->crop_bounds.height = 480;
++      cam->crop_current = cam->crop_defrect = cam->crop_bounds;
++      cam->streamparm.parm.capture.capturemode = 0;
++
++      cam->standard.index = 0;
++      cam->standard.id = V4L2_STD_UNKNOWN;
++      cam->standard.frameperiod.denominator = 30;
++      cam->standard.frameperiod.numerator = 1;
++      cam->standard.framelines = 480;
++      cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++      cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod;
++      cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
++      cam->overlay_on = false;
++      cam->capture_on = false;
++      cam->skip_frame = 0;
++      cam->v4l2_fb.capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
++      cam->v4l2_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
++
++      cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2;
++      cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2;
++      cam->v2f.fmt.pix.width = 288;
++      cam->v2f.fmt.pix.height = 352;
++      cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
++      cam->win.w.width = 160;
++      cam->win.w.height = 160;
++      cam->win.w.left = 0;
++      cam->win.w.top = 0;
++
++      cam->cam_sensor = &camera_sensor_if;
++      cam->enc_callback = camera_callback;
++
++      init_waitqueue_head(&cam->power_queue);
++      cam->int_lock = SPIN_LOCK_UNLOCKED;
++      spin_lock_init(&cam->int_lock);
++}
++
++extern void gpio_sensor_active(void);
++extern void gpio_sensor_inactive(void);
++
++/*!
++ * camera_power function
++ *    Turn Sensor power On/Off
++ *
++ * @param       cameraOn      true to turn camera on, otherwise shut down
++ *
++ * @return status
++ */
++static u8 camera_power(bool cameraOn)
++{
++      if (cameraOn == true) {
++              gpio_sensor_active();
++              csi_enable_mclk(csi_mclk_flag_backup, true, true);
++      } else {
++              csi_mclk_flag_backup = csi_read_mclk_flag();
++              csi_enable_mclk(csi_mclk_flag_backup, false, false);
++              gpio_sensor_inactive();
++      }
++      return 0;
++}
++
++/*!
++ * This function is called to put the sensor in a low power state. Refer to the
++ * document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ *
++ * @param   pdev  the device structure used to give information on which I2C
++ *                to suspend
++ * @param   state the power state the device is entering
++ *
++ * @return  The function returns 0 on success and -1 on failure.
++ */
++static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      cam_data *cam = platform_get_drvdata(pdev);
++
++      cam->low_power = true;
++
++      if (cam->overlay_on == true)
++              stop_preview(cam);
++      if ((cam->capture_on == true) && cam->enc_disable) {
++              cam->enc_disable(cam);
++      }
++      camera_power(false);
++
++      return 0;
++}
++
++/*!
++ * This function is called to bring the sensor back from a low power state.Refer
++ * to the document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ *
++ * @param   pdev  the device structure
++ *
++ * @return  The function returns 0 on success and -1 on failure
++ */
++static int mxc_v4l2_resume(struct platform_device *pdev)
++{
++      cam_data *cam = platform_get_drvdata(pdev);
++
++      cam->low_power = false;
++      wake_up_interruptible(&cam->power_queue);
++
++      if (cam->overlay_on == true)
++              start_preview(cam);
++      if (cam->capture_on == true)
++              mxc_streamon(cam);
++      camera_power(true);
++
++      return 0;
++}
++
++/*!
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct platform_driver mxc_v4l2_driver = {
++      .driver = {
++                 .name = "mxc_v4l2",
++                 .owner = THIS_MODULE,
++                 .bus = &platform_bus_type,
++                 },
++      .probe = NULL,
++      .remove = NULL,
++      .suspend = mxc_v4l2_suspend,
++      .resume = mxc_v4l2_resume,
++      .shutdown = NULL,
++};
++
++/*!
++ * Entry point for the V4L2
++ *
++ * @return  Error code indicating success or failure
++ */
++static __init int camera_init(void)
++{
++      u8 err = 0;
++      cam_data *cam;
++
++      if ((g_cam = cam = kzalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) {
++              pr_debug("failed to mxc_v4l_register_camera\n");
++              return -ENOMEM;
++      }
++
++      init_camera_struct(cam);
++
++      v4l2_work = create_singlethread_workqueue("v4l2_emma");
++
++      /* Register the I2C device */
++      err = platform_device_register(&mxc_v4l2_devices);
++      if (err != 0) {
++              pr_debug("camera_init: platform_device_register failed.\n");
++              video_device_release(cam->video_dev);
++              kfree(cam);
++              g_cam = NULL;
++      }
++
++      /* Register the device driver structure. */
++      err = platform_driver_register(&mxc_v4l2_driver);
++      if (err != 0) {
++              platform_device_unregister(&mxc_v4l2_devices);
++              pr_debug("camera_init: driver_register failed.\n");
++              video_device_release(cam->video_dev);
++              kfree(cam);
++              g_cam = NULL;
++              return err;
++      }
++
++      /* register v4l device */
++      err = video_register_device(cam->video_dev, VFL_TYPE_GRABBER, video_nr);
++      if (err != 0) {
++              platform_driver_unregister(&mxc_v4l2_driver);
++              platform_device_unregister(&mxc_v4l2_devices);
++              video_device_release(cam->video_dev);
++              kfree(cam);
++              g_cam = NULL;
++              pr_debug("video_register_device failed\n");
++              return err;
++      }
++
++      return err;
++}
++
++/*!
++ * Exit and cleanup for the V4L2
++ *
++ */
++static void __exit camera_exit(void)
++{
++      pr_debug("unregistering video\n");
++
++      flush_workqueue(v4l2_work);
++      destroy_workqueue(v4l2_work);
++
++      video_unregister_device(g_cam->video_dev);
++
++      platform_driver_unregister(&mxc_v4l2_driver);
++      platform_device_unregister(&mxc_v4l2_devices);
++
++      if (g_cam->open_count) {
++              pr_debug("camera open -- setting ops to NULL\n");
++      } else {
++              pr_debug("freeing camera\n");
++              mxc_free_frame_buf(g_cam);
++              kfree(g_cam);
++              g_cam = NULL;
++      }
++}
++
++module_init(camera_init);
++module_exit(camera_exit);
++
++module_param(video_nr, int, 0444);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("V4L2 capture driver for Mxc based cameras");
++MODULE_LICENSE("GPL");
++MODULE_SUPPORTED_DEVICE("video");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mxc_v4l2_capture.c linux-2.6.28-karo/drivers/media/video/mxc/capture/mxc_v4l2_capture.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/mxc_v4l2_capture.c    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mxc_v4l2_capture.c       2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,1867 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file drivers/media/video/mxc/capture/mxc_v4l2_capture.c
++ *
++ * @brief Mxc Video For Linux 2 driver
++ *
++ * @ingroup MXC_V4L2_CAPTURE
++ */
++
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/fs.h>
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include <asm/io.h>
++#include <asm/semaphore.h>
++#include <linux/pagemap.h>
++#include <linux/vmalloc.h>
++#include <linux/types.h>
++#include <linux/fb.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/arch/mxcfb.h>
++#include "mxc_v4l2_capture.h"
++#include "ipu_prp_sw.h"
++
++static int csi_mclk_flag_backup;
++static int video_nr = -1;
++cam_data *g_cam;
++EXPORT_SYMBOL(g_cam);
++
++#define MXC_V4L2_CAPTURE_NUM_OUTPUTS        2
++static struct v4l2_output mxc_capture_outputs[MXC_V4L2_CAPTURE_NUM_OUTPUTS] = {
++      {
++       .index = 0,
++       .name = "DISP3",
++       .type = V4L2_OUTPUT_TYPE_ANALOG,
++       .audioset = 0,
++       .modulator = 0,
++       .std = V4L2_STD_UNKNOWN,
++       },
++      {
++       .index = 1,
++       .name = "DISP0",
++       .type = V4L2_OUTPUT_TYPE_ANALOG,
++       .audioset = 0,
++       .modulator = 0,
++       .std = V4L2_STD_UNKNOWN,
++       }
++};
++
++/*!
++ * Free frame buffers
++ *
++ * @param cam      Structure cam_data *
++ *
++ * @return status  0 success.
++ */
++static int mxc_free_frame_buf(cam_data * cam)
++{
++      int i;
++
++      for (i = 0; i < FRAME_NUM; i++) {
++              if (cam->frame[i].vaddress != 0) {
++                      dma_free_coherent(0, cam->frame[i].buffer.length,
++                                        cam->frame[i].vaddress,
++                                        cam->frame[i].paddress);
++                      cam->frame[i].vaddress = 0;
++              }
++      }
++
++      return 0;
++}
++
++/*!
++ * Allocate frame buffers
++ *
++ * @param cam      Structure cam_data *
++ *
++ * @param count    int number of buffer need to allocated
++ *
++ * @return status  -0 Successfully allocated a buffer, -ENOBUFS       failed.
++ */
++static int mxc_allocate_frame_buf(cam_data * cam, int count)
++{
++      int i;
++
++      for (i = 0; i < count; i++) {
++              cam->frame[i].vaddress =
++                  dma_alloc_coherent(0,
++                                     PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
++                                     &cam->frame[i].paddress,
++                                     GFP_DMA | GFP_KERNEL);
++              if (cam->frame[i].vaddress == 0) {
++                      printk(KERN_ERR "mxc_allocate_frame_buf failed.\n");
++                      mxc_free_frame_buf(cam);
++                      return -ENOBUFS;
++              }
++              cam->frame[i].buffer.index = i;
++              cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
++              cam->frame[i].buffer.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++              cam->frame[i].buffer.length =
++                  PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage);
++              cam->frame[i].buffer.memory = V4L2_MEMORY_MMAP;
++              cam->frame[i].buffer.m.offset = cam->frame[i].paddress;
++              cam->frame[i].index = i;
++      }
++
++      return 0;
++}
++
++/*!
++ * Free frame buffers status
++ *
++ * @param cam    Structure cam_data *
++ *
++ * @return none
++ */
++static void mxc_free_frames(cam_data * cam)
++{
++      int i;
++
++      for (i = 0; i < FRAME_NUM; i++) {
++              cam->frame[i].buffer.flags = V4L2_BUF_FLAG_MAPPED;
++      }
++
++      cam->enc_counter = 0;
++      cam->skip_frame = 0;
++      INIT_LIST_HEAD(&cam->ready_q);
++      INIT_LIST_HEAD(&cam->working_q);
++      INIT_LIST_HEAD(&cam->done_q);
++}
++
++/*!
++ * Return the buffer status
++ *
++ * @param cam            Structure cam_data *
++ * @param buf      Structure v4l2_buffer *
++ *
++ * @return status  0 success, EINVAL failed.
++ */
++static int mxc_v4l2_buffer_status(cam_data * cam, struct v4l2_buffer *buf)
++{
++      if (buf->index < 0 || buf->index >= FRAME_NUM) {
++              printk(KERN_ERR
++                     "mxc_v4l2_buffer_status buffers not allocated\n");
++              return -EINVAL;
++      }
++
++      memcpy(buf, &(cam->frame[buf->index].buffer), sizeof(*buf));
++      return 0;
++}
++
++/*!
++ * start the encoder job
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static int mxc_streamon(cam_data * cam)
++{
++      struct mxc_v4l_frame *frame;
++      int err = 0;
++
++      if (list_empty(&cam->ready_q)) {
++              printk(KERN_ERR "mxc_streamon buffer not been queued yet\n");
++              return -EINVAL;
++      }
++
++      cam->capture_pid = current->pid;
++
++      if (cam->enc_enable) {
++              err = cam->enc_enable(cam);
++              if (err != 0) {
++                      return err;
++              }
++      }
++
++      cam->ping_pong_csi = 0;
++      if (cam->enc_update_eba) {
++              frame =
++                  list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
++              list_del(cam->ready_q.next);
++              list_add_tail(&frame->queue, &cam->working_q);
++              err =
++                  cam->enc_update_eba(frame->buffer.m.offset,
++                                      &cam->ping_pong_csi);
++
++              frame =
++                  list_entry(cam->ready_q.next, struct mxc_v4l_frame, queue);
++              list_del(cam->ready_q.next);
++              list_add_tail(&frame->queue, &cam->working_q);
++              err |=
++                  cam->enc_update_eba(frame->buffer.m.offset,
++                                      &cam->ping_pong_csi);
++      } else {
++              return -EINVAL;
++      }
++
++      cam->capture_on = true;
++      return err;
++}
++
++/*!
++ * Shut down the encoder job
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static int mxc_streamoff(cam_data * cam)
++{
++      int err = 0;
++
++      if (cam->capture_on == false)
++              return 0;
++
++      if (cam->enc_disable) {
++              err = cam->enc_disable(cam);
++      }
++      mxc_free_frames(cam);
++      cam->capture_on = false;
++      return err;
++}
++
++/*!
++ * Valid whether the palette is supported
++ *
++ * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32
++ *
++ * @return 0 if failed
++ */
++static inline int valid_mode(u32 palette)
++{
++      return ((palette == V4L2_PIX_FMT_RGB565) ||
++              (palette == V4L2_PIX_FMT_BGR24) ||
++              (palette == V4L2_PIX_FMT_RGB24) ||
++              (palette == V4L2_PIX_FMT_BGR32) ||
++              (palette == V4L2_PIX_FMT_RGB32) ||
++              (palette == V4L2_PIX_FMT_YUV422P) ||
++              (palette == V4L2_PIX_FMT_UYVY) ||
++              (palette == V4L2_PIX_FMT_YUV420));
++}
++
++/*!
++ * Valid and adjust the overlay window size, position
++ *
++ * @param cam      structure cam_data *
++ * @param win      struct v4l2_window  *
++ *
++ * @return 0
++ */
++static int verify_preview(cam_data * cam, struct v4l2_window *win)
++{
++      int i = 0;
++      int *width, *height;
++
++      do {
++              cam->overlay_fb = (struct fb_info *)registered_fb[i];
++              if (cam->overlay_fb == NULL) {
++                      printk(KERN_ERR "verify_preview No matched.\n");
++                      return -1;
++              }
++              if (strncmp(cam->overlay_fb->fix.id,
++                          mxc_capture_outputs[cam->output].name, 5) == 0) {
++                      break;
++              }
++      } while (++i < FB_MAX);
++
++      /* 4 bytes alignment for both FG and BG */
++      if (cam->overlay_fb->var.bits_per_pixel == 24) {
++              win->w.left -= win->w.left % 4;
++      } else if (cam->overlay_fb->var.bits_per_pixel == 16) {
++              win->w.left -= win->w.left % 2;
++      }
++
++      if (win->w.width + win->w.left > cam->overlay_fb->var.xres)
++              win->w.width = cam->overlay_fb->var.xres - win->w.left;
++      if (win->w.height + win->w.top > cam->overlay_fb->var.yres)
++              win->w.height = cam->overlay_fb->var.yres - win->w.top;
++
++      /* stride line limitation */
++      win->w.height -= win->w.height % 8;
++      win->w.width -= win->w.width % 8;
++
++      if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
++              height = &win->w.width;
++              width = &win->w.height;
++      } else {
++              width = &win->w.width;
++              height = &win->w.height;
++      }
++
++      if ((cam->crop_bounds.width / *width > 8) ||
++          ((cam->crop_bounds.width / *width == 8) &&
++           (cam->crop_bounds.width % *width))) {
++              *width = cam->crop_bounds.width / 8;
++              if (*width % 8)
++                      *width += 8 - *width % 8;
++              if (*width + win->w.left > cam->overlay_fb->var.xres) {
++                      printk(KERN_ERR "width exceed resize limit.\n");
++                      return -1;
++              }
++              printk(KERN_ERR "width exceed limit resize to %d.\n", *width);
++      }
++
++      if ((cam->crop_bounds.height / *height > 8) ||
++          ((cam->crop_bounds.height / *height == 8) &&
++           (cam->crop_bounds.height % *height))) {
++              *height = cam->crop_bounds.height / 8;
++              if (*height % 8)
++                      *height += 8 - *height % 8;
++              if (*height + win->w.top > cam->overlay_fb->var.yres) {
++                      printk(KERN_ERR "height exceed resize limit.\n");
++                      return -1;
++              }
++              printk(KERN_ERR "height exceed limit resize to %d.\n", *height);
++      }
++
++      return 0;
++}
++
++/*!
++ * start the viewfinder job
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static int start_preview(cam_data * cam)
++{
++      int err = 0;
++#if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE)
++      if (cam->output == 0) {
++              if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)
++                      err = prp_vf_sdc_select(cam);
++              else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)
++                      err = prp_vf_sdc_select_bg(cam);
++              if (err != 0)
++                      return err;
++
++              err = cam->vf_start_sdc(cam);
++      }
++#endif
++
++#if defined(CONFIG_MXC_IPU_PRP_VF_ADC) || defined(CONFIG_MXC_IPU_PRP_VF_ADC_MODULE)
++      if (cam->output == 1) {
++              err = prp_vf_adc_select(cam);
++              if (err != 0)
++                      return err;
++
++              err = cam->vf_start_adc(cam);
++      }
++#endif
++
++      return err;
++}
++
++/*!
++ * shut down the viewfinder job
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static int stop_preview(cam_data * cam)
++{
++      int err = 0;
++
++#if defined(CONFIG_MXC_IPU_PRP_VF_ADC) || defined(CONFIG_MXC_IPU_PRP_VF_ADC_MODULE)
++      if (cam->output == 1) {
++              err = prp_vf_adc_deselect(cam);
++      }
++#endif
++
++#if defined(CONFIG_MXC_IPU_PRP_VF_SDC) || defined(CONFIG_MXC_IPU_PRP_VF_SDC_MODULE)
++      if (cam->output == 0) {
++              if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY)
++                      err = prp_vf_sdc_deselect(cam);
++              else if (cam->v4l2_fb.flags == V4L2_FBUF_FLAG_PRIMARY)
++                      err = prp_vf_sdc_deselect_bg(cam);
++      }
++#endif
++
++      return err;
++}
++
++/*!
++ * V4L2 - mxc_v4l2_g_fmt function
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param f           structure v4l2_format *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2_g_fmt(cam_data * cam, struct v4l2_format *f)
++{
++      int retval = 0;
++
++      switch (f->type) {
++      case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++              f->fmt.pix = cam->v2f.fmt.pix;
++              retval = 0;
++              break;
++      case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++              f->fmt.win = cam->win;
++              break;
++      default:
++              retval = -EINVAL;
++      }
++      return retval;
++}
++
++/*!
++ * V4L2 - mxc_v4l2_s_fmt function
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param f           structure v4l2_format *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2_s_fmt(cam_data * cam, struct v4l2_format *f)
++{
++      int retval = 0;
++      int size = 0;
++      int bytesperline = 0;
++      int *width, *height;
++
++      switch (f->type) {
++      case V4L2_BUF_TYPE_VIDEO_CAPTURE:
++              if (!valid_mode(f->fmt.pix.pixelformat)) {
++                      printk(KERN_ERR
++                             "mxc_v4l2_s_fmt: format not supported\n");
++                      return -EINVAL;
++              }
++
++              if (cam->rotation >= IPU_ROTATE_90_RIGHT) {
++                      height = &f->fmt.pix.width;
++                      width = &f->fmt.pix.height;
++              } else {
++                      width = &f->fmt.pix.width;
++                      height = &f->fmt.pix.height;
++              }
++
++              /* stride line limitation */
++              *width -= *width % 8;
++              *height -= *height % 8;
++
++              if ((cam->crop_bounds.width / *width > 8) ||
++                  ((cam->crop_bounds.width / *width == 8) &&
++                   (cam->crop_bounds.width % *width))) {
++                      *width = cam->crop_bounds.width / 8;
++                      if (*width % 8)
++                              *width += 8 - *width % 8;
++                      printk(KERN_ERR "width exceed limit resize to %d.\n",
++                             *width);
++              }
++
++              if ((cam->crop_bounds.height / *height > 8) ||
++                  ((cam->crop_bounds.height / *height == 8) &&
++                   (cam->crop_bounds.height % *height))) {
++                      *height = cam->crop_bounds.height / 8;
++                      if (*height % 8)
++                              *height += 8 - *height % 8;
++                      printk(KERN_ERR "height exceed limit resize to %d.\n",
++                             *height);
++              }
++
++              switch (f->fmt.pix.pixelformat) {
++              case V4L2_PIX_FMT_RGB565:
++                      size = f->fmt.pix.width * f->fmt.pix.height * 2;
++                      bytesperline = f->fmt.pix.width * 2;
++                      break;
++              case V4L2_PIX_FMT_BGR24:
++                      size = f->fmt.pix.width * f->fmt.pix.height * 3;
++                      bytesperline = f->fmt.pix.width * 3;
++                      break;
++              case V4L2_PIX_FMT_RGB24:
++                      size = f->fmt.pix.width * f->fmt.pix.height * 3;
++                      bytesperline = f->fmt.pix.width * 3;
++                      break;
++              case V4L2_PIX_FMT_BGR32:
++                      size = f->fmt.pix.width * f->fmt.pix.height * 4;
++                      bytesperline = f->fmt.pix.width * 4;
++                      break;
++              case V4L2_PIX_FMT_RGB32:
++                      size = f->fmt.pix.width * f->fmt.pix.height * 4;
++                      bytesperline = f->fmt.pix.width * 4;
++                      break;
++              case V4L2_PIX_FMT_YUV422P:
++                      size = f->fmt.pix.width * f->fmt.pix.height * 2;
++                      bytesperline = f->fmt.pix.width;
++                      break;
++              case V4L2_PIX_FMT_UYVY:
++                      size = f->fmt.pix.width * f->fmt.pix.height * 2;
++                      bytesperline = f->fmt.pix.width * 2;
++                      break;
++              case V4L2_PIX_FMT_YUV420:
++                      size = f->fmt.pix.width * f->fmt.pix.height * 3 / 2;
++                      bytesperline = f->fmt.pix.width;
++                      break;
++              default:
++                      break;
++              }
++
++              if (f->fmt.pix.bytesperline < bytesperline) {
++                      f->fmt.pix.bytesperline = bytesperline;
++              } else {
++                      bytesperline = f->fmt.pix.bytesperline;
++              }
++
++              if (f->fmt.pix.sizeimage < size) {
++                      f->fmt.pix.sizeimage = size;
++              } else {
++                      size = f->fmt.pix.sizeimage;
++              }
++
++              cam->v2f.fmt.pix = f->fmt.pix;
++
++              if (cam->v2f.fmt.pix.priv != 0) {
++                      if (copy_from_user(&cam->offset,
++                                         (void *)cam->v2f.fmt.pix.priv,
++                                         sizeof(cam->offset))) {
++                              retval = -EFAULT;
++                              break;
++                      }
++              }
++              retval = 0;
++              break;
++      case V4L2_BUF_TYPE_VIDEO_OVERLAY:
++              retval = verify_preview(cam, &f->fmt.win);
++              cam->win = f->fmt.win;
++              break;
++      default:
++              retval = -EINVAL;
++      }
++      return retval;
++}
++
++/*!
++ * get control param
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param c           structure v4l2_control *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_get_v42l_control(cam_data * cam, struct v4l2_control *c)
++{
++      int status = 0;
++
++      switch (c->id) {
++      case V4L2_CID_HFLIP:
++              if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)
++                      c->value = 1;
++              break;
++      case V4L2_CID_VFLIP:
++              if (cam->rotation == IPU_ROTATE_VERT_FLIP)
++                      c->value = 1;
++              break;
++      case V4L2_CID_MXC_ROT:
++              c->value = cam->rotation;
++              break;
++      case V4L2_CID_BRIGHTNESS:
++              c->value = cam->bright;
++              break;
++      case V4L2_CID_HUE:
++              c->value = cam->hue;
++              break;
++      case V4L2_CID_CONTRAST:
++              c->value = cam->contrast;
++              break;
++      case V4L2_CID_SATURATION:
++              c->value = cam->saturation;
++              break;
++      case V4L2_CID_RED_BALANCE:
++              c->value = cam->red;
++              break;
++      case V4L2_CID_BLUE_BALANCE:
++              c->value = cam->blue;
++              break;
++      case V4L2_CID_BLACK_LEVEL:
++              c->value = cam->ae_mode;
++              break;
++      default:
++              status = -EINVAL;
++      }
++      return status;
++}
++
++/*!
++ * V4L2 - set_control function
++ *          V4L2_CID_PRIVATE_BASE is the extention for IPU preprocessing.
++ *          0 for normal operation
++ *          1 for vertical flip
++ *          2 for horizontal flip
++ *          3 for horizontal and vertical flip
++ *          4 for 90 degree rotation
++ * @param cam         structure cam_data *
++ *
++ * @param c           structure v4l2_control *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_set_v42l_control(cam_data * cam, struct v4l2_control *c)
++{
++      switch (c->id) {
++      case V4L2_CID_HFLIP:
++              if (c->value == 1) {
++                      if ((cam->rotation != IPU_ROTATE_VERT_FLIP) &&
++                          (cam->rotation != IPU_ROTATE_180))
++                              cam->rotation = IPU_ROTATE_HORIZ_FLIP;
++                      else
++                              cam->rotation = IPU_ROTATE_180;
++              } else {
++                      if (cam->rotation == IPU_ROTATE_HORIZ_FLIP)
++                              cam->rotation = IPU_ROTATE_NONE;
++                      if (cam->rotation == IPU_ROTATE_180)
++                              cam->rotation = IPU_ROTATE_VERT_FLIP;
++              }
++              break;
++      case V4L2_CID_VFLIP:
++              if (c->value == 1) {
++                      if ((cam->rotation != IPU_ROTATE_HORIZ_FLIP) &&
++                          (cam->rotation != IPU_ROTATE_180))
++                              cam->rotation = IPU_ROTATE_VERT_FLIP;
++                      else
++                              cam->rotation = IPU_ROTATE_180;
++              } else {
++                      if (cam->rotation == IPU_ROTATE_VERT_FLIP)
++                              cam->rotation = IPU_ROTATE_NONE;
++                      if (cam->rotation == IPU_ROTATE_180)
++                              cam->rotation = IPU_ROTATE_HORIZ_FLIP;
++              }
++              break;
++      case V4L2_CID_MXC_ROT:
++              switch (c->value) {
++              case V4L2_MXC_ROTATE_NONE:
++                      cam->rotation = IPU_ROTATE_NONE;
++                      break;
++              case V4L2_MXC_ROTATE_VERT_FLIP:
++                      cam->rotation = IPU_ROTATE_VERT_FLIP;
++                      break;
++              case V4L2_MXC_ROTATE_HORIZ_FLIP:
++                      cam->rotation = IPU_ROTATE_HORIZ_FLIP;
++                      break;
++              case V4L2_MXC_ROTATE_180:
++                      cam->rotation = IPU_ROTATE_180;
++                      break;
++              case V4L2_MXC_ROTATE_90_RIGHT:
++                      cam->rotation = IPU_ROTATE_90_RIGHT;
++                      break;
++              case V4L2_MXC_ROTATE_90_RIGHT_VFLIP:
++                      cam->rotation = IPU_ROTATE_90_RIGHT_VFLIP;
++                      break;
++              case V4L2_MXC_ROTATE_90_RIGHT_HFLIP:
++                      cam->rotation = IPU_ROTATE_90_RIGHT_HFLIP;
++                      break;
++              case V4L2_MXC_ROTATE_90_LEFT:
++                      cam->rotation = IPU_ROTATE_90_LEFT;
++                      break;
++              default:
++                      return -EINVAL;
++              }
++              break;
++      case V4L2_CID_HUE:
++              cam->hue = c->value;
++              break;
++      case V4L2_CID_CONTRAST:
++              cam->contrast = c->value;
++              break;
++      case V4L2_CID_BRIGHTNESS:
++              cam->bright = c->value;
++      case V4L2_CID_SATURATION:
++              cam->saturation = c->value;
++      case V4L2_CID_RED_BALANCE:
++              cam->red = c->value;
++      case V4L2_CID_BLUE_BALANCE:
++              cam->blue = c->value;
++              ipu_csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              cam->cam_sensor->set_color(cam->bright, cam->saturation,
++                                         cam->red, cam->green, cam->blue);
++              ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              break;
++      case V4L2_CID_BLACK_LEVEL:
++              cam->ae_mode = c->value & 0x03;
++              ipu_csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              if (cam->cam_sensor->set_ae_mode)
++                      cam->cam_sensor->set_ae_mode(cam->ae_mode);
++              ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false);
++              break;
++      case V4L2_CID_MXC_FLASH:
++              ipu_csi_flash_strobe(true);
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/*!
++ * V4L2 - mxc_v4l2_s_param function
++ *
++ * @param cam         structure cam_data *
++ *
++ * @param parm        structure v4l2_streamparm *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2_s_param(cam_data * cam, struct v4l2_streamparm *parm)
++{
++      sensor_interface *param;
++      ipu_csi_signal_cfg_t csi_param;
++      int err = 0;
++
++      if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++              printk(KERN_ERR "mxc_v4l2_s_param invalid type\n");
++              return -EINVAL;
++      }
++
++      if (parm->parm.capture.timeperframe.denominator >
++          cam->standard.frameperiod.denominator) {
++              printk(KERN_ERR "mxc_v4l2_s_param frame rate %d larger "
++                     "than standard supported %d\n",
++                     parm->parm.capture.timeperframe.denominator,
++                     cam->standard.frameperiod.denominator);
++              return -EINVAL;
++      }
++
++      /* Stop the viewfinder */
++      if (cam->overlay_on == true) {
++              stop_preview(cam);
++      }
++
++      cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
++
++      ipu_csi_enable_mclk(CSI_MCLK_I2C, true, true);
++      param = cam->cam_sensor->config
++          (&parm->parm.capture.timeperframe.denominator,
++           parm->parm.capture.capturemode);
++      ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false);
++      cam->streamparm.parm.capture.timeperframe =
++          parm->parm.capture.timeperframe;
++
++      if ((parm->parm.capture.capturemode != 0) &&
++          (parm->parm.capture.capturemode != V4L2_MODE_HIGHQUALITY)) {
++              printk(KERN_ERR
++                     "mxc_v4l2_s_param frame un-supported capture mode\n");
++              err = -EINVAL;
++              goto exit;
++      }
++
++      if (parm->parm.capture.capturemode ==
++          cam->streamparm.parm.capture.capturemode) {
++              goto exit;
++      }
++
++      /* resolution changed, so need to re-program the CSI */
++      csi_param.sens_clksrc = 0;
++      csi_param.clk_mode = param->clk_mode;
++      csi_param.pixclk_pol = param->pixclk_pol;
++      csi_param.data_width = param->data_width;
++      csi_param.data_pol = param->data_pol;
++      csi_param.ext_vsync = param->ext_vsync;
++      csi_param.Vsync_pol = param->Vsync_pol;
++      csi_param.Hsync_pol = param->Hsync_pol;
++      ipu_csi_init_interface(param->width, param->height,
++                             param->pixel_fmt, csi_param);
++      ipu_csi_set_window_size(param->width + 1, param->height + 1);
++
++      if (parm->parm.capture.capturemode != V4L2_MODE_HIGHQUALITY) {
++              cam->streamparm.parm.capture.capturemode = 0;
++      } else {
++              cam->streamparm.parm.capture.capturemode =
++                  V4L2_MODE_HIGHQUALITY;
++              cam->streamparm.parm.capture.extendedmode =
++                  parm->parm.capture.extendedmode;
++              cam->streamparm.parm.capture.readbuffers = 1;
++      }
++
++      exit:
++      if (cam->overlay_on == true) {
++              start_preview(cam);
++      }
++
++      return err;
++}
++
++/*!
++ * Dequeue one V4L capture buffer
++ *
++ * @param cam         structure cam_data *
++ * @param buf         structure v4l2_buffer *
++ *
++ * @return  status    0 success, EINVAL invalid frame number,
++ *                    ETIME timeout, ERESTARTSYS interrupted by user
++ */
++static int mxc_v4l_dqueue(cam_data * cam, struct v4l2_buffer *buf)
++{
++      int retval = 0;
++      struct mxc_v4l_frame *frame;
++
++      if (!wait_event_interruptible_timeout(cam->enc_queue,
++                                            cam->enc_counter != 0, 10 * HZ)) {
++              printk(KERN_ERR "mxc_v4l_dqueue timeout enc_counter %x\n",
++                     cam->enc_counter);
++              return -ETIME;
++      } else if (signal_pending(current)) {
++              printk(KERN_ERR "mxc_v4l_dqueue() interrupt received\n");
++              mxc_free_frames(cam);
++              return -ERESTARTSYS;
++      }
++
++      cam->enc_counter--;
++
++      frame = list_entry(cam->done_q.next, struct mxc_v4l_frame, queue);
++      list_del(cam->done_q.next);
++      if (frame->buffer.flags & V4L2_BUF_FLAG_DONE) {
++              frame->buffer.flags &= ~V4L2_BUF_FLAG_DONE;
++      } else if (frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
++              printk(KERN_ERR "VIDIOC_DQBUF: Buffer not filled.\n");
++              frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
++              retval = -EINVAL;
++      } else if ((frame->buffer.flags & 0x7) == V4L2_BUF_FLAG_MAPPED) {
++              printk(KERN_ERR "VIDIOC_DQBUF: Buffer not queued.\n");
++              retval = -EINVAL;
++      }
++
++      buf->bytesused = cam->v2f.fmt.pix.sizeimage;
++      buf->index = frame->index;
++      buf->flags = frame->buffer.flags;
++      buf->m = cam->frame[frame->index].buffer.m;
++
++      return retval;
++}
++
++/*!
++ * V4L interface - open function
++ *
++ * @param inode        structure inode *
++ * @param file         structure file *
++ *
++ * @return  status    0 success, ENODEV invalid device instance,
++ *                    ENODEV timeout, ERESTARTSYS interrupted by user
++ */
++static int mxc_v4l_open(struct inode *inode, struct file *file)
++{
++      sensor_interface *param;
++      ipu_csi_signal_cfg_t csi_param;
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++      int err = 0;
++
++      if (!cam) {
++              printk(KERN_ERR "Internal error, cam_data not found!\n");
++              return -EBADF;
++      }
++
++      down(&cam->busy_lock);
++
++      err = 0;
++      if (signal_pending(current))
++              goto oops;
++
++      if (cam->open_count++ == 0) {
++              wait_event_interruptible(cam->power_queue,
++                                       cam->low_power == false);
++
++#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
++              err = prp_enc_select(cam);
++#endif
++
++              cam->enc_counter = 0;
++              cam->skip_frame = 0;
++              INIT_LIST_HEAD(&cam->ready_q);
++              INIT_LIST_HEAD(&cam->working_q);
++              INIT_LIST_HEAD(&cam->done_q);
++
++              ipu_csi_enable_mclk(CSI_MCLK_I2C, true, true);
++              param = cam->cam_sensor->reset();
++              if (param == NULL) {
++                      cam->open_count--;
++                      ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false);
++                      err = -ENODEV;
++                      goto oops;
++              }
++
++              csi_param.sens_clksrc = 0;
++              csi_param.clk_mode = param->clk_mode;
++              csi_param.pixclk_pol = param->pixclk_pol;
++              csi_param.data_width = param->data_width;
++              csi_param.data_pol = param->data_pol;
++              csi_param.ext_vsync = param->ext_vsync;
++              csi_param.Vsync_pol = param->Vsync_pol;
++              csi_param.Hsync_pol = param->Hsync_pol;
++              ipu_csi_init_interface(param->width, param->height,
++                                     param->pixel_fmt, csi_param);
++
++              cam->cam_sensor->get_color(&cam->bright, &cam->saturation,
++                                         &cam->red, &cam->green, &cam->blue);
++              if (cam->cam_sensor->get_ae_mode)
++                      cam->cam_sensor->get_ae_mode(&cam->ae_mode);
++
++              /* pr_info("mxc_v4l_open saturation %x ae_mode %x\n",
++                 cam->saturation, cam->ae_mode); */
++
++              ipu_csi_enable_mclk(CSI_MCLK_I2C, false, false);
++      }
++
++      file->private_data = dev;
++      oops:
++      up(&cam->busy_lock);
++      return err;
++}
++
++/*!
++ * V4L interface - close function
++ *
++ * @param inode    struct inode *
++ * @param file     struct file *
++ *
++ * @return         0 success
++ */
++static int mxc_v4l_close(struct inode *inode, struct file *file)
++{
++      struct video_device *dev = video_devdata(file);
++      int err = 0;
++      cam_data *cam = dev->priv;
++
++      if (!cam) {
++              printk(KERN_ERR "Internal error, cam_data not found!\n");
++              return -EBADF;
++      }
++
++      /* for the case somebody hit the ctrl C */
++      if (cam->overlay_pid == current->pid) {
++              err = stop_preview(cam);
++              cam->overlay_on = false;
++      }
++      if (cam->capture_pid == current->pid) {
++              err |= mxc_streamoff(cam);
++              wake_up_interruptible(&cam->enc_queue);
++      }
++
++      if (--cam->open_count == 0) {
++              wait_event_interruptible(cam->power_queue,
++                                       cam->low_power == false);
++              pr_info("mxc_v4l_close: release resource\n");
++
++#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
++              err |= prp_enc_deselect(cam);
++#endif
++              mxc_free_frame_buf(cam);
++              file->private_data = NULL;
++
++              /* capture off */
++              wake_up_interruptible(&cam->enc_queue);
++              mxc_free_frames(cam);
++              cam->enc_counter++;
++      }
++      return err;
++}
++
++#if defined(CONFIG_MXC_IPU_PRP_ENC) || defined(CONFIG_MXC_IPU_PRP_ENC_MODULE)
++/*
++ * V4L interface - read function
++ *
++ * @param file       struct file *
++ * @param read buf   char *
++ * @param count      size_t
++ * @param ppos       structure loff_t *
++ *
++ * @return           bytes read
++ */
++static ssize_t
++mxc_v4l_read(struct file *file, char *buf, size_t count, loff_t * ppos)
++{
++      int err = 0;
++      u8 *v_address;
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++
++      if (down_interruptible(&cam->busy_lock))
++              return -EINTR;
++
++      /* Stop the viewfinder */
++      if (cam->overlay_on == true)
++              stop_preview(cam);
++
++      v_address = dma_alloc_coherent(0,
++                                     PAGE_ALIGN(cam->v2f.fmt.pix.sizeimage),
++                                     &cam->still_buf, GFP_DMA | GFP_KERNEL);
++
++      if (!v_address) {
++              err = -ENOBUFS;
++              goto exit0;
++      }
++
++      err = prp_still_select(cam);
++      if (err != 0) {
++              err = -EIO;
++              goto exit1;
++      }
++
++      cam->still_counter = 0;
++      err = cam->csi_start(cam);
++      if (err != 0) {
++              err = -EIO;
++              goto exit2;
++      }
++
++      if (!wait_event_interruptible_timeout(cam->still_queue,
++                                            cam->still_counter != 0,
++                                            10 * HZ)) {
++              printk(KERN_ERR "mxc_v4l_read timeout counter %x\n",
++                     cam->still_counter);
++              err = -ETIME;
++              goto exit2;
++      }
++      err = copy_to_user(buf, v_address, cam->v2f.fmt.pix.sizeimage);
++
++      exit2:
++      prp_still_deselect(cam);
++
++      exit1:
++      dma_free_coherent(0, cam->v2f.fmt.pix.sizeimage, v_address,
++                        cam->still_buf);
++      cam->still_buf = 0;
++
++      exit0:
++      if (cam->overlay_on == true) {
++              start_preview(cam);
++      }
++
++      up(&cam->busy_lock);
++      if (err < 0)
++              return err;
++
++      return (cam->v2f.fmt.pix.sizeimage - err);
++}
++#endif
++
++/*!
++ * V4L interface - ioctl function
++ *
++ * @param inode      struct inode *
++ *
++ * @param file       struct file *
++ *
++ * @param ioctlnr    unsigned int
++ *
++ * @param arg        void *
++ *
++ * @return           0 success, ENODEV for invalid device instance,
++ *                   -1 for other errors.
++ */
++static int
++mxc_v4l_do_ioctl(struct inode *inode, struct file *file,
++               unsigned int ioctlnr, void *arg)
++{
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++      int retval = 0;
++      unsigned long lock_flags;
++
++      wait_event_interruptible(cam->power_queue, cam->low_power == false);
++      /* make this _really_ smp-safe */
++      if (down_interruptible(&cam->busy_lock))
++              return -EBUSY;
++
++      switch (ioctlnr) {
++              /*!
++               * V4l2 VIDIOC_QUERYCAP ioctl
++               */
++      case VIDIOC_QUERYCAP:{
++                      struct v4l2_capability *cap = arg;
++                      strcpy(cap->driver, "mxc_v4l2");
++                      cap->version = KERNEL_VERSION(0, 1, 11);
++                      cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
++                          V4L2_CAP_VIDEO_OVERLAY | V4L2_CAP_STREAMING
++                          | V4L2_CAP_READWRITE;
++                      cap->card[0] = '\0';
++                      cap->bus_info[0] = '\0';
++                      retval = 0;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_G_FMT ioctl
++               */
++      case VIDIOC_G_FMT:{
++                      struct v4l2_format *gf = arg;
++                      retval = mxc_v4l2_g_fmt(cam, gf);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_S_FMT ioctl
++               */
++      case VIDIOC_S_FMT:{
++                      struct v4l2_format *sf = arg;
++                      retval = mxc_v4l2_s_fmt(cam, sf);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_REQBUFS ioctl
++               */
++      case VIDIOC_REQBUFS:{
++                      struct v4l2_requestbuffers *req = arg;
++                      if (req->count > FRAME_NUM) {
++                              printk(KERN_ERR
++                                     "VIDIOC_REQBUFS: not enough buffer\n");
++                              req->count = FRAME_NUM;
++                      }
++
++                      if ((req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
++                          (req->memory != V4L2_MEMORY_MMAP)) {
++                              printk(KERN_ERR
++                                     "VIDIOC_REQBUFS: wrong buffer type\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      mxc_streamoff(cam);
++                      mxc_free_frame_buf(cam);
++
++                      retval = mxc_allocate_frame_buf(cam, req->count);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_QUERYBUF ioctl
++               */
++      case VIDIOC_QUERYBUF:{
++                      struct v4l2_buffer *buf = arg;
++                      int index = buf->index;
++
++                      if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++                              printk(KERN_ERR
++                                     "VIDIOC_QUERYBUFS: wrong buffer type\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      memset(buf, 0, sizeof(buf));
++                      buf->index = index;
++
++                      down(&cam->param_lock);
++                      retval = mxc_v4l2_buffer_status(cam, buf);
++                      up(&cam->param_lock);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_QBUF ioctl
++               */
++      case VIDIOC_QBUF:{
++                      struct v4l2_buffer *buf = arg;
++                      int index = buf->index;
++
++                      spin_lock_irqsave(&cam->int_lock, lock_flags);
++                      cam->frame[index].buffer.m.offset = buf->m.offset;
++                      if ((cam->frame[index].buffer.flags & 0x7) ==
++                          V4L2_BUF_FLAG_MAPPED) {
++                              cam->frame[index].buffer.flags |=
++                                  V4L2_BUF_FLAG_QUEUED;
++                              if (cam->skip_frame > 0) {
++                                      list_add_tail(&cam->frame[index].queue,
++                                                    &cam->working_q);
++                                      retval =
++                                          cam->enc_update_eba(cam->
++                                                              frame[index].
++                                                              buffer.m.offset,
++                                                              &cam->
++                                                              ping_pong_csi);
++                                      cam->skip_frame = 0;
++                              } else {
++                                      list_add_tail(&cam->frame[index].queue,
++                                                    &cam->ready_q);
++                              }
++                      } else if (cam->frame[index].buffer.
++                                 flags & V4L2_BUF_FLAG_QUEUED) {
++                              printk(KERN_ERR
++                                     "VIDIOC_QBUF: buffer already queued\n");
++                      } else if (cam->frame[index].buffer.
++                                 flags & V4L2_BUF_FLAG_DONE) {
++                              printk(KERN_ERR
++                                     "VIDIOC_QBUF: overwrite done buffer.\n");
++                              cam->frame[index].buffer.flags &=
++                                  ~V4L2_BUF_FLAG_DONE;
++                              cam->frame[index].buffer.flags |=
++                                  V4L2_BUF_FLAG_QUEUED;
++                      }
++
++                      buf->flags = cam->frame[index].buffer.flags;
++                      spin_unlock_irqrestore(&cam->int_lock, lock_flags);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_DQBUF ioctl
++               */
++      case VIDIOC_DQBUF:{
++                      struct v4l2_buffer *buf = arg;
++
++                      retval = mxc_v4l_dqueue(cam, buf);
++
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_STREAMON ioctl
++               */
++      case VIDIOC_STREAMON:{
++                      retval = mxc_streamon(cam);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_STREAMOFF ioctl
++               */
++      case VIDIOC_STREAMOFF:{
++                      retval = mxc_streamoff(cam);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_G_CTRL ioctl
++               */
++      case VIDIOC_G_CTRL:{
++                      retval = mxc_get_v42l_control(cam, arg);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_S_CTRL ioctl
++               */
++      case VIDIOC_S_CTRL:{
++                      retval = mxc_set_v42l_control(cam, arg);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_CROPCAP ioctl
++               */
++      case VIDIOC_CROPCAP:{
++                      struct v4l2_cropcap *cap = arg;
++
++                      if (cap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++                          cap->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      cap->bounds = cam->crop_bounds;
++                      cap->defrect = cam->crop_defrect;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_G_CROP ioctl
++               */
++      case VIDIOC_G_CROP:{
++                      struct v4l2_crop *crop = arg;
++
++                      if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++                          crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      crop->c = cam->crop_current;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_S_CROP ioctl
++               */
++      case VIDIOC_S_CROP:{
++                      struct v4l2_crop *crop = arg;
++                      struct v4l2_rect *b = &cam->crop_bounds;
++
++                      if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
++                          crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      crop->c.top = (crop->c.top < b->top) ? b->top
++                          : crop->c.top;
++                      if (crop->c.top > b->top + b->height)
++                              crop->c.top = b->top + b->height - 1;
++                      if (crop->c.height > b->top + b->height - crop->c.top)
++                              crop->c.height =
++                                  b->top + b->height - crop->c.top;
++
++                      crop->c.left = (crop->c.left < b->left) ? b->left
++                          : crop->c.left;
++                      if (crop->c.left > b->left + b->width)
++                              crop->c.left = b->left + b->width - 1;
++                      if (crop->c.width > b->left - crop->c.left + b->width)
++                              crop->c.width =
++                                  b->left - crop->c.left + b->width;
++
++                      crop->c.width -= crop->c.width % 8;
++                      crop->c.left -= crop->c.left % 4;
++                      cam->crop_current = crop->c;
++
++                      ipu_csi_set_window_size(cam->crop_current.width,
++                                              cam->crop_current.height);
++                      ipu_csi_set_window_pos(cam->crop_current.left,
++                                             cam->crop_current.top);
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_OVERLAY ioctl
++               */
++      case VIDIOC_OVERLAY:{
++                      int *on = arg;
++                      if (*on) {
++                              cam->overlay_on = true;
++                              cam->overlay_pid = current->pid;
++                              retval = start_preview(cam);
++                      }
++                      if (!*on) {
++                              retval = stop_preview(cam);
++                              cam->overlay_on = false;
++                      }
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_G_FBUF ioctl
++               */
++      case VIDIOC_G_FBUF:{
++                      struct v4l2_framebuffer *fb = arg;
++                      *fb = cam->v4l2_fb;
++                      fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
++                      break;
++              }
++
++              /*!
++               * V4l2 VIDIOC_S_FBUF ioctl
++               */
++      case VIDIOC_S_FBUF:{
++                      struct v4l2_framebuffer *fb = arg;
++                      cam->v4l2_fb = *fb;
++                      break;
++              }
++
++      case VIDIOC_G_PARM:{
++                      struct v4l2_streamparm *parm = arg;
++                      if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
++                              printk(KERN_ERR "VIDIOC_G_PARM invalid type\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++                      parm->parm.capture = cam->streamparm.parm.capture;
++                      break;
++              }
++      case VIDIOC_S_PARM:{
++                      struct v4l2_streamparm *parm = arg;
++                      retval = mxc_v4l2_s_param(cam, parm);
++                      break;
++              }
++
++              /* linux v4l2 bug, kernel c0485619 user c0405619 */
++      case VIDIOC_ENUMSTD:{
++                      struct v4l2_standard *e = arg;
++                      *e = cam->standard;
++                      printk(KERN_ERR "VIDIOC_ENUMSTD call\n");
++                      retval = 0;
++                      break;
++              }
++
++      case VIDIOC_G_STD:{
++                      v4l2_std_id *e = arg;
++                      *e = cam->standard.id;
++                      break;
++              }
++
++      case VIDIOC_S_STD:{
++                      break;
++              }
++
++      case VIDIOC_ENUMOUTPUT:
++              {
++                      struct v4l2_output *output = arg;
++
++                      if (output->index >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      *output = mxc_capture_outputs[output->index];
++
++                      break;
++              }
++      case VIDIOC_G_OUTPUT:
++              {
++                      int *p_output_num = arg;
++
++                      *p_output_num = cam->output;
++                      break;
++              }
++      case VIDIOC_S_OUTPUT:
++              {
++                      int *p_output_num = arg;
++
++                      if (*p_output_num >= MXC_V4L2_CAPTURE_NUM_OUTPUTS) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      cam->output = *p_output_num;
++                      break;
++              }
++
++      case VIDIOC_ENUM_FMT:
++      case VIDIOC_TRY_FMT:
++      case VIDIOC_QUERYCTRL:
++      case VIDIOC_ENUMINPUT:
++      case VIDIOC_G_INPUT:
++      case VIDIOC_S_INPUT:
++      case VIDIOC_G_TUNER:
++      case VIDIOC_S_TUNER:
++      case VIDIOC_G_FREQUENCY:
++      case VIDIOC_S_FREQUENCY:
++      default:
++              retval = -EINVAL;
++              break;
++      }
++
++      up(&cam->busy_lock);
++      return retval;
++}
++
++/*
++ * V4L interface - ioctl function
++ *
++ * @return  None
++ */
++static int
++mxc_v4l_ioctl(struct inode *inode, struct file *file,
++            unsigned int cmd, unsigned long arg)
++{
++      return video_usercopy(inode, file, cmd, arg, mxc_v4l_do_ioctl);
++}
++
++/*!
++ * V4L interface - mmap function
++ *
++ * @param file        structure file *
++ *
++ * @param vma         structure vm_area_struct *
++ *
++ * @return status     0 Success, EINTR busy lock error, ENOBUFS remap_page error
++ */
++static int mxc_mmap(struct file *file, struct vm_area_struct *vma)
++{
++      struct video_device *dev = video_devdata(file);
++      unsigned long size;
++      int res = 0;
++      cam_data *cam = dev->priv;
++
++      pr_debug("pgoff=0x%lx, start=0x%lx, end=0x%lx\n",
++               vma->vm_pgoff, vma->vm_start, vma->vm_end);
++
++      /* make this _really_ smp-safe */
++      if (down_interruptible(&cam->busy_lock))
++              return -EINTR;
++
++      size = vma->vm_end - vma->vm_start;
++      vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
++
++      if (remap_pfn_range(vma, vma->vm_start,
++                          vma->vm_pgoff, size, vma->vm_page_prot)) {
++              printk(KERN_ERR "mxc_mmap: remap_pfn_range failed\n");
++              res = -ENOBUFS;
++              goto mxc_mmap_exit;
++      }
++
++      vma->vm_flags &= ~VM_IO;        /* using shared anonymous pages */
++
++      mxc_mmap_exit:
++      up(&cam->busy_lock);
++      return res;
++}
++
++/*!
++ * V4L interface - poll function
++ *
++ * @param file       structure file *
++ *
++ * @param wait       structure poll_table *
++ *
++ * @return  status   POLLIN | POLLRDNORM
++ */
++static unsigned int mxc_poll(struct file *file, poll_table * wait)
++{
++      struct video_device *dev = video_devdata(file);
++      cam_data *cam = dev->priv;
++      wait_queue_head_t *queue = NULL;
++      int res = POLLIN | POLLRDNORM;
++
++      if (down_interruptible(&cam->busy_lock))
++              return -EINTR;
++
++      queue = &cam->enc_queue;
++      poll_wait(file, queue, wait);
++
++      up(&cam->busy_lock);
++      return res;
++}
++
++static struct
++file_operations mxc_v4l_fops = {
++      .owner = THIS_MODULE,
++      .open = mxc_v4l_open,
++      .release = mxc_v4l_close,
++      .read = mxc_v4l_read,
++      .ioctl = mxc_v4l_ioctl,
++      .mmap = mxc_mmap,
++      .poll = mxc_poll,
++};
++
++static struct video_device mxc_v4l_template = {
++      .owner = THIS_MODULE,
++      .name = "Mxc Camera",
++      .type = 0,
++      .type2 = VID_TYPE_CAPTURE,
++      .hardware = 0,
++      .fops = &mxc_v4l_fops,
++      .release = video_device_release,
++};
++
++static void camera_platform_release(struct device *device)
++{
++}
++
++/*! Device Definition for Mt9v111 devices */
++static struct platform_device mxc_v4l2_devices = {
++      .name = "mxc_v4l2",
++      .dev = {
++              .release = camera_platform_release,
++              },
++      .id = 0,
++};
++
++extern struct camera_sensor camera_sensor_if;
++
++/*!
++* Camera V4l2 callback function.
++*
++* @param mask      u32
++*
++* @param dev       void device structure
++*
++* @return status
++*/
++static void camera_callback(u32 mask, void *dev)
++{
++      struct mxc_v4l_frame *done_frame;
++      struct mxc_v4l_frame *ready_frame;
++
++      cam_data *cam = (cam_data *) dev;
++      if (cam == NULL)
++              return;
++
++      if (list_empty(&cam->working_q)) {
++              printk(KERN_ERR "camera_callback: working queue empty\n");
++              return;
++      }
++
++      done_frame =
++          list_entry(cam->working_q.next, struct mxc_v4l_frame, queue);
++      if (done_frame->buffer.flags & V4L2_BUF_FLAG_QUEUED) {
++              done_frame->buffer.flags |= V4L2_BUF_FLAG_DONE;
++              done_frame->buffer.flags &= ~V4L2_BUF_FLAG_QUEUED;
++
++              if (list_empty(&cam->ready_q)) {
++                      cam->skip_frame++;
++              } else {
++                      ready_frame =
++                          list_entry(cam->ready_q.next, struct mxc_v4l_frame,
++                                     queue);
++                      list_del(cam->ready_q.next);
++                      list_add_tail(&ready_frame->queue, &cam->working_q);
++                      cam->enc_update_eba(ready_frame->buffer.m.offset,
++                                          &cam->ping_pong_csi);
++              }
++
++              /* Added to the done queue */
++              list_del(cam->working_q.next);
++              list_add_tail(&done_frame->queue, &cam->done_q);
++
++              /* Wake up the queue */
++              cam->enc_counter++;
++              wake_up_interruptible(&cam->enc_queue);
++      } else {
++              printk(KERN_ERR "camera_callback :buffer not queued\n");
++      }
++}
++
++/*!
++ * initialize cam_data structure
++ *
++ * @param cam      structure cam_data *
++ *
++ * @return status  0 Success
++ */
++static void init_camera_struct(cam_data * cam)
++{
++      /* Default everything to 0 */
++      memset(cam, 0, sizeof(cam_data));
++
++      init_MUTEX(&cam->param_lock);
++      init_MUTEX(&cam->busy_lock);
++
++      cam->video_dev = video_device_alloc();
++      if (cam->video_dev == NULL)
++              return;
++
++      *(cam->video_dev) = mxc_v4l_template;
++
++      video_set_drvdata(cam->video_dev, cam);
++      dev_set_drvdata(&mxc_v4l2_devices.dev, (void *)cam);
++      cam->video_dev->minor = -1;
++
++      init_waitqueue_head(&cam->enc_queue);
++      init_waitqueue_head(&cam->still_queue);
++
++      /* setup cropping */
++      cam->crop_bounds.left = 0;
++      cam->crop_bounds.width = 640;
++      cam->crop_bounds.top = 0;
++      cam->crop_bounds.height = 480;
++      cam->crop_current = cam->crop_defrect = cam->crop_bounds;
++      ipu_csi_set_window_size(cam->crop_current.width,
++                              cam->crop_current.height);
++      ipu_csi_set_window_pos(cam->crop_current.left, cam->crop_current.top);
++      cam->streamparm.parm.capture.capturemode = 0;
++
++      cam->standard.index = 0;
++      cam->standard.id = V4L2_STD_UNKNOWN;
++      cam->standard.frameperiod.denominator = 30;
++      cam->standard.frameperiod.numerator = 1;
++      cam->standard.framelines = 480;
++      cam->streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
++      cam->streamparm.parm.capture.timeperframe = cam->standard.frameperiod;
++      cam->streamparm.parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
++      cam->overlay_on = false;
++      cam->capture_on = false;
++      cam->skip_frame = 0;
++      cam->v4l2_fb.flags = V4L2_FBUF_FLAG_OVERLAY;
++
++      cam->v2f.fmt.pix.sizeimage = 352 * 288 * 3 / 2;
++      cam->v2f.fmt.pix.bytesperline = 288 * 3 / 2;
++      cam->v2f.fmt.pix.width = 288;
++      cam->v2f.fmt.pix.height = 352;
++      cam->v2f.fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
++      cam->win.w.width = 160;
++      cam->win.w.height = 160;
++      cam->win.w.left = 0;
++      cam->win.w.top = 0;
++
++      cam->cam_sensor = &camera_sensor_if;
++      cam->enc_callback = camera_callback;
++      init_waitqueue_head(&cam->power_queue);
++      cam->int_lock = SPIN_LOCK_UNLOCKED;
++      spin_lock_init(&cam->int_lock);
++}
++
++extern void gpio_sensor_active(void);
++extern void gpio_sensor_inactive(void);
++
++/*!
++ * camera_power function
++ *    Turn Sensor power On/Off
++ *
++ * @param       cameraOn      true to turn camera on, otherwise shut down
++ *
++ * @return status
++ */
++static u8 camera_power(bool cameraOn)
++{
++      if (cameraOn == true) {
++              gpio_sensor_active();
++              ipu_csi_enable_mclk(csi_mclk_flag_backup, true, true);
++      } else {
++              csi_mclk_flag_backup = ipu_csi_read_mclk_flag();
++              ipu_csi_enable_mclk(csi_mclk_flag_backup, false, false);
++              gpio_sensor_inactive();
++      }
++      return 0;
++}
++
++/*!
++ * This function is called to put the sensor in a low power state. Refer to the
++ * document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ *
++ * @param   pdev  the device structure used to give information on which I2C
++ *                to suspend
++ * @param   state the power state the device is entering
++ *
++ * @return  The function returns 0 on success and -1 on failure.
++ */
++static int mxc_v4l2_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      cam_data *cam = platform_get_drvdata(pdev);
++
++      if (cam == NULL) {
++              return -1;
++      }
++
++      cam->low_power = true;
++
++      if (cam->overlay_on == true)
++              stop_preview(cam);
++      if ((cam->capture_on == true) && cam->enc_disable) {
++              cam->enc_disable(cam);
++      }
++      camera_power(false);
++
++      return 0;
++}
++
++/*!
++ * This function is called to bring the sensor back from a low power state.Refer
++ * to the document driver-model/driver.txt in the kernel source tree for more
++ * information.
++ *
++ * @param   pdev   the device structure
++ *
++ * @return  The function returns 0 on success and -1 on failure
++ */
++static int mxc_v4l2_resume(struct platform_device *pdev)
++{
++      cam_data *cam = platform_get_drvdata(pdev);
++
++      if (cam == NULL) {
++              return -1;
++      }
++
++      cam->low_power = false;
++      wake_up_interruptible(&cam->power_queue);
++
++      if (cam->overlay_on == true)
++              start_preview(cam);
++      if (cam->capture_on == true)
++              mxc_streamon(cam);
++      camera_power(true);
++
++      return 0;
++}
++
++/*!
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct platform_driver mxc_v4l2_driver = {
++      .driver = {
++                 .name = "mxc_v4l2",
++                 },
++      .probe = NULL,
++      .remove = NULL,
++      .suspend = mxc_v4l2_suspend,
++      .resume = mxc_v4l2_resume,
++      .shutdown = NULL,
++};
++
++/*!
++ * Entry point for the V4L2
++ *
++ * @return  Error code indicating success or failure
++ */
++static __init int camera_init(void)
++{
++      u8 err = 0;
++
++      /* Register the device driver structure. */
++      err = platform_driver_register(&mxc_v4l2_driver);
++      if (err != 0) {
++              printk("camera_init: platform_driver_register failed.\n");
++              return err;
++      }
++
++      if ((g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL)) == NULL) {
++              printk(KERN_ERR "failed to mxc_v4l_register_camera\n");
++              return -1;
++      }
++
++      init_camera_struct(g_cam);
++
++      /* Register the I2C device */
++      err = platform_device_register(&mxc_v4l2_devices);
++      if (err != 0) {
++              printk(KERN_ERR
++                     "camera_init: platform_device_register failed.\n");
++              video_device_release(g_cam->video_dev);
++              kfree(g_cam);
++              g_cam = NULL;
++      }
++
++      /* register v4l device */
++      if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr)
++          == -1) {
++              platform_device_unregister(&mxc_v4l2_devices);
++              platform_driver_unregister(&mxc_v4l2_driver);
++              video_device_release(g_cam->video_dev);
++              kfree(g_cam);
++              g_cam = NULL;
++              printk(KERN_ERR "video_register_device failed\n");
++              return -1;
++      }
++
++      return err;
++}
++
++/*!
++ * Exit and cleanup for the V4L2
++ *
++ */
++static void __exit camera_exit(void)
++{
++      pr_info("unregistering video\n");
++      video_unregister_device(g_cam->video_dev);
++
++      platform_driver_unregister(&mxc_v4l2_driver);
++      platform_device_unregister(&mxc_v4l2_devices);
++
++      if (g_cam->open_count) {
++              printk(KERN_ERR "camera open -- setting ops to NULL\n");
++      } else {
++              pr_info("freeing camera\n");
++              mxc_free_frame_buf(g_cam);
++              kfree(g_cam);
++              g_cam = NULL;
++      }
++}
++
++module_init(camera_init);
++module_exit(camera_exit);
++
++module_param(video_nr, int, 0444);
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("V4L2 capture driver for Mxc based cameras");
++MODULE_LICENSE("GPL");
++MODULE_SUPPORTED_DEVICE("video");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/mxc_v4l2_capture.h linux-2.6.28-karo/drivers/media/video/mxc/capture/mxc_v4l2_capture.h
+--- linux-2.6.28/drivers/media/video/mxc/capture/mxc_v4l2_capture.h    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/mxc_v4l2_capture.h       2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,190 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup MXC_V4L2_CAPTURE MXC V4L2 Video Capture Driver
++ */
++/*!
++ * @file mxc_v4l2_capture.h
++ *
++ * @brief mxc V4L2 capture device API  Header file
++ *
++ * It include all the defines for frame operations, also three structure defines
++ * use case ops structure, common v4l2 driver structure and frame structure.
++ *
++ * @ingroup MXC_V4L2_CAPTURE
++ */
++#ifndef __MXC_V4L2_CAPTURE_H__
++#define __MXC_V4L2_CAPTURE_H__
++
++#include <asm/uaccess.h>
++#include <linux/list.h>
++#include <linux/smp_lock.h>
++
++#include <media/v4l2-dev.h>
++#include <asm/arch/ipu.h>
++#include <asm/arch/mxc_v4l2.h>
++
++#define FRAME_NUM 3
++
++/*!
++ * v4l2 frame structure.
++ */
++struct mxc_v4l_frame {
++      u32 paddress;
++      void *vaddress;
++      int count;
++      int width;
++      int height;
++
++      struct v4l2_buffer buffer;
++      struct list_head queue;
++      int index;
++};
++
++typedef struct {
++      u8 clk_mode;
++      u8 ext_vsync;
++      u8 Vsync_pol;
++      u8 Hsync_pol;
++      u8 pixclk_pol;
++      u8 data_pol;
++      u8 data_width;
++      u16 width;
++      u16 height;
++      u32 pixel_fmt;
++      u32 mclk;
++} sensor_interface;
++
++/* Sensor control function */
++struct camera_sensor {
++      struct module *owner;
++      void (*set_color) (int bright, int saturation, int red, int green,
++                         int blue);
++      void (*get_color) (int *bright, int *saturation, int *red, int *green,
++                         int *blue);
++      void (*set_ae_mode) (int ae_mode);
++      void (*get_ae_mode) (int *ae_mode);
++      void (*set_ae) (int active);
++      void (*set_ae_limit) (int limit);
++      void (*set_awb) (int active);
++      void (*flicker_control) (int control);
++      void (*get_control_params) (int *ae, int *awb, int *flicker);
++      sensor_interface *(*config) (int *frame_rate, int high_quality);
++      sensor_interface *(*reset) (void);
++      int (*get_status) (void);
++};
++
++/*!
++ * common v4l2 driver structure.
++ */
++typedef struct _cam_data {
++      struct video_device *video_dev;
++
++      /* semaphore guard against SMP multithreading */
++      struct semaphore busy_lock;
++
++      int open_count;
++
++      /* params lock for this camera */
++      struct semaphore param_lock;
++
++      /* Encorder */
++      struct list_head ready_q;
++      struct list_head done_q;
++      struct list_head working_q;
++      int ping_pong_csi;
++      spinlock_t int_lock;
++      struct mxc_v4l_frame frame[FRAME_NUM];
++      int skip_frame;
++      wait_queue_head_t overflow_queue;
++      int overflow;
++      wait_queue_head_t enc_queue;
++      int enc_counter;
++      dma_addr_t rot_enc_bufs[2];
++      void *rot_enc_bufs_vaddr[2];
++      int rot_enc_buf_size[2];
++      enum v4l2_buf_type type;
++
++      /* still image capture */
++      wait_queue_head_t still_queue;
++      int still_counter;
++      dma_addr_t still_buf;
++      void *still_buf_vaddr;
++
++      /* overlay */
++      struct v4l2_window win;
++      struct v4l2_framebuffer v4l2_fb;
++      dma_addr_t vf_bufs[2];
++      void *vf_bufs_vaddr[2];
++      int vf_bufs_size[2];
++      dma_addr_t rot_vf_bufs[2];
++      void *rot_vf_bufs_vaddr[2];
++      int rot_vf_buf_size[2];
++      bool overlay_active;
++      int output;
++      struct fb_info *overlay_fb;
++
++      /* v4l2 format */
++      struct v4l2_format v2f;
++      int rotation;
++      struct v4l2_mxc_offset offset;
++
++      /* V4l2 control bit */
++      int bright;
++      int hue;
++      int contrast;
++      int saturation;
++      int red;
++      int green;
++      int blue;
++      int ae_mode;
++      int ae_enable;
++      int ae_limit;
++      int awb_enable;
++      int flicker_ctrl;
++
++      /* standart */
++      struct v4l2_streamparm streamparm;
++      struct v4l2_standard standard;
++
++      /* crop */
++      struct v4l2_rect crop_bounds;
++      struct v4l2_rect crop_defrect;
++      struct v4l2_rect crop_current;
++
++      int (*enc_update_eba) (dma_addr_t eba, int *bufferNum);
++      int (*enc_enable) (void *private);
++      int (*enc_disable) (void *private);
++      void (*enc_callback) (u32 mask, void *dev);
++      int (*vf_start_adc) (void *private);
++      int (*vf_stop_adc) (void *private);
++      int (*vf_start_sdc) (void *private);
++      int (*vf_stop_sdc) (void *private);
++      int (*csi_start) (void *private);
++      int (*csi_stop) (void *private);
++
++      /* misc status flag */
++      bool overlay_on;
++      bool capture_on;
++      int overlay_pid;
++      int capture_pid;
++      bool low_power;
++      wait_queue_head_t power_queue;
++
++      /* camera sensor interface */
++      struct camera_sensor *cam_sensor;
++} cam_data;
++
++void set_mclk_rate(uint32_t * p_mclk_freq);
++#endif                                /* __MXC_V4L2_CAPTURE_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/ov2640.c linux-2.6.28-karo/drivers/media/video/mxc/capture/ov2640.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/ov2640.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/ov2640.c 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,817 @@
++/*
++ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/ctype.h>
++#include <linux/types.h>
++#include <linux/delay.h>
++#include <linux/device.h>
++#include <linux/i2c.h>
++#include <asm/arch/mxc_i2c.h>
++
++#ifdef NONSENSE
++#include <asm/arch/pmic_power.h>
++#endif
++
++#include "mxc_v4l2_capture.h"
++
++#define OV2640_DEBUG
++#ifdef OV2640_DEBUG
++#define PRINTK(fmt...) printk(KERN_DEBUG fmt)
++#else
++#define PRINTK(fmt...)
++#endif
++
++#define OV2640_I2C_ADDRESS 0x30
++
++static sensor_interface *interface_param = NULL;
++static int reset_frame_rate = 30;
++static int ov2640_attach(struct i2c_adapter *adapter);
++static int ov2640_detach(struct i2c_client *client);
++
++static struct i2c_driver ov2640_i2c_driver = {
++      .driver = {
++                 .owner = THIS_MODULE,
++                 .name = "OV2640 Client",
++                 },
++      .attach_adapter = ov2640_attach,
++      .detach_client = ov2640_detach,
++};
++
++static struct i2c_client ov2640_i2c_client = {
++      .name = "ov2640 I2C dev",
++      .addr = OV2640_I2C_ADDRESS,
++      .driver = &ov2640_i2c_driver,
++};
++
++/*!
++ * ov2640 I2C attach function
++ *
++ * @param adapter            struct i2c_adapter *
++ * @return  Error code indicating success or failure
++ */
++static int ov2640_attach(struct i2c_adapter *adapter)
++{
++      int ret;
++
++      if (strcmp(adapter->name, MXC_ADAPTER_NAME) != 0) {
++              PRINTK("%s: %s\n", __func__, adapter->name);
++              return -ENODEV;
++      }
++      ov2640_i2c_client.adapter = adapter;
++
++      ret = i2c_attach_client(&ov2640_i2c_client);
++      if (ret != 0) {
++              ov2640_i2c_client.adapter = NULL;
++              PRINTK("%s: i2c_attach_client failed\n", __func__);
++              return ret;
++      }
++
++      interface_param = kzalloc(sizeof(sensor_interface), GFP_KERNEL);
++      if (!interface_param) {
++              PRINTK("%s: kmalloc failed\n", __func__);
++              return -ENOMEM;
++      }
++      return 0;
++}
++
++/*!
++ * ov2640 I2C detach function
++ *
++ * @param client            struct i2c_client *
++ * @return  Error code indicating success or failure
++ */
++static int ov2640_detach(struct i2c_client *client)
++{
++      int err;
++#ifdef NONSENSE
++      PMIC_STATUS ret;
++#endif
++      err = i2c_detach_client(&ov2640_i2c_client);
++      ov2640_i2c_client.adapter = NULL;
++
++      kfree(interface_param);
++      interface_param = NULL;
++
++#ifdef NONSENSE
++      /* DOVDD */
++      if ((ret = pmic_power_regulator_off(REGU_GPO3)) < 0) {
++              PRINTK("%s:REGU_GPO3 power off error:%d\n", __func__, ret);
++              return 0;
++      } else {
++              PRINTK("%s:REGU_GPO3 power off ok\n", __func__);
++      }
++      PRINTK("%s:OV2640 power off ok\n", __func__);
++#endif
++      return err;
++}
++
++static int
++ov2640_i2c_client_xfer(int addr, u8 reg, char *buf, int num, int tran_flag)
++{
++      struct i2c_msg msg[2];
++      int ret;
++
++      msg[0].addr = addr;
++      msg[0].len = 1;
++      msg[0].buf = &reg;
++      msg[0].flags = tran_flag;
++      msg[0].flags &= ~I2C_M_RD;
++
++      msg[1].addr = addr;
++      msg[1].len = num;
++      msg[1].buf = buf;
++      msg[1].flags = tran_flag;
++
++      if (tran_flag & MXC_I2C_FLAG_READ) {
++              msg[1].flags |= I2C_M_RD;
++      } else {
++              msg[1].flags &= ~I2C_M_RD;
++      }
++
++#if 1
++      BUG_ON(ov2640_i2c_client.adapter == NULL);
++#else
++      if (ov2640_i2c_client.adapter == NULL) {
++              PRINTK("%s: adapter error\n", __func__);
++              return -ENODEV;
++      }
++#endif
++      ret = i2c_transfer(ov2640_i2c_client.adapter, msg, 2);
++      if (ret >= 0) {
++              /* PRINTK("%s:i2c transfer num:%d\n", __func__, ret); */
++              return 0;
++      }
++      PRINTK("%s: i2c transfer error: %d\n", __func__, ret);
++      return ret;
++}
++
++static int ov2640_write_reg(u8 reg, u8 val)
++{
++      int ret;
++
++      ret = ov2640_i2c_client_xfer(OV2640_I2C_ADDRESS, reg, &val, 1, 0);
++      if (ret < 0) {
++              PRINTK("%s: write reg error: reg=%02x, val=%02x ret=%d\n",
++                     __func__, reg, val, ret);
++              return ret;
++      } else if (ret != 1) {
++              PRINTK("%s: write reg error: reg=%02x, val=%02x ret=%d\n",
++                     __func__, reg, val, ret);
++              return -EIO;
++      }
++      return 0;
++}
++
++/* should be replaced by width and height version. */
++static int ov2640_init_1600_1120(void)
++{
++      int ret;
++
++      ret = ov2640_write_reg(0xff, 1);
++      if (ret != 0) {
++              return ret;
++      }
++      ov2640_write_reg(0x12, 0x80);
++      udelay(1000);
++      ov2640_write_reg(0xff, 0x00);
++      ov2640_write_reg(0x2c, 0xff);
++      ov2640_write_reg(0x2e, 0xdf);
++      ov2640_write_reg(0xff, 0x01);
++      ov2640_write_reg(0x3c, 0x32);
++      ov2640_write_reg(0x11, 0x01);
++      ov2640_write_reg(0x09, 0x00);
++      ov2640_write_reg(0x04, 0x28);
++      ov2640_write_reg(0x13, 0xe5);
++      ov2640_write_reg(0x14, 0x48);
++      ov2640_write_reg(0x2c, 0x0c);
++      ov2640_write_reg(0x33, 0x78);
++      ov2640_write_reg(0x3a, 0x33);
++      ov2640_write_reg(0x3b, 0xfb);
++      ov2640_write_reg(0x3e, 0x00);
++      ov2640_write_reg(0x43, 0x11);
++      ov2640_write_reg(0x16, 0x10);
++      ov2640_write_reg(0x39, 0x82);
++      ov2640_write_reg(0x35, 0x88);
++      ov2640_write_reg(0x22, 0x0a);
++      ov2640_write_reg(0x37, 0x40);
++      ov2640_write_reg(0x23, 0x00);
++      ov2640_write_reg(0x34, 0xa0);
++      ov2640_write_reg(0x36, 0x1a);
++      ov2640_write_reg(0x06, 0x02);
++      ov2640_write_reg(0x07, 0xc0);
++      ov2640_write_reg(0x0d, 0xb7);
++      ov2640_write_reg(0x0e, 0x01);
++      ov2640_write_reg(0x4c, 0x00);
++      ov2640_write_reg(0x4a, 0x81);
++      ov2640_write_reg(0x21, 0x99);
++      ov2640_write_reg(0x24, 0x40);
++      ov2640_write_reg(0x25, 0x38);
++      ov2640_write_reg(0x26, 0x82);
++      ov2640_write_reg(0x5c, 0x00);
++      ov2640_write_reg(0x63, 0x00);
++      ov2640_write_reg(0x46, 0x3f);
++      ov2640_write_reg(0x0c, 0x3c);
++      ov2640_write_reg(0x5d, 0x55);
++      ov2640_write_reg(0x5e, 0x7d);
++      ov2640_write_reg(0x5f, 0x7d);
++      ov2640_write_reg(0x60, 0x55);
++      ov2640_write_reg(0x61, 0x70);
++      ov2640_write_reg(0x62, 0x80);
++      ov2640_write_reg(0x7c, 0x05);
++      ov2640_write_reg(0x20, 0x80);
++      ov2640_write_reg(0x28, 0x30);
++      ov2640_write_reg(0x6c, 0x00);
++      ov2640_write_reg(0x6d, 0x80);
++      ov2640_write_reg(0x6e, 0x00);
++      ov2640_write_reg(0x70, 0x02);
++      ov2640_write_reg(0x71, 0x94);
++      ov2640_write_reg(0x73, 0xc1);
++      ov2640_write_reg(0x3d, 0x34);
++      ov2640_write_reg(0x5a, 0x57);
++      ov2640_write_reg(0x4f, 0xbb);
++      ov2640_write_reg(0x50, 0x9c);
++      ov2640_write_reg(0xff, 0x00);
++      ov2640_write_reg(0xe5, 0x7f);
++      ov2640_write_reg(0xf9, 0xc0);
++      ov2640_write_reg(0x41, 0x24);
++      ov2640_write_reg(0x44, 0x06);
++      ov2640_write_reg(0xe0, 0x14);
++      ov2640_write_reg(0x76, 0xff);
++      ov2640_write_reg(0x33, 0xa0);
++      ov2640_write_reg(0x42, 0x20);
++      ov2640_write_reg(0x43, 0x18);
++      ov2640_write_reg(0x4c, 0x00);
++      ov2640_write_reg(0x87, 0xd0);
++      ov2640_write_reg(0xd7, 0x03);
++      ov2640_write_reg(0xd9, 0x10);
++      ov2640_write_reg(0xd3, 0x82);
++      ov2640_write_reg(0xc8, 0x08);
++      ov2640_write_reg(0xc9, 0x80);
++      ov2640_write_reg(0x7c, 0x00);
++      ov2640_write_reg(0x7d, 0x00);
++      ov2640_write_reg(0x7c, 0x03);
++      ov2640_write_reg(0x7d, 0x48);
++      ov2640_write_reg(0x7d, 0x48);
++      ov2640_write_reg(0x7c, 0x08);
++      ov2640_write_reg(0x7d, 0x20);
++      ov2640_write_reg(0x7d, 0x10);
++      ov2640_write_reg(0x7d, 0x0e);
++      ov2640_write_reg(0x90, 0x00);
++      ov2640_write_reg(0x91, 0x0e);
++      ov2640_write_reg(0x91, 0x1a);
++      ov2640_write_reg(0x91, 0x31);
++      ov2640_write_reg(0x91, 0x5a);
++      ov2640_write_reg(0x91, 0x69);
++      ov2640_write_reg(0x91, 0x75);
++      ov2640_write_reg(0x91, 0x7e);
++      ov2640_write_reg(0x91, 0x88);
++      ov2640_write_reg(0x91, 0x8f);
++      ov2640_write_reg(0x91, 0x96);
++      ov2640_write_reg(0x91, 0xa3);
++      ov2640_write_reg(0x91, 0xaf);
++      ov2640_write_reg(0x91, 0xc4);
++      ov2640_write_reg(0x91, 0xd7);
++      ov2640_write_reg(0x91, 0xe8);
++      ov2640_write_reg(0x91, 0x20);
++
++      ov2640_write_reg(0x92, 0x00);
++      ov2640_write_reg(0x93, 0x06);
++      ov2640_write_reg(0x93, 0xe3);
++      ov2640_write_reg(0x93, 0x03);
++      ov2640_write_reg(0x93, 0x03);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x02);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++
++      ov2640_write_reg(0x96, 0x00);
++      ov2640_write_reg(0x97, 0x08);
++      ov2640_write_reg(0x97, 0x19);
++      ov2640_write_reg(0x97, 0x02);
++      ov2640_write_reg(0x97, 0x0c);
++      ov2640_write_reg(0x97, 0x24);
++      ov2640_write_reg(0x97, 0x30);
++      ov2640_write_reg(0x97, 0x28);
++      ov2640_write_reg(0x97, 0x26);
++      ov2640_write_reg(0x97, 0x02);
++      ov2640_write_reg(0x97, 0x98);
++      ov2640_write_reg(0x97, 0x80);
++      ov2640_write_reg(0x97, 0x00);
++      ov2640_write_reg(0x97, 0x00);
++
++      ov2640_write_reg(0xa4, 0x00);
++      ov2640_write_reg(0xa8, 0x00);
++      ov2640_write_reg(0xc5, 0x11);
++      ov2640_write_reg(0xc6, 0x51);
++      ov2640_write_reg(0xbf, 0x80);
++      ov2640_write_reg(0xc7, 0x10);
++      ov2640_write_reg(0xb6, 0x66);
++      ov2640_write_reg(0xb8, 0xa5);
++      ov2640_write_reg(0xb7, 0x64);
++      ov2640_write_reg(0xb9, 0x7c);
++      ov2640_write_reg(0xb3, 0xaf);
++      ov2640_write_reg(0xb4, 0x97);
++      ov2640_write_reg(0xb5, 0xff);
++      ov2640_write_reg(0xb0, 0xc5);
++      ov2640_write_reg(0xb1, 0x94);
++      ov2640_write_reg(0xb2, 0x0f);
++      ov2640_write_reg(0xc4, 0x5c);
++
++      ov2640_write_reg(0xa6, 0x00);
++      ov2640_write_reg(0xa7, 0x20);
++      ov2640_write_reg(0xa7, 0xd8);
++      ov2640_write_reg(0xa7, 0x1b);
++      ov2640_write_reg(0xa7, 0x31);
++      ov2640_write_reg(0xa7, 0x00);
++      ov2640_write_reg(0xa7, 0x18);
++      ov2640_write_reg(0xa7, 0x20);
++      ov2640_write_reg(0xa7, 0xd8);
++      ov2640_write_reg(0xa7, 0x19);
++      ov2640_write_reg(0xa7, 0x31);
++      ov2640_write_reg(0xa7, 0x00);
++      ov2640_write_reg(0xa7, 0x18);
++      ov2640_write_reg(0xa7, 0x20);
++      ov2640_write_reg(0xa7, 0xd8);
++      ov2640_write_reg(0xa7, 0x19);
++      ov2640_write_reg(0xa7, 0x31);
++      ov2640_write_reg(0xa7, 0x00);
++      ov2640_write_reg(0xa7, 0x18);
++
++      ov2640_write_reg(0xc0, 0xc8);
++      ov2640_write_reg(0xc1, 0x96);
++      ov2640_write_reg(0x86, 0x3d);
++      ov2640_write_reg(0x50, 0x00);
++      ov2640_write_reg(0x51, 0x90);
++      ov2640_write_reg(0x52, 0x18);
++      ov2640_write_reg(0x53, 0x00);
++      ov2640_write_reg(0x54, 0x00);
++      ov2640_write_reg(0x55, 0x88);
++      ov2640_write_reg(0x57, 0x00);
++      ov2640_write_reg(0x5a, 0x90);
++      ov2640_write_reg(0x5b, 0x18);
++      ov2640_write_reg(0x5c, 0x05);
++      ov2640_write_reg(0xc3, 0xef);
++      ov2640_write_reg(0x7f, 0x00);
++      ov2640_write_reg(0xda, 0x01);
++      ov2640_write_reg(0xe5, 0x1f);
++      ov2640_write_reg(0xe1, 0x67);
++      ov2640_write_reg(0xe0, 0x00);
++      ov2640_write_reg(0xdd, 0x7f);
++      ov2640_write_reg(0x05, 0x00);
++
++      return 0;
++}
++
++static int ov2640_init_800_600(void)
++{
++      int ret;
++      ret = ov2640_write_reg(0xff, 0x00);
++      if (ret != 0) {
++              return ret;
++      }
++      ov2640_write_reg(0xff, 0x01);
++      ov2640_write_reg(0x12, 0x80);
++      udelay(1000);
++      ov2640_write_reg(0xff, 0x00);
++      ov2640_write_reg(0x2c, 0xff);
++      ov2640_write_reg(0x2e, 0xdf);
++      ov2640_write_reg(0xff, 0x01);
++      ov2640_write_reg(0x3c, 0x32);
++      ov2640_write_reg(0x11, 0x01);
++      ov2640_write_reg(0x09, 0x00);
++      ov2640_write_reg(0x04, 0x28);
++      ov2640_write_reg(0x13, 0xe5);
++      ov2640_write_reg(0x14, 0x48);
++      ov2640_write_reg(0x2c, 0x0c);
++      ov2640_write_reg(0x33, 0x78);
++      ov2640_write_reg(0x3a, 0x33);
++      ov2640_write_reg(0x3b, 0xfb);
++      ov2640_write_reg(0x3e, 0x00);
++      ov2640_write_reg(0x43, 0x11);
++      ov2640_write_reg(0x16, 0x10);
++      ov2640_write_reg(0x39, 0x92);
++      ov2640_write_reg(0x35, 0xda);
++      ov2640_write_reg(0x22, 0x1a);
++      ov2640_write_reg(0x37, 0xc3);
++      ov2640_write_reg(0x23, 0x00);
++      ov2640_write_reg(0x34, 0xc0);
++      ov2640_write_reg(0x36, 0x1a);
++      ov2640_write_reg(0x06, 0x88);
++      ov2640_write_reg(0x07, 0xc0);
++      ov2640_write_reg(0x0d, 0x87);
++      ov2640_write_reg(0x0e, 0x41);
++      ov2640_write_reg(0x4c, 0x00);
++      ov2640_write_reg(0x4a, 0x81);
++      ov2640_write_reg(0x21, 0x99);
++      ov2640_write_reg(0x24, 0x40);
++      ov2640_write_reg(0x25, 0x38);
++      ov2640_write_reg(0x26, 0x82);
++      ov2640_write_reg(0x5c, 0x00);
++      ov2640_write_reg(0x63, 0x00);
++      ov2640_write_reg(0x46, 0x22);
++      ov2640_write_reg(0x0c, 0x3c);
++      ov2640_write_reg(0x5d, 0x55);
++      ov2640_write_reg(0x5e, 0x7d);
++      ov2640_write_reg(0x5f, 0x7d);
++      ov2640_write_reg(0x60, 0x55);
++      ov2640_write_reg(0x61, 0x70);
++      ov2640_write_reg(0x62, 0x80);
++      ov2640_write_reg(0x7c, 0x05);
++      ov2640_write_reg(0x20, 0x80);
++      ov2640_write_reg(0x28, 0x30);
++      ov2640_write_reg(0x6c, 0x00);
++      ov2640_write_reg(0x6d, 0x80);
++      ov2640_write_reg(0x6e, 0x00);
++      ov2640_write_reg(0x70, 0x02);
++      ov2640_write_reg(0x71, 0x94);
++      ov2640_write_reg(0x73, 0xc1);
++      ov2640_write_reg(0x12, 0x40);
++      ov2640_write_reg(0x17, 0x11);
++      ov2640_write_reg(0x18, 0x43);
++      ov2640_write_reg(0x19, 0x00);
++      ov2640_write_reg(0x1a, 0x4b);
++      ov2640_write_reg(0x32, 0x09);
++      ov2640_write_reg(0x37, 0xc0);
++      ov2640_write_reg(0x4f, 0xca);
++      ov2640_write_reg(0x50, 0xa8);
++      ov2640_write_reg(0x6d, 0x00);
++      ov2640_write_reg(0x3d, 0x38);
++      ov2640_write_reg(0xff, 0x00);
++      ov2640_write_reg(0xe5, 0x7f);
++      ov2640_write_reg(0xf9, 0xc0);
++      ov2640_write_reg(0x41, 0x24);
++      ov2640_write_reg(0x44, 0x06);
++      ov2640_write_reg(0xe0, 0x14);
++      ov2640_write_reg(0x76, 0xff);
++      ov2640_write_reg(0x33, 0xa0);
++      ov2640_write_reg(0x42, 0x20);
++      ov2640_write_reg(0x43, 0x18);
++      ov2640_write_reg(0x4c, 0x00);
++      ov2640_write_reg(0x87, 0xd0);
++      ov2640_write_reg(0x88, 0x3f);
++      ov2640_write_reg(0xd7, 0x03);
++      ov2640_write_reg(0xd9, 0x10);
++      ov2640_write_reg(0xd3, 0x82);
++      ov2640_write_reg(0xc8, 0x08);
++      ov2640_write_reg(0xc9, 0x80);
++      ov2640_write_reg(0x7c, 0x00);
++      ov2640_write_reg(0x7d, 0x00);
++      ov2640_write_reg(0x7c, 0x03);
++      ov2640_write_reg(0x7d, 0x48);
++      ov2640_write_reg(0x7d, 0x48);
++      ov2640_write_reg(0x7c, 0x08);
++      ov2640_write_reg(0x7d, 0x20);
++      ov2640_write_reg(0x7d, 0x10);
++      ov2640_write_reg(0x7d, 0x0e);
++      ov2640_write_reg(0x90, 0x00);
++      ov2640_write_reg(0x91, 0x0e);
++      ov2640_write_reg(0x91, 0x1a);
++      ov2640_write_reg(0x91, 0x31);
++      ov2640_write_reg(0x91, 0x5a);
++      ov2640_write_reg(0x91, 0x69);
++      ov2640_write_reg(0x91, 0x75);
++      ov2640_write_reg(0x91, 0x7e);
++      ov2640_write_reg(0x91, 0x88);
++      ov2640_write_reg(0x91, 0x8f);
++      ov2640_write_reg(0x91, 0x96);
++      ov2640_write_reg(0x91, 0xa3);
++      ov2640_write_reg(0x91, 0xaf);
++      ov2640_write_reg(0x91, 0xc4);
++      ov2640_write_reg(0x91, 0xd7);
++      ov2640_write_reg(0x91, 0xe8);
++      ov2640_write_reg(0x91, 0x20);
++
++      ov2640_write_reg(0x92, 0x00);
++      ov2640_write_reg(0x93, 0x06);
++      ov2640_write_reg(0x93, 0xe3);
++      ov2640_write_reg(0x93, 0x03);
++      ov2640_write_reg(0x93, 0x03);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x02);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++      ov2640_write_reg(0x93, 0x00);
++
++      ov2640_write_reg(0x96, 0x00);
++      ov2640_write_reg(0x97, 0x08);
++      ov2640_write_reg(0x97, 0x19);
++      ov2640_write_reg(0x97, 0x02);
++      ov2640_write_reg(0x97, 0x0c);
++      ov2640_write_reg(0x97, 0x24);
++      ov2640_write_reg(0x97, 0x30);
++      ov2640_write_reg(0x97, 0x28);
++      ov2640_write_reg(0x97, 0x26);
++      ov2640_write_reg(0x97, 0x02);
++      ov2640_write_reg(0x97, 0x98);
++      ov2640_write_reg(0x97, 0x80);
++      ov2640_write_reg(0x97, 0x00);
++      ov2640_write_reg(0x97, 0x00);
++
++      ov2640_write_reg(0xa4, 0x00);
++      ov2640_write_reg(0xa8, 0x00);
++      ov2640_write_reg(0xc5, 0x11);
++      ov2640_write_reg(0xc6, 0x51);
++      ov2640_write_reg(0xbf, 0x80);
++      ov2640_write_reg(0xc7, 0x10);
++      ov2640_write_reg(0xb6, 0x66);
++      ov2640_write_reg(0xb8, 0xa5);
++      ov2640_write_reg(0xb7, 0x64);
++      ov2640_write_reg(0xb9, 0x7c);
++      ov2640_write_reg(0xb3, 0xaf);
++      ov2640_write_reg(0xb4, 0x97);
++      ov2640_write_reg(0xb5, 0xff);
++      ov2640_write_reg(0xb0, 0xc5);
++      ov2640_write_reg(0xb1, 0x94);
++      ov2640_write_reg(0xb2, 0x0f);
++      ov2640_write_reg(0xc4, 0x5c);
++
++      ov2640_write_reg(0xa6, 0x00);
++      ov2640_write_reg(0xa7, 0x20);
++      ov2640_write_reg(0xa7, 0xd8);
++      ov2640_write_reg(0xa7, 0x1b);
++      ov2640_write_reg(0xa7, 0x31);
++      ov2640_write_reg(0xa7, 0x00);
++      ov2640_write_reg(0xa7, 0x18);
++      ov2640_write_reg(0xa7, 0x20);
++      ov2640_write_reg(0xa7, 0xd8);
++      ov2640_write_reg(0xa7, 0x19);
++      ov2640_write_reg(0xa7, 0x31);
++      ov2640_write_reg(0xa7, 0x00);
++      ov2640_write_reg(0xa7, 0x18);
++      ov2640_write_reg(0xa7, 0x20);
++      ov2640_write_reg(0xa7, 0xd8);
++      ov2640_write_reg(0xa7, 0x19);
++      ov2640_write_reg(0xa7, 0x31);
++      ov2640_write_reg(0xa7, 0x00);
++      ov2640_write_reg(0xa7, 0x18);
++
++      ov2640_write_reg(0xc0, 0x64);
++      ov2640_write_reg(0xc1, 0x4b);
++      ov2640_write_reg(0x86, 0x1d);
++      ov2640_write_reg(0x50, 0x00);
++      ov2640_write_reg(0x51, 0xc8);
++      ov2640_write_reg(0x52, 0x96);
++      ov2640_write_reg(0x53, 0x00);
++      ov2640_write_reg(0x54, 0x00);
++      ov2640_write_reg(0x55, 0x00);
++      ov2640_write_reg(0x57, 0x00);
++      ov2640_write_reg(0x5a, 0xc8);
++      ov2640_write_reg(0x5b, 0x96);
++      ov2640_write_reg(0x5c, 0x00);
++      ov2640_write_reg(0xc3, 0xef);
++      ov2640_write_reg(0x7f, 0x00);
++      ov2640_write_reg(0xda, 0x01);
++      ov2640_write_reg(0xe5, 0x1f);
++      ov2640_write_reg(0xe1, 0x67);
++      ov2640_write_reg(0xe0, 0x00);
++      ov2640_write_reg(0xdd, 0x7f);
++      ov2640_write_reg(0x05, 0x00);
++
++      return 0;
++}
++
++/*!
++ * ov2640 sensor interface Initialization
++ * @param param            sensor_interface *
++ * @param width            u32
++ * @param height           u32
++ * @return  None
++ */
++static void ov2640_interface(sensor_interface * param, u32 width, u32 height)
++{
++      param->Vsync_pol = 0x0;
++      param->clk_mode = 0x0;  /* gated */
++      param->pixclk_pol = 0x0;
++      param->data_width = 0x1;
++      param->data_pol = 0x0;
++      param->ext_vsync = 0x0;
++      param->Vsync_pol = 0x0;
++      param->Hsync_pol = 0x0;
++      param->width = width - 1;
++      param->height = height - 1;
++      param->pixel_fmt = IPU_PIX_FMT_UYVY;
++      param->mclk = 27000000;
++}
++
++static void
++ov2640_set_color(int bright, int saturation, int red, int green, int blue)
++{
++      return;
++}
++
++static void
++ov2640_get_color(int *bright, int *saturation, int *red, int *green, int *blue)
++{
++      return;
++}
++
++static void ov2640_set_ae_mode(int ae_mode)
++{
++      return;
++}
++
++static void ov2640_get_ae_mode(int *ae_mode)
++{
++      return;
++}
++
++extern void gpio_sensor_active(void);
++extern cam_data *g_cam;
++
++static sensor_interface *ov2640_config(int *frame_rate, int high_quality)
++{
++      u32 out_width, out_height;
++
++      if (interface_param == NULL) {
++              return NULL;
++      }
++#ifdef NONSENSE
++      PMIC_STATUS ret;
++      t_regulator_voltage voltage;
++
++      /* AVDD--2.8v */
++      voltage.vmmc1 = VMMC1_2_8V;
++      if ((ret = pmic_power_regulator_set_voltage(REGU_VMMC1, voltage)) < 0) {
++              PRINTK("%s:vmmc1 set voltage error:%d\n", __func__, ret);
++              return NULL;
++      } else {
++              PRINTK("%s:vmmc1 set voltage ok\n", __func__);
++      }
++
++      if ((ret = pmic_power_regulator_on(REGU_VMMC1)) < 0) {
++              PRINTK("%s:vmmc1 power on error:%d\n", __func__, ret);
++              return NULL;
++      } else {
++              PRINTK("%s:vmmc1 power on ok\n", __func__);
++      }
++
++      /* DVDD--1.3v */
++      voltage.vvib = VVIB_1_3V;
++      if ((ret = pmic_power_regulator_set_voltage(REGU_VVIB, voltage)) < 0) {
++              PRINTK("%s:VVIB set voltage error:%d\n", __func__, ret);
++              return NULL;
++      } else {
++              PRINTK("%s:VVIB set voltage ok\n", __func__);
++      }
++      if ((ret = pmic_power_regulator_on(REGU_VVIB)) < 0) {
++              PRINTK("%s:VVIB power regulator on error:%d\n", __func__, ret);
++              return NULL;
++      } else {
++              PRINTK("%s:VVIB power on ok\n", __func__);
++      }
++
++      /* DOVDD--2v(1.8-3.0) */
++      voltage.sw2b = SW2B_2V;
++      if ((ret = pmic_power_regulator_set_voltage(SW_SW2B, voltage)) < 0) {
++              PRINTK("%s:SW2B set voltage error:%d\n", __func__, ret);
++              return NULL;
++      } else {
++              PRINTK("%s:SW2B set voltage ok\n", __func__);
++      }
++      if (pmic_power_set_regen_assig(REGU_GPO3, 1) < 0) {
++              PRINTK("%s:set_regen_assig error\n", __func__);
++              return NULL;
++      } else {
++              PRINTK("%s:set_regen_assig ok\n", __func__);
++      }
++      if ((ret = pmic_power_regulator_on(REGU_GPO3)) < 0) {
++              PRINTK("%s:REGU_GPO3 power on error:%d\n", __func__, ret);
++              return NULL;
++      } else {
++              PRINTK("%s:REGU_GPO3 power on ok\n", __func__);
++      }
++      PRINTK("%s:OV2640 power on ok\n", __func__);
++#endif
++      if (high_quality) {
++              out_width = 1600;
++              out_height = 1120;
++              g_cam->crop_bounds.left = 0;
++              g_cam->crop_bounds.width = 1600;
++              g_cam->crop_bounds.top = 0;
++              g_cam->crop_bounds.height = 1120;
++              g_cam->crop_current = g_cam->crop_defrect = g_cam->crop_bounds;
++#ifdef CONFIG_ARCH_MX3
++              ipu_csi_set_window_size(g_cam->crop_current.width,
++                                      g_cam->crop_current.height);
++              ipu_csi_set_window_pos(g_cam->crop_current.left,
++                                     g_cam->crop_current.top);
++#endif
++              g_cam->streamparm.parm.capture.capturemode = 1;
++      } else {
++              out_width = 640;
++              out_height = 480;
++              g_cam->crop_bounds.left = 0;
++              g_cam->crop_bounds.width = 640;
++              g_cam->crop_bounds.top = 0;
++              g_cam->crop_bounds.height = 480;
++              g_cam->crop_current = g_cam->crop_defrect = g_cam->crop_bounds;
++#ifdef CONFIG_ARCH_MX3
++              ipu_csi_set_window_size(g_cam->crop_current.width,
++                                      g_cam->crop_current.height);
++              ipu_csi_set_window_pos(g_cam->crop_current.left,
++                                     g_cam->crop_current.top);
++#endif
++              g_cam->streamparm.parm.capture.capturemode = 0;
++      }
++      ov2640_interface(interface_param, out_width, out_height);
++      set_mclk_rate(&interface_param->mclk);
++
++      if (high_quality) {
++              if (ov2640_init_1600_1120() != 0) {
++                      return NULL;
++              }
++      } else {
++              if (ov2640_init_800_600() != 0) {
++                      return NULL;
++              }
++      }
++      return interface_param;
++}
++
++static void ov2640_get_control_params(int *ae, int *awb, int *flicker)
++{
++      *ae = 0;
++      *awb = 0;
++      *flicker = 0;
++}
++
++static sensor_interface *ov2640_reset(void)
++{
++      return ov2640_config(&reset_frame_rate, 0);
++}
++
++static int ov2640_get_status(void)
++{
++      return 0;
++}
++
++struct camera_sensor camera_sensor_if = {
++      .set_color = ov2640_set_color,
++      .get_color = ov2640_get_color,
++      .set_ae_mode = ov2640_set_ae_mode,
++      .get_ae_mode = ov2640_get_ae_mode,
++      .get_control_params = ov2640_get_control_params,
++      .config = ov2640_config,
++      .reset = ov2640_reset,
++      .get_status = ov2640_get_status,
++};
++
++EXPORT_SYMBOL(camera_sensor_if);
++
++/*!
++ * ov2640 init function
++ *
++ * @return  Error code indicating success or failure
++ */
++static __init int ov2640_init(void)
++{
++      u8 err;
++
++      gpio_sensor_active();
++
++      err = i2c_add_driver(&ov2640_i2c_driver);
++
++      return err;
++}
++
++extern void gpio_sensor_inactive(void);
++/*!
++ * OV2640 cleanup function
++ *
++ * @return  Error code indicating success or failure
++ */
++static void __exit ov2640_clean(void)
++{
++      i2c_del_driver(&ov2640_i2c_driver);
++
++      gpio_sensor_inactive();
++}
++
++module_init(ov2640_init);
++module_exit(ov2640_clean);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("OV2640 Camera Driver");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/capture/sensor_clock.c linux-2.6.28-karo/drivers/media/video/mxc/capture/sensor_clock.c
+--- linux-2.6.28/drivers/media/video/mxc/capture/sensor_clock.c        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/capture/sensor_clock.c   2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,56 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file sensor_clock.c
++ *
++ * @brief camera clock function
++ *
++ * @ingroup Camera
++ */
++#include <linux/init.h>
++#include <linux/ctype.h>
++#include <linux/types.h>
++#include <linux/device.h>
++#include <linux/clk.h>
++
++/*
++ * set_mclk_rate
++ *
++ * @param       p_mclk_freq  mclk frequence
++ *
++ */
++void set_mclk_rate(uint32_t * p_mclk_freq)
++{
++      struct clk *clk;
++      int i;
++      uint32_t freq = 0;
++      uint32_t step = *p_mclk_freq / 8;
++
++      clk = clk_get(NULL, "csi_clk");
++
++      for (i = 0; i <= 8; i++) {
++              freq = clk_round_rate(clk, *p_mclk_freq - (i * step));
++              if (freq <= *p_mclk_freq)
++                      break;
++      }
++      clk_set_rate(clk, freq);
++
++      *p_mclk_freq = freq;
++
++      clk_put(clk);
++      pr_debug("mclk frequency = %d\n", *p_mclk_freq);
++}
++
++/* Exported symbols for modules. */
++EXPORT_SYMBOL(set_mclk_rate);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/Makefile linux-2.6.28-karo/drivers/media/video/mxc/opl/Makefile
+--- linux-2.6.28/drivers/media/video/mxc/opl/Makefile  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/Makefile     2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,5 @@
++opl-objs      := opl_mod.o rotate90_u16.o rotate270_u16.o     \
++                 rotate90_u16_qcif.o rotate270_u16_qcif.o     \
++                 vmirror_u16.o hmirror_rotate180_u16.o
++
++obj-$(CONFIG_VIDEO_MXC_OPL)   += opl.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/hmirror_rotate180_u16.c linux-2.6.28-karo/drivers/media/video/mxc/opl/hmirror_rotate180_u16.c
+--- linux-2.6.28/drivers/media/video/mxc/opl/hmirror_rotate180_u16.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/hmirror_rotate180_u16.c      2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,259 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/module.h>
++#include "opl.h"
++
++static inline u32 rot_left_u16(u16 x, unsigned int n)
++{
++      return (x << n) | (x >> (16 - n));
++}
++
++static inline u32 rot_left_u32(u32 x, unsigned int n)
++{
++      return (x << n) | (x >> (32 - n));
++}
++
++static inline u32 byte_swap_u32(u32 x)
++{
++      u32 t1, t2, t3;
++
++      t1 = x ^ ((x << 16) | x >> 16);
++      t2 = t1 & 0xff00ffff;
++      t3 = (x >> 8) | (x << 24);
++      return t3 ^ (t2 >> 8);
++}
++
++static int opl_hmirror_u16_by1(const u8 * src, int src_line_stride, int width,
++                             int height, u8 * dst, int dst_line_stride,
++                             int vmirror);
++static int opl_hmirror_u16_by2(const u8 * src, int src_line_stride, int width,
++                             int height, u8 * dst, int dst_line_stride,
++                             int vmirror);
++static int opl_hmirror_u16_by4(const u8 * src, int src_line_stride, int width,
++                             int height, u8 * dst, int dst_line_stride,
++                             int vmirror);
++static int opl_hmirror_u16_by8(const u8 * src, int src_line_stride, int width,
++                             int height, u8 * dst, int dst_line_stride,
++                             int vmirror);
++
++int opl_hmirror_u16(const u8 * src, int src_line_stride, int width, int height,
++                  u8 * dst, int dst_line_stride)
++{
++      if (!src || !dst)
++              return OPLERR_NULL_PTR;
++
++      if (width == 0 || height == 0 || src_line_stride == 0
++          || dst_line_stride == 0)
++              return OPLERR_BAD_ARG;
++
++      if (width % 8 == 0)
++              return opl_hmirror_u16_by8(src, src_line_stride, width, height,
++                                         dst, dst_line_stride, 0);
++      else if (width % 4 == 0)
++              return opl_hmirror_u16_by4(src, src_line_stride, width, height,
++                                         dst, dst_line_stride, 0);
++      else if (width % 2 == 0)
++              return opl_hmirror_u16_by2(src, src_line_stride, width, height,
++                                         dst, dst_line_stride, 0);
++      else                    /* (width % 1) */
++              return opl_hmirror_u16_by1(src, src_line_stride, width, height,
++                                         dst, dst_line_stride, 0);
++}
++
++int opl_rotate180_u16(const u8 * src, int src_line_stride, int width,
++                    int height, u8 * dst, int dst_line_stride)
++{
++      if (!src || !dst)
++              return OPLERR_NULL_PTR;
++
++      if (width == 0 || height == 0 || src_line_stride == 0
++          || dst_line_stride == 0)
++              return OPLERR_BAD_ARG;
++
++      if (width % 8 == 0)
++              return opl_hmirror_u16_by8(src, src_line_stride, width, height,
++                                         dst, dst_line_stride, 1);
++      else if (width % 4 == 0)
++              return opl_hmirror_u16_by4(src, src_line_stride, width, height,
++                                         dst, dst_line_stride, 1);
++      else if (width % 2 == 0)
++              return opl_hmirror_u16_by2(src, src_line_stride, width, height,
++                                         dst, dst_line_stride, 1);
++      else                    /* (width % 1) */
++              return opl_hmirror_u16_by1(src, src_line_stride, width, height,
++                                         dst, dst_line_stride, 1);
++}
++
++static int opl_hmirror_u16_by1(const u8 * src, int src_line_stride, int width,
++                             int height, u8 * dst, int dst_line_stride,
++                             int vmirror)
++{
++      const u8 *src_row_addr;
++      const u8 *psrc;
++      u8 *dst_row_addr, *pdst;
++      int i, j;
++      u16 pixel;
++
++      src_row_addr = src;
++      if (vmirror) {
++              dst_row_addr = dst + dst_line_stride * (height - 1);
++              dst_line_stride = -dst_line_stride;
++      } else
++              dst_row_addr = dst;
++
++      /* Loop over all rows */
++      for (i = 0; i < height; i++) {
++              /* Loop over each pixel */
++              psrc = src_row_addr;
++              pdst = dst_row_addr + (width - 1) * BYTES_PER_PIXEL
++                  - (BYTES_PER_PIXEL - BYTES_PER_PIXEL);
++              for (j = 0; j < width; j++) {
++                      pixel = *(u16 *) psrc;
++                      *(u16 *) pdst = pixel;
++                      psrc += BYTES_PER_PIXEL;
++                      pdst -= BYTES_PER_PIXEL;
++              }
++              src_row_addr += src_line_stride;
++              dst_row_addr += dst_line_stride;
++      }
++
++      return OPLERR_SUCCESS;
++}
++
++static int opl_hmirror_u16_by2(const u8 * src, int src_line_stride, int width,
++                             int height, u8 * dst, int dst_line_stride,
++                             int vmirror)
++{
++      const u8 *src_row_addr;
++      const u8 *psrc;
++      u8 *dst_row_addr, *pdst;
++      int i, j;
++      u32 pixelsin, pixelsout;
++
++      src_row_addr = src;
++      if (vmirror) {
++              dst_row_addr = dst + dst_line_stride * (height - 1);
++              dst_line_stride = -dst_line_stride;
++      } else
++              dst_row_addr = dst;
++
++      /* Loop over all rows */
++      for (i = 0; i < height; i++) {
++              /* Loop over each pixel */
++              psrc = src_row_addr;
++              pdst = dst_row_addr + (width - 2) * BYTES_PER_PIXEL;
++              for (j = 0; j < (width >> 1); j++) {
++                      pixelsin = *(u32 *) psrc;
++                      pixelsout = rot_left_u32(pixelsin, 16);
++                      *(u32 *) pdst = pixelsout;
++                      psrc += BYTES_PER_2PIXEL;
++                      pdst -= BYTES_PER_2PIXEL;
++              }
++              src_row_addr += src_line_stride;
++              dst_row_addr += dst_line_stride;
++      }
++
++      return OPLERR_SUCCESS;
++}
++
++static int opl_hmirror_u16_by4(const u8 * src, int src_line_stride, int width,
++                             int height, u8 * dst, int dst_line_stride,
++                             int vmirror)
++{
++      const u8 *src_row_addr;
++      const u8 *psrc;
++      u8 *dst_row_addr, *pdst;
++      int i, j;
++
++      union doubleword {
++              u64 dw;
++              u32 w[2];
++      };
++
++      union doubleword inbuf;
++      union doubleword outbuf;
++
++      src_row_addr = src;
++      if (vmirror) {
++              dst_row_addr = dst + dst_line_stride * (height - 1);
++              dst_line_stride = -dst_line_stride;
++      } else
++              dst_row_addr = dst;
++
++      /* Loop over all rows */
++      for (i = 0; i < height; i++) {
++              /* Loop over each pixel */
++              psrc = src_row_addr;
++              pdst = dst_row_addr + (width - 4) * BYTES_PER_PIXEL;
++              for (j = 0; j < (width >> 2); j++) {
++                      inbuf.dw = *(u64 *) psrc;
++                      outbuf.w[0] = rot_left_u32(inbuf.w[1], 16);
++                      outbuf.w[1] = rot_left_u32(inbuf.w[0], 16);
++                      *(u64 *) pdst = outbuf.dw;
++                      psrc += BYTES_PER_4PIXEL;
++                      pdst -= BYTES_PER_4PIXEL;
++              }
++              src_row_addr += src_line_stride;
++              dst_row_addr += dst_line_stride;
++      }
++      return OPLERR_SUCCESS;
++}
++
++static int opl_hmirror_u16_by8(const u8 * src, int src_line_stride, int width,
++                             int height, u8 * dst, int dst_line_stride,
++                             int vmirror)
++{
++      const u8 *src_row_addr;
++      const u8 *psrc;
++      u8 *dst_row_addr, *pdst;
++      int i, j;
++
++      src_row_addr = src;
++      if (vmirror) {
++              dst_row_addr = dst + dst_line_stride * (height - 1);
++              dst_line_stride = -dst_line_stride;
++      } else
++              dst_row_addr = dst;
++
++      /* Loop over all rows */
++      for (i = 0; i < height; i++) {
++              /* Loop over each pixel */
++              psrc = src_row_addr;
++              pdst = dst_row_addr + (width - 1) * BYTES_PER_PIXEL - 2;
++              for (j = (width >> 3); j > 0; j--) {
++                      __asm__ volatile (
++                              "ldmia  %0!,{r2-r5}\n\t"
++                              "mov    r6, r2\n\t"
++                              "mov    r7, r3\n\t"
++                              "mov    r2, r5, ROR #16\n\t"
++                              "mov    r3, r4, ROR #16\n\t"
++                              "mov    r4, r7, ROR #16\n\t"
++                              "mov    r5, r6, ROR #16\n\t"
++                              "stmda  %1!,{r2-r5}\n\t"
++
++                              :"+r"(psrc), "+r"(pdst)
++                              :"0"(psrc), "1"(pdst)
++                              :"r2", "r3", "r4", "r5", "r6", "r7",
++                              "memory"
++                      );
++              }
++              src_row_addr += src_line_stride;
++              dst_row_addr += dst_line_stride;
++      }
++
++      return OPLERR_SUCCESS;
++}
++
++EXPORT_SYMBOL(opl_hmirror_u16);
++EXPORT_SYMBOL(opl_rotate180_u16);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/opl.h linux-2.6.28-karo/drivers/media/video/mxc/opl/opl.h
+--- linux-2.6.28/drivers/media/video/mxc/opl/opl.h     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/opl.h        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,162 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup OPLIP OPL Image Processing
++ */
++/*!
++ * @file opl.h
++ *
++ * @brief The OPL (Open Primitives Library) Image Processing library defines
++ * efficient functions for rotation and mirroring.
++ *
++ * It includes ARM9-optimized rotation and mirroring functions. It is derived
++ * from the original OPL project which is found at sourceforge.freescale.net.
++ *
++ * @ingroup OPLIP
++ */
++#ifndef __OPL_H__
++#define __OPL_H__
++
++#include <linux/types.h>
++
++#define BYTES_PER_PIXEL                       2
++#define CACHE_LINE_WORDS              8
++#define BYTES_PER_WORD                        4
++
++#define BYTES_PER_2PIXEL              (BYTES_PER_PIXEL * 2)
++#define BYTES_PER_4PIXEL              (BYTES_PER_PIXEL * 4)
++#define BYTES_PER_8PIXEL              (BYTES_PER_PIXEL * 8)
++
++#define QCIF_Y_WIDTH                  176
++#define QCIF_Y_HEIGHT                 144
++
++/*! Enumerations of opl error code */
++enum opl_error {
++      OPLERR_SUCCESS = 0,
++      OPLERR_NULL_PTR,
++      OPLERR_BAD_ARG,
++      OPLERR_DIV_BY_ZERO,
++      OPLERR_OVER_FLOW,
++      OPLERR_UNDER_FLOW,
++      OPLERR_MISALIGNED,
++};
++
++/*!
++ * @brief Rotate a 16bbp buffer 90 degrees clockwise.
++ *
++ * @param src             Pointer to the input buffer
++ * @param src_line_stride Length in bytes of a raster line of the input buffer
++ * @param width           Width in pixels of the region in the input buffer
++ * @param height          Height in pixels of the region in the input buffer
++ * @param dst             Pointer to the output buffer
++ * @param dst_line_stride Length in bytes of a raster line of the output buffer
++ *
++ * @return Standard OPL error code. See enumeration for possible result codes.
++ */
++int opl_rotate90_u16(const u8 * src, int src_line_stride, int width, int height,
++                   u8 * dst, int dst_line_stride);
++
++/*!
++ * @brief Rotate a 16bbp buffer 180 degrees clockwise.
++ *
++ * @param src             Pointer to the input buffer
++ * @param src_line_stride Length in bytes of a raster line of the input buffer
++ * @param width           Width in pixels of the region in the input buffer
++ * @param height          Height in pixels of the region in the input buffer
++ * @param dst             Pointer to the output buffer
++ * @param dst_line_stride Length in bytes of a raster line of the output buffer
++ *
++ * @return Standard OPL error code. See enumeration for possible result codes.
++ */
++int opl_rotate180_u16(const u8 * src, int src_line_stride, int width,
++                    int height, u8 * dst, int dst_line_stride);
++
++/*!
++ * @brief Rotate a 16bbp buffer 270 degrees clockwise
++ *
++ * @param src             Pointer to the input buffer
++ * @param src_line_stride Length in bytes of a raster line of the input buffer
++ * @param width           Width in pixels of the region in the input buffer
++ * @param height          Height in pixels of the region in the input buffer
++ * @param dst             Pointer to the output buffer
++ * @param dst_line_stride Length in bytes of a raster line of the output buffer
++ *
++ * @return Standard OPL error code. See enumeration for possible result codes.
++ */
++int opl_rotate270_u16(const u8 * src, int src_line_stride, int width,
++                    int height, u8 * dst, int dst_line_stride);
++
++/*!
++ * @brief Mirror a 16bpp buffer horizontally
++ *
++ * @param src             Pointer to the input buffer
++ * @param src_line_stride Length in bytes of a raster line of the input buffer
++ * @param width           Width in pixels of the region in the input buffer
++ * @param height          Height in pixels of the region in the input buffer
++ * @param dst             Pointer to the output buffer
++ * @param dst_line_stride Length in bytes of a raster line of the output buffer
++ *
++ * @return Standard OPL error code. See enumeration for possible result codes.
++ */
++int opl_hmirror_u16(const u8 * src, int src_line_stride, int width, int height,
++                  u8 * dst, int dst_line_stride);
++
++/*!
++ * @brief Mirror a 16bpp buffer vertically
++ *
++ * @param src             Pointer to the input buffer
++ * @param src_line_stride Length in bytes of a raster line of the input buffer
++ * @param width           Width in pixels of the region in the input buffer
++ * @param height          Height in pixels of the region in the input buffer
++ * @param dst             Pointer to the output buffer
++ * @param dst_line_stride Length in bytes of a raster line of the output buffer
++ *
++ * @return Standard OPL error code. See enumeration for possible result codes.
++ */
++int opl_vmirror_u16(const u8 * src, int src_line_stride, int width, int height,
++                  u8 * dst, int dst_line_stride);
++
++/*!
++ * @brief Rotate a 16bbp buffer 90 degrees clockwise and mirror vertically
++ *      It is equivalent to rotate 270 degree and mirror horizontally
++ *
++ * @param src             Pointer to the input buffer
++ * @param src_line_stride Length in bytes of a raster line of the input buffer
++ * @param width           Width in pixels of the region in the input buffer
++ * @param height          Height in pixels of the region in the input buffer
++ * @param dst             Pointer to the output buffer
++ * @param dst_line_stride Length in bytes of a raster line of the output buffer
++ *
++ * @return Standard OPL error code. See enumeration for possible result codes.
++ */
++int opl_rotate90_vmirror_u16(const u8 * src, int src_line_stride, int width,
++                           int height, u8 * dst, int dst_line_stride);
++
++/*!
++ * @brief Rotate a 16bbp buffer 270 degrees clockwise and mirror vertically
++ *      It is equivalent to rotate 90 degree and mirror horizontally
++ *
++ * @param src             Pointer to the input buffer
++ * @param src_line_stride Length in bytes of a raster line of the input buffer
++ * @param width           Width in pixels of the region in the input buffer
++ * @param height          Height in pixels of the region in the input buffer
++ * @param dst             Pointer to the output buffer
++ * @param dst_line_stride Length in bytes of a raster line of the output buffer
++ *
++ * @return Standard OPL error code. See enumeration for possible result codes.
++ */
++int opl_rotate270_vmirror_u16(const u8 * src, int src_line_stride, int width,
++                            int height, u8 * dst, int dst_line_stride);
++
++#endif                                /* __OPL_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/opl_mod.c linux-2.6.28-karo/drivers/media/video/mxc/opl/opl_mod.c
+--- linux-2.6.28/drivers/media/video/mxc/opl/opl_mod.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/opl_mod.c    2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,30 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/module.h>
++
++static __init int opl_init(void)
++{
++      return 0;
++}
++
++static void __exit opl_exit(void)
++{
++}
++
++module_init(opl_init);
++module_exit(opl_exit);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("OPL Software Rotation/Mirroring");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/rotate270_u16.c linux-2.6.28-karo/drivers/media/video/mxc/opl/rotate270_u16.c
+--- linux-2.6.28/drivers/media/video/mxc/opl/rotate270_u16.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/rotate270_u16.c      2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,285 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/module.h>
++#include "opl.h"
++
++static int opl_rotate270_u16_by16(const u8 * src, int src_line_stride,
++                                int width, int height, u8 * dst,
++                                int dst_line_stride, int vmirror);
++static int opl_rotate270_u16_by4(const u8 * src, int src_line_stride, int width,
++                               int height, u8 * dst, int dst_line_stride,
++                               int vmirror);
++static int opl_rotate270_vmirror_u16_both(const u8 * src, int src_line_stride,
++                                        int width, int height, u8 * dst,
++                                        int dst_line_stride, int vmirror);
++int opl_rotate270_u16_qcif(const u8 * src, u8 * dst);
++
++int opl_rotate270_u16(const u8 * src, int src_line_stride, int width,
++                    int height, u8 * dst, int dst_line_stride)
++{
++      return opl_rotate270_vmirror_u16_both(src, src_line_stride, width,
++                                            height, dst, dst_line_stride, 0);
++}
++
++int opl_rotate270_vmirror_u16(const u8 * src, int src_line_stride, int width,
++                            int height, u8 * dst, int dst_line_stride)
++{
++      return opl_rotate270_vmirror_u16_both(src, src_line_stride, width,
++                                            height, dst, dst_line_stride, 1);
++}
++
++static int opl_rotate270_vmirror_u16_both(const u8 * src, int src_line_stride,
++                                        int width, int height, u8 * dst,
++                                        int dst_line_stride, int vmirror)
++{
++      const int BLOCK_SIZE_PIXELS = CACHE_LINE_WORDS * BYTES_PER_WORD
++          / BYTES_PER_PIXEL;
++      const int BLOCK_SIZE_PIXELS_BY4 = CACHE_LINE_WORDS * BYTES_PER_WORD
++          / BYTES_PER_PIXEL / 4;
++
++      if (!src || !dst)
++              return OPLERR_NULL_PTR;
++
++      if (width == 0 || height == 0 || src_line_stride == 0
++          || dst_line_stride == 0)
++              return OPLERR_BAD_ARG;
++
++      /* The QCIF algorithm doesn't support vertical mirroring */
++      if (vmirror == 0 && width == QCIF_Y_WIDTH && height == QCIF_Y_HEIGHT
++          && src_line_stride == QCIF_Y_WIDTH * 2
++          && src_line_stride == QCIF_Y_HEIGHT * 2)
++              return opl_rotate270_u16_qcif(src, dst);
++      else if (width % BLOCK_SIZE_PIXELS == 0
++               && height % BLOCK_SIZE_PIXELS == 0)
++              return opl_rotate270_u16_by16(src, src_line_stride, width,
++                                            height, dst, dst_line_stride,
++                                            vmirror);
++      else if (width % BLOCK_SIZE_PIXELS_BY4 == 0
++               && height % BLOCK_SIZE_PIXELS_BY4 == 0)
++              return opl_rotate270_u16_by4(src, src_line_stride, width,
++                                           height, dst, dst_line_stride,
++                                           vmirror);
++      else
++              return OPLERR_BAD_ARG;
++}
++
++/*
++ * Rotate Counter Clockwise, divide RGB component into 16 row strips, read
++ * non sequentially and write sequentially. This is done in 16 line strips
++ * so that the cache is used better. Cachelines are 8 words = 32 bytes. Pixels
++ * are 2 bytes. The 16 reads will be cache misses, but the next 240 should
++ * be from cache. The writes to the output buffer will be sequential for 16
++ * writes.
++ *
++ * Example: 
++ * Input data matrix:     output matrix
++ *
++ * 0 | 1 | 2 | 3 | 4 |      4 | 0 | 0 | 3 | 
++ * 4 | 3 | 2 | 1 | 0 |      3 | 1 | 9 | 6 |
++ * 6 | 7 | 8 | 9 | 0 |      2 | 2 | 8 | 2 |
++ * 5 | 3 | 2 | 6 | 3 |      1 | 3 | 7 | 3 |
++ * ^                      0 | 4 | 6 | 5 | < Write the input data sequentially
++ * Read first column
++ * Start at the bottom
++ * Move to next column and repeat
++ *
++ * Loop over k decreasing (blocks)
++ * in_block_ptr = src + (((RGB_HEIGHT_PIXELS / BLOCK_SIZE_PIXELS) - k)
++ *                * BLOCK_SIZE_PIXELS) * (RGB_WIDTH_BYTES)
++ * out_block_ptr = dst + (((RGB_HEIGHT_PIXELS / BLOCK_SIZE_PIXELS) - k)
++ *                * BLOCK_SIZE_BYTES) + (RGB_WIDTH_PIXELS - 1)
++ *                * RGB_HEIGHT_PIXELS * BYTES_PER_PIXEL 
++ *
++ * Loop over i decreasing (width)
++ * Each pix:
++ * in_block_ptr += RGB_WIDTH_BYTES
++ * out_block_ptr += 4
++ *
++ * Each row of block:
++ * in_block_ptr -= RGB_WIDTH_BYTES * BLOCK_SIZE_PIXELS - 2
++ * out_block_ptr -= RGB_HEIGHT_PIXELS * BYTES_PER_PIXEL + 2 * BLOCK_SIZE_PIXELS;
++ *
++ * It may perform vertical mirroring too depending on the vmirror flag.
++ */
++static int opl_rotate270_u16_by16(const u8 * src, int src_line_stride,
++                                int width, int height, u8 * dst,
++                                int dst_line_stride, int vmirror)
++{
++      const int BLOCK_SIZE_PIXELS = CACHE_LINE_WORDS * BYTES_PER_WORD
++          / BYTES_PER_PIXEL;
++      const int IN_INDEX = src_line_stride * BLOCK_SIZE_PIXELS
++          - BYTES_PER_PIXEL;
++      const int OUT_INDEX = vmirror ?
++          -dst_line_stride + BYTES_PER_PIXEL * BLOCK_SIZE_PIXELS
++          : dst_line_stride + BYTES_PER_PIXEL * BLOCK_SIZE_PIXELS;
++      const u8 *in_block_ptr;
++      u8 *out_block_ptr;
++      int i, k;
++
++      for (k = height / BLOCK_SIZE_PIXELS; k > 0; k--) {
++              in_block_ptr = src + (((height / BLOCK_SIZE_PIXELS) - k)
++                                    * BLOCK_SIZE_PIXELS) * src_line_stride;
++              out_block_ptr = dst + (((height / BLOCK_SIZE_PIXELS) - k)
++                                     * BLOCK_SIZE_PIXELS * BYTES_PER_PIXEL) +
++                  (width - 1) * dst_line_stride;
++
++              /*
++              * For vertical mirroring the writing starts from the
++              * first line
++              */
++              if (vmirror)
++                      out_block_ptr -= dst_line_stride * (width - 1);
++
++              for (i = width; i > 0; i--) {
++                      __asm__ volatile (
++                              "ldrh   r2, [%0], %4\n\t"
++                              "ldrh   r3, [%0], %4\n\t"
++                              "ldrh   r4, [%0], %4\n\t"
++                              "ldrh   r5, [%0], %4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              "ldrh   r2, [%0], %4\n\t"
++                              "ldrh   r3, [%0], %4\n\t"
++                              "ldrh   r4, [%0], %4\n\t"
++                              "ldrh   r5, [%0], %4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              "ldrh   r2, [%0], %4\n\t"
++                              "ldrh   r3, [%0], %4\n\t"
++                              "ldrh   r4, [%0], %4\n\t"
++                              "ldrh   r5, [%0], %4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              "ldrh   r2, [%0], %4\n\t"
++                              "ldrh   r3, [%0], %4\n\t"
++                              "ldrh   r4, [%0], %4\n\t"
++                              "ldrh   r5, [%0], %4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              :"+r" (in_block_ptr), "+r"(out_block_ptr)       /* output */
++                              :"0"(in_block_ptr), "1"(out_block_ptr), "r"(src_line_stride)    /* input  */
++                              :"r2", "r3", "r4", "r5", "memory"       /* modify */
++                      );
++                      in_block_ptr -= IN_INDEX;
++                      out_block_ptr -= OUT_INDEX;
++              }
++      }
++
++      return OPLERR_SUCCESS;
++}
++
++/*
++ * Rotate Counter Clockwise, divide RGB component into 4 row strips, read
++ * non sequentially and write sequentially. This is done in 4 line strips
++ * so that the cache is used better. Cachelines are 8 words = 32 bytes. Pixels
++ * are 2 bytes. The 4 reads will be cache misses, but the next 60 should
++ * be from cache. The writes to the output buffer will be sequential for 4
++ * writes.
++ *
++ * Example: 
++ * Input data matrix:     output matrix
++ *
++ * 0 | 1 | 2 | 3 | 4 |      4 | 0 | 0 | 3 | 
++ * 4 | 3 | 2 | 1 | 0 |      3 | 1 | 9 | 6 |
++ * 6 | 7 | 8 | 9 | 0 |      2 | 2 | 8 | 2 |
++ * 5 | 3 | 2 | 6 | 3 |      1 | 3 | 7 | 3 |
++ * ^                      0 | 4 | 6 | 5 | < Write the input data sequentially
++ * Read first column
++ * Start at the bottom
++ * Move to next column and repeat
++ *
++ * Loop over k decreasing (blocks)
++ * in_block_ptr = src + (((RGB_HEIGHT_PIXELS / BLOCK_SIZE_PIXELS) - k)
++ *                * BLOCK_SIZE_PIXELS) * (RGB_WIDTH_BYTES)
++ * out_block_ptr = dst + (((RGB_HEIGHT_PIXELS / BLOCK_SIZE_PIXELS) - k)
++ *                * BLOCK_SIZE_BYTES) + (RGB_WIDTH_PIXELS - 1)
++ *                * RGB_HEIGHT_PIXELS * BYTES_PER_PIXEL 
++ *
++ * Loop over i decreasing (width)
++ * Each pix:
++ * in_block_ptr += RGB_WIDTH_BYTES
++ * out_block_ptr += 4
++ *
++ * Each row of block:
++ * in_block_ptr -= RGB_WIDTH_BYTES * BLOCK_SIZE_PIXELS - 2
++ * out_block_ptr -= RGB_HEIGHT_PIXELS * BYTES_PER_PIXEL + 2 * BLOCK_SIZE_PIXELS;
++ *
++ * It may perform vertical mirroring too depending on the vmirror flag.
++ */
++static int opl_rotate270_u16_by4(const u8 * src, int src_line_stride, int width,
++                               int height, u8 * dst, int dst_line_stride,
++                               int vmirror)
++{
++      const int BLOCK_SIZE_PIXELS = CACHE_LINE_WORDS * BYTES_PER_WORD
++          / BYTES_PER_PIXEL / 4;
++      const int IN_INDEX = src_line_stride * BLOCK_SIZE_PIXELS
++          - BYTES_PER_PIXEL;
++      const int OUT_INDEX = vmirror ?
++          -dst_line_stride + BYTES_PER_PIXEL * BLOCK_SIZE_PIXELS
++          : dst_line_stride + BYTES_PER_PIXEL * BLOCK_SIZE_PIXELS;
++      const u8 *in_block_ptr;
++      u8 *out_block_ptr;
++      int i, k;
++
++      for (k = height / BLOCK_SIZE_PIXELS; k > 0; k--) {
++              in_block_ptr = src + (((height / BLOCK_SIZE_PIXELS) - k)
++                                    * BLOCK_SIZE_PIXELS) * src_line_stride;
++              out_block_ptr = dst + (((height / BLOCK_SIZE_PIXELS) - k)
++                                     * BLOCK_SIZE_PIXELS * BYTES_PER_PIXEL)
++                  + (width - 1) * dst_line_stride;
++
++              /*
++              * For vertical mirroring the writing starts from the
++              * first line
++              */
++              if (vmirror)
++                      out_block_ptr -= dst_line_stride * (width - 1);
++
++              for (i = width; i > 0; i--) {
++                      __asm__ volatile (
++                              "ldrh   r2, [%0], %4\n\t"
++                              "ldrh   r3, [%0], %4\n\t"
++                              "ldrh   r4, [%0], %4\n\t"
++                              "ldrh   r5, [%0], %4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              :"+r" (in_block_ptr), "+r"(out_block_ptr)       /* output */
++                              :"0"(in_block_ptr), "1"(out_block_ptr), "r"(src_line_stride)    /* input  */
++                              :"r2", "r3", "r4", "r5", "memory"       /* modify */
++                      );
++                      in_block_ptr -= IN_INDEX;
++                      out_block_ptr -= OUT_INDEX;
++              }
++      }
++
++      return OPLERR_SUCCESS;
++}
++
++EXPORT_SYMBOL(opl_rotate270_u16);
++EXPORT_SYMBOL(opl_rotate270_vmirror_u16);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/rotate270_u16_qcif.S linux-2.6.28-karo/drivers/media/video/mxc/opl/rotate270_u16_qcif.S
+--- linux-2.6.28/drivers/media/video/mxc/opl/rotate270_u16_qcif.S      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/rotate270_u16_qcif.S 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,70 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++#include <linux/linkage.h>
++
++      .text
++      .align  2
++ENTRY(opl_rotate270_u16_qcif)
++      STMFD    sp!,{r4-r10}
++        MOV      r12,#0x160
++        MOV      r10,#0x90
++        MOV      r3,r10,LSR #4
++.L1.16:
++        RSB      r2,r3,r10,LSR #4
++        MOV      r5,r2,LSL #5
++        MOV      r4,r12,LSR #1
++        SMULBB   r4,r5,r4
++        ADD      r2,r1,r2,LSL #5
++        ADD      r5,r2,#0xc000
++        ADD      r5,r5,#0x4e0
++        MOV      r2,r12,LSR #1
++        ADD      r4,r0,r4
++.L1.52:
++        LDRH     r6,[r4],r12
++        LDRH     r7,[r4],r12
++        LDRH     r8,[r4],r12
++        LDRH     r9,[r4],r12
++        ORR      r6,r6,r7,LSL #16
++        ORR      r7,r8,r9,LSL #16
++        STMIA    r5!,{r6,r7}
++        SUBS     r2,r2,#1
++        LDRH     r6,[r4],r12
++        LDRH     r7,[r4],r12
++        LDRH     r8,[r4],r12
++        LDRH     r9,[r4],r12
++        ORR      r6,r6,r7,LSL #16
++        ORR      r7,r8,r9,LSL #16
++        STMIA    r5!,{r6,r7}
++        LDRH     r6,[r4],r12
++        LDRH     r7,[r4],r12
++        LDRH     r8,[r4],r12
++        LDRH     r9,[r4],r12
++        ORR      r6,r6,r7,LSL #16
++        ORR      r7,r8,r9,LSL #16
++        STMIA    r5!,{r6,r7}
++        LDRH     r6,[r4],r12
++        LDRH     r7,[r4],r12
++        LDRH     r8,[r4],r12
++        LDRH     r9,[r4],r12
++        ORR      r6,r6,r7,LSL #16
++        ORR      r7,r8,r9,LSL #16
++        SUB      r4,r4,#0x1500
++        STMIA    r5,{r6,r7}
++        SUB      r5,r5,#0x138
++        SUB      r4,r4,#0xfe
++        BGT      .L1.52
++        SUBS     r3,r3,#1
++        BGT      .L1.16
++        LDMFD    sp!,{r4-r10}
++        BX       lr
++      .size   opl_rotate270_u16_qcif, . - opl_rotate270_u16_qcif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/rotate90_u16.c linux-2.6.28-karo/drivers/media/video/mxc/opl/rotate90_u16.c
+--- linux-2.6.28/drivers/media/video/mxc/opl/rotate90_u16.c    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/rotate90_u16.c       2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,220 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/module.h>
++#include "opl.h"
++
++static int opl_rotate90_u16_by16(const u8 * src, int src_line_stride, int width,
++                               int height, u8 * dst, int dst_line_stride,
++                               int vmirror);
++static int opl_rotate90_u16_by4(const u8 * src, int src_line_stride, int width,
++                              int height, u8 * dst, int dst_line_stride,
++                              int vmirror);
++static int opl_rotate90_vmirror_u16_both(const u8 * src, int src_line_stride,
++                                       int width, int height, u8 * dst,
++                                       int dst_line_stride, int vmirror);
++int opl_rotate90_u16_qcif(const u8 * src, u8 * dst);
++
++int opl_rotate90_u16(const u8 * src, int src_line_stride, int width, int height,
++                   u8 * dst, int dst_line_stride)
++{
++      return opl_rotate90_vmirror_u16_both(src, src_line_stride, width,
++                                          height, dst, dst_line_stride, 0);
++}
++
++int opl_rotate90_vmirror_u16(const u8 * src, int src_line_stride, int width,
++                          int height, u8 * dst, int dst_line_stride)
++{
++      return opl_rotate90_vmirror_u16_both(src, src_line_stride, width,
++                                          height, dst, dst_line_stride, 1);
++}
++
++static int opl_rotate90_vmirror_u16_both(const u8 * src, int src_line_stride,
++                                       int width, int height, u8 * dst,
++                                       int dst_line_stride, int vmirror)
++{
++      const int BLOCK_SIZE_PIXELS = CACHE_LINE_WORDS * BYTES_PER_WORD
++          / BYTES_PER_PIXEL;
++      const int BLOCK_SIZE_PIXELS_BY4 = CACHE_LINE_WORDS * BYTES_PER_WORD
++          / BYTES_PER_PIXEL / 4;
++
++      if (!src || !dst)
++              return OPLERR_NULL_PTR;
++
++      if (width == 0 || height == 0 || src_line_stride == 0
++          || dst_line_stride == 0)
++              return OPLERR_BAD_ARG;
++
++      /* The QCIF algorithm doesn't support vertical mirroring */
++      if (vmirror == 0 && width == QCIF_Y_WIDTH && height == QCIF_Y_HEIGHT
++          && src_line_stride == QCIF_Y_WIDTH * 2
++          && src_line_stride == QCIF_Y_HEIGHT * 2)
++              return opl_rotate90_u16_qcif(src, dst);
++      else if (width % BLOCK_SIZE_PIXELS == 0
++               && height % BLOCK_SIZE_PIXELS == 0)
++              return opl_rotate90_u16_by16(src, src_line_stride, width,
++                                           height, dst, dst_line_stride,
++                                           vmirror);
++      else if (width % BLOCK_SIZE_PIXELS_BY4 == 0
++               && height % BLOCK_SIZE_PIXELS_BY4 == 0)
++              return opl_rotate90_u16_by4(src, src_line_stride, width, height,
++                                          dst, dst_line_stride, vmirror);
++      else
++              return OPLERR_BAD_ARG;
++}
++
++/*
++ * Performs clockwise rotation (and possibly vertical mirroring depending
++ * on the vmirror flag) using block sizes of 16x16
++ * The algorithm is similar to 270 degree clockwise rotation algorithm
++ */
++static int opl_rotate90_u16_by16(const u8 * src, int src_line_stride, int width,
++                               int height, u8 * dst, int dst_line_stride,
++                               int vmirror)
++{
++      const int BLOCK_SIZE_PIXELS = CACHE_LINE_WORDS * BYTES_PER_WORD
++          / BYTES_PER_PIXEL;
++      const int BLOCK_SIZE_BYTES = BYTES_PER_PIXEL * BLOCK_SIZE_PIXELS;
++      const int IN_INDEX = src_line_stride * BLOCK_SIZE_PIXELS
++          + BYTES_PER_PIXEL;
++      const int OUT_INDEX = vmirror ?
++          -dst_line_stride - BLOCK_SIZE_BYTES
++          : dst_line_stride - BLOCK_SIZE_BYTES;
++      const u8 *in_block_ptr;
++      u8 *out_block_ptr;
++      int i, k;
++
++      for (k = height / BLOCK_SIZE_PIXELS; k > 0; k--) {
++              in_block_ptr = src + src_line_stride * (height - 1)
++                  - (src_line_stride * BLOCK_SIZE_PIXELS *
++                     (height / BLOCK_SIZE_PIXELS - k));
++              out_block_ptr = dst + BYTES_PER_PIXEL * BLOCK_SIZE_PIXELS *
++                  ((height / BLOCK_SIZE_PIXELS) - k);
++
++              /*
++               * For vertical mirroring the writing starts from the
++               * bottom line
++               */
++              if (vmirror)
++                      out_block_ptr += dst_line_stride * (width - 1);
++
++              for (i = width; i > 0; i--) {
++                      __asm__ volatile (
++                              "ldrh   r2, [%0], -%4\n\t"
++                              "ldrh   r3, [%0], -%4\n\t"
++                              "ldrh   r4, [%0], -%4\n\t"
++                              "ldrh   r5, [%0], -%4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              "ldrh   r2, [%0], -%4\n\t"
++                              "ldrh   r3, [%0], -%4\n\t"
++                              "ldrh   r4, [%0], -%4\n\t"
++                              "ldrh   r5, [%0], -%4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              "ldrh   r2, [%0], -%4\n\t"
++                              "ldrh   r3, [%0], -%4\n\t"
++                              "ldrh   r4, [%0], -%4\n\t"
++                              "ldrh   r5, [%0], -%4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              "ldrh   r2, [%0], -%4\n\t"
++                              "ldrh   r3, [%0], -%4\n\t"
++                              "ldrh   r4, [%0], -%4\n\t"
++                              "ldrh   r5, [%0], -%4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              :"+r" (in_block_ptr), "+r"(out_block_ptr)       /* output */
++                              :"0"(in_block_ptr), "1"(out_block_ptr), "r"(src_line_stride)    /* input  */
++                              :"r2", "r3", "r4", "r5", "memory"       /* modify */
++                      );
++                      in_block_ptr += IN_INDEX;
++                      out_block_ptr += OUT_INDEX;
++              }
++      }
++
++      return OPLERR_SUCCESS;
++}
++
++/*
++ * Performs clockwise rotation (and possibly vertical mirroring depending
++ * on the vmirror flag) using block sizes of 4x4
++ * The algorithm is similar to 270 degree clockwise rotation algorithm
++ */
++static int opl_rotate90_u16_by4(const u8 * src, int src_line_stride, int width,
++                              int height, u8 * dst, int dst_line_stride,
++                              int vmirror)
++{
++      const int BLOCK_SIZE_PIXELS = CACHE_LINE_WORDS * BYTES_PER_WORD
++          / BYTES_PER_PIXEL / 4;
++      const int BLOCK_SIZE_BYTES = BYTES_PER_PIXEL * BLOCK_SIZE_PIXELS;
++      const int IN_INDEX = src_line_stride * BLOCK_SIZE_PIXELS
++          + BYTES_PER_PIXEL;
++      const int OUT_INDEX = vmirror ?
++          -dst_line_stride - BLOCK_SIZE_BYTES
++          : dst_line_stride - BLOCK_SIZE_BYTES;
++      const u8 *in_block_ptr;
++      u8 *out_block_ptr;
++      int i, k;
++
++      for (k = height / BLOCK_SIZE_PIXELS; k > 0; k--) {
++              in_block_ptr = src + src_line_stride * (height - 1)
++                  - (src_line_stride * BLOCK_SIZE_PIXELS *
++                     (height / BLOCK_SIZE_PIXELS - k));
++              out_block_ptr = dst + BYTES_PER_PIXEL * BLOCK_SIZE_PIXELS
++                  * ((height / BLOCK_SIZE_PIXELS) - k);
++
++              /*
++               * For horizontal mirroring the writing starts from the
++               * bottom line
++               */
++              if (vmirror)
++                      out_block_ptr += dst_line_stride * (width - 1);
++
++              for (i = width; i > 0; i--) {
++                      __asm__ volatile (
++                              "ldrh   r2, [%0], -%4\n\t"
++                              "ldrh   r3, [%0], -%4\n\t"
++                              "ldrh   r4, [%0], -%4\n\t"
++                              "ldrh   r5, [%0], -%4\n\t"
++                              "orr    r2, r2, r3, lsl #16\n\t"
++                              "orr    r4, r4, r5, lsl #16\n\t"
++                              "str    r2, [%1], #4\n\t"
++                              "str    r4, [%1], #4\n\t"
++
++                              :"+r" (in_block_ptr), "+r"(out_block_ptr)       /* output */
++                              :"0"(in_block_ptr), "1"(out_block_ptr), "r"(src_line_stride)    /* input  */
++                              :"r2", "r3", "r4", "r5", "memory"       /* modify */
++                      );
++                      in_block_ptr += IN_INDEX;
++                      out_block_ptr += OUT_INDEX;
++              }
++      }
++
++      return OPLERR_SUCCESS;
++}
++
++EXPORT_SYMBOL(opl_rotate90_u16);
++EXPORT_SYMBOL(opl_rotate90_vmirror_u16);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/rotate90_u16_qcif.S linux-2.6.28-karo/drivers/media/video/mxc/opl/rotate90_u16_qcif.S
+--- linux-2.6.28/drivers/media/video/mxc/opl/rotate90_u16_qcif.S       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/rotate90_u16_qcif.S  2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,71 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++#include <linux/linkage.h>
++
++      .text
++      .align  2
++ENTRY(opl_rotate90_u16_qcif)
++        STMFD    sp!,{r4-r10}
++        MOV      r12,#0x160
++        MOV      r10,#0x90
++        MOV      r3,r10,LSR #4
++.L1.216:
++        RSB      r2,r3,r10,LSR #4
++        MOV      r4,#0x20
++        SMULBB   r5,r4,r2
++        MOV      r4,#0x1600
++        SMULBB   r2,r4,r2
++        ADD      r4,r0,#0xc000
++        ADD      r4,r4,#0x4a0
++        SUB      r4,r4,r2
++        MOV      r2,r12,LSR #1
++        ADD      r5,r1,r5
++.L1.256:
++        LDRH     r6,[r4],-r12
++        LDRH     r7,[r4],-r12
++        LDRH     r8,[r4],-r12
++        LDRH     r9,[r4],-r12
++        ORR      r6,r6,r7,LSL #16
++        ORR      r7,r8,r9,LSL #16
++        STMIA    r5!,{r6,r7}
++        SUBS     r2,r2,#1
++        LDRH     r6,[r4],-r12
++        LDRH     r7,[r4],-r12
++        LDRH     r8,[r4],-r12
++        LDRH     r9,[r4],-r12
++        ORR      r6,r6,r7,LSL #16
++        ORR      r7,r8,r9,LSL #16
++        STMIA    r5!,{r6,r7}
++        LDRH     r6,[r4],-r12
++        LDRH     r7,[r4],-r12
++        LDRH     r8,[r4],-r12
++        LDRH     r9,[r4],-r12
++        ORR      r6,r6,r7,LSL #16
++        ORR      r7,r8,r9,LSL #16
++        STMIA    r5!,{r6,r7}
++        LDRH     r6,[r4],-r12
++        LDRH     r7,[r4],-r12
++        LDRH     r8,[r4],-r12
++        LDRH     r9,[r4],-r12
++        ORR      r6,r6,r7,LSL #16
++        ORR      r7,r8,r9,LSL #16
++        ADD      r4,r4,#0x1600
++        STMIA    r5!,{r6,r7}
++        ADD      r5,r5,#0x100
++        ADD      r4,r4,#2
++        BGT      .L1.256
++        SUBS     r3,r3,#1
++        BGT      .L1.216
++        LDMFD    sp!,{r4-r10}
++        BX       lr
++      .size   opl_rotate90_u16_qcif, . - opl_rotate90_u16_qcif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/opl/vmirror_u16.c linux-2.6.28-karo/drivers/media/video/mxc/opl/vmirror_u16.c
+--- linux-2.6.28/drivers/media/video/mxc/opl/vmirror_u16.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/opl/vmirror_u16.c        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,46 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++#include <linux/module.h>
++#include <linux/string.h>
++#include "opl.h"
++
++int opl_vmirror_u16(const u8 * src, int src_line_stride, int width, int height,
++                  u8 * dst, int dst_line_stride)
++{
++      const u8 *src_row_addr;
++      u8 *dst_row_addr;
++      int i;
++
++      if (!src || !dst)
++              return OPLERR_NULL_PTR;
++
++      if (width == 0 || height == 0 || src_line_stride == 0
++          || dst_line_stride == 0)
++              return OPLERR_BAD_ARG;
++
++      src_row_addr = src;
++      dst_row_addr = dst + (height - 1) * dst_line_stride;
++
++      /* Loop over all rows */
++      for (i = 0; i < height; i++) {
++              /* memcpy each row */
++              memcpy(dst_row_addr, src_row_addr, BYTES_PER_PIXEL * width);
++              src_row_addr += src_line_stride;
++              dst_row_addr -= dst_line_stride;
++      }
++
++      return OPLERR_SUCCESS;
++}
++
++EXPORT_SYMBOL(opl_vmirror_u16);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/output/Kconfig linux-2.6.28-karo/drivers/media/video/mxc/output/Kconfig
+--- linux-2.6.28/drivers/media/video/mxc/output/Kconfig        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/output/Kconfig   2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,19 @@
++config VIDEO_MXC_OUTPUT_DEBUG
++      bool "Verbose MXC video output debugging"
++      depends on VIDEO_MXC_OUTPUT
++      default n
++
++config VIDEO_MXC_IPU_OUTPUT
++      bool 
++      depends on VIDEO_MXC_OUTPUT && MXC_IPU
++      default y
++      ---help---
++        This is the video4linux2 driver for IPU post processing video output.
++
++config VIDEO_MXC_EMMA_OUTPUT
++      tristate "EMMA video output postprocessor"
++      depends on VIDEO_MXC_OUTPUT && MXC_EMMA && FB_IMX
++      default y
++      ---help---
++        This is the video4linux2 driver for EMMA post processing video output.
++
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/output/Makefile linux-2.6.28-karo/drivers/media/video/mxc/output/Makefile
+--- linux-2.6.28/drivers/media/video/mxc/output/Makefile       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/output/Makefile  2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,8 @@
++ifneq ($(CONFIG_VIDEO_MXC_OUTPUT_DEBUG),)
++      EXTRA_CFLAGS += -DDEBUG
++endif
++
++mx27_output-objs := mx27_v4l2_output.o mx27_pp.o
++obj-$(CONFIG_VIDEO_MXC_EMMA_OUTPUT) += mx27_output.o 
++
++obj-$(CONFIG_VIDEO_MXC_IPU_OUTPUT)    += mxc_v4l2_output.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/output/mx27_pp.c linux-2.6.28-karo/drivers/media/video/mxc/output/mx27_pp.c
+--- linux-2.6.28/drivers/media/video/mxc/output/mx27_pp.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/output/mx27_pp.c 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,1114 @@
++/*
++ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_pp.c
++ *
++ * @brief MX27 V4L2 Video Output Driver
++ *
++ * Video4Linux2 Output Device using MX27 eMMA Post-processing functionality.
++ *
++ * @ingroup MXC_V4L2_OUTPUT
++ */
++#include <linux/kernel.h>
++#include <linux/string.h>
++#include <linux/module.h>
++#include <linux/fb.h>
++#include <linux/clk.h>
++#include <linux/interrupt.h>
++#include <asm/io.h>
++#include <mach/mx27.h>
++
++#include "mx27_pp.h"
++#include "mxc_v4l2_output.h"
++
++#define SCALE_RETRY   32      /* to be more relax, less precise */
++#define PP_SKIP               1
++#define PP_TBL_MAX    40
++
++static unsigned short scale_tbl[PP_TBL_MAX];
++static int g_hlen, g_vlen;
++
++static emma_pp_cfg g_pp_cfg;
++static int g_disp_num = 0;
++static char pp_dev[] = "emma_pp";
++
++/*!
++ * @brief PP resizing routines
++ */
++static int scale_2d(emma_pp_scale *sz);
++
++static irqreturn_t pp_isr(int irq, void *dev_id);
++static int set_output_addr(emma_pp_cfg *cfg, vout_data *vout);
++static int pphw_reset(void);
++static int pphw_enable(int flag);
++static int pphw_ptr(emma_pp_cfg *cfg);
++static int pphw_outptr(emma_pp_cfg *cfg);
++static int pphw_cfg(emma_pp_cfg *cfg);
++static int pphw_isr(void);
++static int pphw_init(void);
++static void pphw_exit(void);
++
++#define PP_DUMP(reg)  pr_debug("%s[%08lx]\t = 0x%08x\n", #reg, \
++                      reg - IO_ADDRESS(EMMA_PP_BASE_ADDR) + EMMA_PP_BASE_ADDR, __raw_readl(reg))
++void pp_dump(void)
++{
++      PP_DUMP(PP_CNTL);
++      PP_DUMP(PP_INTRCNTL);
++      PP_DUMP(PP_INTRSTATUS);
++      PP_DUMP(PP_SOURCE_Y_PTR);
++      PP_DUMP(PP_SOURCE_CB_PTR);
++      PP_DUMP(PP_SOURCE_CR_PTR);
++      PP_DUMP(PP_DEST_RGB_PTR);
++      PP_DUMP(PP_QUANTIZER_PTR);
++      PP_DUMP(PP_PROCESS_FRAME_PARA);
++      PP_DUMP(PP_SOURCE_FRAME_WIDTH);
++      PP_DUMP(PP_DEST_DISPLAY_WIDTH);
++      PP_DUMP(PP_DEST_IMAGE_SIZE);
++      PP_DUMP(PP_DEST_FRAME_FMT_CNTL);
++      PP_DUMP(PP_RESIZE_INDEX);
++      PP_DUMP(PP_CSC_COEF_0123);
++      PP_DUMP(PP_CSC_COEF_4);
++}
++
++static const unsigned char pp_coeftab[] = {
++      2, 1,
++      19, 10,
++      17, 9,
++      15, 8,
++      13, 7,
++      11, 6,
++      20, 11,
++      9, 5,
++      16, 9,
++      7, 4,
++      19, 11,
++      12, 7,
++      17, 10,
++      5, 3,
++      18, 11,
++      13, 8,
++      8, 5,
++      19, 12,
++      11, 7,
++      14, 9,
++      17, 11,
++      20, 13,
++      3, 2,
++      19, 13,
++      16, 11,
++      13, 9,
++      10, 7,
++      17, 12,
++      7, 5,
++      18, 13,
++      11, 8,
++      15, 11,
++      19, 14,
++      4, 3,
++      17, 13,
++      13, 10,
++      9, 7,
++      14, 11,
++      19, 15,
++      5, 4,
++      16, 13,
++      11, 9,
++      17, 14,
++      6, 5,
++      19, 16,
++      13, 11,
++      20, 17,
++      7, 6,
++      15, 13,
++      8, 7,
++      17, 15,
++      9, 8,
++      19, 17,
++      10, 9,
++      11, 10,
++      12, 11,
++      13, 12,
++      14, 13,
++      15, 14,
++      16, 15,
++      17, 16,
++      18, 17,
++      19, 18,
++      20, 19,
++      1, 1,
++      19, 20,
++      18, 19,
++      17, 18,
++      16, 17,
++      15, 16,
++      14, 15,
++      13, 14,
++      12, 13,
++      11, 12,
++      10, 11,
++      9, 10,
++      17, 19,
++      8, 9,
++      15, 17,
++      7, 8,
++      13, 15,
++      6, 7,
++      17, 20,
++      11, 13,
++      16, 19,
++      5, 6,
++      14, 17,
++      9, 11,
++      13, 16,
++      4, 5,
++      15, 19,
++      11, 14,
++      7, 9,
++      10, 13,
++      13, 17,
++      3, 4,
++      14, 19,
++      11, 15,
++      8, 11,
++      13, 18,
++      5, 7,
++      12, 17,
++      7, 10,
++      9, 13,
++      11, 16,
++      13, 19,
++      2, 3,
++      13, 20,
++      11, 17,
++      9, 14,
++      7, 11,
++      12, 19,
++      5, 8,
++      8, 13,
++      11, 18,
++      3, 5,
++      10, 17,
++      7, 12,
++      11, 19,
++      4, 7,
++      9, 16,
++      5, 9,
++      11, 20,
++      6, 11,
++      7, 13,
++      8, 15,
++      9, 17,
++      10, 19,
++      1, 2,
++      9, 19,
++      8, 17,
++      7, 15,
++      6, 13,
++      5, 11,
++      9, 20,
++      4, 9,
++      7, 16,
++      3, 7,
++      8, 19,
++      5, 12,
++      7, 17,
++      2, 5,
++      7, 18,
++      5, 13,
++      3, 8,
++      7, 19,
++      4, 11,
++      5, 14,
++      6, 17,
++      7, 20,
++      1, 3,
++      6, 19,
++      5, 16,
++      4, 13,
++      3, 10,
++      5, 17,
++      2, 7,
++      5, 18,
++      3, 11,
++      4, 15,
++      5, 19,
++      1, 4
++};
++
++/*!
++ * @brief Set PP input address.
++ * @param ptr The pointer to the Y value of input
++ * @return    Zero on success, others on failure
++ */
++int pp_ptr(unsigned long ptr, struct v4l2_mxc_offset offset)
++{
++      g_pp_cfg.ptr.y = ptr + offset.y_offset;
++      g_pp_cfg.ptr.u = ptr + offset.u_offset;
++      g_pp_cfg.ptr.v = ptr + offset.v_offset;
++      g_pp_cfg.ptr.qp = ptr + offset.qp_offset;
++
++      return pphw_ptr(&g_pp_cfg);
++}
++
++/*!
++ * @brief Enable or disable PP.
++ * @param flag        Zero to disable PP, others to enable PP
++ * @return    Zero on success, others on failure
++ */
++int pp_enable(int flag)
++{
++      return pphw_enable(flag);
++}
++
++/*!
++ * @brief Get the display No. of last completed PP frame.
++ * @return    The display No. of last completed PP frame.
++ */
++int pp_num_last(void)
++{
++      return g_disp_num ? 0 : 1;
++}
++
++/*!
++ * @brief Initialize PP.
++ * @param vout        Pointer to _vout_data structure
++ * @return    Zero on success, others on failure
++ */
++static int interrupts;
++
++int pp_init(vout_data *vout)
++{
++      int ret = pphw_init();
++      if (ret) {
++              return ret;
++      }
++      ret = pphw_enable(0);
++      if (ret) {
++              pphw_exit();
++              return ret;
++      }
++      interrupts = 0;
++      ret = request_irq(MXC_INT_EMMAPP, pp_isr, 0, pp_dev, vout);
++      if (ret) {
++              pphw_exit();
++              return ret;
++      }
++      return 0;
++}
++
++/*!
++ * @brief Deinitialize PP.
++ * @param vout        Pointer to _vout_data structure
++ */
++void pp_exit(vout_data *vout)
++{
++      free_irq(MXC_INT_EMMAPP, vout);
++      pr_debug("%s: Interrupts: %d\n", __FUNCTION__, interrupts);
++      pphw_enable(0);
++      pphw_exit();
++}
++
++/*!
++ * @brief Configure PP.
++ * @param vout        Pointer to _vout_data structure
++ * @return    Zero on success, others on failure
++ */
++int pp_cfg(vout_data *vout)
++{
++      unsigned long flags;
++
++      /* PP accepts YUV420 input only */
++      if ((vout->v2f.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) &&
++          (vout->v2f.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV422P)) {
++//    if (vout->v2f.fmt.pix.pixelformat != V4L2_PIX_FMT_YUV420) {
++              pr_debug("unsupported pixel format: %08x\n", vout->v2f.fmt.pix.pixelformat);
++              return -EINVAL;
++      }
++
++      g_pp_cfg.operation = 0;
++
++      memset(g_pp_cfg.csc_table, 0, sizeof(g_pp_cfg.csc_table));
++
++      /* Convert output pixel format to PP required format */
++      switch (vout->v4l2_fb.fmt.pixelformat) {
++      case V4L2_PIX_FMT_BGR32:
++              g_pp_cfg.red_width = 8;
++              g_pp_cfg.green_width = 8;
++              g_pp_cfg.blue_width = 8;
++              g_pp_cfg.red_offset = 8;
++              g_pp_cfg.green_offset = 16;
++              g_pp_cfg.blue_offset = 24;
++              g_pp_cfg.rgb_resolution = 32;
++              break;
++      case V4L2_PIX_FMT_RGB32:
++              g_pp_cfg.red_width = 8;
++              g_pp_cfg.green_width = 8;
++              g_pp_cfg.blue_width = 8;
++              g_pp_cfg.red_offset = 24;
++              g_pp_cfg.green_offset = 16;
++              g_pp_cfg.blue_offset = 8;
++              g_pp_cfg.rgb_resolution = 32;
++              break;
++      case V4L2_PIX_FMT_YUYV:
++              g_pp_cfg.red_width = 0;
++              g_pp_cfg.green_width = 0;
++              g_pp_cfg.blue_width = 0;
++              g_pp_cfg.red_offset = 0;
++              g_pp_cfg.green_offset = 0;
++              g_pp_cfg.blue_offset = PP_PIX_YUYV;
++              g_pp_cfg.rgb_resolution = 16;
++              break;
++      case V4L2_PIX_FMT_UYVY:
++              g_pp_cfg.red_width = 0;
++              g_pp_cfg.green_width = 0;
++              g_pp_cfg.blue_width = 0;
++              g_pp_cfg.red_offset = 0;
++              g_pp_cfg.green_offset = 0;
++              g_pp_cfg.blue_offset = PP_PIX_UYVY;
++              g_pp_cfg.rgb_resolution = 16;
++              break;
++      case V4L2_PIX_FMT_RGB565:
++      default:
++              g_pp_cfg.red_width = 5;
++              g_pp_cfg.green_width = 6;
++              g_pp_cfg.blue_width = 5;
++              g_pp_cfg.red_offset = 11;
++              g_pp_cfg.green_offset = 5;
++              g_pp_cfg.blue_offset = 0;
++              g_pp_cfg.rgb_resolution = 16;
++              break;
++      }
++      spin_lock_irqsave(&vout->irq_lock, flags);
++      if (vout->active != NULL) {
++              g_pp_cfg.ptr.y = vout->active->dma_desc.dma_addr;
++      } else {
++              g_pp_cfg.ptr.y = 0;
++      }
++      spin_unlock_irqrestore(&vout->irq_lock, flags);
++      g_pp_cfg.ptr.u = g_pp_cfg.ptr.v = g_pp_cfg.ptr.qp = 0;
++      if ((vout->crop_rect.width != 0) && (vout->crop_rect.height != 0)) {
++              g_pp_cfg.dim.in.width = vout->crop_rect.width;
++              g_pp_cfg.dim.in.height = vout->crop_rect.height;
++      } else {
++              g_pp_cfg.dim.in.width = vout->v2f.fmt.pix.width;
++              g_pp_cfg.dim.in.height = vout->v2f.fmt.pix.height;
++      }
++
++      g_pp_cfg.dim.out.width = vout->crop_current.width;
++      g_pp_cfg.dim.out.height = vout->crop_current.height;
++      g_pp_cfg.dim.num.width = 0;
++      g_pp_cfg.dim.num.height = 0;
++      g_pp_cfg.dim.den.width = 0;
++      g_pp_cfg.dim.den.height = 0;
++
++      pr_debug("input dimensions: %dx%d output dimensions: %dx%d\n",
++               g_pp_cfg.dim.in.width, g_pp_cfg.dim.in.height,
++               g_pp_cfg.dim.out.width, g_pp_cfg.dim.out.height);
++
++      if (scale_2d(&g_pp_cfg.dim)) {
++              printk(KERN_ERR "unsupported resize ratio\n");
++              return -EINVAL;
++      }
++
++      g_pp_cfg.dim.out.width = vout->crop_current.width;
++      g_pp_cfg.dim.out.height = vout->crop_current.height;
++
++      g_pp_cfg.in_y_stride = vout->v2f.fmt.pix.width;
++      g_pp_cfg.in_height = vout->v2f.fmt.pix.height;
++      if (set_output_addr(&g_pp_cfg, vout)) {
++              printk(KERN_ERR "failed to set pp output address\n");
++              return -EINVAL;
++      }
++
++      return pphw_cfg(&g_pp_cfg);
++}
++
++irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id);
++
++/*!
++ * @brief PP IRQ handler.
++ */
++static irqreturn_t pp_isr(int irq, void *dev_id)
++{
++      int status;
++      vout_data *vout = dev_id;
++
++interrupts++;
++      status = pphw_isr();
++      if ((status & 0x1) == 0) {      /* Not frame complete interrupt */
++              pr_debug("not pp frame complete interrupt\n");
++              return IRQ_HANDLED;
++      }
++
++      if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              g_disp_num = g_disp_num ? 0 : 1;
++              g_pp_cfg.outptr = (unsigned int)vout->display_bufs[g_disp_num];
++              pphw_outptr(&g_pp_cfg);
++      }
++
++      return mxc_v4l2out_pp_in_irq_handler(irq, dev_id);
++}
++
++/*!
++ * @brief Set PP output address.
++ * @param cfg Pointer to emma_pp_cfg structure
++ * @param vout        Pointer to _vout_data structure
++ * @return    Zero on success, others on failure
++ */
++static int set_output_addr(emma_pp_cfg *cfg, vout_data *vout)
++{
++      if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              g_disp_num = 0;
++              cfg->outptr = (unsigned int)vout->display_bufs[g_disp_num];
++              cfg->out_stride = vout->crop_current.width;
++              return 0;
++      } else {
++              struct fb_info *fb;
++
++              fb = registered_fb[vout->output_fb_num[vout->cur_disp_output]];
++              if (!fb)
++                      return -ENODEV;
++
++              cfg->outptr = fb->fix.smem_start;
++              cfg->outptr += vout->crop_current.top * fb->var.xres_virtual *
++                      (fb->var.bits_per_pixel >> 3) +
++                      vout->crop_current.left * (fb->var.bits_per_pixel >> 3);
++              cfg->out_stride = fb->var.xres_virtual;
++
++              return 0;
++      }
++}
++
++/*!
++ * @brief Get maximum common divisor.
++ * @param x   First input value
++ * @param y   Second input value
++ * @return    Maximum common divisor of x and y
++ */
++static int gcd(int x, int y)
++{
++      int k;
++
++      if (x < y) {
++              k = x;
++              x = y;
++              y = k;
++      }
++
++      while ((k = x % y)) {
++              x = y;
++              y = k;
++      }
++
++      return y;
++}
++
++/*!
++ * @brief Get ratio.
++ * @param x   First input value
++ * @param y   Second input value
++ * @param den Denominator of the ratio (corresponding to y)
++ * @return    Numerator of the ratio (corresponding to x)
++ */
++static int ratio(int x, int y, int *den)
++{
++      int g;
++
++      if (!x || !y)
++              return 0;
++
++      g = gcd(x, y);
++      *den = y / g;
++
++      return x / g;
++}
++
++/*!
++ * @brief Build PP coefficient entry
++ * Build one or more coefficient entries for PP coefficient table based
++ * on given coefficient.
++ *
++ * @param k   The index of the coefficient in coefficient table
++ * @param coeff       The weighting coefficient
++ * @param base        The base of the coefficient
++ * @param nxt Number of pixels to be read
++ *
++ * @return    The index of the next coefficient entry on success
++ *            -1 on failure
++ */
++static int scale_0d(int k, int coeff, int base, int nxt)
++{
++      if (k >= PP_TBL_MAX) {
++              /* no more space in table */
++              pr_debug("no space in scale table, k = %d\n", k);
++              return -ENOSPC;
++      }
++
++      coeff = ((coeff << BC_COEF) + (base >> 1)) / base;
++
++      /*
++       * Valid values for weighting coefficient are 0, 2 to 30, and 31.
++       * A value of 31 is treated as 32 and therefore 31 is an
++       * invalid co-efficient.
++       */
++      if (coeff >= SZ_COEF - 1)
++              coeff--;
++      else if (coeff == 1)
++              coeff++;
++      coeff = coeff << BC_NXT;
++
++      if (nxt < SZ_NXT) {
++              coeff |= nxt;
++              coeff <<= 1;
++              coeff |= 1;
++      } else {
++              /*
++               * src inc field is 2 bit wide, for 4+, use special
++               * code 0:0:1 to prevent dest inc
++               */
++              coeff |= PP_SKIP;
++              coeff <<= 1;
++              coeff |= 1;
++              nxt -= PP_SKIP;
++              do {
++                      pr_debug("tbl = %03X\n", coeff);
++                      scale_tbl[k++] = coeff;
++                      coeff = (nxt > PP_SKIP) ? PP_SKIP : nxt;
++                      coeff <<= 1;
++              } while ((nxt -= PP_SKIP) > 0);
++      }
++      pr_debug("tbl = %03X\n", coeff);
++      scale_tbl[k++] = coeff;
++
++      return k;
++}
++
++/*!
++ * @brief Get approximate ratio
++ *
++ * @param pscale      The pointer to scale_t structure which holdes
++ *                    coefficient tables
++ * @param mt          Scale ratio numerator
++ * @param nt          Scale ratio denominator
++ * @param *n          denominator of approximate ratio
++ * @return            numerator of approximate ratio
++ */
++static int approx_ratio(int mt, int nt, int *n)
++{
++      int index = sizeof(pp_coeftab) / sizeof(pp_coeftab[0]) / 2;
++      int left = 0;
++      int right = index - 1;
++      int nom = 0, den = 0;
++      while (index > 0) {
++              nom = pp_coeftab[(((right + left) >> 1) << 1)];
++              den = pp_coeftab[(((right + left) >> 1) << 1) + 1];
++              if ((nom * nt - mt * den) > 0) {
++                      left = (right + left) >> 1;
++              } else {
++                      right = (right + left) >> 1;
++              }
++              index = index >> 1;
++      }
++      *n = pp_coeftab[right * 2 + 1];
++      nom = pp_coeftab[right * 2];
++      return nom;
++}
++
++/*
++ * @brief Build PP coefficient table
++ * Build PP coefficient table for one dimension (width or height)
++ * based on given input and output resolution
++ *
++ * @param inv input resolution
++ * @param outv        output resolution
++ * @param k   index of free table entry
++ *
++ * @return    The index of the next free coefficient entry on success
++ *            -1 on failure
++ */
++static int scale_1d(int inv, int outv, int k)
++{
++      int v;                  /* overflow counter */
++      int coeff, nxt;         /* table output */
++
++      if (inv == outv)
++              return scale_0d(k, 1, 1, 1);    /* force scaling */
++
++      v = 0;
++      if (inv < outv) {
++              /* upscale: mix <= 2 input pixels per output pixel */
++              do {
++                      coeff = outv - v;
++                      v += inv;
++                      if (v >= outv) {
++                              v -= outv;
++                              nxt = 1;
++                      } else
++                              nxt = 0;
++                      pr_debug("upscale: coeff = %d/%d nxt = %d\n", coeff,
++                               outv, nxt);
++                      k = scale_0d(k, coeff, outv, nxt);
++                      if (k < 0)
++                              return -1;
++              } while (v);
++      } else if (inv >= 2 * outv) {
++              /* PP doesn't support resize ratio > 2:1 except 4:1. */
++              if ((inv != 2 * outv) && (inv != 4 * outv))
++                      return -1;
++              /* downscale: >=2:1 bilinear approximation */
++              coeff = inv - 2 * outv;
++              v = 0;
++              nxt = 0;
++              do {
++                      v += coeff;
++                      nxt = 2;
++                      while (v >= outv) {
++                              v -= outv;
++                              nxt++;
++                      }
++                      pr_debug("downscale: coeff = 1/2 nxt = %d\n", nxt);
++                      k = scale_0d(k, 1, 2, nxt);
++                      if (k < 0)
++                              return -1;
++              } while (v);
++      } else {
++              /* downscale: bilinear */
++              int in_pos_inc = 2 * outv;
++              int out_pos = inv;
++              int out_pos_inc = 2 * inv;
++              int init_carry = inv - outv;
++              int carry = init_carry;
++
++              v = outv + in_pos_inc;
++              do {
++                      coeff = v - out_pos;
++                      out_pos += out_pos_inc;
++                      carry += out_pos_inc;
++                      for (nxt = 0; v < out_pos; nxt++) {
++                              v += in_pos_inc;
++                              carry -= in_pos_inc;
++                      }
++                      pr_debug("downscale: coeff = %d/%d nxt = %d\n", coeff,
++                               in_pos_inc, nxt);
++                      k = scale_0d(k, coeff, in_pos_inc, nxt);
++                      if (k < 0)
++                              return -1;
++              } while (carry != init_carry);
++      }
++      return k;
++}
++
++/*
++ * @brief Build PP coefficient table
++ * Build PP coefficient table for one dimension (width or height)
++ * based on given input and output resolution. The given input
++ * and output resolution might be not supported due to hardware
++ * limits. In this case this functin rounds the input and output
++ * to closest possible values and return them to caller.
++ *
++ * @param inv input resolution, might be modified after the call
++ * @param outv        output resolution, might be modified after the call
++ * @param k   index of free table entry
++ *
++ * @return    The index of the next free coefficient entry on success
++ *            -1 on failure
++ */
++static int scale_1d_smart(int *inv, int *outv, int index)
++{
++      int len, num, den, approx_num, approx_den;
++      static int num1, den1;
++
++      if (!inv || !outv)
++              return -1;
++
++      /* Both should be non-zero */
++      if (!(*inv) || !(*outv))
++              return -1;
++
++      if ((*outv > 4 * (*inv)) ||
++          ((*inv > 2 * (*outv)) && (*inv != 4 * (*outv)))) {
++              pr_debug("unsupported pp resize ration: inv/outv = %d/%d\n",
++                       *inv, *outv);
++              return -1;
++      }
++
++      num = ratio(*inv, *outv, &den);
++      pr_debug("%s: num=%d den=%d\n", __FUNCTION__, num, den);
++
++      if (index == 0) {
++              if ((num > 20) || (den > 20)) {
++                      approx_num = approx_ratio(num, den, &approx_den);
++                      num = approx_num;
++                      den = approx_den;
++              }
++      } else {
++              if ((num > (40 - index)) || (den > (40 - index))) {
++                      approx_num = approx_ratio(num, den, &approx_den);
++                      num = approx_num;
++                      den = approx_den;
++              }
++              if ((num == num1) && (den == den1)) {
++                      return index;
++              }
++      }
++
++      if ((len = scale_1d(num, den, index)) < 0) {
++              return -1;
++      } else {
++              if (index == 0) {
++                      num1 = num;
++                      den1 = den;
++              }
++              return len;
++      }
++
++}
++
++/*
++ * @brief Build PP coefficient table for both width and height
++ * Build PP coefficient table for both width and height based on
++ * given resizing ratios.
++ *
++ * @param sz  Structure contains resizing ratio informations
++ *
++ * @return    0 on success, others on failure
++ */
++static int scale_2d(emma_pp_scale *sz)
++{
++      int inv, outv;
++
++      /* horizontal resizing. parameter check - must provide in size */
++      if (!sz->in.width)
++              return -1;
++
++      /* Resizing based on num:den */
++      inv = sz->num.width;
++      outv = sz->den.width;
++
++      if ((g_hlen = scale_1d_smart(&inv, &outv, 0)) > 0) {
++              /* Resizing succeeded */
++              sz->den.width = outv;
++              sz->out.width = (sz->in.width * outv) / inv;
++      } else {
++              /* Resizing based on in:out */
++              inv = sz->in.width;
++              outv = sz->out.width;
++
++              if ((g_hlen = scale_1d_smart(&inv, &outv, 0)) > 0) {
++                      /* Resizing succeeded */
++                      sz->out.width = outv;
++                      sz->num.width = ratio(sz->in.width, sz->out.width,
++                                            &sz->den.width);
++              } else
++                      return -1;
++      }
++
++      sz->out.width &= ~1;
++
++      /* vertical resizing. parameter check - must provide in size */
++      if (!sz->in.height)
++              return -1;
++
++      /* Resizing based on num:den */
++      inv = sz->num.height;
++      outv = sz->den.height;
++
++      if ((g_vlen = scale_1d_smart(&inv, &outv, g_hlen)) > 0) {
++              /* Resizing succeeded */
++              sz->den.height = outv;
++              sz->out.height = (sz->in.height * outv) / inv;
++      } else {
++              /* Resizing based on in:out */
++              inv = sz->in.height;
++              outv = sz->out.height;
++
++              if ((g_vlen = scale_1d_smart(&inv, &outv, g_hlen)) > 0) {
++                      /* Resizing succeeded */
++                      sz->out.height = outv;
++                      sz->num.height = ratio(sz->in.height, sz->out.height,
++                                             &sz->den.height);
++              } else
++                      return -1;
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Set PP resizing registers.
++ * @param sz  Pointer to pp scaling structure
++ * @return    Zero on success, others on failure
++ */
++static int pphw_scale(emma_pp_scale * sz)
++{
++      __raw_writel((sz->out.width << 16) | sz->out.height,
++                   PP_DEST_IMAGE_SIZE);
++      __raw_writel(((g_hlen - 1) << 16) | (g_vlen ==
++                                           g_hlen ? 0 : (g_hlen << 8)) |
++                   (g_vlen - 1), PP_RESIZE_INDEX);
++      for (g_hlen = 0; g_hlen < g_vlen; g_hlen++)
++              __raw_writel(scale_tbl[g_hlen],
++                           PP_RESIZE_COEF_TBL + g_hlen * 4);
++
++      return 0;
++}
++
++/*!
++ * @brief Reset PP.
++ * @return    Zero on success, others on failure
++ */
++static int pphw_reset(void)
++{
++      int i;
++      u32 pp_cntl;
++
++      __raw_writel(0x100, PP_CNTL);
++
++      /* timeout */
++      for (i = 0; i < 1000; i++) {
++              if (!((pp_cntl = __raw_readl(PP_CNTL)) & 0x100)) {
++                      pr_debug("pp reset over\n");
++                      break;
++              }
++      }
++
++      /* check reset value */
++      if (pp_cntl != 0x876) {
++              pr_debug("pp reset value err = 0x%08X\n", pp_cntl);
++              return -EIO;
++      }
++
++      return 0;
++}
++
++/*!
++ * @brief Enable or disable PP.
++ * @param flag        Zero to disable PP, others to enable PP
++ * @return    Zero on success, others on failure
++ */
++static int pphw_enable(int flag)
++{
++      int ret = 0;
++
++      if (flag)
++              __raw_writel(__raw_readl(PP_CNTL) | 1, PP_CNTL);
++      else
++              ret = pphw_reset();
++
++      return ret;
++}
++
++/*!
++ * @brief Set PP input address.
++ * @param cfg The pointer to PP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++static int pphw_ptr(emma_pp_cfg *cfg)
++{
++      __raw_writel(cfg->ptr.y, PP_SOURCE_Y_PTR);
++      __raw_writel(cfg->ptr.u, PP_SOURCE_CB_PTR);
++      __raw_writel(cfg->ptr.v, PP_SOURCE_CR_PTR);
++      __raw_writel(cfg->ptr.qp, PP_QUANTIZER_PTR);
++
++      return 0;
++}
++
++/*!
++ * @brief Set PP output address.
++ * @param cfg The pointer to PP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++static int pphw_outptr(emma_pp_cfg *cfg)
++{
++      __raw_writel(cfg->outptr, PP_DEST_RGB_PTR);
++      return 0;
++}
++
++/*!
++ * @brief Configuration PP.
++ * @param cfg The pointer to PP configuration parameter
++ * @return    Zero on success, others on failure
++ */
++static int pphw_cfg(emma_pp_cfg *cfg)
++{
++      int rt;
++      register int r;
++
++      pphw_scale(&cfg->dim);
++
++      if (!cfg->in_y_stride)
++              cfg->in_y_stride = cfg->dim.in.width;
++
++      if (!cfg->out_stride)
++              cfg->out_stride = cfg->dim.out.width;
++
++      r = __raw_readl(PP_CNTL) & ~EN_MASK;
++
++      /* config parms */
++      r |= cfg->operation & EN_MASK;
++      if (cfg->operation & EN_MACROBLOCK) {
++              /* Macroblock Mode */
++              r |= 0x0200;
++              __raw_writel(0x06, PP_INTRCNTL);
++      } else {
++              /* Frame mode */
++              __raw_writel(0x05, PP_INTRCNTL);
++      }
++
++      if (cfg->red_width | cfg->green_width | cfg->blue_width) {
++              /* color conversion to be performed */
++              r |= EN_CSC;
++              if (!(cfg->red_offset | cfg->green_offset)) {
++                      /* auto offset B:G:R LSb to Msb */
++                      cfg->green_offset = cfg->blue_offset + cfg->blue_width;
++                      cfg->red_offset = cfg->green_offset + cfg->green_width;
++              }
++              if (!cfg->rgb_resolution) {
++                      /* derive minimum resolution required */
++                      int w, w2;
++
++                      w = cfg->red_offset + cfg->red_width;
++                      w2 = cfg->blue_offset + cfg->blue_width;
++                      if (w < w2)
++                              w = w2;
++                      w2 = cfg->green_offset + cfg->green_width;
++                      if (w < w2)
++                              w = w2;
++                      if (w > 16)
++                              w = 24;
++                      else if (w > 8)
++                              w = 16;
++                      else
++                              w = 8;
++                      cfg->rgb_resolution = w;
++              }
++              /* 00,11 - 32 bpp, 10 - 16 bpp, 01 - 8 bpp */
++              r &= ~0xC00;
++              if (cfg->rgb_resolution < 32)
++                      r |= (cfg->rgb_resolution << 7);
++              __raw_writel((cfg->red_offset << 26) |
++                           (cfg->green_offset << 21) |
++                           (cfg->blue_offset << 16) |
++                           (cfg->red_width << 8) |
++                           (cfg->green_width << 4) |
++                           cfg->blue_width, PP_DEST_FRAME_FMT_CNTL);
++      } else {
++              /* add YUV422 formatting */
++              static const unsigned int _422[] = {
++                      0x62000888,
++                      0x60100888,
++                      0x43080888,
++                      0x41180888
++              };
++
++              __raw_writel(_422[(cfg->blue_offset >> 3) & 3],
++                           PP_DEST_FRAME_FMT_CNTL);
++              cfg->rgb_resolution = 16;
++              r &= ~0xC00;
++              r |= (cfg->rgb_resolution << 7);
++      }
++
++      /* add csc formatting */
++      if (!cfg->csc_table[1]) {
++              static const unsigned short _csc[][6] = {
++                      {0x80, 0xb4, 0x2c, 0x5b, 0x0e4, 0},
++                      {0x95, 0xcc, 0x32, 0x68, 0x104, 1},
++                      {0x80, 0xca, 0x18, 0x3c, 0x0ec, 0},
++                      {0x95, 0xe5, 0x1b, 0x44, 0x10e, 1},
++              };
++              memcpy(cfg->csc_table, _csc[cfg->csc_table[0]],
++                     sizeof(_csc[0]));
++      }
++      __raw_writel((cfg->csc_table[0] << 24) |
++                   (cfg->csc_table[1] << 16) |
++                   (cfg->csc_table[2] << 8) |
++                   cfg->csc_table[3], PP_CSC_COEF_0123);
++      __raw_writel((cfg->csc_table[5] ? (1 << 9) : 0) | cfg->csc_table[4],
++                   PP_CSC_COEF_4);
++
++      __raw_writel(r, PP_CNTL);
++
++      pphw_ptr(cfg);
++      pphw_outptr(cfg);
++
++      /*
++       * #MB in a row = input_width / 16pix
++       * 1 byte per QP per MB
++       * QP must be formatted to be 4-byte aligned
++       * YUV lines are to be 4-byte aligned as well
++       * So Y is 8 byte aligned, as U = V = Y/2 for 420
++       * MPEG MBs are 16x16 anyway
++       */
++      __raw_writel((cfg->dim.in.width << 16) | cfg->dim.in.height,
++                   PP_PROCESS_FRAME_PARA);
++      __raw_writel(cfg->in_y_stride | (PP_CALC_QP_WIDTH(cfg) << 16),
++                   PP_SOURCE_FRAME_WIDTH);
++
++      /* in bytes */
++      rt = cfg->rgb_resolution >> 3;
++      if (rt == 3)
++              rt = 4;
++      __raw_writel(cfg->out_stride * rt, PP_DEST_DISPLAY_WIDTH);
++
++      pp_dump();
++      return 0;
++}
++
++/*!
++ * @brief Check PP interrupt status.
++ * @return    PP interrupt status
++ */
++static int pphw_isr(void)
++{
++      unsigned long status;
++
++      status = __raw_readl(PP_INTRSTATUS) & 7;
++      if (!status) {
++              pr_debug("pp: not my isr err\n");
++              return status;
++      }
++
++      if (status & 4)
++              pr_debug("pp: isr state error\n");
++
++      /* clear interrupt status */
++      __raw_writel(status, PP_INTRSTATUS);
++
++      return status;
++}
++
++static struct clk *emma_clk;
++
++/*!
++ * @brief PP module clock enable
++ */
++static int pphw_init(void)
++{
++      emma_clk = clk_get(NULL, "emma_clk");
++      if (IS_ERR(emma_clk)) {
++              printk(KERN_ERR "Could not get emma_clk: %ld\n", PTR_ERR(emma_clk));
++              return PTR_ERR(emma_clk);
++      }
++      clk_enable(emma_clk);
++      return 0;
++}
++
++/*!
++ * @brief PP module clock disable
++ */
++static void pphw_exit(void)
++{
++      clk_disable(emma_clk);
++      clk_put(emma_clk);
++}
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/output/mx27_pp.h linux-2.6.28-karo/drivers/media/video/mxc/output/mx27_pp.h
+--- linux-2.6.28/drivers/media/video/mxc/output/mx27_pp.h      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/output/mx27_pp.h 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,181 @@
++/*
++ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_pp.h
++ *
++ * @brief Header file for MX27 V4L2 Video Output Driver
++ *
++ * @ingroup MXC_V4L2_OUTPUT
++ */
++#ifndef __MX27_PP_H__
++#define __MX27_PP_H__
++
++#include "mxc_v4l2_output.h"
++
++/* PP register definitions */
++#define PP_REG(ofs)    (IO_ADDRESS(EMMA_PP_BASE_ADDR) + ofs)
++
++/* Register offsets */
++#define PP_CNTL                       PP_REG(0x00)
++#define PP_INTRCNTL           PP_REG(0x04)
++#define PP_INTRSTATUS         PP_REG(0x08)
++#define PP_SOURCE_Y_PTR               PP_REG(0x0C)
++#define PP_SOURCE_CB_PTR      PP_REG(0x10)
++#define PP_SOURCE_CR_PTR      PP_REG(0x14)
++#define PP_DEST_RGB_PTR       PP_REG(0x18)
++#define PP_QUANTIZER_PTR      PP_REG(0x1C)
++#define PP_PROCESS_FRAME_PARA PP_REG(0x20)
++#define PP_SOURCE_FRAME_WIDTH PP_REG(0x24)
++#define PP_DEST_DISPLAY_WIDTH PP_REG(0x28)
++#define PP_DEST_IMAGE_SIZE    PP_REG(0x2C)
++#define PP_DEST_FRAME_FMT_CNTL        PP_REG(0x30)
++#define PP_RESIZE_INDEX               PP_REG(0x34)
++#define       PP_CSC_COEF_0123        PP_REG(0x38)
++#define       PP_CSC_COEF_4           PP_REG(0x3C)
++#define PP_RESIZE_COEF_TBL    PP_REG(0x100)
++
++/* resize table dimensions 
++    dest pixel index    left/32    right/32    #src pixels to read
++    0                   [BC_COEF]  [BC_COEF]   [BC_NXT]
++    :
++    pp_tbl_max-1
++*/
++#define BC_NXT                2
++#define BC_COEF               5
++#define SZ_COEF               (1 << BC_COEF)
++#define SZ_NXT                (1 << BC_NXT)
++
++/* PP operations */
++#define EN_DEBLOCK    0x02
++#define EN_DERING     0x04
++#define EN_CSC                0x10
++#define EN_MACROBLOCK 0x20
++#define EN_DEF                0x16
++#define EN_MASK               0x36
++#define EN_BIGDATA    0x1000
++#define EN_BIGQP      0x2000
++
++/* PP CSC tables */
++#define CSC_TBL_NONE  0x80
++#define CSC_TBL_REUSE 0x81
++#define CSC_TBL_A1    0x00
++#define CSC_TBL_A0    0x20
++#define CSC_TBL_B1    0x40
++#define CSC_TBL_B0    0x60
++/* converts from 4 decimal fixed point to hw setting & vice versa */
++#define PP_CSC_FP4_2_HW(coeff)        ((((coeff) << 7) + 5000) / 10000)
++#define PP_CSC_HW_2_FP4(coeff)        ((((coeff) * 10000) + 64) >> 7)
++
++#define PP_PIX_YUYV   0
++#define PP_PIX_YVYU   8
++#define PP_PIX_UYVY   16
++#define PP_PIX_VYUY   24
++
++/* PP size & width calculation macros */
++#define PP_CALC_QP_WIDTH(cfg) \
++      (!((cfg)->operation & (EN_DEBLOCK | EN_DERING)) ? 0 : \
++              (((((cfg)->in_y_stride + 15) >> 4) + 3) & ~3))
++#define PP_CALC_Y_SIZE(cfg)           \
++      ((cfg)->in_y_stride * (cfg)->in_height)
++#define PP_CALC_CH_SIZE(cfg)          (PP_CALC_Y_SIZE(cfg) >> 2)
++#define PP_CALC_BPP(cfg)              \
++      ((cfg)->rgb_resolution > 16 ?  4 : ((cfg)->rgb_resolution >> 3))
++#define PP_CALC_YUV_SIZE(cfg)         \
++      ((PP_CALC_Y_SIZE(cfg) * 3) >> 1)
++#define PP_CALC_QP_SIZE(cfg)          \
++      (PP_CALC_QP_WIDTH(cfg) * (((cfg)->in_height + 15) >> 4))
++#define PP_CALC_DEST_WIDTH(cfg)       \
++      (((cfg)->out_stride & ~1) * PP_CALC_BPP(cfg))
++#define PP_CALC_DEST_SIZE(cfg)        \
++      ((cfg)->dim.out.height * PP_CALC_DEST_WIDTH(cfg))
++
++/*
++ * physical addresses for bus mastering 
++ * v=0 -> yuv packed 
++ * v=0 & qp=0 -> yuv packed with qp appended
++ */
++typedef struct _emma_pp_ptr {
++      unsigned int y;         /* Y data (line align8) */
++      unsigned int u;         /* U data (line align4) */
++      unsigned int v;         /* V data (line align4) */
++      unsigned int qp;        /* Quantization (line align4) */
++} emma_pp_ptr;
++
++typedef struct _emma_pp_size {
++      int width;
++      int height;
++} emma_pp_size;
++
++/*
++ * if num.width != 0
++ *    resize ratio = num.width : den.width
++ * else
++ *    resize ratio = in.width : out.width
++ * same for height
++ */
++typedef struct _emma_pp_scale {
++      emma_pp_size num;
++      emma_pp_size den;
++      emma_pp_size in;        /* clip */
++      emma_pp_size out;       /* 0 -> same as in */
++} emma_pp_scale;
++
++typedef struct _emma_pp_cfg {
++      unsigned char operation;        /* OR of EN_xx defines */
++
++      /*
++       * input color coeff 
++       * fixed pt 8 bits, steps of 1/128
++       * csc[5] is 1 or 0 to indicate Y + 16
++       * csc[0] is matrix id 0-3 while csc[1-5]=0
++       */
++      unsigned short csc_table[6];
++
++      /* 
++       * Output color (shade width, shade offset, pixel resolution)
++       * Eg. 16bpp RGB565 resolution, the values could be:
++       * red_width = 5, green_width = 6, blue_width = 6
++       * red_offset = 11, green_offset = 5, blue_offset = 0 (defaults)
++       * rgb_resolution = 16 (default)
++       * For YUV422: xxx_width=0, blue_offset=PP_PIX_xxx
++       */
++      unsigned short red_width;
++      unsigned short green_width;
++      unsigned short blue_width;
++      /* if offsets are 0, the offsets are by width LSb to MSb B:G:R */
++      unsigned short red_offset;
++      unsigned short blue_offset;
++      unsigned short green_offset;
++      /* if resolution is 0, the minimum for the sum of widths is chosen */
++      short rgb_resolution;   /* 8,16,24 bpp only */
++
++      emma_pp_ptr ptr;        /* dma buffer pointers */
++      unsigned int outptr;    /* RGB/YUV output */
++      emma_pp_scale dim;      /* in/out dimensions */
++
++      /* pixels between two adjacent input Y rows */
++      unsigned short in_y_stride;     /* 0 = in_width */
++      unsigned short in_height;       /* Input image height */
++      /* PIXELS between two adjacent output rows */
++      unsigned short out_stride;      /* 0 = out_width */
++} emma_pp_cfg;
++
++int pp_ptr(unsigned long ptr, struct v4l2_mxc_offset offset);
++int pp_enable(int flag);
++int pp_cfg(vout_data * vout);
++int pp_init(vout_data * vout);
++int pp_num_last(void);
++void pp_exit(vout_data * vout);
++
++#endif                                /* __MX27_PP_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/output/mx27_v4l2_output.c linux-2.6.28-karo/drivers/media/video/mxc/output/mx27_v4l2_output.c
+--- linux-2.6.28/drivers/media/video/mxc/output/mx27_v4l2_output.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/output/mx27_v4l2_output.c        2009-03-11 13:48:58.000000000 +0100
+@@ -0,0 +1,1897 @@
++/*
++ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mx27_v4l2_output.c
++ *
++ * @brief MX27 V4L2 Video Output Driver
++ *
++ * Video4Linux2 Output Device using MX27 eMMA Post-processing functionality.
++ *
++ * @ingroup MXC_V4L2_OUTPUT
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/fs.h>
++#include <linux/irq.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/pci.h>
++#include <linux/platform_device.h>
++#include <media/v4l2-dev.h>
++#include <media/v4l2-common.h>
++#include <media/v4l2-ioctl.h>
++#include <asm/poll.h>
++#include <asm/io.h>
++//#include <asm/semaphore.h>
++#include <mach/imxfb.h>
++
++#include "mxc_v4l2_output.h"
++#include "mx27_pp.h"
++
++//#define SDC_FG_FB_FORMAT    V4L2_PIX_FMT_RGB565
++#define SDC_FG_FB_FORMAT      V4L2_PIX_FMT_RGB32
++
++struct v4l2_output mxc_outputs[1] = {
++      {
++              .index = 0,
++              .name = "DISP%d Video Out",
++              .type = V4L2_OUTPUT_TYPE_ANALOG,        /* not really correct,
++                                                 but no other choice */
++              .audioset = 0,
++              .modulator = 0,
++              .std = V4L2_STD_UNKNOWN,
++      },
++};
++
++#ifdef DEBUG
++int debug = 1;
++#define dbg_lvl(n)    ((n) < debug)
++module_param(debug, int, S_IRUGO | S_IWUSR);
++
++#define DBG(lvl, fmt...)      do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0)
++#else
++int debug;
++#define dbg_lvl(n)    0
++#define DBG(lvl, fmt...)      do { } while (0)
++module_param(debug, int, 0);
++#endif
++#define pr_warn(fmt,arg...)   printk(KERN_WARNING fmt,##arg)
++
++
++static int video_nr = 16;
++
++/* debug counters */
++static uint32_t g_irq_cnt;
++static uint32_t g_buf_output_cnt;
++static uint32_t g_buf_q_cnt;
++static uint32_t g_buf_dq_cnt;
++static uint32_t g_paused_cnt;
++static uint32_t g_busy_cnt;
++static uint32_t g_late_cnt;
++
++static int dq_intr_cnt;
++
++static int using_default_fps = -1;
++
++static inline unsigned long diff_usec(struct timeval *t1, struct timeval *t0)
++{
++      unsigned long diff = (t1->tv_sec - t0->tv_sec) * 1000000;
++
++      if (t1->tv_usec >= t0->tv_usec) {
++              diff += t1->tv_usec - t0->tv_usec;
++      } else {
++              diff += 1000000 - (t0->tv_usec - t1->tv_usec);
++      }
++      return diff;
++}
++
++#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
++
++static int fb_event_notify(struct notifier_block *self,
++                         unsigned long action, void *data)
++{
++      vout_data *vout = container_of(self, vout_data, fb_event_notifier);
++      struct fb_event *event = data;
++      struct fb_info *info = event->info;
++      unsigned long flags;
++      int blank, i;
++
++      for (i = 0; i < num_registered_fb; i++)
++              if (registered_fb[i] == info)
++                      break;
++
++      /*
++       * Check if the event is sent by the framebuffer in which
++       * the video is displayed.
++       */
++      if (i != vout->output_fb)
++              return 0;
++
++      switch (action) {
++      case FB_EVENT_BLANK:
++              DBG(0, "%s: BLANK\n", __FUNCTION__);
++              blank = *(int *)event->data;
++              down(&vout->user_lock);
++              vout->fb_enabled = !blank;
++              if (blank && vout->pp_ready) {
++                      if (pp_enable(1))
++                              pr_warn("unable to enable PP\n");
++                      vout->pp_ready = 0;
++              }
++              up(&vout->user_lock);
++              break;
++      case FB_EVENT_MXC_EOF:
++              down(&vout->user_lock);
++              vout->fb_enabled = 1;
++              if (vout->pp_ready) {
++                      DBG(2, "%s: enable PP\n", __FUNCTION__);
++                      if (pp_enable(1))
++                              pr_warn("unable to enable PP\n");
++                      vout->pp_ready = 0;
++              }
++              up(&vout->user_lock);
++              break;
++      }
++
++      return 0;
++}
++#endif
++
++static inline struct v4l_queue *find_buffer(struct list_head *list, int index)
++{
++      struct v4l_queue *q;
++
++      list_for_each_entry(q, list, head) {
++              if (q->buf.index == index) {
++                      return q;
++              }
++      }
++      return NULL;
++}
++
++static __inline unsigned long get_jiffies(struct timeval *t)
++{
++      struct timeval cur;
++
++      if (WARN_ON(t->tv_usec >= 1000000)) {
++              t->tv_sec += t->tv_usec / 1000000;
++              t->tv_usec = t->tv_usec % 1000000;
++      }
++
++      do_gettimeofday(&cur);
++      if ((t->tv_sec < cur.tv_sec) ||
++          ((t->tv_sec == cur.tv_sec) && (t->tv_usec < cur.tv_usec))) {
++              DBG(0, "%s: timestamp is %luµs in the past\n", __FUNCTION__,
++                  (cur.tv_sec - t->tv_sec) * 1000000 + cur.tv_usec - t->tv_usec);
++              g_late_cnt++;
++              return jiffies;
++      }
++
++      if (t->tv_usec < cur.tv_usec) {
++              cur.tv_sec = t->tv_sec - cur.tv_sec - 1;
++              cur.tv_usec = t->tv_usec + 1000000 - cur.tv_usec;
++      } else {
++              cur.tv_sec = t->tv_sec - cur.tv_sec;
++              cur.tv_usec = t->tv_usec - cur.tv_usec;
++      }
++
++      return jiffies + timeval_to_jiffies(&cur);
++}
++
++/* must be called with irq_lock held */
++static void mxc_v4l2out_start_pp(vout_data *vout)
++{
++      BUG_ON(vout->active == NULL);
++      DBG(0, "%s: Updating HW PTR to %08x\n", __FUNCTION__,
++          vout->active->dma_desc.dma_addr);
++      do_gettimeofday(&vout->frame_start);
++      if (pp_ptr(vout->active->dma_desc.dma_addr, vout->offset)) {
++              pr_warn("%s: unable to update buffer\n", __FUNCTION__);
++              return;
++      }
++#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
++      if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) {
++              if (vout->fb_enabled && (vout->v4l2_fb.flags != V4L2_FBUF_FLAG_OVERLAY)) {
++                      vout->pp_ready = 1;
++              } else {
++                      pp_enable(1);
++              }
++      } else {
++              pp_enable(1);
++      }
++#else
++      pp_enable(1);
++#endif
++      vout->busy = 1;
++}
++
++static __inline void mxc_v4l2out_schedule_frame(vout_data *vout, struct timeval *tv, int init)
++{
++      unsigned long timeout;
++
++      DBG(1, "%s: ts %6lu.%06lu\n", __FUNCTION__, tv->tv_sec, tv->tv_usec);
++      if (0 || ((tv->tv_sec == 0) && (tv->tv_usec == 0))) {
++              if (using_default_fps != 1) {
++                      DBG(-1, "%s: using default fps\n", __FUNCTION__);
++                      using_default_fps = 1;
++              }
++              mxc_v4l2out_start_pp(vout);
++              return;
++      } else {
++              timeout = get_jiffies(tv);
++              if (using_default_fps != 0) {
++                      struct timeval now;
++                      do_gettimeofday(&now);
++
++                      DBG(-1, "%s: using timestamp %lu.%06lu (now: %lu.%06lu)\n", __FUNCTION__,
++                          tv->tv_sec, tv->tv_usec, now.tv_sec, now.tv_usec);
++                      using_default_fps = 0;
++              }
++      }
++#ifdef DEBUG
++      {
++              unsigned long cur = jiffies;
++              static unsigned long last_tv;
++              static unsigned int last_fps;
++              static unsigned int last_avg;
++              static unsigned int fps_avg;
++              static unsigned int avg_count;
++
++              if (vout->frame_count == 0) {
++                      avg_count = 0;
++              }
++              if (avg_count++ == 0) {
++                      last_tv = timeout;
++                      fps_avg = 0;
++                      last_fps = 0;
++              } else {
++                      unsigned long t = timeout;
++                      unsigned int fps;
++
++                      DBG(3, "%s: t=%lu last=%lu diff=%ld\n", __FUNCTION__,
++                          t, last_tv, t - last_tv);
++                      if (t - last_tv) {
++                              fps = HZ / (t - last_tv);
++                              fps_avg = ((fps_avg * (avg_count - 1)) + fps) / avg_count;
++                              last_tv = t;
++                              if (last_fps != fps || last_avg != fps_avg) {
++                                      DBG(1, "%s: FPS: %u AVG %u\n", __FUNCTION__, fps, fps_avg);
++                                      last_fps = fps;
++                                      last_avg = fps_avg;
++                              }
++                      } else {
++                              avg_count--;
++                      }
++              }
++
++              DBG(1, "%s: frame %u start %lu cur %lu timeout %lu\n", __FUNCTION__,
++                  vout->frame_count, vout->start_jiffies, cur, timeout);
++      }
++#endif
++      if (!time_before(jiffies, timeout)) {
++              DBG(0, "%s: timeout already expired: %lu >= %lu\n", __FUNCTION__,
++                  jiffies, timeout);
++              mxc_v4l2out_start_pp(vout);
++              return;
++      }
++      if (init) {
++              vout->output_timer.expires = timeout;
++              add_timer(&vout->output_timer);
++      } else {
++              WARN_ON(mod_timer(&vout->output_timer, timeout));
++      }
++}
++
++/*!
++ * Private function to free buffers
++ *
++ * @param bufs_paddr  Array of physical address of buffers to be freed
++ *
++ * @param bufs_vaddr  Array of virtual address of buffers to be freed
++ *
++ * @param num_buf     Number of buffers to be freed
++ *
++ * @param size                Size for each buffer to be free
++ *
++ * @return status  0 success.
++ */
++static void mxc_free_buffers(vout_data *vout, struct list_head *list)
++{
++      struct v4l_queue *q;
++      struct v4l_queue *tmp;
++      struct device *dev = vout->video_dev->parent;
++      unsigned long flags;
++
++      list_for_each_entry(q, list, head) {
++              DBG(-1, "%s: dma_addr: %08x cpu_addr: %p size %08x\n", __FUNCTION__,
++                  q->dma_desc.dma_addr, q->dma_desc.cpu_addr, q->dma_desc.size);
++      }
++      list_for_each_entry_safe(q, tmp, list, head) {
++              struct dma_buf_desc *dma = &q->dma_desc;
++              DBG(-1, "%s: dma_addr: %08x cpu_addr: %p size %08x\n", __FUNCTION__,
++                  dma->dma_addr, dma->cpu_addr, dma->size);
++              if (dma->cpu_addr != NULL) {
++                      dma_free_coherent(dev,
++                                        dma->size, dma->cpu_addr,
++                                        dma->dma_addr);
++                      DBG(2, "freed @ paddr=0x%08x\n", dma->dma_addr);
++              }
++              spin_lock_irqsave(&vout->irq_lock, flags);
++              list_del(&q->head);
++              spin_unlock_irqrestore(&vout->irq_lock, flags);
++              kfree(q);
++      }
++}
++
++/*!
++ * Private function to allocate buffers
++ *
++ * @param bufs_paddr  Output array of physical address of buffers allocated
++ *
++ * @param bufs_vaddr  Output array of virtual address of buffers allocated
++ *
++ * @param num_buf     Input number of buffers to allocate
++ *
++ * @param size                Input size for each buffer to allocate
++ *
++ * @return status     -0 Successfully allocated a buffer, -ENOBUFS failed.
++ */
++static int mxc_allocate_buffers(vout_data *vout, struct list_head *list, int num_buf, int size)
++{
++      int i;
++      unsigned long flags;
++      struct device *dev = vout->video_dev->parent;
++
++      DBG(2, "Trying to allocate %u buffers of %08x byte each\n",
++          num_buf, size);
++
++      for (i = 0; i < num_buf; i++) {
++              struct v4l_queue *q = kzalloc(sizeof(*q), GFP_KERNEL);
++              struct dma_buf_desc *dma;
++
++              if (q == NULL) {
++                      pr_err("failed to allocate memory for queue descriptor\n");
++                      return i;
++              }
++              DBG(2, "%s: queue header allocated %p\n", __FUNCTION__, q);
++              q->buf.index = i;
++              dma = &q->dma_desc;
++              if (size != 0) {
++                      DBG(2, "Trying to allocate %08x byte DMA memory for queue %p\n",
++                          size, list);
++                      dma->size = size;
++                      dma->cpu_addr = dma_alloc_coherent(dev,
++                                                         size,
++                                                         &dma->dma_addr,
++                                                         GFP_KERNEL);
++                      if (dma->cpu_addr == NULL) {
++                              pr_err("dma_alloc_coherent failed for buffer %u out of %u\n",
++                                     i, num_buf);
++                              kfree(q);
++                              return i;
++                      }
++                      DBG(2, "allocated @ paddr=0x%08x, size=%d\n",
++                          dma->dma_addr, size);
++              }
++              spin_lock_irqsave(&vout->irq_lock, flags);
++              list_add_tail(&q->head, list);
++              spin_unlock_irqrestore(&vout->irq_lock, flags);
++      }
++      return i;
++}
++
++static void mxc_v4l2out_timer_handler(unsigned long arg)
++{
++      unsigned long flags;
++      vout_data *vout = (vout_data *)arg;
++      struct timeval now;
++
++      do_gettimeofday(&now);
++
++      DBG(1, "timer handler: %lu\n", jiffies);
++
++      spin_lock_irqsave(&vout->irq_lock, flags);
++
++      if (vout->state == STATE_STREAM_OFF && vout->active == NULL) {
++              pr_warn("stream has stopped\n");
++              spin_unlock_irqrestore(&vout->irq_lock, flags);
++              return;
++      }
++
++      BUG_ON(vout->active == NULL);
++
++      if (vout->busy) {
++              pr_warn("Buffer %d is still busy in frame %u\n",
++                      vout->active->buf.index, vout->frame_count);
++              g_busy_cnt++;
++      }
++      vout->frame_count++;
++      mxc_v4l2out_start_pp(vout);
++
++      spin_unlock_irqrestore(&vout->irq_lock, flags);
++}
++
++irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id)
++{
++      unsigned long flags;
++      vout_data *vout = dev_id;
++      struct timeval now;
++
++      spin_lock_irqsave(&vout->irq_lock, flags);
++
++      do_gettimeofday(&now);
++      DBG(2, "%s: PP IRQ%d #%d\n", __FUNCTION__, irq, g_irq_cnt);
++
++      g_irq_cnt++;
++
++      if (WARN_ON(vout->state == STATE_STREAM_OFF && vout->active == NULL)) {
++              spin_unlock_irqrestore(&vout->irq_lock, flags);
++              return IRQ_HANDLED;
++      }
++#if 0
++      if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              struct fb_gwinfo gwinfo;
++
++              gwinfo.enabled = 1;
++              gwinfo.alpha_value = 255;
++              gwinfo.ck_enabled = 0;
++              gwinfo.xpos = vout->crop_current.left;
++              gwinfo.ypos = vout->crop_current.top;
++              gwinfo.base = vout->display_bufs[pp_num_last()];
++              gwinfo.xres = vout->crop_current.width;
++              gwinfo.yres = vout->crop_current.height;
++              gwinfo.xres_virtual = vout->crop_current.width;
++              gwinfo.vs_reversed = 0;
++
++              mx2_gw_set(&gwinfo);
++      }
++#endif
++      /* Process previous buffer */
++      BUG_ON(vout->active == NULL);
++      BUG_ON(vout->active->buf.index >= vout->buffer_cnt);
++      DBG(3, "%s: queue entry %p g_irq_cnt %d\n", __FUNCTION__,
++          vout->active, g_irq_cnt);
++      DBG(0, "%s: frame %u finished after %lums\n", __FUNCTION__,
++          g_buf_output_cnt, diff_usec(&now, &vout->frame_start) / 1000);
++      g_buf_output_cnt++;
++      vout->active->buf.flags |= V4L2_BUF_FLAG_DONE;
++      list_add_tail(&vout->active->head, &vout->done_q);
++      DBG(2, "%s: buffer[%d] %p moved to done queue %p\n", __FUNCTION__,
++          vout->active->buf.index, vout->active, &vout->done_q);
++      vout->active = NULL;
++      vout->busy = 0;
++      wake_up_interruptible(&vout->v4l_bufq);
++
++      BUG_ON(vout->active != NULL);
++
++      if ((vout->state == STATE_STREAM_ON ||
++           vout->state == STATE_STREAM_STOPPING ||
++           vout->state == STATE_STREAM_PAUSED) &&
++          !list_empty(&vout->ready_q)) {
++              vout->active = list_first_entry(&vout->ready_q, struct v4l_queue, head);
++              list_del_init(&vout->active->head);
++              vout->queued--;
++              g_buf_dq_cnt++;
++              DBG(3, "next buffer[%d] %p\n", vout->active->buf.index, vout->active);
++              if (vout->state == STATE_STREAM_PAUSED) {
++                      vout->state = STATE_STREAM_ON;
++              }
++              mxc_v4l2out_schedule_frame(vout, &vout->active->buf.timestamp, 0);
++      }
++      if (list_empty(&vout->ready_q)) {
++              if (vout->state == STATE_STREAM_STOPPING) {
++                      DBG(-1, "Stream idle\n");
++                      //vout->state = STATE_STREAM_OFF;
++              } else if (vout->state == STATE_STREAM_ON) {
++                      DBG(0, "No more buffers ready; pausing stream; queued: %d\n", vout->queued);
++                      g_paused_cnt++;
++                      vout->state = STATE_STREAM_PAUSED;
++              }
++      }
++      spin_unlock_irqrestore(&vout->irq_lock, flags);
++
++      return IRQ_HANDLED;
++}
++
++/*!
++ * Start the output stream
++ *
++ * @param vout      structure vout_data *
++ *
++ * @return status  0 Success
++ *
++ * called with vout->user_lock held
++ */
++static int mxc_v4l2out_streamon(vout_data *vout)
++{
++      unsigned long flags;
++      int ret;
++
++      if (vout->state != STATE_STREAM_OFF) {
++              return -EBUSY;
++      }
++      if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              int index = 0;
++              struct v4l_queue *q;
++
++              /* Free previously allocated buffer */
++              mxc_free_buffers(vout, &vout->display_q);
++              /* Allocate buffers for foreground */
++              ret = mxc_allocate_buffers(vout, &vout->display_q,
++                                         2, vout->display_buf_size);
++              if (ret != 2) {
++                      pr_err("unable to allocate SDC FG buffers\n");
++                      return ret;
++              }
++              list_for_each_entry(q, &vout->display_q, head) {
++                      DBG(2, "%s: Display buffer %d @ %08x\n", __FUNCTION__,
++                          index, q->dma_desc.dma_addr);
++                      vout->display_bufs[index++] = q->dma_desc.dma_addr;
++              }
++      }
++
++      /* Configure PP */
++      ret = pp_cfg(vout);
++      if (ret != 0) {
++              /* Free previously allocated buffer */
++              mxc_free_buffers(vout, &vout->display_q);
++              pr_err("failed to config PP: %d\n", ret);
++              return ret;
++      }
++
++#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
++      if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) {
++              vout->output_fb = vout->output_fb_num[vout->cur_disp_output];
++              vout->fb_enabled = 0;
++              vout->pp_ready = 0;
++              vout->fb_event_notifier.notifier_call = fb_event_notify;
++              fb_register_client(&vout->fb_event_notifier);
++              mx2fb_register_client(&vout->fb_event_notifier);
++      }
++#endif
++      spin_lock_irqsave(&vout->irq_lock, flags);
++      if (list_empty(&vout->ready_q)) {
++              pr_warn("no buffers queued yet!\n");
++              spin_unlock_irqrestore(&vout->irq_lock, flags);
++              return EINVAL;
++      }
++      BUG_ON(vout->active);
++      vout->active = list_first_entry(&vout->ready_q, struct v4l_queue, head);
++      list_del_init(&vout->active->head);
++      vout->queued--;
++      g_buf_dq_cnt++;
++      DBG(2, "%s: processing buffer[%d] %p from ready queue %p\n", __FUNCTION__,
++          vout->active->buf.index, vout->active, &vout->ready_q);
++
++      vout->frame_count = 0;
++      vout->state = STATE_STREAM_ON;
++      vout->start_jiffies = jiffies;
++      mxc_v4l2out_schedule_frame(vout, &vout->active->buf.timestamp, 1);
++      spin_unlock_irqrestore(&vout->irq_lock, flags);
++
++      return 0;
++}
++
++/*!
++ * Shut down the voutera
++ *
++ * @param vout      structure vout_data *
++ *
++ * @return status  0 Success
++ *
++ * called with vout->user_lock held
++ */
++static int mxc_v4l2out_streamoff(vout_data *vout)
++{
++      struct v4l_queue *q;
++      struct v4l_queue *tmp;
++      unsigned long flags;
++
++      if (vout->state == STATE_STREAM_OFF) {
++              return -EINVAL;
++      }
++
++      del_timer_sync(&vout->output_timer);
++
++      pp_enable(0);           /* Disable PP */
++
++      spin_lock_irqsave(&vout->irq_lock, flags);
++
++      if (vout->active != NULL) {
++#ifdef DEBUG
++              list_for_each_entry(q, &vout->free_q, head) {
++                      DBG(-1, "%s: dma_addr: %08x cpu_addr: %p size %08x\n", __FUNCTION__,
++                          q->dma_desc.dma_addr, q->dma_desc.cpu_addr, q->dma_desc.size);
++              }
++#endif
++              DBG(-1, "%s: Moving active buffer %p (%08x:%p) to free list\n", __FUNCTION__,
++                  vout->active, vout->active->dma_desc.dma_addr,
++                  vout->active->dma_desc.cpu_addr);
++              list_add_tail(&vout->active->head, &vout->free_q);
++#ifdef DEBUG
++              list_for_each_entry(q, &vout->free_q, head) {
++                      DBG(-1, "%s: dma_addr: %08x cpu_addr: %p size %08x\n", __FUNCTION__,
++                          q->dma_desc.dma_addr, q->dma_desc.cpu_addr, q->dma_desc.size);
++              }
++#endif
++              vout->active = NULL;
++      }
++      list_for_each_entry_safe(q, tmp, &vout->ready_q, head) {
++              DBG(-1, "%s: Moving buffer %p (%08x:%p) from ready to free list\n", __FUNCTION__,
++                  q, q->dma_desc.dma_addr, q->dma_desc.cpu_addr);
++              list_move_tail(&q->head, &vout->free_q);
++              vout->queued--;
++      }
++      list_for_each_entry_safe(q, tmp, &vout->done_q, head) {
++              DBG(-1, "%s: Moving buffer %p (%08x:%p) from done to free list\n", __FUNCTION__,
++                  q, q->dma_desc.dma_addr, q->dma_desc.cpu_addr);
++              list_move_tail(&q->head, &vout->free_q);
++      }
++
++      BUG_ON(vout->queued < 0);
++      if (WARN_ON(vout->queued)) {
++              DBG(-1, "queued=%d\n", vout->queued);
++      }
++      list_for_each_entry(q, &vout->free_q, head) {
++              DBG(-1, "%s: Reinitializing buffer %p (%08x:%p)\n", __FUNCTION__,
++                  q, q->dma_desc.dma_addr, q->dma_desc.cpu_addr);
++              q->buf.flags = 0;
++              q->buf.timestamp.tv_sec = 0;
++              q->buf.timestamp.tv_usec = 0;
++      }
++
++      vout->state = STATE_STREAM_OFF;
++#if 0
++      if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) {
++              struct fb_gwinfo gwinfo;
++
++              /* Disable graphic window */
++              gwinfo.enabled = 0;
++              mx2_gw_set(&gwinfo);
++      }
++#endif
++#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
++      if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) {
++              vout->output_fb = -1;
++              vout->fb_enabled = 0;
++              vout->pp_ready = 0;
++              fb_unregister_client(&vout->fb_event_notifier);
++              mx2fb_unregister_client(&vout->fb_event_notifier);
++      }
++#endif
++      spin_unlock_irqrestore(&vout->irq_lock, flags);
++      mxc_free_buffers(vout, &vout->display_q);
++      up(&vout->user_lock);
++
++      return 0;
++}
++
++/*
++ * Valid whether the palette is supported
++ *
++ * @param palette  V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32
++ *
++ * @return 1 if supported, 0 if failed
++ */
++static inline int valid_mode(u32 palette)
++{
++      return palette == V4L2_PIX_FMT_YUV420 ||
++              palette == V4L2_PIX_FMT_YUV422P;
++}
++
++/*
++ * Returns bits per pixel for given pixel format
++ *
++ * @param pixelformat  V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32
++ *
++ * @return bits per pixel of pixelformat
++ */
++static u32 fmt_to_bpp(u32 pixelformat)
++{
++      u32 bpp;
++
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_RGB565:
++              bpp = 16;
++              break;
++      case V4L2_PIX_FMT_BGR24:
++      case V4L2_PIX_FMT_RGB24:
++              bpp = 24;
++              break;
++      case V4L2_PIX_FMT_BGR32:
++      case V4L2_PIX_FMT_RGB32:
++              bpp = 32;
++              break;
++      default:
++              bpp = 8;
++              break;
++      }
++      return bpp;
++}
++
++/*
++ * V4L2 - Handles VIDIOC_G_FMT Ioctl
++ *
++ * @param vout         structure vout_data *
++ *
++ * @param v4l2_format structure v4l2_format *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2out_g_fmt(vout_data *vout, struct v4l2_format *f)
++{
++      if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++              return -EINVAL;
++      }
++      *f = vout->v2f;
++      DBG(0, "%s: fmt=%dx%d %08x bpl=%d size=%d colorspace=%d\n", __FUNCTION__,
++          f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat,
++          f->fmt.pix.bytesperline, f->fmt.pix.sizeimage, f->fmt.pix.colorspace);
++      return 0;
++}
++
++/*
++ * V4L2 - Handles VIDIOC_S_FMT Ioctl
++ *
++ * @param vout         structure vout_data *
++ *
++ * @param v4l2_format structure v4l2_format *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2out_s_fmt(vout_data *vout, struct v4l2_format *f)
++{
++      int retval = 0;
++      u32 size = 0;
++      u32 bytesperline;
++
++      DBG(0, "%s: fmt=%dx%d %08x bpl=%d size=%d colorspace=%d\n", __FUNCTION__,
++          f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.pixelformat,
++          f->fmt.pix.bytesperline, f->fmt.pix.sizeimage, f->fmt.pix.colorspace);
++
++      if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++              pr_err("buffer type %d not supported\n", f->type);
++              retval = -EINVAL;
++              goto err0;
++      }
++      if (!valid_mode(f->fmt.pix.pixelformat)) {
++              pr_err("pixel format %08x not supported\n", f->fmt.pix.pixelformat);
++              retval = -EINVAL;
++              goto err0;
++      }
++
++      bytesperline = (f->fmt.pix.width * fmt_to_bpp(f->fmt.pix.pixelformat)) / 8;
++      if (f->fmt.pix.bytesperline < bytesperline) {
++              f->fmt.pix.bytesperline = bytesperline;
++      } else {
++              bytesperline = f->fmt.pix.bytesperline;
++      }
++      if (bytesperline == 0) {
++              return -EINVAL;
++      }
++
++      vout->v2f.fmt.pix.width = f->fmt.pix.width;
++      vout->v2f.fmt.pix.height = f->fmt.pix.height;
++      vout->v2f.fmt.pix.priv = f->fmt.pix.priv;
++      if (vout->v2f.fmt.pix.priv) {
++              if (copy_from_user(&vout->crop_rect,
++                                 (void __user *)vout->v2f.fmt.pix.priv,
++                                 sizeof(struct v4l2_rect))) {
++                      retval = -EFAULT;
++                      goto err0;
++              }
++      }
++      DBG(0, "%s: format: %dx%d-%dbpp %u bytes per line\n", __FUNCTION__,
++          f->fmt.pix.width, f->fmt.pix.height, fmt_to_bpp(f->fmt.pix.pixelformat),
++          bytesperline);
++
++      if ((vout->crop_rect.top > f->fmt.pix.height) ||
++          (vout->crop_rect.left > f->fmt.pix.width)) {
++              retval = -EINVAL;
++              goto err0;
++      }
++
++      if ((vout->crop_rect.top + vout->crop_rect.height) > f->fmt.pix.height)
++              vout->crop_rect.height =
++                  f->fmt.pix.height - vout->crop_rect.top;
++      if ((vout->crop_rect.left + vout->crop_rect.width) > f->fmt.pix.width)
++              vout->crop_rect.width = f->fmt.pix.width - vout->crop_rect.left;
++
++      vout->crop_rect.width -= vout->crop_rect.width % 8;
++      vout->crop_rect.height -= vout->crop_rect.height % 8;
++      vout->crop_rect.top -= vout->crop_rect.top % 2;
++      vout->crop_rect.left += vout->crop_rect.left % 2;
++
++      switch (f->fmt.pix.pixelformat) {
++      case V4L2_PIX_FMT_YUV422P:
++              /* bytesperline for YUV planar formats is for
++                 Y plane only */
++              size = bytesperline * f->fmt.pix.height * 2;
++              if ((vout->crop_rect.width != 0)
++                  && (vout->crop_rect.height != 0)) {
++                      vout->offset.y_offset =
++                          (vout->v2f.fmt.pix.width * vout->crop_rect.top) +
++                          (vout->crop_rect.left);
++                      vout->offset.u_offset =
++                          (vout->v2f.fmt.pix.width *
++                           vout->v2f.fmt.pix.height) +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->crop_rect.top) >> 1) +
++                          (vout->crop_rect.left >> 1);
++                      vout->offset.v_offset =
++                          (vout->v2f.fmt.pix.width *
++                           vout->v2f.fmt.pix.height) +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->v2f.fmt.pix.height) >> 1) +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->crop_rect.top) >> 1) +
++                          (vout->crop_rect.left >> 1);
++                      vout->offset.qp_offset =
++                          ((vout->v2f.fmt.pix.width *
++                            vout->v2f.fmt.pix.height) << 1) +
++                          (((vout->v2f.fmt.pix.width * vout->crop_rect.top) +
++                            vout->crop_rect.left) >> 10);
++              } else {
++                      vout->offset.y_offset = 0;
++                      vout->offset.u_offset =
++                          (vout->v2f.fmt.pix.width *
++                           vout->v2f.fmt.pix.height);
++                      vout->offset.v_offset =
++                          vout->offset.u_offset +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->v2f.fmt.pix.height) >> 1);
++                      vout->offset.qp_offset =
++                          vout->offset.v_offset +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->v2f.fmt.pix.height) >> 1);
++              }
++              break;
++      case V4L2_PIX_FMT_YUV420:
++              size = (bytesperline * f->fmt.pix.height * 3) / 2;
++              if ((vout->crop_rect.width != 0)
++                  && (vout->crop_rect.height != 0)) {
++                      vout->offset.y_offset =
++                          (vout->v2f.fmt.pix.width * vout->crop_rect.top) +
++                          (vout->crop_rect.left);
++                      vout->offset.u_offset =
++                          (vout->v2f.fmt.pix.width *
++                           vout->v2f.fmt.pix.height) +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->crop_rect.top) >> 2) +
++                          (vout->crop_rect.left >> 1);
++                      vout->offset.v_offset =
++                          (vout->v2f.fmt.pix.width *
++                           vout->v2f.fmt.pix.height) +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->v2f.fmt.pix.height) >> 2) +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->crop_rect.top) >> 2) +
++                          (vout->crop_rect.left >> 1);
++                      vout->offset.qp_offset =
++                          (vout->v2f.fmt.pix.width *
++                           vout->v2f.fmt.pix.height) +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->v2f.fmt.pix.height) >> 1) +
++                          (((vout->v2f.fmt.pix.width * vout->crop_rect.top) +
++                            vout->crop_rect.left) >> 10);
++              } else {
++                      vout->offset.y_offset = 0;
++                      vout->offset.u_offset =
++                          (vout->v2f.fmt.pix.width *
++                           vout->v2f.fmt.pix.height);
++                      vout->offset.v_offset =
++                          vout->offset.u_offset +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->v2f.fmt.pix.height) >> 2);
++                      vout->offset.qp_offset =
++                          vout->offset.v_offset +
++                          ((vout->v2f.fmt.pix.width *
++                            vout->v2f.fmt.pix.height) >> 2);
++              }
++              break;
++      default:
++              size = bytesperline * f->fmt.pix.height;
++              vout->offset.y_offset = 0;
++              vout->offset.u_offset =
++                  (vout->v2f.fmt.pix.width * vout->v2f.fmt.pix.height);
++              vout->offset.v_offset =
++                  vout->offset.u_offset +
++                  ((vout->v2f.fmt.pix.width * vout->v2f.fmt.pix.height) >> 2);
++              vout->offset.qp_offset =
++                  vout->offset.v_offset +
++                  ((vout->v2f.fmt.pix.width * vout->v2f.fmt.pix.height) >> 2);
++              break;
++      }
++
++      /* Return the actual size of the image to the app */
++      f->fmt.pix.sizeimage = size;
++      vout->v2f.fmt.pix.sizeimage = size;
++      vout->v2f.fmt.pix.pixelformat = f->fmt.pix.pixelformat;
++      vout->v2f.fmt.pix.bytesperline = f->fmt.pix.bytesperline;
++
++      DBG(0, "%s: Y: %08x..%08x\n", __FUNCTION__,
++          vout->offset.y_offset, vout->offset.y_offset + f->fmt.pix.height * bytesperline);
++      DBG(0, "%s: U: %08x..%08x\n", __FUNCTION__,
++          vout->offset.u_offset, vout->offset.u_offset + f->fmt.pix.height * bytesperline / 2);
++      DBG(0, "%s: V: %08x..%08x\n", __FUNCTION__,
++          vout->offset.v_offset, vout->offset.v_offset + f->fmt.pix.height * bytesperline / 2);
++
++      retval = 0;
++ err0:
++      return retval;
++}
++
++/*
++ * V4L2 - Handles VIDIOC_G_CTRL Ioctl
++ *
++ * @param vout         structure vout_data *
++ *
++ * @param c           structure v4l2_control *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_get_v4l2out_control(vout_data *vout, struct v4l2_control *c)
++{
++      switch (c->id) {
++      case V4L2_CID_HFLIP:
++              c->value = (vout->rotate & IPU_ROTATE_HORIZ_FLIP) ? 1 : 0;
++              break;
++      case V4L2_CID_VFLIP:
++              c->value = (vout->rotate & IPU_ROTATE_VERT_FLIP) ? 1 : 0;
++              break;
++      case (V4L2_CID_PRIVATE_BASE + 1):
++              c->value = vout->rotate;
++              break;
++      case V4L2_CID_MXC_TEAR_PROTECT:
++              c->value = vout->tear_protection;
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/*
++ * V4L2 - Handles VIDIOC_S_CTRL Ioctl
++ *
++ * @param vout         structure vout_data *
++ *
++ * @param c           structure v4l2_control *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_set_v4l2out_control(vout_data *vout, struct v4l2_control *c)
++{
++      switch (c->id) {
++      case V4L2_CID_HFLIP:
++      case V4L2_CID_VFLIP:
++      case V4L2_CID_MXC_ROT:
++              if (c->value < 0 || c->value > 7) {
++                      return -EINVAL;
++              }
++              vout->rotate = c->value;
++              break;
++      case V4L2_CID_MXC_TEAR_PROTECT:
++#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
++              if (c->value == TEARING_PROTECTION_ACTIVE)
++                      vout->tear_protection = TEARING_PROTECTION_ACTIVE;
++              else
++                      vout->tear_protection = TEARING_PROTECTION_INACTIVE;;
++#else
++              vout->tear_protection = TEARING_PROTECTION_UNSUPPORTED;
++#endif
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/*!
++ * V4L2 interface - open function
++ *
++ * @param inode        structure inode *
++ *
++ * @param file         structure file *
++ *
++ * @return  status    0 success, ENODEV invalid device instance,
++ *                    ENODEV timeout, ERESTARTSYS interrupted by user
++ */
++static int mxc_v4l2out_open(struct inode *inode, struct file *file)
++{
++      struct video_device *dev = video_devdata(file);
++      vout_data *vout = video_get_drvdata(dev);
++      int err;
++
++      dq_intr_cnt = 0;
++      if (!vout) {
++              pr_info("Internal error, vout_data not found!\n");
++              return -ENODEV;
++      }
++
++      down(&vout->user_lock);
++      if (vout->open_count == 0) {
++              err = pp_init(vout);
++              if (err) {
++                      goto out;
++              }
++              init_timer(&vout->output_timer);
++              vout->output_timer.function = mxc_v4l2out_timer_handler;
++              vout->output_timer.data = (unsigned long)vout;
++
++              vout->state = STATE_STREAM_OFF;
++              vout->queued = 0;
++              g_irq_cnt = g_buf_output_cnt = g_buf_q_cnt = g_buf_dq_cnt = 0;
++              g_busy_cnt = 0;
++              g_paused_cnt = 0;
++              g_late_cnt = 0;
++              using_default_fps = -1;
++              vout->open_count++;
++      }
++#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
++      vout->tear_protection = TEARING_PROTECTION_ACTIVE;
++#else
++      vout->tear_protection = TEARING_PROTECTION_UNSUPPORTED;
++#endif
++
++      file->private_data = dev;
++ out:
++      up(&vout->user_lock);
++      return err;
++}
++
++/*!
++ * V4L2 interface - close function
++ *
++ * @param inode    struct inode *
++ *
++ * @param file     struct file *
++ *
++ * @return         0 success
++ */
++static int mxc_v4l2out_close(struct inode *inode, struct file *file)
++{
++      struct video_device *dev = file->private_data;
++      vout_data *vout = video_get_drvdata(dev);
++
++      down(&vout->user_lock);
++      if (vout->open_count) {
++              DBG(-1, "%s: %u interrupts handled frames output: %u queued: %u dequeued: %u paused: %u busy: %u late: %u\n",
++                  __FUNCTION__, g_irq_cnt, g_buf_output_cnt, g_buf_q_cnt, g_buf_dq_cnt,
++                  g_paused_cnt, g_busy_cnt, g_late_cnt);
++
++              pp_exit(vout);
++              mxc_v4l2out_streamoff(vout);
++              file->private_data = NULL;
++              WARN_ON(!list_empty(&vout->done_q));
++              if (WARN_ON(vout->active)) {
++                      DBG(-1, "%s: Moving active buffer %p (%08x:%p) to done list\n",
++                          __FUNCTION__, vout->active, vout->active->dma_desc.dma_addr,
++                          vout->active->dma_desc.cpu_addr);
++                      list_add_tail(&vout->active->head, &vout->done_q);
++                      vout->active = NULL;
++              }
++              WARN_ON(!list_empty(&vout->ready_q));
++              DBG(-1, "%s: Releasing buffers from ready queue\n", __FUNCTION__);
++              mxc_free_buffers(vout, &vout->ready_q);
++              DBG(-1, "%s: Releasing buffers from done queue\n", __FUNCTION__);
++              mxc_free_buffers(vout, &vout->done_q);
++              DBG(-1, "%s: Releasing buffers from free queue\n", __FUNCTION__);
++              mxc_free_buffers(vout, &vout->free_q);
++              vout->buffer_cnt = 0;
++              DBG(-1, "%s: Releasing display buffers\n", __FUNCTION__);
++              mxc_free_buffers(vout, &vout->display_q);
++
++              /* capture off */
++              wake_up_interruptible(&vout->v4l_bufq);
++              WARN_ON(--vout->open_count);
++      }
++      up(&vout->user_lock);
++
++      return 0;
++}
++
++static int do_dequeue(vout_data *vout, struct v4l2_buffer *user_buf)
++{
++      int retval;
++      unsigned long flags;
++
++      if (vout->active == NULL &&
++          list_empty(&vout->done_q) &&
++          list_empty(&vout->ready_q)) {
++              return -EINVAL;
++      }
++      up(&vout->user_lock);
++      retval = wait_event_interruptible_timeout(vout->v4l_bufq,
++                                                !list_empty(&vout->done_q),
++                                                10 * HZ);
++      down(&vout->user_lock);
++      spin_lock_irqsave(&vout->irq_lock, flags);
++      if (retval >= 0 && !list_empty(&vout->done_q)) {
++              struct v4l_queue *q;
++              struct v4l2_buffer *buf;
++
++              q = list_first_entry(&vout->done_q, struct v4l_queue, head);
++              DBG(2, "%s: processing buffer[%d] %p from done queue %p\n",
++                  __FUNCTION__, q->buf.index, q, &vout->done_q);
++              WARN_ON(!(q->buf.flags & V4L2_BUF_FLAG_DONE));
++              q->buf.flags &= ~(V4L2_BUF_FLAG_DONE | V4L2_BUF_FLAG_QUEUED);
++              list_move_tail(&q->head, &vout->free_q);
++              buf = &q->buf;
++              DBG(2, "%s: buffer[%d] %p moved to free queue %p\n", __FUNCTION__,
++                  buf->index, q, &vout->free_q);
++              BUG_ON(buf->index >= vout->buffer_cnt);
++              if (user_buf != NULL) {
++                      memcpy(user_buf, buf, sizeof(*user_buf));
++              }
++              DBG(1, "VIDIOC_DQBUF: buffer %d: %d\n", buf->index, retval);
++              retval = 0;
++      } else if (retval == 0) {
++              pr_warn("VIDIOC_DQBUF: timeout\n");
++              retval = -ETIME;
++              DBG(3, "VIDIOC_DQBUF: ret: %d\n", retval);
++      }
++      spin_unlock_irqrestore(&vout->irq_lock, flags);
++      return retval;
++}
++/*!
++ * V4L2 interface - ioctl function
++ *
++ * @param inode      struct inode *
++ *
++ * @param file       struct file *
++ *
++ * @param ioctlnr    unsigned int
++ *
++ * @param arg        void *
++ *
++ * @return           0 success, ENODEV for invalid device instance,
++ *                   -1 for other errors.
++ */
++static int
++mxc_v4l2out_do_ioctl(struct inode *inode, struct file *file,
++                   unsigned int ioctlnr, void *arg)
++{
++      struct video_device *vdev = file->private_data;
++      vout_data *vout = video_get_drvdata(vdev);
++      int retval = 0;
++      int i = 0;
++
++      if (dbg_lvl(3)) {
++              v4l_printk_ioctl(ioctlnr);
++              printk(" arg=%p\n", arg);
++      }
++
++      if (!vout)
++              return -EBADF;
++
++      down(&vout->user_lock);
++      switch (ioctlnr) {
++      case VIDIOC_QUERYCAP:
++              {
++                      struct v4l2_capability *cap = arg;
++                      strcpy(cap->driver, "mxc_v4l2_output");
++                      cap->version = 0;
++                      cap->capabilities = V4L2_CAP_VIDEO_OUTPUT |
++                              V4L2_CAP_STREAMING;
++                      strlcpy(cap->card, "MX27 eMMA", sizeof(cap->card));
++                      cap->bus_info[0] = '\0';
++                      retval = 0;
++              }
++              break;
++      case VIDIOC_G_FMT:
++              {
++                      struct v4l2_format *gf = arg;
++                      retval = mxc_v4l2out_g_fmt(vout, gf);
++              }
++              break;
++      case VIDIOC_S_FMT:
++              {
++                      struct v4l2_format *sf = arg;
++                      if (vout->state != STATE_STREAM_OFF) {
++                              retval = -EBUSY;
++                              break;
++                      }
++                      retval = mxc_v4l2out_s_fmt(vout, sf);
++              }
++              break;
++      case VIDIOC_REQBUFS:
++              {
++                      struct v4l2_requestbuffers *req = arg;
++                      struct v4l_queue *q;
++                      size_t bufsize = PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage);
++                      unsigned long flags;
++
++                      if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
++                          (req->memory != V4L2_MEMORY_MMAP)) {
++                              pr_warn("VIDIOC_REQBUFS: incorrect buffer type: %d\n", req->type);
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      DBG(0, "%s: VIDIOC_REQBUFS: %d buffers of %u byte requested\n",
++                          __FUNCTION__, req->count, bufsize);
++
++                      if (req->count == 0) {
++                              spin_lock_irqsave(&vout->irq_lock, flags);
++                              if (vout->state == STATE_STREAM_ON) {
++                                      vout->state = STATE_STREAM_STOPPING;
++                              }
++                              spin_unlock_irqrestore(&vout->irq_lock, flags);
++                              while (vout->active || !list_empty(&vout->ready_q)) {
++                                      DBG(-1, "%s: Waiting for stream to drain queued: %d\n",
++                                          __FUNCTION__, vout->queued);
++                                      retval = do_dequeue(vout, NULL);
++                                      if (retval != 0) {
++                                              DBG(-1, "do_dequeue() returned %d\n", retval);
++                                      }
++                                      if (retval == -ERESTARTSYS) {
++                                              break;
++                                      }
++                              }
++#if 1
++                              retval = mxc_v4l2out_streamoff(vout);
++#else
++                              pp_enable(0);           /* Disable PP */
++                              WARN_ON(!list_empty(&vout->ready_q));
++                              WARN_ON(vout->active);
++                              mxc_free_buffers(vout, &vout->done_q);
++                              mxc_free_buffers(vout, &vout->free_q);
++#endif
++                              break;
++                      }
++                      if (vout->state != STATE_STREAM_OFF) {
++                              pr_warn("VIDIOC_REQBUFS: streaming active\n");
++                              retval = -EBUSY;
++                              break;
++                      }
++#if 0
++                      if (!list_empty(&vout->done_q) || !list_empty(&vout->ready_q)) {
++                              pr_warn("VIDIOC_REQBUFS: busy buffers exist\n");
++                              retval = -EBUSY;
++                              break;
++                      }
++#endif
++                      /* This needs no interrupt locking, since we have the busy_lock
++                       * and are in STATE_STREAM_OFF where there cannot be any interrupts
++                       */
++                      if (!list_empty(&vout->free_q)) {
++                              q = list_first_entry(&vout->free_q, struct v4l_queue, head);
++                              if (q->buf.length != bufsize ||
++                                  q->buf.type != req->type ||
++                                  q->buf.memory != req->memory) {
++                                      pr_err("VIDIOC_REQBUFS: Mismatch between old and new buffer parameters\n");
++                                      retval = -EINVAL;
++                                      break;
++                              }
++                      }
++
++                      if (req->count > MAX_FRAME_NUM) {
++                              req->count = MAX_FRAME_NUM;
++                      }
++                      if (req->count == vout->buffer_cnt) {
++                              break;
++                      } else if (req->count < vout->buffer_cnt) {
++                              struct list_head release_q;
++                              struct list_head *tmp;
++                              struct list_head *x;
++
++                              list_for_each_prev_safe(x, tmp, &vout->free_q) {
++                                      if (vout->buffer_cnt-- > req->count) {
++                                              q = container_of(x, struct v4l_queue, head);
++                                              DBG(-1, "%s: Moving buffer[%d:%d] %p (%08x:%p) from free to release list\n",
++                                                  __FUNCTION__, vout->buffer_cnt,
++                                                  q->buf.index, q, q->dma_desc.dma_addr,
++                                                  q->dma_desc.cpu_addr);
++                                              list_move(x, &release_q);
++                                      }
++                              }
++                              BUG_ON(vout->buffer_cnt != req->count);
++                              mxc_free_buffers(vout, &release_q);
++                              break;
++                      }
++                      retval = mxc_allocate_buffers(vout, &vout->free_q,
++                                                    req->count - vout->buffer_cnt,
++                                                    bufsize);
++                      if (retval + vout->buffer_cnt < req->count) {
++                              pr_warn("Could only allocate %u of %u buffers\n",
++                                      retval + vout->buffer_cnt, req->count);
++                              req->count = retval + vout->buffer_cnt;
++                      }
++                      vout->buffer_cnt = req->count;
++                      i = 0;
++                      list_for_each_entry(q, &vout->free_q, head) {
++                              q->buf.memory = V4L2_MEMORY_MMAP;
++                              q->buf.index = i;
++                              q->buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
++                              q->buf.length = bufsize;
++                              q->buf.m.offset = q->dma_desc.dma_addr;
++                              i++;
++                      }
++                      BUG_ON(i != vout->buffer_cnt);
++              }
++              break;
++      case VIDIOC_QUERYBUF:
++              {
++                      struct v4l2_buffer *buf = arg;
++                      struct v4l_queue *q;
++                      unsigned long flags;
++
++                      if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++                              pr_warn("VIDIOC_QUERYBUF: incorrect buffer type: %d expected %d\n",
++                                      buf->type, V4L2_BUF_TYPE_VIDEO_OUTPUT);
++                              retval = -EINVAL;
++                              break;
++                      }
++                      if (buf->index >= vout->buffer_cnt) {
++                              pr_warn("VIDIOC_QUERYBUF: buffer index out of range: %d [0..%d]\n",
++                                      buf->index, vout->buffer_cnt);
++                              retval = -EINVAL;
++                              break;
++                      }
++                      spin_lock_irqsave(&vout->irq_lock, flags);
++                      q = find_buffer(&vout->free_q, buf->index);
++                      if (q == NULL) {
++                              q = find_buffer(&vout->ready_q, buf->index);
++                              if (q == NULL) {
++                                      q = find_buffer(&vout->done_q, buf->index);
++                                      if (q != NULL) {
++                                              DBG(2, "VIDIOC_QUERYBUF: buffer[%d] %p found in done list\n",
++                                                  q->buf.index, q);
++                                      }
++                              } else {
++                                      DBG(2, "VIDIOC_QUERYBUF: buffer[%d] %p found in ready list\n",
++                                          q->buf.index, q);
++                              }
++                      } else {
++                              DBG(2, "VIDIOC_QUERYBUF: buffer[%d] %p found in free list\n",
++                                  q->buf.index, q);
++                      }
++                      spin_unlock_irqrestore(&vout->irq_lock, flags);
++                      if (q == NULL) {
++                              pr_warn("VIDIOC_QUERYBUF: buffer %d not found in any list\n",
++                                      buf->index);
++                              retval = -ENOENT;
++                              break;
++                      }
++                      memcpy(buf, &q->buf, sizeof(q->buf));
++              }
++              break;
++      case VIDIOC_QBUF:
++              {
++                      struct v4l2_buffer *buf = arg;
++                      struct v4l_queue *q;
++                      unsigned long flags;
++
++                      if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++                              pr_err("VIDIOC_QBUF: invalid buffer type: %u\n",
++                                     buf->type);
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      if (buf->index >= vout->buffer_cnt) {
++                              pr_err("VIDIOC_QBUF: invalid buffer index: %u/%u\n",
++                                     buf->index, vout->buffer_cnt);
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      if (vout->state == STATE_STREAM_STOPPING) {
++                              pr_err("VIDIOC_QBUF: stream is draining\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++                      DBG(1, "VIDIOC_QBUF: %d/%d ts %6lu.%06lu\n", buf->index,
++                          vout->queued, buf->timestamp.tv_sec, buf->timestamp.tv_usec);
++
++                      spin_lock_irqsave(&vout->irq_lock, flags);
++                      q = find_buffer(&vout->free_q, buf->index);
++                      if (q == NULL || (q->buf.flags & V4L2_BUF_FLAG_QUEUED)) {
++                              spin_unlock_irqrestore(&vout->irq_lock, flags);
++                              if (q == NULL) {
++                                      printk(KERN_ERR "buffer %d not on free queue %p\n",
++                                             buf->index, &vout->free_q);
++                                      retval = -ENOENT;
++                              } else {
++                                      retval = -EBUSY;
++                              }
++                              break;
++                      }
++                      q->buf.timestamp = buf->timestamp;
++                      buf = &q->buf;
++                      WARN_ON(buf->flags & V4L2_BUF_FLAG_DONE);
++                      buf->flags |= V4L2_BUF_FLAG_QUEUED;
++
++                      BUG_ON(buf->index >= vout->buffer_cnt);
++
++                      if (vout->state == STATE_STREAM_PAUSED &&
++                          vout->active == NULL) {
++                              DBG(0, "%s: Restarting stream\n", __FUNCTION__);
++                              vout->active = q;
++                              list_del_init(&vout->active->head);
++                              vout->state = STATE_STREAM_ON;
++
++                              mxc_v4l2out_schedule_frame(vout, &buf->timestamp, 0);
++                      } else {
++                              list_move_tail(&q->head, &vout->ready_q);
++                              vout->queued++;
++                              g_buf_q_cnt++;
++                              DBG(2, "%s: buffer[%d] %p moved to ready queue %p\n", __FUNCTION__,
++                                  buf->index, q, &vout->ready_q);
++                      }
++                      if (vout->state == STATE_STREAM_PAUSED) {
++                              vout->state = STATE_STREAM_ON;
++                      }
++                      spin_unlock_irqrestore(&vout->irq_lock, flags);
++              }
++              break;
++      case VIDIOC_DQBUF:
++              {
++                      struct v4l2_buffer *buf = arg;
++
++                      DBG(1, "VIDIOC_DQBUF: queued: %d\n", vout->queued);
++
++                      if (list_empty(&vout->done_q) &&
++                          (file->f_flags & O_NONBLOCK)) {
++                              retval = -EAGAIN;
++                              DBG(3, "VIDIOC_DQBUF: ret: %d\n", retval);
++                              break;
++                      }
++
++                      retval = do_dequeue(vout, buf);
++                      if (retval == -ETIME) {
++                              pr_warn("VIDIOC_DQBUF: timeout\n");
++                              DBG(3, "VIDIOC_DQBUF: ret: %d\n", retval);
++                      } else if (retval == -ERESTARTSYS) {
++                              if (dq_intr_cnt == 0)
++                                      DBG(0, "VIDIOC_DQBUF: interrupt received\n");
++                              dq_intr_cnt++;
++                              DBG(0, "VIDIOC_DQBUF: ret: %d\n", retval);
++                      } else {
++                              DBG(0, "VIDIOC_DQBUF: ret: %d\n", retval);
++                      }
++              }
++              break;
++      case VIDIOC_STREAMON:
++              retval = mxc_v4l2out_streamon(vout);
++              break;
++      case VIDIOC_STREAMOFF:
++              retval = mxc_v4l2out_streamoff(vout);
++              break;
++      case VIDIOC_G_CTRL:
++              retval = mxc_get_v4l2out_control(vout, arg);
++              break;
++      case VIDIOC_S_CTRL:
++              retval = mxc_set_v4l2out_control(vout, arg);
++              break;
++      case VIDIOC_CROPCAP:
++              {
++                      struct v4l2_cropcap *cap = arg;
++
++                      if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      cap->bounds = vout->crop_bounds[vout->cur_disp_output];
++                      cap->defrect = vout->crop_bounds[vout->cur_disp_output];
++                      retval = 0;
++              }
++              break;
++      case VIDIOC_G_CROP:
++              {
++                      struct v4l2_crop *crop = arg;
++
++                      if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      crop->c = vout->crop_current;
++              }
++              break;
++      case VIDIOC_S_CROP:
++              {
++                      struct v4l2_crop *crop = arg;
++                      struct v4l2_rect *b = &vout->crop_bounds[vout->cur_disp_output];
++
++                      if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      if (crop->c.height < 0) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      if (crop->c.width < 0) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      if (crop->c.top < b->top)
++                              crop->c.top = b->top;
++                      if (crop->c.top > b->top + b->height)
++                              crop->c.top = b->top + b->height;
++                      if (crop->c.height > b->top - crop->c.top + b->height)
++                              crop->c.height =
++                                  b->top - crop->c.top + b->height;
++
++                      if (crop->c.left < b->left)
++                              crop->c.top = b->left;
++                      if (crop->c.left > b->left + b->width)
++                              crop->c.top = b->left + b->width;
++                      if (crop->c.width > b->left - crop->c.left + b->width)
++                              crop->c.width =
++                                  b->left - crop->c.left + b->width;
++
++                      /* stride line limitation */
++                      crop->c.height -= crop->c.height % 8;
++                      crop->c.width -= crop->c.width % 8;
++
++                      vout->crop_current = crop->c;
++                      DBG(0, "%s: crop rect: %dx%d%+d%+d\n", __FUNCTION__,
++                          crop->c.width, crop->c.height,
++                          crop->c.left, crop->c.top);
++
++                      vout->display_buf_size = vout->crop_current.width *
++                          vout->crop_current.height;
++                      vout->display_buf_size *=
++                          fmt_to_bpp(SDC_FG_FB_FORMAT) / 8;
++              }
++              break;
++      case VIDIOC_ENUMOUTPUT:
++              {
++                      struct v4l2_output *output = arg;
++
++                      if ((output->index >= 2) || !vout->output_enabled[output->index]) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      memcpy(output, &mxc_outputs[0], sizeof(*output));
++                      snprintf(output->name, sizeof(output->name), mxc_outputs[0].name,
++                               output->index);
++              }
++              break;
++      case VIDIOC_G_OUTPUT:
++              {
++                      u32 *index = arg;
++
++                      *index = vout->cur_disp_output;
++              }
++              break;
++      case VIDIOC_S_OUTPUT:
++              {
++                      u32 *index = arg;
++
++                      if ((*index >= 2) || !vout->output_enabled[*index]) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      if (vout->state != STATE_STREAM_OFF) {
++                              retval = -EBUSY;
++                              break;
++                      }
++
++                      vout->cur_disp_output = *index;
++              }
++              break;
++      case VIDIOC_G_FBUF:
++              {
++                      struct v4l2_framebuffer *fb = arg;
++
++                      memcpy(fb, &vout->v4l2_fb, sizeof(*fb));
++              }
++              break;
++      case VIDIOC_S_FBUF:
++              {
++                      struct v4l2_framebuffer *fb = arg;
++
++                      memcpy(&vout->v4l2_fb, fb, sizeof(vout->v4l2_fb));
++                      vout->v4l2_fb.capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
++              }
++              break;
++      case VIDIOC_ENUM_FMT:
++      case VIDIOC_TRY_FMT:
++      case VIDIOC_QUERYCTRL:
++      case VIDIOC_G_PARM:
++      case VIDIOC_ENUMSTD:
++      case VIDIOC_G_STD:
++      case VIDIOC_S_STD:
++      case VIDIOC_G_TUNER:
++      case VIDIOC_S_TUNER:
++      case VIDIOC_G_FREQUENCY:
++      case VIDIOC_S_FREQUENCY:
++      default:
++              retval = -EINVAL;
++      }
++
++      up(&vout->user_lock);
++      return retval;
++}
++
++/*
++ * V4L2 interface - ioctl function
++ *
++ * @return  None
++ */
++static int
++mxc_v4l2out_ioctl(struct inode *inode, struct file *file,
++                unsigned int cmd, unsigned long arg)
++{
++      return video_usercopy(inode, file, cmd, arg, mxc_v4l2out_do_ioctl);
++}
++
++/*!
++ * V4L2 interface - mmap function
++ *
++ * @param file          structure file *
++ *
++ * @param vma           structure vm_area_struct *
++ *
++ * @return status       0 Success, EINTR busy lock error,
++ *                      ENOBUFS remap_page error
++ */
++static int mxc_v4l2out_mmap(struct file *file, struct vm_area_struct *vma)
++{
++      struct video_device *vdev = file->private_data;
++      unsigned long start = vma->vm_start;
++      unsigned long size = vma->vm_end - vma->vm_start;
++      int res = 0;
++      vout_data *vout = video_get_drvdata(vdev);
++
++      down(&vout->user_lock);
++
++      /* make buffers write-thru cacheable */
++      vma->vm_page_prot = __pgprot(pgprot_val(vma->vm_page_prot) &
++                                   ~L_PTE_BUFFERABLE);
++
++      if (remap_pfn_range(vma, start, vma->vm_pgoff, size, vma->vm_page_prot)) {
++              pr_err("%s: - remap_pfn_range failed\n", __FUNCTION__);
++              res = -ENOBUFS;
++      }
++
++      up(&vout->user_lock);
++      return res;
++}
++
++/*!
++ * V4L2 interface - poll function
++ *
++ * @param file       structure file *
++ *
++ * @param wait       structure poll_table *
++ *
++ * @return  status   POLLIN | POLLRDNORM
++ */
++static unsigned int mxc_v4l2out_poll(struct file *file, poll_table *wait)
++{
++      struct video_device *vdev = file->private_data;
++      vout_data *vout = video_get_drvdata(vdev);
++
++      wait_queue_head_t *queue = NULL;
++      int res = POLLIN | POLLRDNORM;
++
++      down(&vout->user_lock);
++
++      queue = &vout->v4l_bufq;
++      poll_wait(file, queue, wait);
++
++      up(&vout->user_lock);
++      return res;
++}
++
++static struct file_operations mxc_v4l2out_fops = {
++      .owner = THIS_MODULE,
++      .open = mxc_v4l2out_open,
++      .release = mxc_v4l2out_close,
++      .ioctl = mxc_v4l2out_ioctl,
++      .mmap = mxc_v4l2out_mmap,
++      .poll = mxc_v4l2out_poll,
++};
++
++static struct video_device mxc_v4l2out_template = {
++      //.owner = THIS_MODULE,
++      .name = "MXC Video Output",
++      //.type = 0,
++      //.type2 = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING,
++      //.hardware = 39,
++      .fops = &mxc_v4l2out_fops,
++      .release = video_device_release,
++};
++
++/*!
++ * Probe routine for the framebuffer driver. It is called during the
++ * driver binding process.      The following functions are performed in
++ * this routine: Framebuffer initialization, Memory allocation and
++ * mapping, Framebuffer registration, IPU initialization.
++ *
++ * @return      Appropriate error code to the kernel common code
++ */
++static int mxc_v4l2out_probe(struct platform_device *pdev)
++{
++      int ret;
++      int i;
++      vout_data *vout;
++
++      /*
++       * Allocate sufficient memory for the fb structure
++       */
++      vout = kzalloc(sizeof(vout_data), GFP_KERNEL);
++      if (!vout)
++              return -ENOMEM;
++
++      vout->video_dev = video_device_alloc();
++      if (vout->video_dev == NULL) {
++              kfree(vout);
++              return -ENOMEM;
++      }
++      *vout->video_dev = mxc_v4l2out_template;
++
++      vout->video_dev->parent = &pdev->dev;
++      vout->video_dev->minor = -1;
++
++      init_waitqueue_head(&vout->v4l_bufq);
++
++      INIT_LIST_HEAD(&vout->free_q);
++      INIT_LIST_HEAD(&vout->ready_q);
++      INIT_LIST_HEAD(&vout->done_q);
++
++      INIT_LIST_HEAD(&vout->display_q);
++
++      spin_lock_init(&vout->irq_lock);
++
++      init_MUTEX(&vout->user_lock);
++      //mutex_init(&vout->user_lock);
++
++      /* register v4l device */
++      ret = video_register_device(vout->video_dev,
++                                  VFL_TYPE_GRABBER, video_nr);
++      if (ret != 0) {
++              pr_err("video_register_device failed: %d\n", ret);
++              kfree(vout->video_dev);
++              kfree(vout);
++              return ret;
++      }
++      DBG(0, "mxc_v4l2out: registered device video%d\n",
++          vout->video_dev->minor & 0x1f);
++
++      video_set_drvdata(vout->video_dev, vout);
++      platform_set_drvdata(pdev, vout);
++
++      /* setup outputs and cropping */
++      vout->cur_disp_output = -1;
++#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
++      vout->output_fb = -1;
++#endif
++      for (i = 0; i < num_registered_fb && i < MXC_V4L2_OUT_NUM_OUTPUTS; i++) {
++              char *idstr = registered_fb[i]->fix.id;
++              DBG(0, "Checking FB '%s'\n", idstr);
++              if (strncmp(idstr, "IMX", 3) == 0) {
++                      int disp_num = i;
++                      vout->crop_bounds[disp_num].left = 0;
++                      vout->crop_bounds[disp_num].top = 0;
++                      vout->crop_bounds[disp_num].width =
++                          registered_fb[i]->var.xres;
++                      vout->crop_bounds[disp_num].height =
++                          registered_fb[i]->var.yres;
++                      vout->output_enabled[disp_num] = true;
++                      vout->output_fb_num[disp_num] = i;
++                      DBG(0, "crop bounds: %dx%d%+d%+d\n",
++                          vout->crop_bounds[disp_num].left,
++                          vout->crop_bounds[disp_num].top,
++                          vout->crop_bounds[disp_num].width,
++                          vout->crop_bounds[disp_num].height);
++                      if (vout->cur_disp_output == -1)
++                              vout->cur_disp_output = disp_num;
++              }
++
++      }
++      if (vout->cur_disp_output >= 0) {
++              vout->crop_current = vout->crop_bounds[vout->cur_disp_output];
++      }
++
++      /* Setup framebuffer parameters */
++      vout->v4l2_fb.capability = V4L2_FBUF_CAP_EXTERNOVERLAY;
++      vout->v4l2_fb.flags = V4L2_FBUF_FLAG_PRIMARY;
++      // FIXME: Use the pixelformat of the FB driver!
++      vout->v4l2_fb.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
++
++      return 0;
++}
++
++static int mxc_v4l2out_remove(struct platform_device *pdev)
++{
++      vout_data *vout = platform_get_drvdata(pdev);
++
++      video_unregister_device(vout->video_dev);
++      kfree(vout);
++      return 0;
++}
++
++#define DRV_NAME "MXC Video Output"
++/*!
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct platform_driver mxc_v4l2out_driver = {
++      .driver = {
++              .name = DRV_NAME,
++              .owner = THIS_MODULE,
++      },
++      .probe = mxc_v4l2out_probe,
++      .remove = mxc_v4l2out_remove,
++};
++
++#ifdef REGISTER_PDEV
++#if 1
++static struct platform_device *mxc_v4l2out_device;
++#else
++static struct platform_device mxc_v4l2out_device = {
++      .name = "MXC Video Output",
++      .id = 0,
++};
++#endif
++#endif
++
++/*!
++ * mxc v4l2 init function
++ *
++ */
++static int mxc_v4l2out_init(void)
++{
++      int err;
++
++      err = platform_driver_register(&mxc_v4l2out_driver);
++#ifdef REGISTER_PDEV
++      if (err == 0) {
++#if 1
++              mxc_v4l2out_device = platform_device_register_simple(DRV_NAME, 0, NULL, 0);
++              if (IS_ERR(mxc_v4l2out_device)) {
++                      platform_driver_unregister(&mxc_v4l2out_driver);
++                      return PTR_ERR(mxc_v4l2out_device);
++              }
++#else
++              platform_device_register(&mxc_v4l2out_device);
++#endif
++      }
++#endif
++      return err;
++}
++
++/*!
++ * mxc v4l2 cleanup function
++ *
++ */
++static void mxc_v4l2out_clean(void)
++{
++      DBG(0, "unregistering video\n");
++
++      platform_driver_unregister(&mxc_v4l2out_driver);
++#ifdef REGISTER_PDEV
++#if 1
++      platform_device_unregister(mxc_v4l2out_device);
++#else
++      platform_device_unregister(&mxc_v4l2out_device);
++#endif
++#endif
++}
++
++module_init(mxc_v4l2out_init);
++module_exit(mxc_v4l2out_clean);
++
++module_param(video_nr, int, S_IRUGO);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("V4L2-driver for MXC video output");
++MODULE_LICENSE("GPL");
++MODULE_SUPPORTED_DEVICE("video");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/output/mxc_v4l2_output.c linux-2.6.28-karo/drivers/media/video/mxc/output/mxc_v4l2_output.c
+--- linux-2.6.28/drivers/media/video/mxc/output/mxc_v4l2_output.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/output/mxc_v4l2_output.c 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,1720 @@
++/*
++ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file drivers/media/video/mxc/output/mxc_v4l2_output.c
++ *
++ * @brief MXC V4L2 Video Output Driver
++ *
++ * Video4Linux2 Output Device using MXC IPU Post-processing functionality.
++ *
++ * @ingroup MXC_V4L2_OUTPUT
++ */
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/console.h>
++#include <linux/fs.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++#include <asm/cacheflush.h>
++#include <asm/io.h>
++#include <asm/semaphore.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/arch/mxcfb.h>
++#include <mach/ipu.h>
++
++#include "mxc_v4l2_output.h"
++
++vout_data *g_vout;
++#define SDC_FG_FB_FORMAT        IPU_PIX_FMT_RGB565
++
++struct v4l2_output mxc_outputs[2] = {
++      {
++       .index = MXC_V4L2_OUT_2_SDC,
++       .name = "DISP3 Video Out",
++       .type = V4L2_OUTPUT_TYPE_ANALOG,       /* not really correct,
++                                                 but no other choice */
++       .audioset = 0,
++       .modulator = 0,
++       .std = V4L2_STD_UNKNOWN},
++      {
++       .index = MXC_V4L2_OUT_2_ADC,
++       .name = "DISPx Video Out",
++       .type = V4L2_OUTPUT_TYPE_ANALOG,       /* not really correct,
++                                                 but no other choice */
++       .audioset = 0,
++       .modulator = 0,
++       .std = V4L2_STD_UNKNOWN}
++};
++
++static int video_nr = 16;
++static spinlock_t g_lock = SPIN_LOCK_UNLOCKED;
++
++/* debug counters */
++uint32_t g_irq_cnt;
++uint32_t g_buf_output_cnt;
++uint32_t g_buf_q_cnt;
++uint32_t g_buf_dq_cnt;
++
++static int dq_intr_cnt=0;
++static int dq_timeout_cnt=0;
++
++#define QUEUE_SIZE (MAX_FRAME_NUM + 1)
++static __inline int queue_size(v4l_queue * q)
++{
++      if (q->tail >= q->head)
++              return (q->tail - q->head);
++      else
++              return ((q->tail + QUEUE_SIZE) - q->head);
++}
++
++static __inline int queue_buf(v4l_queue * q, int idx)
++{
++      if (((q->tail + 1) % QUEUE_SIZE) == q->head)
++              return -1;      /* queue full */
++      q->list[q->tail] = idx;
++      q->tail = (q->tail + 1) % QUEUE_SIZE;
++      return 0;
++}
++
++static __inline int dequeue_buf(v4l_queue * q)
++{
++      int ret;
++      if (q->tail == q->head)
++              return -1;      /* queue empty */
++      ret = q->list[q->head];
++      q->head = (q->head + 1) % QUEUE_SIZE;
++      return ret;
++}
++
++static __inline int peek_next_buf(v4l_queue * q)
++{
++      if (q->tail == q->head)
++              return -1;      /* queue empty */
++      return q->list[q->head];
++}
++
++static __inline unsigned long get_jiffies(struct timeval *t)
++{
++      struct timeval cur;
++
++      if (t->tv_usec >= 1000000) {
++              t->tv_sec += t->tv_usec / 1000000;
++              t->tv_usec = t->tv_usec % 1000000;
++      }
++
++      do_gettimeofday(&cur);
++      if ((t->tv_sec < cur.tv_sec)
++          || ((t->tv_sec == cur.tv_sec) && (t->tv_usec < cur.tv_usec)))
++              return jiffies;
++
++      if (t->tv_usec < cur.tv_usec) {
++              cur.tv_sec = t->tv_sec - cur.tv_sec - 1;
++              cur.tv_usec = t->tv_usec + 1000000 - cur.tv_usec;
++      } else {
++              cur.tv_sec = t->tv_sec - cur.tv_sec;
++              cur.tv_usec = t->tv_usec - cur.tv_usec;
++      }
++
++      return jiffies + timeval_to_jiffies(&cur);
++}
++
++/*!
++ * Private function to free buffers
++ *
++ * @param bufs_paddr  Array of physical address of buffers to be freed
++ *
++ * @param bufs_vaddr  Array of virtual address of buffers to be freed
++ *
++ * @param num_buf     Number of buffers to be freed
++ *
++ * @param size                Size for each buffer to be free
++ *
++ * @return status  0 success.
++ */
++static int mxc_free_buffers(dma_addr_t bufs_paddr[], void *bufs_vaddr[],
++                          int num_buf, int size)
++{
++      int i;
++
++      for (i = 0; i < num_buf; i++) {
++              if (bufs_vaddr[i] != 0) {
++                      dma_free_coherent(0, size, bufs_vaddr[i],
++                                        bufs_paddr[i]);
++                      pr_debug("freed @ paddr=0x%08X\n", (u32) bufs_paddr[i]);
++                      bufs_paddr[i] = 0;
++                      bufs_vaddr[i] = NULL;
++              }
++      }
++      return 0;
++}
++
++/*!
++ * Private function to allocate buffers
++ *
++ * @param bufs_paddr  Output array of physical address of buffers allocated
++ *
++ * @param bufs_vaddr  Output array of virtual address of buffers allocated
++ *
++ * @param num_buf     Input number of buffers to allocate
++ *
++ * @param size                Input size for each buffer to allocate
++ *
++ * @return status     -0 Successfully allocated a buffer, -ENOBUFS failed.
++ */
++static int mxc_allocate_buffers(dma_addr_t bufs_paddr[], void *bufs_vaddr[],
++                              int num_buf, int size)
++{
++      int i;
++
++      for (i = 0; i < num_buf; i++) {
++              bufs_vaddr[i] = dma_alloc_coherent(0, size,
++                                                 &bufs_paddr[i],
++                                                 GFP_DMA | GFP_KERNEL);
++
++              if (bufs_vaddr[i] == 0) {
++                      mxc_free_buffers(bufs_paddr, bufs_vaddr, i, size);
++                      printk(KERN_ERR "dma_alloc_coherent failed.\n");
++                      return -ENOBUFS;
++              }
++              pr_debug("allocated @ paddr=0x%08X, size=%d.\n",
++                       (u32) bufs_paddr[i], size);
++      }
++
++      return 0;
++}
++
++/*
++ * Returns bits per pixel for given pixel format
++ *
++ * @param pixelformat  V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32
++ *
++ * @return bits per pixel of pixelformat
++ */
++static u32 fmt_to_bpp(u32 pixelformat)
++{
++      u32 bpp;
++
++      switch (pixelformat) {
++      case V4L2_PIX_FMT_RGB565:
++              bpp = 16;
++              break;
++      case V4L2_PIX_FMT_BGR24:
++      case V4L2_PIX_FMT_RGB24:
++              bpp = 24;
++              break;
++      case V4L2_PIX_FMT_BGR32:
++      case V4L2_PIX_FMT_RGB32:
++              bpp = 32;
++              break;
++      default:
++              bpp = 8;
++              break;
++      }
++      return bpp;
++}
++
++static void mxc_v4l2out_timer_handler(unsigned long arg)
++{
++      int index;
++      unsigned long timeout;
++      unsigned long lock_flags = 0;
++      vout_data *vout = (vout_data *) arg;
++
++      dev_dbg(vout->video_dev->dev, "timer handler: %lu\n", jiffies);
++
++      spin_lock_irqsave(&g_lock, lock_flags);
++
++      /*
++       * If timer occurs before IPU h/w is ready, then set the state to
++       * paused and the timer will be set again when next buffer is queued
++       * or PP comletes
++       */
++      if (vout->ipu_buf[vout->next_rdy_ipu_buf] != -1) {
++              dev_dbg(vout->video_dev->dev, "IPU buffer busy\n");
++              vout->state = STATE_STREAM_PAUSED;
++              goto exit0;
++      }
++
++      /* Dequeue buffer and pass to IPU */
++      index = dequeue_buf(&vout->ready_q);
++      if (index == -1) {      /* no buffers ready, should never occur */
++              dev_err(vout->video_dev->dev,
++                      "mxc_v4l2out: timer - no queued buffers ready\n");
++              goto exit0;
++      }
++
++      g_buf_dq_cnt++;
++      vout->frame_count++;
++      vout->ipu_buf[vout->next_rdy_ipu_buf] = index;
++      if (ipu_update_channel_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
++                                    vout->next_rdy_ipu_buf,
++                                    vout->v4l2_bufs[index].m.offset) < 0) {
++              dev_err(vout->video_dev->dev,
++                      "unable to update buffer %d address\n",
++                      vout->next_rdy_ipu_buf);
++              goto exit0;
++      }
++      if (ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER,
++                            vout->next_rdy_ipu_buf) < 0) {
++              dev_err(vout->video_dev->dev,
++                      "unable to set IPU buffer ready\n");
++      }
++      vout->next_rdy_ipu_buf = !vout->next_rdy_ipu_buf;
++
++      /* Setup timer for next buffer */
++      index = peek_next_buf(&vout->ready_q);
++      if (index != -1) {
++              /* if timestamp is 0, then default to 30fps */
++              if ((vout->v4l2_bufs[index].timestamp.tv_sec == 0)
++                  && (vout->v4l2_bufs[index].timestamp.tv_usec == 0))
++                      timeout =
++                          vout->start_jiffies + vout->frame_count * HZ / 30;
++              else
++                      timeout =
++                          get_jiffies(&vout->v4l2_bufs[index].timestamp);
++
++              if (jiffies >= timeout) {
++                      dev_dbg(vout->video_dev->dev,
++                              "warning: timer timeout already expired.\n");
++              }
++              if (mod_timer(&vout->output_timer, timeout))
++                      dev_dbg(vout->video_dev->dev,
++                              "warning: timer was already set\n");
++
++              dev_dbg(vout->video_dev->dev,
++                      "timer handler next schedule: %lu\n", timeout);
++      } else {
++              vout->state = STATE_STREAM_PAUSED;
++      }
++
++      exit0:
++      spin_unlock_irqrestore(&g_lock, lock_flags);
++}
++
++static irqreturn_t mxc_v4l2out_pp_in_irq_handler(int irq, void *dev_id)
++{
++      int last_buf;
++      int index;
++      unsigned long timeout;
++      unsigned long lock_flags = 0;
++      vout_data *vout = dev_id;
++
++      spin_lock_irqsave(&g_lock, lock_flags);
++
++      g_irq_cnt++;
++
++      /* Process previous buffer */
++      last_buf = vout->ipu_buf[vout->next_done_ipu_buf];
++      if (last_buf != -1) {
++              g_buf_output_cnt++;
++              vout->v4l2_bufs[last_buf].flags = V4L2_BUF_FLAG_DONE;
++              queue_buf(&vout->done_q, last_buf);
++              vout->ipu_buf[vout->next_done_ipu_buf] = -1;
++              wake_up_interruptible(&vout->v4l_bufq);
++              /* printk("pp_irq: buf %d done\n", vout->next_done_ipu_buf); */
++              vout->next_done_ipu_buf = !vout->next_done_ipu_buf;
++      }
++
++      if (vout->state == STATE_STREAM_STOPPING) {
++              if ((vout->ipu_buf[0] == -1) && (vout->ipu_buf[1] == -1)) {
++                      vout->state = STATE_STREAM_OFF;
++              }
++      } else if ((vout->state == STATE_STREAM_PAUSED)
++                 && ((index = peek_next_buf(&vout->ready_q)) != -1)) {
++              /* Setup timer for next buffer, when stream has been paused */
++              pr_debug("next index %d\n", index);
++
++              /* if timestamp is 0, then default to 30fps */
++              if ((vout->v4l2_bufs[index].timestamp.tv_sec == 0)
++                  && (vout->v4l2_bufs[index].timestamp.tv_usec == 0))
++                      timeout =
++                          vout->start_jiffies + vout->frame_count * HZ / 30;
++              else
++                      timeout =
++                          get_jiffies(&vout->v4l2_bufs[index].timestamp);
++
++              if (jiffies >= timeout) {
++                      pr_debug("warning: timer timeout already expired.\n");
++              }
++
++              vout->state = STATE_STREAM_ON;
++
++              if (mod_timer(&vout->output_timer, timeout))
++                      pr_debug("warning: timer was already set\n");
++
++              pr_debug("timer handler next schedule: %lu\n", timeout);
++      }
++
++      spin_unlock_irqrestore(&g_lock, lock_flags);
++
++      return IRQ_HANDLED;
++}
++
++/*!
++ * Start the output stream
++ *
++ * @param vout      structure vout_data *
++ *
++ * @return status  0 Success
++ */
++static int mxc_v4l2out_streamon(vout_data * vout)
++{
++      struct device *dev = vout->video_dev->dev;
++      ipu_channel_params_t params;
++      struct mxcfb_pos fb_pos;
++      struct fb_var_screeninfo fbvar;
++      struct fb_info *fbi =
++          registered_fb[vout->output_fb_num[vout->cur_disp_output]];
++      int pp_in_buf[2];
++      u16 out_width;
++      u16 out_height;
++      ipu_channel_t display_input_ch = MEM_PP_MEM;
++      bool use_direct_adc = false;
++
++      if (!vout)
++              return -EINVAL;
++
++      if (vout->state != STATE_STREAM_OFF)
++              return -EBUSY;
++
++      if (queue_size(&vout->ready_q) < 2) {
++              dev_err(dev, "2 buffers not been queued yet!\n");
++              return -EINVAL;
++      }
++
++      out_width = vout->crop_current.width;
++      out_height = vout->crop_current.height;
++
++      vout->next_done_ipu_buf = vout->next_rdy_ipu_buf = 0;
++      vout->ipu_buf[0] = pp_in_buf[0] = dequeue_buf(&vout->ready_q);
++      vout->ipu_buf[1] = pp_in_buf[1] = dequeue_buf(&vout->ready_q);
++      vout->frame_count = 2;
++
++      ipu_enable_irq(IPU_IRQ_PP_IN_EOF);
++
++      /* Init Display Channel */
++#ifdef CONFIG_FB_MXC_ASYNC_PANEL
++      if (vout->cur_disp_output < DISP3) {
++              mxcfb_set_refresh_mode(fbi, MXCFB_REFRESH_OFF, 0);
++              if (vout->rotate < IPU_ROTATE_90_RIGHT) {
++                      dev_dbg(dev, "Using PP direct to ADC channel\n");
++                      use_direct_adc = true;
++                      vout->display_ch = MEM_PP_ADC;
++                      vout->post_proc_ch = MEM_PP_ADC;
++
++                      memset(&params, 0, sizeof(params));
++                      params.mem_pp_adc.in_width = vout->v2f.fmt.pix.width;
++                      params.mem_pp_adc.in_height = vout->v2f.fmt.pix.height;
++                      params.mem_pp_adc.in_pixel_fmt =
++                          vout->v2f.fmt.pix.pixelformat;
++                      params.mem_pp_adc.out_width = out_width;
++                      params.mem_pp_adc.out_height = out_height;
++                      params.mem_pp_adc.out_pixel_fmt = SDC_FG_FB_FORMAT;
++#ifdef CONFIG_FB_MXC_EPSON_PANEL
++                      params.mem_pp_adc.out_left =
++                          2 + vout->crop_current.left;
++#else
++                      params.mem_pp_adc.out_left =
++                          12 + vout->crop_current.left;
++#endif
++                      params.mem_pp_adc.out_top = vout->crop_current.top;
++                      if (ipu_init_channel(vout->post_proc_ch, &params) != 0) {
++                              dev_err(dev, "Error initializing PP chan\n");
++                              return -EINVAL;
++                      }
++
++                      if (ipu_init_channel_buffer(vout->post_proc_ch,
++                                                  IPU_INPUT_BUFFER,
++                                                  params.mem_pp_adc.
++                                                  in_pixel_fmt,
++                                                  params.mem_pp_adc.in_width,
++                                                  params.mem_pp_adc.in_height,
++                                                  vout->v2f.fmt.pix.
++                                                  bytesperline /
++                                                  bytes_per_pixel(params.
++                                                                  mem_pp_adc.
++                                                                  in_pixel_fmt),
++                                                  vout->rotate,
++                                                  vout->
++                                                  v4l2_bufs[pp_in_buf[0]].m.
++                                                  offset,
++                                                  vout->
++                                                  v4l2_bufs[pp_in_buf[1]].m.
++                                                  offset,
++                                                  vout->offset.u_offset,
++                                                  vout->offset.v_offset) !=
++                          0) {
++                              dev_err(dev, "Error initializing PP in buf\n");
++                              return -EINVAL;
++                      }
++
++                      if (ipu_init_channel_buffer(vout->post_proc_ch,
++                                                  IPU_OUTPUT_BUFFER,
++                                                  params.mem_pp_adc.
++                                                  out_pixel_fmt, out_width,
++                                                  out_height, out_width,
++                                                  vout->rotate, 0, 0, 0,
++                                                  0) != 0) {
++                              dev_err(dev,
++                                      "Error initializing PP output buffer\n");
++                              return -EINVAL;
++                      }
++
++              } else {
++                      dev_dbg(dev, "Using ADC SYS2 channel\n");
++                      vout->display_ch = ADC_SYS2;
++                      vout->post_proc_ch = MEM_PP_MEM;
++
++                      if (vout->display_bufs[0]) {
++                              mxc_free_buffers(vout->display_bufs,
++                                               vout->display_bufs_vaddr,
++                                               2, vout->display_buf_size);
++                      }
++
++                      vout->display_buf_size = vout->crop_current.width *
++                          vout->crop_current.height *
++                          fmt_to_bpp(SDC_FG_FB_FORMAT) / 8;
++                      mxc_allocate_buffers(vout->display_bufs,
++                                           vout->display_bufs_vaddr,
++                                           2, vout->display_buf_size);
++
++                      memset(&params, 0, sizeof(params));
++                      params.adc_sys2.disp = vout->cur_disp_output;
++                      params.adc_sys2.ch_mode = WriteTemplateNonSeq;
++#ifdef CONFIG_FB_MXC_EPSON_PANEL
++                      params.adc_sys2.out_left = 2 + vout->crop_current.left;
++#else
++                      params.adc_sys2.out_left = 12 + vout->crop_current.left;
++#endif
++                      params.adc_sys2.out_top = vout->crop_current.top;
++                      if (ipu_init_channel(ADC_SYS2, &params) < 0)
++                              return -EINVAL;
++
++                      if (ipu_init_channel_buffer(vout->display_ch,
++                                                  IPU_INPUT_BUFFER,
++                                                  SDC_FG_FB_FORMAT,
++                                                  out_width, out_height,
++                                                  out_width, IPU_ROTATE_NONE,
++                                                  vout->display_bufs[0],
++                                                  vout->display_bufs[1], 0,
++                                                  0) != 0) {
++                              dev_err(dev,
++                                      "Error initializing SDC FG buffer\n");
++                              return -EINVAL;
++                      }
++              }
++      } else
++#endif
++      {                       /* Use SDC */
++              dev_dbg(dev, "Using SDC channel\n");
++
++              fbvar = fbi->var;
++              fbvar.xres = fbvar.xres_virtual = out_width;
++              fbvar.yres = out_height;
++              fbvar.yres_virtual = out_height * 2;
++              fbvar.bits_per_pixel = 16;
++              fb_set_var(fbi, &fbvar);
++
++              fb_pos.x = vout->crop_current.left;
++              fb_pos.y = vout->crop_current.top;
++              if (fbi->fbops->fb_ioctl)
++                      fbi->fbops->fb_ioctl(fbi, MXCFB_SET_OVERLAY_POS,
++                                           (unsigned long)&fb_pos);
++
++              vout->display_bufs[0] = fbi->fix.smem_start;
++              vout->display_bufs[1] = fbi->fix.smem_start +
++                  (fbi->fix.line_length * fbi->var.yres);
++              vout->display_buf_size = vout->crop_current.width *
++                  vout->crop_current.height *
++                  fmt_to_bpp(SDC_FG_FB_FORMAT) / 8;
++
++              if (vout->cur_disp_output == 3)
++                      vout->display_ch = MEM_SDC_FG;
++              else
++                      vout->display_ch = MEM_SDC_BG;
++
++              vout->post_proc_ch = MEM_PP_MEM;
++      }
++
++      /* Init PP */
++      if (use_direct_adc == false) {
++              if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
++                      out_width = vout->crop_current.height;
++                      out_height = vout->crop_current.width;
++              }
++              memset(&params, 0, sizeof(params));
++              params.mem_pp_mem.in_width = vout->v2f.fmt.pix.width;
++              params.mem_pp_mem.in_height = vout->v2f.fmt.pix.height;
++              params.mem_pp_mem.in_pixel_fmt = vout->v2f.fmt.pix.pixelformat;
++              params.mem_pp_mem.out_width = out_width;
++              params.mem_pp_mem.out_height = out_height;
++              params.mem_pp_mem.out_pixel_fmt = SDC_FG_FB_FORMAT;
++              if (ipu_init_channel(vout->post_proc_ch, &params) != 0) {
++                      dev_err(dev, "Error initializing PP channel\n");
++                      return -EINVAL;
++              }
++
++              if (ipu_init_channel_buffer(vout->post_proc_ch,
++                                          IPU_INPUT_BUFFER,
++                                          params.mem_pp_mem.in_pixel_fmt,
++                                          params.mem_pp_mem.in_width,
++                                          params.mem_pp_mem.in_height,
++                                          vout->v2f.fmt.pix.bytesperline /
++                                          bytes_per_pixel(params.mem_pp_mem.
++                                                          in_pixel_fmt),
++                                          IPU_ROTATE_NONE,
++                                          vout->v4l2_bufs[pp_in_buf[0]].m.
++                                          offset,
++                                          vout->v4l2_bufs[pp_in_buf[1]].m.
++                                          offset, vout->offset.u_offset,
++                                          vout->offset.v_offset) != 0) {
++                      dev_err(dev, "Error initializing PP input buffer\n");
++                      return -EINVAL;
++              }
++
++              if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
++                      if (vout->rot_pp_bufs[0]) {
++                              mxc_free_buffers(vout->rot_pp_bufs,
++                                               vout->rot_pp_bufs_vaddr, 2,
++                                               vout->display_buf_size);
++                      }
++                      if (mxc_allocate_buffers
++                          (vout->rot_pp_bufs, vout->rot_pp_bufs_vaddr, 2,
++                           vout->display_buf_size) < 0) {
++                              return -ENOBUFS;
++                      }
++
++                      if (ipu_init_channel_buffer(vout->post_proc_ch,
++                                                  IPU_OUTPUT_BUFFER,
++                                                  params.mem_pp_mem.
++                                                  out_pixel_fmt, out_width,
++                                                  out_height, out_width,
++                                                  IPU_ROTATE_NONE,
++                                                  vout->rot_pp_bufs[0],
++                                                  vout->rot_pp_bufs[1], 0,
++                                                  0) != 0) {
++                              dev_err(dev,
++                                      "Error initializing PP output buffer\n");
++                              return -EINVAL;
++                      }
++
++                      if (ipu_init_channel(MEM_ROT_PP_MEM, NULL) != 0) {
++                              dev_err(dev,
++                                      "Error initializing PP ROT channel\n");
++                              return -EINVAL;
++                      }
++
++                      if (ipu_init_channel_buffer(MEM_ROT_PP_MEM,
++                                                  IPU_INPUT_BUFFER,
++                                                  params.mem_pp_mem.
++                                                  out_pixel_fmt, out_width,
++                                                  out_height, out_width,
++                                                  vout->rotate,
++                                                  vout->rot_pp_bufs[0],
++                                                  vout->rot_pp_bufs[1], 0,
++                                                  0) != 0) {
++                              dev_err(dev,
++                                      "Error initializing PP ROT input buffer\n");
++                              return -EINVAL;
++                      }
++
++                      /* swap width and height */
++                      out_width = vout->crop_current.width;
++                      out_height = vout->crop_current.height;
++
++                      if (ipu_init_channel_buffer(MEM_ROT_PP_MEM,
++                                                  IPU_OUTPUT_BUFFER,
++                                                  params.mem_pp_mem.
++                                                  out_pixel_fmt, out_width,
++                                                  out_height, out_width,
++                                                  IPU_ROTATE_NONE,
++                                                  vout->display_bufs[0],
++                                                  vout->display_bufs[1], 0,
++                                                  0) != 0) {
++                              dev_err(dev,
++                                      "Error initializing PP output buffer\n");
++                              return -EINVAL;
++                      }
++
++                      if (ipu_link_channels(vout->post_proc_ch,
++                                            MEM_ROT_PP_MEM) < 0) {
++                              return -EINVAL;
++                      }
++                      ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0);
++                      ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 1);
++
++                      ipu_enable_channel(MEM_ROT_PP_MEM);
++
++                      display_input_ch = MEM_ROT_PP_MEM;
++              } else {
++                      if (ipu_init_channel_buffer(vout->post_proc_ch,
++                                                  IPU_OUTPUT_BUFFER,
++                                                  params.mem_pp_mem.
++                                                  out_pixel_fmt, out_width,
++                                                  out_height, out_width,
++                                                  vout->rotate,
++                                                  vout->display_bufs[0],
++                                                  vout->display_bufs[1], 0,
++                                                  0) != 0) {
++                              dev_err(dev,
++                                      "Error initializing PP output buffer\n");
++                              return -EINVAL;
++                      }
++              }
++              if (ipu_link_channels(display_input_ch, vout->display_ch) < 0) {
++                      dev_err(dev, "Error linking ipu channels\n");
++                      return -EINVAL;
++              }
++      }
++
++      vout->state = STATE_STREAM_PAUSED;
++
++      ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0);
++      ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1);
++
++      if (use_direct_adc == false) {
++              ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0);
++              ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1);
++
++              ipu_enable_channel(vout->post_proc_ch);
++              if ((vout->display_ch == MEM_SDC_FG) ||
++                  (vout->display_ch == MEM_SDC_BG)) {
++                      acquire_console_sem();
++                      fb_blank(fbi, FB_BLANK_UNBLANK);
++                      release_console_sem();
++              } else {
++                      ipu_enable_channel(vout->display_ch);
++              }
++      } else {
++              ipu_enable_channel(vout->post_proc_ch);
++      }
++
++      vout->start_jiffies = jiffies;
++      dev_dbg(dev,
++              "streamon: start time = %lu jiffies\n", vout->start_jiffies);
++
++      return 0;
++}
++
++/*!
++ * Shut down the voutera
++ *
++ * @param vout      structure vout_data *
++ *
++ * @return status  0 Success
++ */
++static int mxc_v4l2out_streamoff(vout_data * vout)
++{
++      struct fb_info *fbi =
++          registered_fb[vout->output_fb_num[vout->cur_disp_output]];
++      int i, retval = 0;
++      unsigned long lockflag = 0;
++
++      if (!vout)
++              return -EINVAL;
++
++      if (vout->state == STATE_STREAM_OFF) {
++              return 0;
++      }
++
++      spin_lock_irqsave(&g_lock, lockflag);
++
++      del_timer(&vout->output_timer);
++
++      if (vout->state == STATE_STREAM_ON) {
++              vout->state = STATE_STREAM_STOPPING;
++      }
++
++      ipu_disable_irq(IPU_IRQ_PP_IN_EOF);
++
++      spin_unlock_irqrestore(&g_lock, lockflag);
++
++      if (vout->post_proc_ch == MEM_PP_MEM) { /* SDC or ADC with Rotation */
++              if (vout->rotate >= IPU_ROTATE_90_RIGHT) {
++                      ipu_unlink_channels(MEM_PP_MEM, MEM_ROT_PP_MEM);
++                      ipu_unlink_channels(MEM_ROT_PP_MEM, vout->display_ch);
++                      ipu_disable_channel(MEM_ROT_PP_MEM, true);
++              } else {
++                      ipu_unlink_channels(MEM_PP_MEM, vout->display_ch);
++              }
++              ipu_disable_channel(MEM_PP_MEM, true);
++              if ((vout->display_ch != MEM_SDC_FG) &&
++                  (vout->display_ch != MEM_SDC_BG)) {
++                      ipu_disable_channel(vout->display_ch, true);
++                      ipu_uninit_channel(vout->display_ch);
++              } else {
++                      fbi->var.activate |= FB_ACTIVATE_FORCE;
++                      fb_set_var(fbi, &fbi->var);
++              }
++
++              ipu_uninit_channel(MEM_PP_MEM);
++              if (vout->rotate >= IPU_ROTATE_90_RIGHT)
++                      ipu_uninit_channel(MEM_ROT_PP_MEM);
++      } else {                /* ADC Direct */
++              ipu_disable_channel(MEM_PP_ADC, true);
++              ipu_uninit_channel(MEM_PP_ADC);
++      }
++      vout->ready_q.head = vout->ready_q.tail = 0;
++      vout->done_q.head = vout->done_q.tail = 0;
++      for (i = 0; i < vout->buffer_cnt; i++) {
++              vout->v4l2_bufs[i].flags = 0;
++              vout->v4l2_bufs[i].timestamp.tv_sec = 0;
++              vout->v4l2_bufs[i].timestamp.tv_usec = 0;
++      }
++
++      vout->state = STATE_STREAM_OFF;
++
++      if (vout->display_bufs[0] != 0) {
++              mxc_free_buffers(vout->display_bufs,
++                               vout->display_bufs_vaddr, 2,
++                               vout->display_buf_size);
++      }
++#ifdef CONFIG_FB_MXC_ASYNC_PANEL
++      if (vout->cur_disp_output < DISP3) {
++              mxcfb_set_refresh_mode(registered_fb
++                                     [vout->
++                                      output_fb_num[vout->cur_disp_output]],
++                                     MXCFB_REFRESH_PARTIAL, 0);
++      }
++#endif
++
++      return retval;
++}
++
++/*
++ * Valid whether the palette is supported
++ *
++ * @param palette  V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32
++ *
++ * @return 1 if supported, 0 if failed
++ */
++static inline int valid_mode(u32 palette)
++{
++      return ((palette == V4L2_PIX_FMT_RGB565) ||
++              (palette == V4L2_PIX_FMT_BGR24) ||
++              (palette == V4L2_PIX_FMT_RGB24) ||
++              (palette == V4L2_PIX_FMT_BGR32) ||
++              (palette == V4L2_PIX_FMT_RGB32) ||
++              (palette == V4L2_PIX_FMT_YUV422P) ||
++              (palette == V4L2_PIX_FMT_YUV420));
++}
++
++/*
++ * V4L2 - Handles VIDIOC_G_FMT Ioctl
++ *
++ * @param vout         structure vout_data *
++ *
++ * @param v4l2_format structure v4l2_format *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2out_g_fmt(vout_data * vout, struct v4l2_format *f)
++{
++      if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++              return -EINVAL;
++      }
++      *f = vout->v2f;
++      return 0;
++}
++
++/*
++ * V4L2 - Handles VIDIOC_S_FMT Ioctl
++ *
++ * @param vout         structure vout_data *
++ *
++ * @param v4l2_format structure v4l2_format *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_v4l2out_s_fmt(vout_data * vout, struct v4l2_format *f)
++{
++      int retval = 0;
++      u32 size = 0;
++      u32 bytesperline;
++
++      if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++              retval = -EINVAL;
++              goto err0;
++      }
++      if (!valid_mode(f->fmt.pix.pixelformat)) {
++              dev_err(vout->video_dev->dev, "pixel format not supported\n");
++              retval = -EINVAL;
++              goto err0;
++      }
++
++      bytesperline = (f->fmt.pix.width * fmt_to_bpp(f->fmt.pix.pixelformat)) /
++          8;
++      if (f->fmt.pix.bytesperline < bytesperline) {
++              f->fmt.pix.bytesperline = bytesperline;
++      } else {
++              bytesperline = f->fmt.pix.bytesperline;
++      }
++
++      switch (f->fmt.pix.pixelformat) {
++      case V4L2_PIX_FMT_YUV422P:
++              /* byteperline for YUV planar formats is for
++                 Y plane only */
++              size = bytesperline * f->fmt.pix.height * 2;
++              break;
++      case V4L2_PIX_FMT_YUV420:
++              size = (bytesperline * f->fmt.pix.height * 3) / 2;
++              break;
++      default:
++              size = bytesperline * f->fmt.pix.height;
++              break;
++      }
++
++      /* Return the actual size of the image to the app */
++      if (f->fmt.pix.sizeimage < size) {
++              f->fmt.pix.sizeimage = size;
++      } else {
++              size = f->fmt.pix.sizeimage;
++      }
++
++      vout->v2f.fmt.pix = f->fmt.pix;
++      if (vout->v2f.fmt.pix.priv != 0) {
++              if (copy_from_user(&vout->offset,
++                                 (void *)vout->v2f.fmt.pix.priv,
++                                 sizeof(vout->offset))) {
++                      retval = -EFAULT;
++                      goto err0;
++              }
++      }
++
++      retval = 0;
++      err0:
++      return retval;
++}
++
++/*
++ * V4L2 - Handles VIDIOC_G_CTRL Ioctl
++ *
++ * @param vout         structure vout_data *
++ *
++ * @param c           structure v4l2_control *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_get_v42lout_control(vout_data * vout, struct v4l2_control *c)
++{
++      switch (c->id) {
++      case V4L2_CID_HFLIP:
++              return (vout->rotate & IPU_ROTATE_HORIZ_FLIP) ? 1 : 0;
++      case V4L2_CID_VFLIP:
++              return (vout->rotate & IPU_ROTATE_VERT_FLIP) ? 1 : 0;
++      case (V4L2_CID_PRIVATE_BASE + 1):
++              return vout->rotate;
++      default:
++              return -EINVAL;
++      }
++}
++
++/*
++ * V4L2 - Handles VIDIOC_S_CTRL Ioctl
++ *
++ * @param vout         structure vout_data *
++ *
++ * @param c           structure v4l2_control *
++ *
++ * @return  status    0 success, EINVAL failed
++ */
++static int mxc_set_v42lout_control(vout_data * vout, struct v4l2_control *c)
++{
++      switch (c->id) {
++      case V4L2_CID_HFLIP:
++              vout->rotate |= c->value ? IPU_ROTATE_HORIZ_FLIP :
++                  IPU_ROTATE_NONE;
++              break;
++      case V4L2_CID_VFLIP:
++              vout->rotate |= c->value ? IPU_ROTATE_VERT_FLIP :
++                  IPU_ROTATE_NONE;
++              break;
++      case V4L2_CID_MXC_ROT:
++              vout->rotate = c->value;
++              break;
++      default:
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/*!
++ * V4L2 interface - open function
++ *
++ * @param inode        structure inode *
++ *
++ * @param file         structure file *
++ *
++ * @return  status    0 success, ENODEV invalid device instance,
++ *                    ENODEV timeout, ERESTARTSYS interrupted by user
++ */
++static int mxc_v4l2out_open(struct inode *inode, struct file *file)
++{
++      struct video_device *dev = video_devdata(file);
++      vout_data *vout = video_get_drvdata(dev);
++      int err;
++
++      dq_intr_cnt = 0;
++      dq_timeout_cnt = 0;
++      if (!vout) {
++              return -ENODEV;
++      }
++
++      down(&vout->busy_lock);
++
++      err = -EINTR;
++      if (signal_pending(current))
++              goto oops;
++
++      if (vout->open_count++ == 0) {
++              ipu_request_irq(IPU_IRQ_PP_IN_EOF,
++                              mxc_v4l2out_pp_in_irq_handler,
++                              0, dev->name, vout);
++
++              init_waitqueue_head(&vout->v4l_bufq);
++
++              init_timer(&vout->output_timer);
++              vout->output_timer.function = mxc_v4l2out_timer_handler;
++              vout->output_timer.data = (unsigned long)vout;
++
++              vout->state = STATE_STREAM_OFF;
++              g_irq_cnt = g_buf_output_cnt = g_buf_q_cnt = g_buf_dq_cnt = 0;
++
++      }
++
++      file->private_data = dev;
++
++      up(&vout->busy_lock);
++
++      return 0;
++
++      oops:
++      up(&vout->busy_lock);
++      return err;
++}
++
++/*!
++ * V4L2 interface - close function
++ *
++ * @param inode    struct inode *
++ *
++ * @param file     struct file *
++ *
++ * @return         0 success
++ */
++static int mxc_v4l2out_close(struct inode *inode, struct file *file)
++{
++      struct video_device *dev = video_devdata(file);
++      vout_data *vout = video_get_drvdata(dev);
++
++      if (--vout->open_count == 0) {
++              if (vout->state != STATE_STREAM_OFF)
++                      mxc_v4l2out_streamoff(vout);
++
++              ipu_free_irq(IPU_IRQ_PP_IN_EOF, vout);
++
++              file->private_data = NULL;
++
++              mxc_free_buffers(vout->queue_buf_paddr, vout->queue_buf_vaddr,
++                               vout->buffer_cnt, vout->queue_buf_size);
++              vout->buffer_cnt = 0;
++              mxc_free_buffers(vout->rot_pp_bufs, vout->rot_pp_bufs_vaddr, 2,
++                               vout->display_buf_size);
++
++              /* capture off */
++              wake_up_interruptible(&vout->v4l_bufq);
++      }
++
++      return 0;
++}
++
++/*!
++ * V4L2 interface - ioctl function
++ *
++ * @param inode      struct inode *
++ *
++ * @param file       struct file *
++ *
++ * @param ioctlnr    unsigned int
++ *
++ * @param arg        void *
++ *
++ * @return           0 success, ENODEV for invalid device instance,
++ *                   -1 for other errors.
++ */
++static int
++mxc_v4l2out_do_ioctl(struct inode *inode, struct file *file,
++                   unsigned int ioctlnr, void *arg)
++{
++      struct video_device *vdev = file->private_data;
++      vout_data *vout = video_get_drvdata(vdev);
++      int retval = 0;
++      int i = 0;
++
++      if (!vout)
++              return -EBADF;
++
++      /* make this _really_ smp-safe */
++      if (down_interruptible(&vout->busy_lock))
++              return -EBUSY;
++
++      switch (ioctlnr) {
++      case VIDIOC_QUERYCAP:
++              {
++                      struct v4l2_capability *cap = arg;
++                      strcpy(cap->driver, "mxc_v4l2_output");
++                      cap->version = 0;
++                      cap->capabilities =
++                          V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
++                      cap->card[0] = '\0';
++                      cap->bus_info[0] = '\0';
++                      retval = 0;
++                      break;
++              }
++      case VIDIOC_G_FMT:
++              {
++                      struct v4l2_format *gf = arg;
++                      retval = mxc_v4l2out_g_fmt(vout, gf);
++                      break;
++              }
++      case VIDIOC_S_FMT:
++              {
++                      struct v4l2_format *sf = arg;
++                      if (vout->state != STATE_STREAM_OFF) {
++                              retval = -EBUSY;
++                              break;
++                      }
++                      retval = mxc_v4l2out_s_fmt(vout, sf);
++                      break;
++              }
++      case VIDIOC_REQBUFS:
++              {
++                      struct v4l2_requestbuffers *req = arg;
++                      if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
++                          (req->memory != V4L2_MEMORY_MMAP)) {
++                              dev_dbg(vdev->dev,
++                                      "VIDIOC_REQBUFS: incorrect buffer type\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      if (req->count == 0)
++                              mxc_v4l2out_streamoff(vout);
++
++                      if (vout->state == STATE_STREAM_OFF) {
++                              if (vout->queue_buf_paddr[0] != 0) {
++                                      mxc_free_buffers(vout->queue_buf_paddr,
++                                                       vout->queue_buf_vaddr,
++                                                       vout->buffer_cnt,
++                                                       vout->queue_buf_size);
++                                      dev_dbg(vdev->dev,
++                                              "VIDIOC_REQBUFS: freed buffers\n");
++                              }
++                              vout->buffer_cnt = 0;
++                      } else {
++                              dev_dbg(vdev->dev,
++                                      "VIDIOC_REQBUFS: Buffer is in use\n");
++                              retval = -EBUSY;
++                              break;
++                      }
++
++                      if (req->count == 0)
++                              break;
++
++                      if (req->count < MIN_FRAME_NUM) {
++                              req->count = MIN_FRAME_NUM;
++                      } else if (req->count > MAX_FRAME_NUM) {
++                              req->count = MAX_FRAME_NUM;
++                      }
++                      vout->buffer_cnt = req->count;
++                      vout->queue_buf_size =
++                          PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage);
++
++                      retval = mxc_allocate_buffers(vout->queue_buf_paddr,
++                                                    vout->queue_buf_vaddr,
++                                                    vout->buffer_cnt,
++                                                    vout->queue_buf_size);
++                      if (retval < 0)
++                              break;
++
++                      /* Init buffer queues */
++                      vout->done_q.head = 0;
++                      vout->done_q.tail = 0;
++                      vout->ready_q.head = 0;
++                      vout->ready_q.tail = 0;
++
++                      for (i = 0; i < vout->buffer_cnt; i++) {
++                              memset(&(vout->v4l2_bufs[i]), 0,
++                                     sizeof(vout->v4l2_bufs[i]));
++                              vout->v4l2_bufs[i].flags = 0;
++                              vout->v4l2_bufs[i].memory = V4L2_MEMORY_MMAP;
++                              vout->v4l2_bufs[i].index = i;
++                              vout->v4l2_bufs[i].type =
++                                  V4L2_BUF_TYPE_VIDEO_OUTPUT;
++                              vout->v4l2_bufs[i].length =
++                                  PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage);
++                              vout->v4l2_bufs[i].m.offset =
++                                  (unsigned long)vout->queue_buf_paddr[i];
++                              vout->v4l2_bufs[i].timestamp.tv_sec = 0;
++                              vout->v4l2_bufs[i].timestamp.tv_usec = 0;
++                      }
++                      break;
++              }
++      case VIDIOC_QUERYBUF:
++              {
++                      struct v4l2_buffer *buf = arg;
++                      u32 type = buf->type;
++                      int index = buf->index;
++
++                      if ((type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
++                          (index >= vout->buffer_cnt)) {
++                              dev_dbg(vdev->dev,
++                                      "VIDIOC_QUERYBUFS: incorrect buffer type\n");
++                              retval = -EINVAL;
++                              break;
++                      }
++                      down(&vout->param_lock);
++                      memcpy(buf, &(vout->v4l2_bufs[index]), sizeof(*buf));
++                      up(&vout->param_lock);
++                      break;
++              }
++      case VIDIOC_QBUF:
++              {
++                      struct v4l2_buffer *buf = arg;
++                      int index = buf->index;
++                      unsigned long lock_flags;
++
++                      if ((buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) ||
++                          (index >= vout->buffer_cnt)) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      dev_dbg(vdev->dev, "VIDIOC_QBUF: %d\n", buf->index);
++
++                      /* mmapped buffers are L1 WB cached,
++                       * so we need to clean them */
++                      if (buf->flags & V4L2_BUF_FLAG_MAPPED) {
++                              flush_cache_all();
++                      }
++
++                      spin_lock_irqsave(&g_lock, lock_flags);
++
++                      memcpy(&(vout->v4l2_bufs[index]), buf, sizeof(*buf));
++                      vout->v4l2_bufs[index].flags |= V4L2_BUF_FLAG_QUEUED;
++
++                      g_buf_q_cnt++;
++                      queue_buf(&vout->ready_q, index);
++                      if (vout->state == STATE_STREAM_PAUSED) {
++                              unsigned long timeout;
++
++                              index = peek_next_buf(&vout->ready_q);
++
++                              /* if timestamp is 0, then default to 30fps */
++                              if ((vout->v4l2_bufs[index].timestamp.tv_sec ==
++                                   0)
++                                  && (vout->v4l2_bufs[index].timestamp.
++                                      tv_usec == 0))
++                                      timeout =
++                                          vout->start_jiffies +
++                                          vout->frame_count * HZ / 30;
++                              else
++                                      timeout =
++                                          get_jiffies(&vout->v4l2_bufs[index].
++                                                      timestamp);
++
++                              if (jiffies >= timeout) {
++                                      dev_dbg(vout->video_dev->dev,
++                                              "warning: timer timeout already expired.\n");
++                              }
++                              vout->output_timer.expires = timeout;
++                              dev_dbg(vdev->dev,
++                                      "QBUF: frame #%u timeout @ %lu jiffies, current = %lu\n",
++                                      vout->frame_count, timeout, jiffies);
++                              add_timer(&vout->output_timer);
++                              vout->state = STATE_STREAM_ON;
++                      }
++
++                      spin_unlock_irqrestore(&g_lock, lock_flags);
++                      break;
++              }
++      case VIDIOC_DQBUF:
++              {
++                      struct v4l2_buffer *buf = arg;
++                      int idx;
++
++                      if ((queue_size(&vout->done_q) == 0) &&
++                          (file->f_flags & O_NONBLOCK)) {
++                              retval = -EAGAIN;
++                              break;
++                      }
++
++                      if (!wait_event_interruptible_timeout(vout->v4l_bufq,
++                                                            queue_size(&vout->
++                                                                       done_q)
++                                                            != 0, 10 * HZ)) {
++                              if(dq_timeout_cnt == 0){
++                                      dev_dbg(vdev->dev, "VIDIOC_DQBUF: timeout\n");
++                              }
++                              dq_timeout_cnt++;
++                              retval = -ETIME;
++                              break;
++                      } else if (signal_pending(current)) {
++                              if (dq_intr_cnt == 0) {
++                                      dev_dbg(vdev->dev,
++                                              "VIDIOC_DQBUF: interrupt received\n");
++                              }
++                              dq_intr_cnt++;
++                              retval = -ERESTARTSYS;
++                              break;
++                      }
++                      idx = dequeue_buf(&vout->done_q);
++                      if (idx == -1) {        /* No frame free */
++                              dev_dbg(vdev->dev,
++                                      "VIDIOC_DQBUF: no free buffers, returning\n");
++                              retval = -EAGAIN;
++                              break;
++                      }
++                      if ((vout->v4l2_bufs[idx].flags & V4L2_BUF_FLAG_DONE) ==
++                          0)
++                              dev_dbg(vdev->dev,
++                                      "VIDIOC_DQBUF: buffer in done q, but not "
++                                      "flagged as done\n");
++
++                      vout->v4l2_bufs[idx].flags = 0;
++                      memcpy(buf, &(vout->v4l2_bufs[idx]), sizeof(*buf));
++                      dev_dbg(vdev->dev, "VIDIOC_DQBUF: %d\n", buf->index);
++                      break;
++              }
++      case VIDIOC_STREAMON:
++              {
++                      retval = mxc_v4l2out_streamon(vout);
++                      break;
++              }
++      case VIDIOC_STREAMOFF:
++              {
++                      retval = mxc_v4l2out_streamoff(vout);
++                      break;
++              }
++      case VIDIOC_G_CTRL:
++              {
++                      retval = mxc_get_v42lout_control(vout, arg);
++                      break;
++              }
++      case VIDIOC_S_CTRL:
++              {
++                      retval = mxc_set_v42lout_control(vout, arg);
++                      break;
++              }
++      case VIDIOC_CROPCAP:
++              {
++                      struct v4l2_cropcap *cap = arg;
++
++                      if (cap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      cap->bounds = vout->crop_bounds[vout->cur_disp_output];
++                      cap->defrect = vout->crop_bounds[vout->cur_disp_output];
++                      retval = 0;
++                      break;
++              }
++      case VIDIOC_G_CROP:
++              {
++                      struct v4l2_crop *crop = arg;
++
++                      if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      crop->c = vout->crop_current;
++                      break;
++              }
++      case VIDIOC_S_CROP:
++              {
++                      struct v4l2_crop *crop = arg;
++                      struct v4l2_rect *b =
++                          &(vout->crop_bounds[vout->cur_disp_output]);
++
++                      if (crop->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      if (crop->c.height < 0) {
++                              retval = -EINVAL;
++                              break;
++                      }
++                      if (crop->c.width < 0) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      /* only full screen supported for SDC BG */
++                      if (vout->cur_disp_output == 4) {
++                              crop->c = vout->crop_current;
++                              break;
++                      }
++
++                      if (crop->c.top < b->top)
++                              crop->c.top = b->top;
++                      if (crop->c.top >= b->top + b->height)
++                              crop->c.top = b->top + b->height - 1;
++                      if (crop->c.height > b->top - crop->c.top + b->height)
++                              crop->c.height =
++                                  b->top - crop->c.top + b->height;
++
++                      if (crop->c.left < b->left)
++                              crop->c.left = b->left;
++                      if (crop->c.left >= b->left + b->width)
++                              crop->c.left = b->left + b->width - 1;
++                      if (crop->c.width > b->left - crop->c.left + b->width)
++                              crop->c.width =
++                                  b->left - crop->c.left + b->width;
++
++                      /* stride line limitation */
++                      crop->c.height -= crop->c.height % 8;
++                      crop->c.width -= crop->c.width % 8;
++
++                      vout->crop_current = crop->c;
++                      break;
++              }
++      case VIDIOC_ENUMOUTPUT:
++              {
++                      struct v4l2_output *output = arg;
++
++                      if ((output->index >= 5) ||
++                          (vout->output_enabled[output->index] == false)) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      if (output->index < 3) {
++                              *output = mxc_outputs[MXC_V4L2_OUT_2_ADC];
++                              output->name[4] = '0' + output->index;
++                      } else {
++                              *output = mxc_outputs[MXC_V4L2_OUT_2_SDC];
++                      }
++                      break;
++              }
++      case VIDIOC_G_OUTPUT:
++              {
++                      int *p_output_num = arg;
++
++                      *p_output_num = vout->cur_disp_output;
++                      break;
++              }
++      case VIDIOC_S_OUTPUT:
++              {
++                      int *p_output_num = arg;
++
++                      if ((*p_output_num >= 5) ||
++                          (vout->output_enabled[*p_output_num] == false)) {
++                              retval = -EINVAL;
++                              break;
++                      }
++
++                      if (vout->state != STATE_STREAM_OFF) {
++                              retval = -EBUSY;
++                              break;
++                      }
++
++                      vout->cur_disp_output = *p_output_num;
++                      vout->crop_current =
++                          vout->crop_bounds[vout->cur_disp_output];
++                      break;
++              }
++      case VIDIOC_ENUM_FMT:
++      case VIDIOC_TRY_FMT:
++      case VIDIOC_QUERYCTRL:
++      case VIDIOC_G_PARM:
++      case VIDIOC_ENUMSTD:
++      case VIDIOC_G_STD:
++      case VIDIOC_S_STD:
++      case VIDIOC_G_TUNER:
++      case VIDIOC_S_TUNER:
++      case VIDIOC_G_FREQUENCY:
++      case VIDIOC_S_FREQUENCY:
++      default:
++              retval = -EINVAL;
++              break;
++      }
++
++      up(&vout->busy_lock);
++      return retval;
++}
++
++/*
++ * V4L2 interface - ioctl function
++ *
++ * @return  None
++ */
++static int
++mxc_v4l2out_ioctl(struct inode *inode, struct file *file,
++                unsigned int cmd, unsigned long arg)
++{
++      return video_usercopy(inode, file, cmd, arg, mxc_v4l2out_do_ioctl);
++}
++
++/*!
++ * V4L2 interface - mmap function
++ *
++ * @param file          structure file *
++ *
++ * @param vma           structure vm_area_struct *
++ *
++ * @return status       0 Success, EINTR busy lock error,
++ *                      ENOBUFS remap_page error
++ */
++static int mxc_v4l2out_mmap(struct file *file, struct vm_area_struct *vma)
++{
++      struct video_device *vdev = video_devdata(file);
++      unsigned long size = vma->vm_end - vma->vm_start;
++      int res = 0;
++      int i;
++      vout_data *vout = video_get_drvdata(vdev);
++
++      dev_dbg(vdev->dev, "pgoff=0x%lx, start=0x%lx, end=0x%lx\n",
++              vma->vm_pgoff, vma->vm_start, vma->vm_end);
++
++      /* make this _really_ smp-safe */
++      if (down_interruptible(&vout->busy_lock))
++              return -EINTR;
++
++      for (i = 0; i < vout->buffer_cnt; i++) {
++              if ((vout->v4l2_bufs[i].m.offset ==
++                   (vma->vm_pgoff << PAGE_SHIFT)) &&
++                  (vout->v4l2_bufs[i].length >= size)) {
++                      vout->v4l2_bufs[i].flags |= V4L2_BUF_FLAG_MAPPED;
++                      break;
++              }
++      }
++      if (i == vout->buffer_cnt) {
++              res = -ENOBUFS;
++              goto mxc_mmap_exit;
++      }
++
++      /* make buffers inner write-back, outer write-thru cacheable */
++      vma->vm_page_prot = pgprot_outer_wrthru(vma->vm_page_prot);
++
++      if (remap_pfn_range(vma, vma->vm_start,
++                          vma->vm_pgoff, size, vma->vm_page_prot)) {
++              dev_dbg(vdev->dev, "mmap remap_pfn_range failed\n");
++              res = -ENOBUFS;
++              goto mxc_mmap_exit;
++      }
++
++      vma->vm_flags &= ~VM_IO;        /* using shared anonymous pages */
++
++      mxc_mmap_exit:
++      up(&vout->busy_lock);
++      return res;
++}
++
++/*!
++ * V4L2 interface - poll function
++ *
++ * @param file       structure file *
++ *
++ * @param wait       structure poll_table *
++ *
++ * @return  status   POLLIN | POLLRDNORM
++ */
++static unsigned int mxc_v4l2out_poll(struct file *file, poll_table * wait)
++{
++      struct video_device *dev = video_devdata(file);
++      vout_data *vout = video_get_drvdata(dev);
++
++      wait_queue_head_t *queue = NULL;
++      int res = POLLIN | POLLRDNORM;
++
++      if (down_interruptible(&vout->busy_lock))
++              return -EINTR;
++
++      queue = &vout->v4l_bufq;
++      poll_wait(file, queue, wait);
++
++      up(&vout->busy_lock);
++      return res;
++}
++
++static struct
++file_operations mxc_v4l2out_fops = {
++      .owner = THIS_MODULE,
++      .open = mxc_v4l2out_open,
++      .release = mxc_v4l2out_close,
++      .ioctl = mxc_v4l2out_ioctl,
++      .mmap = mxc_v4l2out_mmap,
++      .poll = mxc_v4l2out_poll,
++};
++
++static struct video_device mxc_v4l2out_template = {
++      .owner = THIS_MODULE,
++      .name = "MXC Video Output",
++      .type = 0,
++      .type2 = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING,
++      .hardware = 0,
++      .fops = &mxc_v4l2out_fops,
++      .release = video_device_release,
++};
++
++/*!
++ * Probe routine for the framebuffer driver. It is called during the
++ * driver binding process.      The following functions are performed in
++ * this routine: Framebuffer initialization, Memory allocation and
++ * mapping, Framebuffer registration, IPU initialization.
++ *
++ * @return      Appropriate error code to the kernel common code
++ */
++static int mxc_v4l2out_probe(struct platform_device *pdev)
++{
++      int i;
++      vout_data *vout;
++
++      /*
++       * Allocate sufficient memory for the fb structure
++       */
++      g_vout = vout = kmalloc(sizeof(vout_data), GFP_KERNEL);
++
++      if (!vout)
++              return 0;
++
++      memset(vout, 0, sizeof(vout_data));
++
++      vout->video_dev = video_device_alloc();
++      if (vout->video_dev == NULL)
++              return -1;
++      vout->video_dev->dev = &pdev->dev;
++      vout->video_dev->minor = -1;
++
++      *(vout->video_dev) = mxc_v4l2out_template;
++
++      /* register v4l device */
++      if (video_register_device(vout->video_dev,
++                                VFL_TYPE_GRABBER, video_nr) == -1) {
++              dev_dbg(&pdev->dev, "video_register_device failed\n");
++              return 0;
++      }
++      dev_info(&pdev->dev, "Registered device video%d\n",
++               vout->video_dev->minor & 0x1f);
++      vout->video_dev->dev = &pdev->dev;
++
++      video_set_drvdata(vout->video_dev, vout);
++
++      init_MUTEX(&vout->param_lock);
++      init_MUTEX(&vout->busy_lock);
++
++      /* setup outputs and cropping */
++      vout->cur_disp_output = -1;
++      for (i = 0; i < num_registered_fb; i++) {
++              char *idstr = registered_fb[i]->fix.id;
++              if (strncmp(idstr, "DISP", 4) == 0) {
++                      int disp_num = idstr[4] - '0';
++                      if ((disp_num == 3) &&
++                          (strncmp(idstr, "DISP3 BG", 8) == 0)) {
++                              disp_num = 4;
++                      }
++                      vout->crop_bounds[disp_num].left = 0;
++                      vout->crop_bounds[disp_num].top = 0;
++                      vout->crop_bounds[disp_num].width =
++                          registered_fb[i]->var.xres;
++                      vout->crop_bounds[disp_num].height =
++                          registered_fb[i]->var.yres;
++                      vout->output_enabled[disp_num] = true;
++                      vout->output_fb_num[disp_num] = i;
++                      if (vout->cur_disp_output == -1) {
++                              vout->cur_disp_output = disp_num;
++                      }
++              }
++
++      }
++      vout->crop_current = vout->crop_bounds[vout->cur_disp_output];
++
++      platform_set_drvdata(pdev, vout);
++
++      return 0;
++}
++
++static int mxc_v4l2out_remove(struct platform_device *pdev)
++{
++      vout_data *vout = platform_get_drvdata(pdev);
++
++      if (vout->video_dev) {
++              if (-1 != vout->video_dev->minor)
++                      video_unregister_device(vout->video_dev);
++              else
++                      video_device_release(vout->video_dev);
++              vout->video_dev = NULL;
++      }
++
++      platform_set_drvdata(pdev, NULL);
++
++      kfree(vout);
++
++      return 0;
++}
++
++/*!
++ * This structure contains pointers to the power management callback functions.
++ */
++static struct platform_driver mxc_v4l2out_driver = {
++      .driver = {
++                 .name = "MXC Video Output",
++                 },
++      .probe = mxc_v4l2out_probe,
++      .remove = mxc_v4l2out_remove,
++};
++
++static struct platform_device mxc_v4l2out_device = {
++      .name = "MXC Video Output",
++      .id = 0,
++};
++
++/*!
++ * mxc v4l2 init function
++ *
++ */
++static int mxc_v4l2out_init(void)
++{
++      u8 err = 0;
++
++      err = platform_driver_register(&mxc_v4l2out_driver);
++      if (err == 0) {
++              platform_device_register(&mxc_v4l2out_device);
++      }
++      return err;
++}
++
++/*!
++ * mxc v4l2 cleanup function
++ *
++ */
++static void mxc_v4l2out_clean(void)
++{
++      video_unregister_device(g_vout->video_dev);
++
++      platform_driver_unregister(&mxc_v4l2out_driver);
++      platform_device_unregister(&mxc_v4l2out_device);
++      kfree(g_vout);
++      g_vout = NULL;
++}
++
++module_init(mxc_v4l2out_init);
++module_exit(mxc_v4l2out_clean);
++
++module_param(video_nr, int, 0444);
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("V4L2-driver for MXC video output");
++MODULE_LICENSE("GPL");
++MODULE_SUPPORTED_DEVICE("video");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/media/video/mxc/output/mxc_v4l2_output.h linux-2.6.28-karo/drivers/media/video/mxc/output/mxc_v4l2_output.h
+--- linux-2.6.28/drivers/media/video/mxc/output/mxc_v4l2_output.h      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/media/video/mxc/output/mxc_v4l2_output.h 2009-03-11 13:47:25.000000000 +0100
+@@ -0,0 +1,169 @@
++/*
++ * Copyright 2005-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @defgroup MXC_V4L2_OUTPUT MXC V4L2 Video Output Driver
++ */
++/*!
++ * @file mxc_v4l2_output.h
++ *
++ * @brief MXC V4L2 Video Output Driver Header file
++ *
++ * Video4Linux2 Output Device using MXC IPU Post-processing functionality.
++ *
++ * @ingroup MXC_V4L2_OUTPUT
++ */
++#ifndef __MXC_V4L2_OUTPUT_H__
++#define __MXC_V4L2_OUTPUT_H__
++
++#include <linux/list.h>
++#include <linux/spinlock.h>
++#include <media/v4l2-dev.h>
++
++#ifdef __KERNEL__
++
++#include <mach/ipu.h>
++#include <mach/mxc_v4l2.h>
++
++#define MIN_FRAME_NUM 2
++#define MAX_FRAME_NUM 30
++
++#define MXC_V4L2_OUT_NUM_OUTPUTS        5
++#define MXC_V4L2_OUT_2_SDC              0
++#define MXC_V4L2_OUT_2_ADC              1
++
++struct dma_buf_desc {
++      dma_addr_t dma_addr;
++      void *cpu_addr;
++      size_t size;
++};
++
++typedef enum {
++      BUF_IDLE,
++      BUF_DONE,
++      BUF_CANCELED,
++      BUF_ERROR,
++      BUF_BUSY,
++} v4l_buf_state_t;
++
++typedef struct v4l_queue {
++      struct v4l2_buffer buf;
++      struct list_head head;
++      v4l_buf_state_t state;
++      struct dma_buf_desc dma_desc;
++} v4l_queue_t;
++
++/*!
++ * States for the video stream
++ */
++typedef enum {
++      STATE_STREAM_OFF,
++      STATE_STREAM_ON,
++      STATE_STREAM_PAUSED,
++      STATE_STREAM_STOPPING,
++} v4lout_state;
++
++/*!
++ * States for tearing protection 
++ */
++typedef enum {
++      TEARING_PROTECTION_INACTIVE,
++      TEARING_PROTECTION_ACTIVE,
++      TEARING_PROTECTION_UNSUPPORTED
++} v4l_tear_protect;
++
++/*!
++ * common v4l2 driver structure.
++ */
++typedef struct _vout_data {
++      struct video_device *video_dev;
++      /*!
++       * semaphore guard against SMP multithreading
++       */
++#if 1
++      struct semaphore user_lock;
++#else
++      struct mutex user_lock;
++#endif
++      spinlock_t irq_lock;
++
++      struct notifier_block fb_event_notifier;
++
++      /*!
++       * number of process that have device open
++       */
++      int open_count;
++
++      v4l_tear_protect tear_protection;
++
++      /*!
++       * params lock for this camera
++       */
++      struct semaphore param_lock;
++
++      struct timer_list output_timer;
++      unsigned long start_jiffies;
++      u32 frame_count;
++      struct list_head ready_q;
++      struct list_head done_q;
++      struct list_head free_q;
++      struct v4l_queue *active;
++
++      s8 next_rdy_ipu_buf;
++      s8 next_done_ipu_buf;
++      s8 ipu_buf[2];
++      v4lout_state state;
++      int busy;
++
++      int cur_disp_output;
++      int output_fb_num[MXC_V4L2_OUT_NUM_OUTPUTS];
++      int output_enabled[MXC_V4L2_OUT_NUM_OUTPUTS];
++      struct v4l2_framebuffer v4l2_fb;
++#ifdef CONFIG_VIDEO_MXC_IPU_OUTPUT
++      ipu_channel_t display_ch;
++      ipu_channel_t post_proc_ch;
++#endif
++      int buffer_cnt;
++      struct list_head display_q;
++      u32 display_buf_size;
++      dma_addr_t display_bufs[2];
++
++      /*!
++       * Poll wait queue
++       */
++      wait_queue_head_t v4l_bufq;
++
++      /*!
++       * v4l2 format
++       */
++      struct v4l2_format v2f;
++      struct v4l2_mxc_offset offset;
++      struct v4l2_rect crop_rect;
++      enum ipu_rotate_mode rotate;
++
++      /* crop */
++      struct v4l2_rect crop_bounds[MXC_V4L2_OUT_NUM_OUTPUTS];
++      struct v4l2_rect crop_current;
++#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC
++      int output_fb;
++      int fb_enabled;
++      int pp_ready;
++#endif
++#if 1
++      int queued;
++      struct timeval frame_start;
++#endif
++} vout_data;
++
++#endif
++#endif                                /* __MXC_V4L2_OUTPUT_H__ */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mmc/host/Kconfig linux-2.6.28-karo/drivers/mmc/host/Kconfig
+--- linux-2.6.28/drivers/mmc/host/Kconfig      2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mmc/host/Kconfig 2009-03-11 13:16:24.000000000 +0100
+@@ -135,6 +135,16 @@ config MMC_IMX
+         If unsure, say N.
++config MMC_MXC
++      tristate "Freescale i.MX2/3 Multimedia Card Interface support"
++      depends on ARCH_MXC
++      help
++        This selects the Freescale i.MX2/3 Multimedia card Interface.
++        If you have a i.MX platform with a Multimedia Card slot,
++        say Y or M here.
++
++        If unsure, say N.
++
+ config MMC_TIFM_SD
+       tristate "TI Flash Media MMC/SD Interface support  (EXPERIMENTAL)"
+       depends on EXPERIMENTAL && PCI
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mmc/host/Makefile linux-2.6.28-karo/drivers/mmc/host/Makefile
+--- linux-2.6.28/drivers/mmc/host/Makefile     2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mmc/host/Makefile        2009-03-11 13:16:24.000000000 +0100
+@@ -9,6 +9,7 @@ endif
+ obj-$(CONFIG_MMC_ARMMMCI)     += mmci.o
+ obj-$(CONFIG_MMC_PXA)         += pxamci.o
+ obj-$(CONFIG_MMC_IMX)         += imxmmc.o
++obj-$(CONFIG_MMC_MXC)         += mxcmmc.o
+ obj-$(CONFIG_MMC_SDHCI)               += sdhci.o
+ obj-$(CONFIG_MMC_SDHCI_PCI)   += sdhci-pci.o
+ obj-$(CONFIG_MMC_RICOH_MMC)   += ricoh_mmc.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mmc/host/mxcmmc.c linux-2.6.28-karo/drivers/mmc/host/mxcmmc.c
+--- linux-2.6.28/drivers/mmc/host/mxcmmc.c     1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/mmc/host/mxcmmc.c        2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,893 @@
++/*
++ *  linux/drivers/mmc/host/mxcmmc.c - Freescale i.MX MMCI driver
++ *
++ *  This is a driver for the SDHC controller found in Freescale MX2/MX3
++ *  SoCs. It is basically the same hardware as found on MX1 (imxmmc.c).
++ *  Unlike the hardware found on MX1, this hardware just works and does
++ *  not need all the quirks found in imxmmc.c, hence the seperate driver.
++ *
++ *  Copyright (C) 2008 Sascha Hauer, Pengutronix <s.hauer@pengutronix.de>
++ *  Copyright (C) 2006 Pavel Pisa, PiKRON <ppisa@pikron.com>
++ *
++ *  derived from pxamci.c by Russell King
++ *
++ * 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/module.h>
++#include <linux/init.h>
++#include <linux/ioport.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/blkdev.h>
++#include <linux/dma-mapping.h>
++#include <linux/mmc/host.h>
++#include <linux/mmc/card.h>
++#include <linux/delay.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++#include <linux/gpio.h>
++
++#include <asm/dma.h>
++#include <asm/irq.h>
++#include <asm/sizes.h>
++#include <mach/mmc.h>
++
++#ifdef CONFIG_ARCH_MX2
++#include <mach/dma-mx1-mx2.h>
++#define HAS_DMA
++#endif
++
++#define DRIVER_NAME "imx-mmc"
++
++#define MMC_REG_STR_STP_CLK           0x00
++#define MMC_REG_STATUS                        0x04
++#define MMC_REG_CLK_RATE              0x08
++#define MMC_REG_CMD_DAT_CONT          0x0C
++#define MMC_REG_RES_TO                        0x10
++#define MMC_REG_READ_TO                       0x14
++#define MMC_REG_BLK_LEN                       0x18
++#define MMC_REG_NOB                   0x1C
++#define MMC_REG_REV_NO                        0x20
++#define MMC_REG_INT_CNTR              0x24
++#define MMC_REG_CMD                   0x28
++#define MMC_REG_ARG                   0x2C
++#define MMC_REG_RES_FIFO              0x34
++#define MMC_REG_BUFFER_ACCESS         0x38
++
++#define STR_STP_CLK_RESET               (1 << 3)
++#define STR_STP_CLK_START_CLK           (1 << 1)
++#define STR_STP_CLK_STOP_CLK            (1 << 0)
++
++#define STATUS_CARD_INSERTION         (1 << 31)
++#define STATUS_CARD_REMOVAL           (1 << 30)
++#define STATUS_YBUF_EMPTY             (1 << 29)
++#define STATUS_XBUF_EMPTY             (1 << 28)
++#define STATUS_YBUF_FULL              (1 << 27)
++#define STATUS_XBUF_FULL              (1 << 26)
++#define STATUS_BUF_UND_RUN            (1 << 25)
++#define STATUS_BUF_OVFL                       (1 << 24)
++#define STATUS_SDIO_INT_ACTIVE                (1 << 14)
++#define STATUS_END_CMD_RESP           (1 << 13)
++#define STATUS_WRITE_OP_DONE          (1 << 12)
++#define STATUS_DATA_TRANS_DONE                (1 << 11)
++#define STATUS_READ_OP_DONE           (1 << 11)
++#define STATUS_WR_CRC_ERROR_CODE_MASK (3 << 10)
++#define STATUS_CARD_BUS_CLK_RUN               (1 << 8)
++#define STATUS_BUF_READ_RDY           (1 << 7)
++#define STATUS_BUF_WRITE_RDY          (1 << 6)
++#define STATUS_RESP_CRC_ERR           (1 << 5)
++#define STATUS_CRC_READ_ERR           (1 << 3)
++#define STATUS_CRC_WRITE_ERR          (1 << 2)
++#define STATUS_TIME_OUT_RESP          (1 << 1)
++#define STATUS_TIME_OUT_READ          (1 << 0)
++#define STATUS_ERR_MASK                       0x2f
++
++#define CMD_DAT_CONT_CMD_RESP_LONG_OFF        (1 << 12)
++#define CMD_DAT_CONT_STOP_READWAIT    (1 << 11)
++#define CMD_DAT_CONT_START_READWAIT   (1 << 10)
++#define CMD_DAT_CONT_BUS_WIDTH_4      (2 << 8)
++#define CMD_DAT_CONT_INIT             (1 << 7)
++#define CMD_DAT_CONT_WRITE            (1 << 4)
++#define CMD_DAT_CONT_DATA_ENABLE      (1 << 3)
++#define CMD_DAT_CONT_RESPONSE_48BIT_CRC       (1 << 0)
++#define CMD_DAT_CONT_RESPONSE_136BIT  (2 << 0)
++#define CMD_DAT_CONT_RESPONSE_48BIT   (3 << 0)
++
++#define INT_SDIO_INT_WKP_EN           (1 << 18)
++#define INT_CARD_INSERTION_WKP_EN     (1 << 17)
++#define INT_CARD_REMOVAL_WKP_EN               (1 << 16)
++#define INT_CARD_INSERTION_EN         (1 << 15)
++#define INT_CARD_REMOVAL_EN           (1 << 14)
++#define INT_SDIO_IRQ_EN                       (1 << 13)
++#define INT_DAT0_EN                   (1 << 12)
++#define INT_BUF_READ_EN                       (1 << 4)
++#define INT_BUF_WRITE_EN              (1 << 3)
++#define INT_END_CMD_RES_EN            (1 << 2)
++#define INT_WRITE_OP_DONE_EN          (1 << 1)
++#define INT_READ_OP_EN                        (1 << 0)
++
++struct mxcmci_host {
++      struct mmc_host         *mmc;
++      struct resource         *res;
++      void __iomem            *base;
++      int                     irq;
++      int                     detect_irq;
++      int                     dma;
++      int                     do_dma;
++      unsigned int            power_mode;
++      struct imxmmc_platform_data *pdata;
++
++      struct mmc_request      *req;
++      struct mmc_command      *cmd;
++      struct mmc_data         *data;
++
++      unsigned int            dma_nents;
++      unsigned int            datasize;
++      unsigned int            dma_dir;
++
++      u16                     rev_no;
++      unsigned int            cmdat;
++
++      struct clk              *clk;
++
++      int                     clock;
++
++      struct work_struct      datawork;
++};
++
++#ifdef HAS_DMA
++static inline int mxcmci_use_dma(struct mxcmci_host *host)
++{
++      return host->do_dma;
++}
++#else
++static inline int mxcmci_use_dma(struct mxcmci_host *host)
++{
++      return 0;
++}
++#endif
++
++static void mxcmci_softreset(struct mxcmci_host *host)
++{
++      int i;
++
++      /* reset sequence */
++      writew(STR_STP_CLK_RESET, host->base + MMC_REG_STR_STP_CLK);
++      writew(STR_STP_CLK_RESET | STR_STP_CLK_START_CLK,
++                      host->base + MMC_REG_STR_STP_CLK);
++
++      for (i = 0; i < 8; i++)
++              writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
++
++      writew(0xff, host->base + MMC_REG_RES_TO);
++}
++
++static void mxcmci_setup_data(struct mxcmci_host *host, struct mmc_data *data)
++{
++      unsigned int nob = data->blocks;
++      unsigned int blksz = data->blksz;
++      unsigned int datasize = nob * blksz;
++      struct scatterlist *sg;
++      int i;
++
++      if (data->flags & MMC_DATA_STREAM)
++              nob = 0xffff;
++
++      host->data = data;
++      data->bytes_xfered = 0;
++
++      writew(nob, host->base + MMC_REG_NOB);
++      writew(blksz, host->base + MMC_REG_BLK_LEN);
++      host->datasize = datasize;
++
++#ifdef HAS_DMA
++      for_each_sg(data->sg, sg, data->sg_len, i) {
++              if (sg->offset & 3 || sg->length & 3) {
++                      host->do_dma = 0;
++                      return;
++              }
++      }
++
++      if (data->flags & MMC_DATA_READ) {
++              host->dma_dir = DMA_FROM_DEVICE;
++              host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
++                                           data->sg_len,  host->dma_dir);
++
++              imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize,
++                               host->res->start + MMC_REG_BUFFER_ACCESS,
++                               DMA_MODE_READ);
++      } else {
++              host->dma_dir = DMA_TO_DEVICE;
++              host->dma_nents = dma_map_sg(mmc_dev(host->mmc), data->sg,
++                                           data->sg_len,  host->dma_dir);
++
++              imx_dma_setup_sg(host->dma, data->sg, host->dma_nents, datasize,
++                               host->res->start + MMC_REG_BUFFER_ACCESS,
++                               DMA_MODE_WRITE);
++      }
++
++      wmb();
++
++      imx_dma_enable(host->dma);
++#endif /* HAS_DMA */
++}
++
++static int mxcmci_start_cmd(struct mxcmci_host *host, struct mmc_command *cmd,
++              unsigned int cmdat)
++{
++      WARN_ON(host->cmd != NULL);
++      host->cmd = cmd;
++
++      switch (mmc_resp_type(cmd)) {
++      case MMC_RSP_R1: /* short CRC, OPCODE */
++      case MMC_RSP_R1B:/* short CRC, OPCODE, BUSY */
++              cmdat |= CMD_DAT_CONT_RESPONSE_48BIT_CRC;
++              break;
++      case MMC_RSP_R2: /* long 136 bit + CRC */
++              cmdat |= CMD_DAT_CONT_RESPONSE_136BIT;
++              break;
++      case MMC_RSP_R3: /* short */
++              cmdat |= CMD_DAT_CONT_RESPONSE_48BIT;
++              break;
++      case MMC_RSP_NONE:
++              break;
++      default:
++              dev_err(mmc_dev(host->mmc), "unhandled response type 0x%x\n",
++                              mmc_resp_type(cmd));
++              cmd->error = -EINVAL;
++              return -EINVAL;
++      }
++
++      if (mxcmci_use_dma(host))
++              writel(INT_READ_OP_EN | INT_WRITE_OP_DONE_EN |
++                              INT_END_CMD_RES_EN,
++                              host->base + MMC_REG_INT_CNTR);
++      else
++              writel(INT_END_CMD_RES_EN, host->base + MMC_REG_INT_CNTR);
++
++      writew(cmd->opcode, host->base + MMC_REG_CMD);
++      writel(cmd->arg, host->base + MMC_REG_ARG);
++      writew(cmdat, host->base + MMC_REG_CMD_DAT_CONT);
++
++      return 0;
++}
++
++static void mxcmci_finish_request(struct mxcmci_host *host,
++              struct mmc_request *req)
++{
++      writel(0, host->base + MMC_REG_INT_CNTR);
++
++      host->req = NULL;
++      host->cmd = NULL;
++      host->data = NULL;
++
++      mmc_request_done(host->mmc, req);
++}
++
++static int mxcmci_finish_data(struct mxcmci_host *host, unsigned int stat)
++{
++      struct mmc_data *data = host->data;
++      int data_error;
++
++#ifdef HAS_DMA
++      if (mxcmci_use_dma(host)) {
++              imx_dma_disable(host->dma);
++              dma_unmap_sg(mmc_dev(host->mmc), data->sg, host->dma_nents,
++                              host->dma_dir);
++      }
++#endif
++
++      if (stat & STATUS_ERR_MASK) {
++              dev_dbg(mmc_dev(host->mmc), "request failed. status: 0x%08x\n",
++                              stat);
++              if (stat & STATUS_CRC_READ_ERR) {
++                      data->error = -EILSEQ;
++              } else if (stat & STATUS_CRC_WRITE_ERR) {
++                      u32 err_code = (stat >> 9) & 0x3;
++                      if (err_code == 2) /* No CRC response */
++                              data->error = -ETIMEDOUT;
++                      else
++                              data->error = -EILSEQ;
++              } else if (stat & STATUS_TIME_OUT_READ) {
++                      data->error = -ETIMEDOUT;
++              } else {
++                      data->error = -EIO;
++              }
++      } else {
++              data->bytes_xfered = host->datasize;
++      }
++
++      data_error = data->error;
++
++      host->data = NULL;
++
++      return data_error;
++}
++
++static void imxmmc_read_response(struct mxcmci_host *host, unsigned int stat)
++{
++      struct mmc_command *cmd = host->cmd;
++      int i;
++      u32 a, b, c;
++
++      if (!cmd)
++              return;
++
++      if (stat & STATUS_TIME_OUT_RESP) {
++              dev_dbg(mmc_dev(host->mmc), "CMD TIMEOUT\n");
++              cmd->error = -ETIMEDOUT;
++      } else if (stat & STATUS_RESP_CRC_ERR && cmd->flags & MMC_RSP_CRC) {
++              dev_dbg(mmc_dev(host->mmc), "cmd crc error\n");
++              cmd->error = -EILSEQ;
++      }
++
++      if (cmd->flags & MMC_RSP_PRESENT) {
++              if (cmd->flags & MMC_RSP_136) {
++                      for (i = 0; i < 4; i++) {
++                              a = readw(host->base + MMC_REG_RES_FIFO);
++                              b = readw(host->base + MMC_REG_RES_FIFO);
++                              cmd->resp[i] = a << 16 | b;
++                      }
++              } else {
++                      a = readw(host->base + MMC_REG_RES_FIFO);
++                      b = readw(host->base + MMC_REG_RES_FIFO);
++                      c = readw(host->base + MMC_REG_RES_FIFO);
++                      cmd->resp[0] = a << 24 | b << 8 | c >> 8;
++              }
++      }
++}
++
++static int mxcmci_poll_status(struct mxcmci_host *host, u32 mask)
++{
++      u32 stat;
++
++      do {
++              stat = readl(host->base + MMC_REG_STATUS);
++              if (stat & STATUS_ERR_MASK)
++                      return stat;
++      } while (!(stat & mask));
++
++      return 0;
++}
++
++static int mxcmci_pull(struct mxcmci_host *host, void *_buf, int bytes)
++{
++      unsigned int stat;
++      u32 *buf = _buf;
++
++      while (bytes > 3) {
++              stat = mxcmci_poll_status(host, STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
++              if (stat)
++                      return stat;
++              *buf++ = readl(host->base + MMC_REG_BUFFER_ACCESS);
++              bytes -= 4;
++      }
++
++      if (bytes) {
++              u8 *b = (u8 *)buf;
++              u32 tmp;
++
++              stat = mxcmci_poll_status(host, STATUS_BUF_READ_RDY | STATUS_READ_OP_DONE);
++              if (stat)
++                      return stat;
++              tmp = readl(host->base + MMC_REG_BUFFER_ACCESS);
++              memcpy(b, &tmp, bytes);
++      }
++
++      return 0;
++}
++
++static int mxcmci_push(struct mxcmci_host *host, void *_buf, int bytes)
++{
++      unsigned int stat;
++      u32 *buf = _buf;
++
++      while (bytes > 3) {
++              stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
++              if (stat)
++                      return stat;
++              writel(*buf++, host->base + MMC_REG_BUFFER_ACCESS);
++              bytes -= 4;
++      }
++
++      if (bytes) {
++              u8 *b = (u8 *)buf;
++              u32 tmp;
++
++              stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
++              if (stat)
++                      return stat;
++
++              memcpy(&tmp, b, bytes);
++              writel(tmp, host->base + MMC_REG_BUFFER_ACCESS);
++      }
++
++      stat = mxcmci_poll_status(host, STATUS_BUF_WRITE_RDY);
++      if (stat)
++              return stat;
++
++      return 0;
++}
++
++static int mxcmci_transfer_data(struct mxcmci_host *host)
++{
++      struct mmc_data *data = host->req->data;
++      struct scatterlist *sg;
++      unsigned int nob = data->blocks;
++      int stat, i;
++
++      host->datasize = 0;
++
++      if (data->flags & MMC_DATA_STREAM)
++              nob = 0xffff;
++
++      host->data = data;
++      host->datasize = 0;
++
++      if (data->flags & MMC_DATA_READ) {
++              for_each_sg(data->sg, sg, data->sg_len, i) {
++                      stat = mxcmci_pull(host, sg_virt(sg), sg->length);
++                      if (stat)
++                              return stat;
++                      host->datasize += sg->length;
++              }
++      } else {
++              for_each_sg(data->sg, sg, data->sg_len, i) {
++                      stat = mxcmci_push(host, sg_virt(sg), sg->length);
++                      if (stat)
++                              return stat;
++                      host->datasize += sg->length;
++              }
++              stat = mxcmci_poll_status(host, STATUS_WRITE_OP_DONE);
++              if (stat)
++                      return stat;
++      }
++      return 0;
++}
++
++static void mxcmci_datawork(struct work_struct *work)
++{
++      struct mxcmci_host *host = container_of(work, struct mxcmci_host,
++                                                datawork);
++      int datastat = mxcmci_transfer_data(host);
++      mxcmci_finish_data(host, datastat);
++
++      if (host->req->stop) {
++              if (mxcmci_start_cmd(host, host->req->stop, 0)) {
++                      mxcmci_finish_request(host, host->req);
++                      return;
++              }
++      } else {
++              mxcmci_finish_request(host, host->req);
++      }
++}
++
++#ifdef HAS_DMA
++static void mxcmci_data_done(struct mxcmci_host *host, unsigned int stat)
++{
++      struct mmc_data *data = host->data;
++      int data_error;
++
++      if (!data)
++              return;
++
++      data_error = mxcmci_finish_data(host, stat);
++
++      imxmmc_read_response(host, stat);
++      host->cmd = NULL;
++
++      if (host->req->stop) {
++              if (mxcmci_start_cmd(host, host->req->stop, 0)) {
++                      mxcmci_finish_request(host, host->req);
++                      return;
++              }
++      } else {
++              mxcmci_finish_request(host, host->req);
++      }
++}
++#endif /* HAS_DMA */
++
++static void mxcmci_cmd_done(struct mxcmci_host *host, unsigned int stat)
++{
++      imxmmc_read_response(host, stat);
++      host->cmd = NULL;
++
++      if (!host->data && host->req) {
++              mxcmci_finish_request(host, host->req);
++              return;
++      }
++
++      /* For the DMA case the DMA engine handles the data transfer
++       * automatically. For non DMA we have to to it ourselves.
++       * Don't do it in interrupt context though.
++       */
++      if (!mxcmci_use_dma(host) && host->data)
++              schedule_work(&host->datawork);
++
++}
++
++static irqreturn_t mxcmci_irq(int irq, void *devid)
++{
++      struct mxcmci_host *host = devid;
++      u32 stat;
++
++      stat = readl(host->base + MMC_REG_STATUS);
++      writel(stat, host->base + MMC_REG_STATUS);
++
++      dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
++
++      if (stat & STATUS_END_CMD_RESP)
++              mxcmci_cmd_done(host, stat);
++#ifdef HAS_DMA
++      if (mxcmci_use_dma(host) &&
++                (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE)))
++              mxcmci_data_done(host, stat);
++#endif
++      return IRQ_HANDLED;
++}
++
++static void mxcmci_request(struct mmc_host *mmc, struct mmc_request *req)
++{
++      struct mxcmci_host *host = mmc_priv(mmc);
++      unsigned int cmdat = host->cmdat;
++
++      WARN_ON(host->req != NULL);
++
++      host->req = req;
++      host->cmdat &= ~CMD_DAT_CONT_INIT;
++#ifdef HAS_DMA
++      host->do_dma = 1;
++#endif
++      if (req->data) {
++              mxcmci_setup_data(host, req->data);
++
++              cmdat |= CMD_DAT_CONT_DATA_ENABLE;
++
++              if (req->data->flags & MMC_DATA_WRITE)
++                      cmdat |= CMD_DAT_CONT_WRITE;
++      }
++
++      if (mxcmci_start_cmd(host, req->cmd, cmdat))
++              mxcmci_finish_request(host, req);
++}
++
++static void mxcmci_set_clk_rate(struct mxcmci_host *host, unsigned int clk_ios)
++{
++      unsigned int divider;
++      int prescaler = 0;
++      unsigned int clk_in = clk_get_rate(host->clk);
++
++      while (prescaler <= 0x800) {
++              for (divider = 1; divider <= 0xF; divider++) {
++                      int x;
++
++                      x = (clk_in / (divider + 1));
++
++                      if (prescaler)
++                              x /= (prescaler * 2);
++
++                      if (x <= clk_ios)
++                              break;
++              }
++              if (divider < 0x10)
++                      break;
++
++              if (prescaler == 0)
++                      prescaler = 1;
++              else
++                      prescaler <<= 1;
++      }
++
++      writew((prescaler << 4) | divider, host->base + MMC_REG_CLK_RATE);
++
++      dev_dbg(mmc_dev(host->mmc), "scaler: %d divider: %d in: %d out: %d\n",
++                      prescaler, divider, clk_in, clk_ios);
++}
++
++static void mxcmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++      struct mxcmci_host *host = mmc_priv(mmc);
++#ifdef HAS_DMA
++      unsigned int blen;
++      /*
++       * use burstlen of 64 in 4 bit mode (--> reg value  0)
++       * use burstlen of 16 in 1 bit mode (--> reg value 16)
++       */
++      if (ios->bus_width == MMC_BUS_WIDTH_4)
++              blen = 0;
++      else
++              blen = 16;
++
++      imx_dma_config_burstlen(host->dma, blen);
++#endif
++      if (ios->bus_width == MMC_BUS_WIDTH_4)
++              host->cmdat |= CMD_DAT_CONT_BUS_WIDTH_4;
++      else
++              host->cmdat &= ~CMD_DAT_CONT_BUS_WIDTH_4;
++
++      if (host->power_mode != ios->power_mode) {
++              if (host->pdata->setpower)
++                      host->pdata->setpower(mmc_dev(mmc), ios->vdd);
++              host->power_mode = ios->power_mode;
++              if (ios->power_mode == MMC_POWER_ON)
++                      host->cmdat |= CMD_DAT_CONT_INIT;
++      }
++
++      if (ios->clock) {
++              mxcmci_set_clk_rate(host, ios->clock);
++              writew(STR_STP_CLK_START_CLK, host->base + MMC_REG_STR_STP_CLK);
++      } else {
++              writew(STR_STP_CLK_STOP_CLK, host->base + MMC_REG_STR_STP_CLK);
++      }
++
++      host->clock = ios->clock;
++}
++
++static irqreturn_t mxcmci_detect_irq(int irq, void *data)
++{
++      struct mmc_host *mmc = data;
++
++      dev_dbg(mmc_dev(mmc), "%s\n", __func__);
++
++      mmc_detect_change(mmc, msecs_to_jiffies(250));
++      return IRQ_HANDLED;
++}
++
++static int mxcmci_get_ro(struct mmc_host *mmc)
++{
++      struct mxcmci_host *host = mmc_priv(mmc);
++
++      if (host->pdata->get_ro)
++              return !!host->pdata->get_ro(mmc_dev(mmc));
++      /*
++       * Board doesn't support read only detection; let the mmc core
++       * decide what to do.
++       */
++      return -ENOSYS;
++}
++
++
++static const struct mmc_host_ops mxcmci_ops = {
++      .request        = mxcmci_request,
++      .set_ios        = mxcmci_set_ios,
++      .get_ro         = mxcmci_get_ro,
++};
++
++static int mxcmci_probe(struct platform_device *pdev)
++{
++      struct mmc_host *mmc;
++      struct mxcmci_host *host = NULL;
++      struct resource *r;
++      int ret = 0, irq;
++
++      printk(KERN_INFO "i.MX SDHC driver\n");
++
++      r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      irq = platform_get_irq(pdev, 0);
++      if (!r || irq < 0)
++              return -ENODEV;
++
++      mmc = mmc_alloc_host(sizeof(struct mxcmci_host), &pdev->dev);
++      if (!mmc) {
++              return -ENOMEM;
++      }
++
++      r = request_mem_region(r->start, resource_size(r), pdev->name);
++      if (!r) {
++              ret = -EBUSY;
++              goto out_free;
++      }
++
++      mmc->ops = &mxcmci_ops;
++      mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
++      mmc->caps = MMC_CAP_4_BIT_DATA;
++
++      /* MMC core transfer sizes tunable parameters */
++      mmc->max_hw_segs = 64;
++      mmc->max_phys_segs = 64;
++      mmc->max_seg_size = 64 * 512;   /* default PAGE_CACHE_SIZE */
++      mmc->max_req_size = 64 * 512;   /* default PAGE_CACHE_SIZE */
++      mmc->max_blk_size = 2048;
++      mmc->max_blk_count = 65535;
++
++      host = mmc_priv(mmc);
++      host->base = ioremap(r->start, resource_size(r));
++      if (!host->base) {
++              ret = -ENOMEM;
++              goto out_release_mem;
++      }
++
++      host->mmc = mmc;
++      host->pdata = pdev->dev.platform_data;
++      if (!host->pdata) {
++              ret = -ENODEV;
++              dev_err(&pdev->dev, "No platform data provided!\n");
++              goto out_iounmap;
++      }
++
++      host->res = r;
++      host->irq = irq;
++
++      host->clk = clk_get(&pdev->dev, "sdhc_clk");
++      if (IS_ERR(host->clk)) {
++              ret = PTR_ERR(host->clk);
++              goto out_iounmap;
++      }
++      clk_enable(host->clk);
++
++      mxcmci_softreset(host);
++
++      host->rev_no = readw(host->base + MMC_REG_REV_NO);
++      if (host->rev_no != 0x400) {
++              ret = -ENODEV;
++              dev_err(mmc_dev(host->mmc), "wrong rev.no. 0x%08x. aborting.\n",
++                      host->rev_no);
++              goto out_clk_put;
++      }
++
++      mmc->f_min = clk_get_rate(host->clk) >> 7;
++      mmc->f_max = clk_get_rate(host->clk) >> 1;
++
++      /* recommended in data sheet */
++      writew(0x2db4, host->base + MMC_REG_READ_TO);
++
++      writel(0, host->base + MMC_REG_INT_CNTR);
++
++#ifdef HAS_DMA
++      host->dma = imx_dma_request_by_prio(DRIVER_NAME, DMA_PRIO_LOW);
++      if (host->dma < 0) {
++              dev_err(mmc_dev(host->mmc), "imx_dma_request_by_prio failed\n");
++              ret = -EBUSY;
++              goto out_clk_put;
++      }
++
++      r = platform_get_resource(pdev, IORESOURCE_DMA, 0);
++      if (!r) {
++              ret = -ENODEV;
++              goto out_free_dma;
++      }
++
++      ret = imx_dma_config_channel(host->dma,
++                                   IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
++                                   IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
++                                   r->start, 0);
++      if (ret) {
++              dev_err(mmc_dev(host->mmc), "failed to configure DMA channel\n");
++              goto out_free_dma;
++      }
++#endif
++      INIT_WORK(&host->datawork, mxcmci_datawork);
++
++      ret = request_irq(host->irq, mxcmci_irq, 0, DRIVER_NAME, host);
++      if (ret)
++              goto out_free_dma;
++
++      platform_set_drvdata(pdev, mmc);
++      device_set_wakeup_enable(&pdev->dev, 1);
++
++      if (host->pdata->init) {
++              ret = host->pdata->init(&pdev->dev, mxcmci_detect_irq,
++                              host->mmc);
++              if (ret)
++                      goto out_free_irq;
++      }
++
++      mmc_add_host(mmc);
++
++      return 0;
++
++out_free_irq:
++      free_irq(host->irq, host);
++out_free_dma:
++#ifdef HAS_DMA
++      imx_dma_free(host->dma);
++#endif
++out_clk_put:
++      clk_disable(host->clk);
++      clk_put(host->clk);
++out_iounmap:
++      iounmap(host->base);
++out_release_mem:
++      release_mem_region(host->res->start, resource_size(host->res));
++out_free:
++      mmc_free_host(mmc);
++      return ret;
++}
++
++static int mxcmci_remove(struct platform_device *pdev)
++{
++      struct mmc_host *mmc = platform_get_drvdata(pdev);
++      struct mxcmci_host *host = mmc_priv(mmc);
++
++      platform_set_drvdata(pdev, NULL);
++
++      mmc_remove_host(mmc);
++
++      if (host->pdata->exit)
++              host->pdata->exit(&pdev->dev, mmc);
++
++      free_irq(host->irq, host);
++      iounmap(host->base);
++#ifdef HAS_DMA
++      imx_dma_free(host->dma);
++#endif
++      clk_disable(host->clk);
++      clk_put(host->clk);
++
++      release_resource(host->res);
++
++      mmc_free_host(mmc);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int mxcmci_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      struct mmc_host *mmc = platform_get_drvdata(pdev);
++      struct mxcmci_host *host = mmc_priv(mmc);
++      int ret = 0;
++
++      if (host->pdata->suspend)
++              ret = host->pdata->suspend(&pdev->dev, state);
++      if (ret == 0) {
++              ret = mmc_suspend_host(mmc, state);
++              if (ret)
++                      if (host->pdata->resume)
++                              host->pdata->resume(&pdev->dev);
++      }
++
++      return ret;
++}
++
++static int mxcmci_resume(struct platform_device *pdev)
++{
++      struct mmc_host *mmc = platform_get_drvdata(pdev);
++      struct mxcmci_host *host = mmc_priv(mmc);
++      int ret;
++
++      ret = mmc_resume_host(mmc);
++      if (ret == 0)
++              if (host->pdata->resume)
++                      ret = host->pdata->resume(&pdev->dev);
++
++      return ret;
++}
++#else
++#define mxcmci_suspend  NULL
++#define mxcmci_resume   NULL
++#endif /* CONFIG_PM */
++
++static struct platform_driver mxcmci_driver = {
++      .probe          = mxcmci_probe,
++      .remove         = mxcmci_remove,
++      .suspend        = mxcmci_suspend,
++      .resume         = mxcmci_resume,
++      .driver         = {
++              .name           = DRIVER_NAME,
++              .owner          = THIS_MODULE,
++      }
++};
++
++static int __init mxcmci_init(void)
++{
++      return platform_driver_register(&mxcmci_driver);
++}
++
++static void __exit mxcmci_exit(void)
++{
++      platform_driver_unregister(&mxcmci_driver);
++}
++
++module_init(mxcmci_init);
++module_exit(mxcmci_exit);
++
++MODULE_DESCRIPTION("i.MX Multimedia Card Interface Driver");
++MODULE_AUTHOR("Sascha Hauer, Pengutronix");
++MODULE_LICENSE("GPL");
++MODULE_ALIAS("platform:imx-mmc");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/mtdblock.c linux-2.6.28-karo/drivers/mtd/mtdblock.c
+--- linux-2.6.28/drivers/mtd/mtdblock.c        2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/mtdblock.c   2009-03-11 13:16:24.000000000 +0100
+@@ -102,9 +102,9 @@ static int write_cached_data (struct mtd
+       if (mtdblk->cache_state != STATE_DIRTY)
+               return 0;
+-      DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" "
+-                      "at 0x%lx, size 0x%x\n", mtd->name,
+-                      mtdblk->cache_offset, mtdblk->cache_size);
++      MTD_DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: writing cached data for \"%s\" "
++                "at 0x%lx, size 0x%x\n", mtd->name,
++                mtdblk->cache_offset, mtdblk->cache_size);
+       ret = erase_write (mtd, mtdblk->cache_offset,
+                          mtdblk->cache_size, mtdblk->cache_data);
+@@ -131,8 +131,8 @@ static int do_cached_write (struct mtdbl
+       size_t retlen;
+       int ret;
+-      DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
+-              mtd->name, pos, len);
++      MTD_DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: write on \"%s\" at 0x%lx, size 0x%x\n",
++                mtd->name, pos, len);
+       if (!sect_size)
+               return mtd->write(mtd, pos, len, &retlen, buf);
+@@ -201,8 +201,8 @@ static int do_cached_read (struct mtdblk
+       size_t retlen;
+       int ret;
+-      DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",
+-                      mtd->name, pos, len);
++      MTD_DEBUG(MTD_DEBUG_LEVEL2, "mtdblock: read on \"%s\" at 0x%lx, size 0x%x\n",
++                mtd->name, pos, len);
+       if (!sect_size)
+               return mtd->read(mtd, pos, len, &retlen, buf);
+@@ -268,7 +268,7 @@ static int mtdblock_open(struct mtd_blkt
+       struct mtd_info *mtd = mbd->mtd;
+       int dev = mbd->devnum;
+-      DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL1,"mtdblock_open\n");
+       if (mtdblks[dev]) {
+               mtdblks[dev]->count++;
+@@ -292,7 +292,7 @@ static int mtdblock_open(struct mtd_blkt
+       mtdblks[dev] = mtdblk;
+-      DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
+       return 0;
+ }
+@@ -302,7 +302,7 @@ static int mtdblock_release(struct mtd_b
+       int dev = mbd->devnum;
+       struct mtdblk_dev *mtdblk = mtdblks[dev];
+-      DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL1, "mtdblock_release\n");
+       mutex_lock(&mtdblk->cache_mutex);
+       write_cached_data(mtdblk);
+@@ -316,7 +316,7 @@ static int mtdblock_release(struct mtd_b
+               vfree(mtdblk->cache_data);
+               kfree(mtdblk);
+       }
+-      DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL1, "ok\n");
+       return 0;
+ }
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/mtdchar.c linux-2.6.28-karo/drivers/mtd/mtdchar.c
+--- linux-2.6.28/drivers/mtd/mtdchar.c 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/mtdchar.c    2009-03-11 13:16:24.000000000 +0100
+@@ -90,7 +90,7 @@ static int mtd_open(struct inode *inode,
+       struct mtd_info *mtd;
+       struct mtd_file_info *mfi;
+-      DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL0, "MTD_open\n");
+       if (devnum >= MAX_MTD_DEVICES)
+               return -ENODEV;
+@@ -141,7 +141,7 @@ static int mtd_close(struct inode *inode
+       struct mtd_file_info *mfi = file->private_data;
+       struct mtd_info *mtd = mfi->mtd;
+-      DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL0, "MTD_close\n");
+       /* Only sync if opened RW */
+       if ((file->f_mode & FMODE_WRITE) && mtd->sync)
+@@ -169,7 +169,7 @@ static ssize_t mtd_read(struct file *fil
+       int len;
+       char *kbuf;
+-      DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL0,"MTD_read\n");
+       if (*ppos + count > mtd->size)
+               count = mtd->size - *ppos;
+@@ -262,7 +262,7 @@ static ssize_t mtd_write(struct file *fi
+       int ret=0;
+       int len;
+-      DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL0,"MTD_write\n");
+       if (*ppos == mtd->size)
+               return -ENOSPC;
+@@ -388,7 +388,7 @@ static int mtd_ioctl(struct inode *inode
+       u_long size;
+       struct mtd_info_user info;
+-      DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL0, "MTD_ioctl\n");
+       size = (cmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT;
+       if (cmd & IOC_IN) {
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/mtdcore.c linux-2.6.28-karo/drivers/mtd/mtdcore.c
+--- linux-2.6.28/drivers/mtd/mtdcore.c 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/mtdcore.c    2009-03-11 13:16:24.000000000 +0100
+@@ -67,7 +67,7 @@ int add_mtd_device(struct mtd_info *mtd)
+                                              mtd->name);
+                       }
+-                      DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
++                      MTD_DEBUG(0, "mtd: Giving out device %d to %s\n",i, mtd->name);
+                       /* No need to get a refcount on the module containing
+                          the notifier, since we hold the mtd_table_mutex */
+                       list_for_each_entry(not, &mtd_notifiers, list)
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/mtdsuper.c linux-2.6.28-karo/drivers/mtd/mtdsuper.c
+--- linux-2.6.28/drivers/mtd/mtdsuper.c        2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/mtdsuper.c   2009-03-11 13:16:24.000000000 +0100
+@@ -23,13 +23,13 @@ static int get_sb_mtd_compare(struct sup
+       struct mtd_info *mtd = _mtd;
+       if (sb->s_mtd == mtd) {
+-              DEBUG(2, "MTDSB: Match on device %d (\"%s\")\n",
+-                    mtd->index, mtd->name);
++              MTD_DEBUG(2, "MTDSB: Match on device %d (\"%s\")\n",
++                        mtd->index, mtd->name);
+               return 1;
+       }
+-      DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n",
+-            sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);
++      MTD_DEBUG(2, "MTDSB: No match, device %d (\"%s\"), device %d (\"%s\")\n",
++                sb->s_mtd->index, sb->s_mtd->name, mtd->index, mtd->name);
+       return 0;
+ }
+@@ -67,8 +67,8 @@ static int get_sb_mtd_aux(struct file_sy
+               goto already_mounted;
+       /* fresh new superblock */
+-      DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n",
+-            mtd->index, mtd->name);
++      MTD_DEBUG(1, "MTDSB: New superblock for device %d (\"%s\")\n",
++                mtd->index, mtd->name);
+       sb->s_flags = flags;
+@@ -85,8 +85,8 @@ static int get_sb_mtd_aux(struct file_sy
+       /* new mountpoint for an already mounted superblock */
+ already_mounted:
+-      DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n",
+-            mtd->index, mtd->name);
++      MTD_DEBUG(1, "MTDSB: Device %d (\"%s\") is already mounted\n",
++                mtd->index, mtd->name);
+       ret = simple_set_mnt(mnt, sb);
+       goto out_put;
+@@ -109,7 +109,7 @@ static int get_sb_mtd_nr(struct file_sys
+       mtd = get_mtd_device(NULL, mtdnr);
+       if (IS_ERR(mtd)) {
+-              DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr);
++              MTD_DEBUG(0, "MTDSB: Device #%u doesn't appear to exist\n", mtdnr);
+               return PTR_ERR(mtd);
+       }
+@@ -134,7 +134,7 @@ int get_sb_mtd(struct file_system_type *
+       if (!dev_name)
+               return -EINVAL;
+-      DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name);
++      MTD_DEBUG(2, "MTDSB: dev_name \"%s\"\n", dev_name);
+       /* the preferred way of mounting in future; especially when
+        * CONFIG_BLOCK=n - we specify the underlying MTD device by number or
+@@ -145,8 +145,8 @@ int get_sb_mtd(struct file_system_type *
+                       struct mtd_info *mtd;
+                       /* mount by MTD device name */
+-                      DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n",
+-                            dev_name + 4);
++                      MTD_DEBUG(1, "MTDSB: mtd:%%s, name \"%s\"\n",
++                                dev_name + 4);
+                       for (mtdnr = 0; mtdnr < MAX_MTD_DEVICES; mtdnr++) {
+                               mtd = get_mtd_device(NULL, mtdnr);
+@@ -172,8 +172,8 @@ int get_sb_mtd(struct file_system_type *
+                       mtdnr = simple_strtoul(dev_name + 3, &endptr, 0);
+                       if (!*endptr) {
+                               /* It was a valid number */
+-                              DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n",
+-                                    mtdnr);
++                              MTD_DEBUG(1, "MTDSB: mtd%%d, mtdnr %d\n",
++                                        mtdnr);
+                               return get_sb_mtd_nr(fs_type, flags,
+                                                    dev_name, data,
+                                                    mtdnr, fill_super, mnt);
+@@ -188,10 +188,10 @@ int get_sb_mtd(struct file_system_type *
+       bdev = lookup_bdev(dev_name);
+       if (IS_ERR(bdev)) {
+               ret = PTR_ERR(bdev);
+-              DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret);
++              MTD_DEBUG(1, "MTDSB: lookup_bdev() returned %d\n", ret);
+               return ret;
+       }
+-      DEBUG(1, "MTDSB: lookup_bdev() returned 0\n");
++      MTD_DEBUG(1, "MTDSB: lookup_bdev() returned 0\n");
+       ret = -EINVAL;
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/nand/Kconfig linux-2.6.28-karo/drivers/mtd/nand/Kconfig
+--- linux-2.6.28/drivers/mtd/nand/Kconfig      2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/nand/Kconfig 2009-03-12 15:04:48.000000000 +0100
+@@ -358,6 +358,10 @@ config MTD_NAND_TMIO
+         Support for NAND flash connected to a Toshiba Mobile IO
+         Controller in some PDAs, including the Sharp SL6000x.
++config MTD_NAND_MXC_FLASH_BBT
++      bool "Support a flash based bad block table"
++      depends on MTD_NAND_MXC
++
+ config MTD_NAND_NANDSIM
+       tristate "Support for NAND Flash Simulator"
+       depends on MTD_PARTITIONS
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/nand/mxc_nand.c linux-2.6.28-karo/drivers/mtd/nand/mxc_nand.c
+--- linux-2.6.28/drivers/mtd/nand/mxc_nand.c   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/nand/mxc_nand.c      2009-03-16 11:04:21.000000000 +0100
+@@ -141,6 +141,31 @@ static struct nand_ecclayout nand_hw_ecc
+       .oobfree = {{0, 6}, {12, 4}, }
+ };
++#ifdef CONFIG_MTD_NAND_MXC_FLASH_BBT
++static u8 bbt_pattern[] = {'B', 'b', 't', '0' };
++static u8 mirror_pattern[] = {'1', 't', 'b', 'B' };
++
++static struct nand_bbt_descr bbt_main_descr = {
++      .options = (NAND_BBT_LASTBLOCK | NAND_BBT_WRITE |
++                  NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP),
++      .offs = 12,
++      .len = 4,
++      .veroffs = 11,
++      .maxblocks = 4,
++      .pattern = bbt_pattern,
++};
++
++static struct nand_bbt_descr bbt_mirror_descr = {
++      .options = (NAND_BBT_LASTBLOCK | NAND_BBT_WRITE |
++                  NAND_BBT_2BIT | NAND_BBT_VERSION | NAND_BBT_PERCHIP),
++      .offs = 12,
++      .len = 4,
++      .veroffs = 11,
++      .maxblocks = 4,
++      .pattern = mirror_pattern,
++};
++#endif
++
+ #ifdef CONFIG_MTD_PARTITIONS
+ static const char *part_probes[] = { "RedBoot", "cmdlinepart", NULL };
+ #endif
+@@ -193,8 +218,8 @@ static void wait_op_done(struct mxc_nand
+                       udelay(1);
+               }
+               if (max_retries <= 0)
+-                      DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n",
+-                            __func__, param);
++                      MTD_DEBUG(MTD_DEBUG_LEVEL0, "%s(%d): INT not set\n",
++                                __func__, param);
+       }
+ }
+@@ -202,7 +227,7 @@ static void wait_op_done(struct mxc_nand
+  * waits for completion. */
+ static void send_cmd(struct mxc_nand_host *host, uint16_t cmd, int useirq)
+ {
+-      DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_cmd(host, 0x%x, %d)\n", cmd, useirq);
+       writew(cmd, host->regs + NFC_FLASH_CMD);
+       writew(NFC_CMD, host->regs + NFC_CONFIG2);
+@@ -216,7 +241,7 @@ static void send_cmd(struct mxc_nand_hos
+  * a NAND command. */
+ static void send_addr(struct mxc_nand_host *host, uint16_t addr, int islast)
+ {
+-      DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_addr(host, 0x%x %d)\n", addr, islast);
+       writew(addr, host->regs + NFC_FLASH_ADDR);
+       writew(NFC_ADDR, host->regs + NFC_CONFIG2);
+@@ -230,7 +255,7 @@ static void send_addr(struct mxc_nand_ho
+ static void send_prog_page(struct mxc_nand_host *host, uint8_t buf_id,
+                       int spare_only)
+ {
+-      DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_prog_page (%d)\n", spare_only);
+       /* NANDFC buffer 0 is used for page read/write */
+       writew(buf_id, host->regs + NFC_BUF_ADDR);
+@@ -256,7 +281,7 @@ static void send_prog_page(struct mxc_na
+ static void send_read_page(struct mxc_nand_host *host, uint8_t buf_id,
+               int spare_only)
+ {
+-      DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3, "send_read_page (%d)\n", spare_only);
+       /* NANDFC buffer 0 is used for page read/write */
+       writew(buf_id, host->regs + NFC_BUF_ADDR);
+@@ -372,8 +397,8 @@ static int mxc_nand_correct_data(struct 
+       uint16_t ecc_status = readw(host->regs + NFC_ECC_STATUS_RESULT);
+       if (((ecc_status & 0x3) == 2) || ((ecc_status >> 2) == 2)) {
+-              DEBUG(MTD_DEBUG_LEVEL0,
+-                    "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "MXC_NAND: HWECC uncorrectable 2-bit ECC error\n");
+               return -1;
+       }
+@@ -427,8 +452,8 @@ static uint16_t mxc_nand_read_word(struc
+       uint16_t col, rd_word, ret;
+       uint16_t __iomem *p;
+-      DEBUG(MTD_DEBUG_LEVEL3,
+-            "mxc_nand_read_word(col = %d)\n", host->col_addr);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3,
++                "mxc_nand_read_word(col = %d)\n", host->col_addr);
+       col = host->col_addr;
+       /* Adjust saved column address */
+@@ -465,9 +490,9 @@ static void mxc_nand_write_buf(struct mt
+       struct mxc_nand_host *host = nand_chip->priv;
+       int n, col, i = 0;
+-      DEBUG(MTD_DEBUG_LEVEL3,
+-            "mxc_nand_write_buf(col = %d, len = %d)\n", host->col_addr,
+-            len);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3,
++                "mxc_nand_write_buf(col = %d, len = %d)\n",
++                host->col_addr, len);
+       col = host->col_addr;
+@@ -478,8 +503,8 @@ static void mxc_nand_write_buf(struct mt
+       n = mtd->writesize + mtd->oobsize - col;
+       n = min(len, n);
+-      DEBUG(MTD_DEBUG_LEVEL3,
+-            "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3,
++                "%s:%d: col = %d, n = %d\n", __func__, __LINE__, col, n);
+       while (n) {
+               void __iomem *p;
+@@ -490,8 +515,8 @@ static void mxc_nand_write_buf(struct mt
+                       p = host->regs + SPARE_AREA0 -
+                                               mtd->writesize + (col & ~3);
+-              DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__,
+-                    __LINE__, p);
++              MTD_DEBUG(MTD_DEBUG_LEVEL3, "%s:%d: p = %p\n", __func__,
++                        __LINE__, p);
+               if (((col | (int)&buf[i]) & 3) || n < 16) {
+                       uint32_t data = 0;
+@@ -539,9 +564,9 @@ static void mxc_nand_write_buf(struct mt
+                       m = min(n, m) & ~3;
+-                      DEBUG(MTD_DEBUG_LEVEL3,
+-                            "%s:%d: n = %d, m = %d, i = %d, col = %d\n",
+-                            __func__,  __LINE__, n, m, i, col);
++                      MTD_DEBUG(MTD_DEBUG_LEVEL3,
++                                "%s:%d: n = %d, m = %d, i = %d, col = %d\n",
++                                __func__,  __LINE__, n, m, i, col);
+                       memcpy(p, &buf[i], m);
+                       col += m;
+@@ -563,8 +588,9 @@ static void mxc_nand_read_buf(struct mtd
+       struct mxc_nand_host *host = nand_chip->priv;
+       int n, col, i = 0;
+-      DEBUG(MTD_DEBUG_LEVEL3,
+-            "mxc_nand_read_buf(col = %d, len = %d)\n", host->col_addr, len);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3,
++                "mxc_nand_read_buf(col = %d, len = %d)\n",
++                host->col_addr, len);
+       col = host->col_addr;
+@@ -649,8 +675,9 @@ static void mxc_nand_select_chip(struct 
+ #ifdef CONFIG_MTD_NAND_MXC_FORCE_CE
+       if (chip > 0) {
+-              DEBUG(MTD_DEBUG_LEVEL0,
+-                    "ERROR:  Illegal chip select (chip = %d)\n", chip);
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "ERROR:  Illegal chip select (chip = %d)\n",
++                        chip);
+               return;
+       }
+@@ -694,9 +721,9 @@ static void mxc_nand_command(struct mtd_
+       struct mxc_nand_host *host = nand_chip->priv;
+       int useirq = true;
+-      DEBUG(MTD_DEBUG_LEVEL3,
+-            "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
+-            command, column, page_addr);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3,
++                "mxc_nand_command (cmd = 0x%x, col = 0x%x, page = 0x%x)\n",
++                command, column, page_addr);
+       /* Reset command state information */
+       host->status_request = false;
+@@ -831,6 +858,7 @@ static void mxc_nand_command(struct mtd_
+               break;
+       case NAND_CMD_READID:
++              host->col_addr = 0;
+               send_read_id(host);
+               break;
+@@ -879,10 +907,17 @@ static int __init mxcnd_probe(struct pla
+       this->write_buf = mxc_nand_write_buf;
+       this->read_buf = mxc_nand_read_buf;
+       this->verify_buf = mxc_nand_verify_buf;
++#ifdef CONFIG_MTD_NAND_MXC_FLASH_BBT
++      this->bbt_td = &bbt_main_descr;
++      this->bbt_md = &bbt_mirror_descr;
++      this->options |= NAND_USE_FLASH_BBT;
++#endif
+       host->clk = clk_get(&pdev->dev, "nfc_clk");
+-      if (IS_ERR(host->clk))
++      if (IS_ERR(host->clk)) {
++              err = PTR_ERR(host->clk);
+               goto eclk;
++      }
+       clk_enable(host->clk);
+       host->clk_act = 1;
+@@ -895,7 +930,7 @@ static int __init mxcnd_probe(struct pla
+       host->regs = ioremap(res->start, res->end - res->start + 1);
+       if (!host->regs) {
+-              err = -EIO;
++              err = -ENOMEM;
+               goto eres;
+       }
+@@ -952,13 +987,17 @@ static int __init mxcnd_probe(struct pla
+               this->ecc.layout = &nand_hw_eccoob_16;
+       }
+-      host->pagesize_2k = 0;
+-
+       /* Scan to find existence of the device */
+-      if (nand_scan(mtd, 1)) {
+-              DEBUG(MTD_DEBUG_LEVEL0,
+-                    "MXC_ND: Unable to find any NAND device.\n");
+-              err = -ENXIO;
++      err = nand_scan_ident(mtd, 1);
++      if (err) {
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "MXC_ND: Unable to find any NAND device.\n");
++              goto escan;
++      }
++      /* this is required before completing the scan */
++      host->pagesize_2k = mtd->writesize == 2048;
++      err = nand_scan_tail(mtd);
++      if (err) {
+               goto escan;
+       }
+@@ -1010,43 +1049,51 @@ static int __devexit mxcnd_remove(struct
+ #ifdef CONFIG_PM
+ static int mxcnd_suspend(struct platform_device *pdev, pm_message_t state)
+ {
+-      struct mtd_info *info = platform_get_drvdata(pdev);
++      struct mtd_info *mtd = platform_get_drvdata(pdev);
++      struct nand_chip *nand_chip = mtd->priv;
++      struct mxc_nand_host *host = nand_chip->priv;
+       int ret = 0;
+-      DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n");
+-      if (info)
+-              ret = info->suspend(info);
++      MTD_DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND suspend\n");
++      if (mtd)
++              ret = mtd->suspend(mtd);
++      if (host->clk_act) {
+       /* Disable the NFC clock */
+-      clk_disable(nfc_clk);   /* FIXME */
++              clk_disable(host->clk);
++      }
+       return ret;
+ }
+ static int mxcnd_resume(struct platform_device *pdev)
+ {
+-      struct mtd_info *info = platform_get_drvdata(pdev);
++      struct mtd_info *mtd = platform_get_drvdata(pdev);
++      struct nand_chip *nand_chip = mtd->priv;
++      struct mxc_nand_host *host = nand_chip->priv;
+       int ret = 0;
+-      DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n");
+-      /* Enable the NFC clock */
+-      clk_enable(nfc_clk);    /* FIXME */
++      MTD_DEBUG(MTD_DEBUG_LEVEL0, "MXC_ND : NAND resume\n");
+-      if (info)
+-              info->resume(info);
++      if (host->clk_act) {
++              /* Enable the NFC clock */
++              clk_enable(host->clk);
++      }
++      if (mtd)
++              mtd->resume(mtd);
+       return ret;
+ }
+ #else
+-# define mxcnd_suspend   NULL
+-# define mxcnd_resume    NULL
++#define mxcnd_suspend   NULL
++#define mxcnd_resume    NULL
+ #endif                                /* CONFIG_PM */
+ static struct platform_driver mxcnd_driver = {
+       .driver = {
+                  .name = DRIVER_NAME,
+-                 },
++      },
+       .remove = __exit_p(mxcnd_remove),
+       .suspend = mxcnd_suspend,
+       .resume = mxcnd_resume,
+@@ -1054,13 +1101,15 @@ static struct platform_driver mxcnd_driv
+ static int __init mxc_nd_init(void)
+ {
++      int ret;
++
+       /* Register the device driver structure. */
+       pr_info("MXC MTD nand Driver\n");
+-      if (platform_driver_probe(&mxcnd_driver, mxcnd_probe) != 0) {
++      ret = platform_driver_probe(&mxcnd_driver, mxcnd_probe);
++      if (ret != 0) {
+               printk(KERN_ERR "Driver register failed for mxcnd_driver\n");
+-              return -ENODEV;
+       }
+-      return 0;
++      return ret;
+ }
+ static void __exit mxc_nd_cleanup(void)
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/nand/nand_base.c linux-2.6.28-karo/drivers/mtd/nand/nand_base.c
+--- linux-2.6.28/drivers/mtd/nand/nand_base.c  2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/nand/nand_base.c     2009-03-11 13:16:24.000000000 +0100
+@@ -1356,8 +1356,8 @@ static int nand_do_read_oob(struct mtd_i
+       int len;
+       uint8_t *buf = ops->oobbuf;
+-      DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
+-            (unsigned long long)from, readlen);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_read_oob: from = 0x%08Lx, len = %i\n",
++                (unsigned long long)from, readlen);
+       if (ops->mode == MTD_OOB_AUTO)
+               len = chip->ecc.layout->oobavail;
+@@ -1365,8 +1365,8 @@ static int nand_do_read_oob(struct mtd_i
+               len = mtd->oobsize;
+       if (unlikely(ops->ooboffs >= len)) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+-                      "Attempt to start read outside oob\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "nand_read_oob: Attempt to start read outside oob\n");
+               return -EINVAL;
+       }
+@@ -1374,8 +1374,8 @@ static int nand_do_read_oob(struct mtd_i
+       if (unlikely(from >= mtd->size ||
+                    ops->ooboffs + readlen > ((mtd->size >> chip->page_shift) -
+                                       (from >> chip->page_shift)) * len)) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+-                      "Attempt read beyond end of device\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "nand_read_oob: Attempt read beyond end of device\n");
+               return -EINVAL;
+       }
+@@ -1449,8 +1449,8 @@ static int nand_read_oob(struct mtd_info
+       /* Do not allow reads past end of device */
+       if (ops->datbuf && (from + ops->len) > mtd->size) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+-                    "Attempt read beyond end of device\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "nand_read_oob: Attempt read beyond end of device\n");
+               return -EINVAL;
+       }
+@@ -1847,8 +1847,8 @@ static int nand_do_write_oob(struct mtd_
+       int chipnr, page, status, len;
+       struct nand_chip *chip = mtd->priv;
+-      DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
+-            (unsigned int)to, (int)ops->ooblen);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_write_oob: to = 0x%08x, len = %i\n",
++                (unsigned int)to, (int)ops->ooblen);
+       if (ops->mode == MTD_OOB_AUTO)
+               len = chip->ecc.layout->oobavail;
+@@ -1857,14 +1857,14 @@ static int nand_do_write_oob(struct mtd_
+       /* Do not allow write past end of page */
+       if ((ops->ooboffs + ops->ooblen) > len) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_write_oob: "
+-                    "Attempt to write past end of page\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "nand_write_oob: Attempt to write past end of page\n");
+               return -EINVAL;
+       }
+       if (unlikely(ops->ooboffs >= len)) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+-                      "Attempt to start write outside oob\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "nand_read_oob: Attempt to start write outside oob\n");
+               return -EINVAL;
+       }
+@@ -1873,8 +1873,8 @@ static int nand_do_write_oob(struct mtd_
+                    ops->ooboffs + ops->ooblen >
+                       ((mtd->size >> chip->page_shift) -
+                        (to >> chip->page_shift)) * len)) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+-                      "Attempt write beyond end of device\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "nand_read_oob: Attempt write beyond end of device\n");
+               return -EINVAL;
+       }
+@@ -1929,8 +1929,8 @@ static int nand_write_oob(struct mtd_inf
+       /* Do not allow writes past end of device */
+       if (ops->datbuf && (to + ops->len) > mtd->size) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_read_oob: "
+-                    "Attempt read beyond end of device\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "nand_read_oob: Attempt read beyond end of device\n");
+               return -EINVAL;
+       }
+@@ -2019,26 +2019,24 @@ int nand_erase_nand(struct mtd_info *mtd
+       int rewrite_bbt[NAND_MAX_CHIPS]={0};
+       unsigned int bbt_masked_page = 0xffffffff;
+-      DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
+-            (unsigned int)instr->addr, (unsigned int)instr->len);
++      MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_erase: start = 0x%08x, len = %i\n",
++                (unsigned int)instr->addr, (unsigned int)instr->len);
+       /* Start address must align on block boundary */
+       if (instr->addr & ((1 << chip->phys_erase_shift) - 1)) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Unaligned address\n");
+               return -EINVAL;
+       }
+       /* Length must align on block boundary */
+       if (instr->len & ((1 << chip->phys_erase_shift) - 1)) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+-                    "Length not block aligned\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Length not block aligned\n");
+               return -EINVAL;
+       }
+       /* Do not allow erase past end of device */
+       if ((instr->len + instr->addr) > mtd->size) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+-                    "Erase past end of device\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Erase past end of device\n");
+               return -EINVAL;
+       }
+@@ -2059,8 +2057,7 @@ int nand_erase_nand(struct mtd_info *mtd
+       /* Check, if it is write protected */
+       if (nand_check_wp(mtd)) {
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+-                    "Device is write protected!!!\n");
++              MTD_DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: Device is write protected!!!\n");
+               instr->state = MTD_ERASE_FAILED;
+               goto erase_exit;
+       }
+@@ -2113,8 +2110,9 @@ int nand_erase_nand(struct mtd_info *mtd
+               /* See if block erase succeeded */
+               if (status & NAND_STATUS_FAIL) {
+-                      DEBUG(MTD_DEBUG_LEVEL0, "nand_erase: "
+-                            "Failed erase, page 0x%08x\n", page);
++                      MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                                "nand_erase: Failed erase, page 0x%08x\n",
++                                page);
+                       instr->state = MTD_ERASE_FAILED;
+                       instr->fail_addr = (page << chip->page_shift);
+                       goto erase_exit;
+@@ -2172,9 +2170,10 @@ int nand_erase_nand(struct mtd_info *mtd
+               if (!rewrite_bbt[chipnr])
+                       continue;
+               /* update the BBT for chip */
+-              DEBUG(MTD_DEBUG_LEVEL0, "nand_erase_nand: nand_update_bbt "
+-                    "(%d:0x%0x 0x%0x)\n", chipnr, rewrite_bbt[chipnr],
+-                    chip->bbt_td->pages[chipnr]);
++              MTD_DEBUG(MTD_DEBUG_LEVEL0,
++                        "nand_erase_nand: nand_update_bbt (%d:0x%0x 0x%0x)\n",
++                        chipnr, rewrite_bbt[chipnr],
++                        chip->bbt_td->pages[chipnr]);
+               nand_update_bbt(mtd, rewrite_bbt[chipnr]);
+       }
+@@ -2192,7 +2191,7 @@ static void nand_sync(struct mtd_info *m
+ {
+       struct nand_chip *chip = mtd->priv;
+-      DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
++      MTD_DEBUG(MTD_DEBUG_LEVEL3, "nand_sync: called\n");
+       /* Grab the lock and see if the device is available */
+       nand_get_device(chip, mtd, FL_SYNCING);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/nand/nand_bbt.c linux-2.6.28-karo/drivers/mtd/nand/nand_bbt.c
+--- linux-2.6.28/drivers/mtd/nand/nand_bbt.c   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/nand/nand_bbt.c      2009-03-11 13:16:24.000000000 +0100
+@@ -1201,8 +1201,9 @@ int nand_isbad_bbt(struct mtd_info *mtd,
+       block = (int)(offs >> (this->bbt_erase_shift - 1));
+       res = (this->bbt[block >> 3] >> (block & 0x06)) & 0x03;
+-      DEBUG(MTD_DEBUG_LEVEL2, "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
+-            (unsigned int)offs, block >> 1, res);
++      MTD_DEBUG(MTD_DEBUG_LEVEL2,
++                "nand_isbad_bbt(): bbt info for offs 0x%08x: (block %d) 0x%02x\n",
++                (unsigned int)offs, block >> 1, res);
+       switch ((int)res) {
+       case 0x00:
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mtd/nand/nand_ecc.c linux-2.6.28-karo/drivers/mtd/nand/nand_ecc.c
+--- linux-2.6.28/drivers/mtd/nand/nand_ecc.c   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/mtd/nand/nand_ecc.c      2009-03-11 13:16:24.000000000 +0100
+@@ -492,7 +492,6 @@ int nand_correct_data(struct mtd_info *m
+       if ((bitsperbyte[b0] + bitsperbyte[b1] + bitsperbyte[b2]) == 1)
+               return 1;       /* error in ecc data; no action needed */
+-      printk(KERN_ERR "uncorrectable error : ");
+       return -1;
+ }
+ EXPORT_SYMBOL(nand_correct_data);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mxc/Kconfig linux-2.6.28-karo/drivers/mxc/Kconfig
+--- linux-2.6.28/drivers/mxc/Kconfig   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/mxc/Kconfig      2009-03-11 13:39:19.000000000 +0100
+@@ -0,0 +1,27 @@
++# drivers/video/mxc/Kconfig
++
++#if ARCH_MXC
++
++menuconfig DRIVERS_MXC
++      bool "MXC support drivers"
++      depends on ARCH_MXC
++
++menu "MXC VPU(Video Processing Unit) support"
++
++config MXC_VPU
++        tristate "Support for MXC VPU(Video Processing Unit)"
++      depends on DRIVERS_MXC
++      depends on MACH_MX27
++      help
++        The VPU codec device provides codec function for H.264/MPEG4/H.263
++
++config MXC_VPU_DEBUG
++      bool "MXC VPU debugging"
++      depends on MXC_VPU
++      help
++        This is an option for the developers; most people should
++        say N here.  This enables MXC VPU driver debugging.
++
++endmenu
++
++#endif
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mxc/Makefile linux-2.6.28-karo/drivers/mxc/Makefile
+--- linux-2.6.28/drivers/mxc/Makefile  1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/mxc/Makefile     2009-03-11 13:40:14.000000000 +0100
+@@ -0,0 +1,11 @@
++#
++# Makefile for the VPU drivers.
++#
++
++ifeq ($(CONFIG_MXC_VPU_DEBUG),y)
++      EXTRA_CFLAGS += -DDEBUG
++endif
++
++vpu-objs              := mxc_vpu.o
++obj-$(CONFIG_MXC_VPU) += vpu.o
++
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mxc/mxc_vpu.c linux-2.6.28-karo/drivers/mxc/mxc_vpu.c
+--- linux-2.6.28/drivers/mxc/mxc_vpu.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/mxc/mxc_vpu.c    2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,540 @@
++/*
++ * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++
++/*!
++ * @file mxc_vpu.c
++ *
++ * @brief VPU system initialization and file operation implementation
++ *
++ * @ingroup VPU
++ */
++
++#include <linux/kernel.h>
++#include <linux/fs.h>
++#include <linux/mm.h>
++#include <linux/interrupt.h>
++#include <linux/autoconf.h>
++#include <linux/ioport.h>
++#include <linux/stat.h>
++#include <linux/platform_device.h>
++#include <linux/kdev_t.h>
++#include <linux/dma-mapping.h>
++#include <linux/wait.h>
++#include <linux/list.h>
++#include <linux/clk.h>
++#include <linux/io.h>
++
++#include <asm/uaccess.h>
++#include <asm/sizes.h>
++#include <asm/dma-mapping.h>
++#include <asm/atomic.h>
++
++#include <mach/hardware.h>
++
++#include "mxc_vpu.h"
++
++
++#define       BIT_INT_CLEAR           0x00C
++#define       BIT_INT_STATUS          0x010
++#define BIT_INT_ENABLE                0x170
++
++typedef struct vpu_t {
++      struct fasync_struct *async_queue;
++      struct device *dev;
++} vpu_t;
++
++/* To track the allocated memory buffer */
++typedef struct memalloc_record {
++      struct list_head list;
++      vpu_mem_desc mem;
++} memalloc_record;
++
++static DEFINE_MUTEX(vpu_list_lock);
++static DEFINE_MUTEX(vpu_mutex);
++static LIST_HEAD(head);
++
++static int vpu_major = 0;
++static struct class *vpu_class;
++static struct vpu_t vpu_data;
++static int open_count = 0;
++static struct clk *vpu_clk;
++
++/* implement the blocking ioctl */
++static int codec_done = 0;
++static wait_queue_head_t vpu_queue;
++static int wait_intr_cnt = 0;
++
++/*!
++ * Private function to free buffers
++ * @return status  0 success.
++ */
++static int vpu_free_buffers(vpu_t *vpu_data)
++{
++      struct memalloc_record *rec, *n;
++      vpu_mem_desc mem;
++
++      mutex_lock(&vpu_list_lock);
++      list_for_each_entry_safe(rec, n, &head, list) {
++              mem = rec->mem;
++              if (mem.cpu_addr != 0) {
++                      dma_free_coherent(vpu_data->dev, PAGE_ALIGN(mem.size),
++                                        mem.cpu_addr, mem.phy_addr);
++                      pr_debug("[FREE] freed paddr=0x%08X\n", mem.phy_addr);
++
++                      /* delete from list */
++                      list_del(&rec->list);
++                      kfree(rec);
++              }
++      }
++      mutex_unlock(&vpu_list_lock);
++
++      return 0;
++}
++
++/*!
++ * @brief vpu interrupt handler
++ */
++static irqreturn_t vpu_irq_handler(int irq, void *dev_id)
++{
++      struct vpu_t *dev = dev_id;
++
++      //(void)__raw_readl(IO_ADDRESS(VPU_BASE_ADDR + BIT_INT_STATUS));
++      __raw_writel(0x1, IO_ADDRESS(VPU_BASE_ADDR + BIT_INT_CLEAR));
++      if (dev->async_queue)
++              kill_fasync(&dev->async_queue, SIGIO, POLL_IN);
++
++      BUG_ON(codec_done < 0);
++      codec_done++;
++      WARN_ON(codec_done > 1);
++      wake_up_interruptible(&vpu_queue);
++
++      return IRQ_HANDLED;
++}
++
++/*!
++ * @brief vpu hardware enable function
++ *
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_hardware_enable(void)
++{
++      u32 tmp;
++
++      clk_enable(vpu_clk);
++
++      /* Let userspace access the codec engine through the
++       * peripheral access register.
++       */
++#if 0
++      tmp = __raw_readl(IO_ADDRESS(AIPI_BASE_ADDR + 0x00020008));
++      __raw_writel(tmp & ~(1 << 3), IO_ADDRESS(AIPI_BASE_ADDR + 0x00020008));
++#endif
++      codec_done = 0;
++
++      return 0;
++}
++
++/*!
++ * @brief vpu hardware disable function
++ *
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_hardware_disable(void)
++{
++      clk_disable(vpu_clk);
++      return 0;
++
++}
++
++/*!
++ * @brief open function for vpu file operation
++ *
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_open(struct inode *inode, struct file *filp)
++{
++      int ret = 0;
++
++      mutex_lock(&vpu_mutex);
++      if (open_count == 0) {
++              open_count++;
++              filp->private_data = &vpu_data;
++              vpu_hardware_enable();
++      } else {
++              printk(KERN_ERR "VPU has already been opened.\n");
++              ret = -EBUSY;
++      }
++      mutex_unlock(&vpu_mutex);
++
++      return ret;
++}
++
++/*!
++ * @brief IO ctrl function for vpu file operation
++ * @param cmd IO ctrl command
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_ioctl(struct inode *inode, struct file *filp, u_int cmd,
++                   u_long arg)
++{
++      int ret = 0;
++      vpu_t *vpu_data = filp->private_data;
++
++      switch (cmd) {
++      case VPU_IOC_PHYMEM_ALLOC:
++              {
++                      struct memalloc_record *rec;
++
++                      rec = kzalloc(sizeof(*rec), GFP_KERNEL);
++                      if (!rec)
++                              return -ENOMEM;
++
++                      ret = copy_from_user(&rec->mem, (const void __user *)arg,
++                                           sizeof(vpu_mem_desc));
++                      if (ret) {
++                              kfree(rec);
++                              return -EFAULT;
++                      }
++
++                      pr_debug("[ALLOC] mem alloc size = 0x%x\n",
++                               rec->mem.size);
++                      rec->mem.cpu_addr = dma_alloc_coherent(vpu_data->dev,
++                                      PAGE_ALIGN(rec->mem.size),
++                                      &rec->mem.phy_addr,
++                                      GFP_DMA | GFP_KERNEL);
++                      pr_debug("[ALLOC] mem alloc cpu_addr = 0x%p\n",
++                               rec->mem.cpu_addr);
++                      if (rec->mem.cpu_addr == NULL) {
++                              kfree(rec);
++                              printk(KERN_ERR
++                                     "Physical memory allocation error!\n");
++                              ret = -ENOMEM;
++                              break;
++                      }
++                      ret = copy_to_user((void __user *)arg, &rec->mem,
++                                         sizeof(vpu_mem_desc));
++                      if (ret) {
++                              kfree(rec);
++                              ret = -EFAULT;
++                              break;
++                      }
++
++                      mutex_lock(&vpu_list_lock);
++                      list_add(&rec->list, &head);
++                      mutex_unlock(&vpu_list_lock);
++
++                      break;
++              }
++      case VPU_IOC_PHYMEM_FREE:
++              {
++                      struct memalloc_record *rec, *n;
++                      vpu_mem_desc vpu_mem;
++                      int found = 0;
++
++                      ret = copy_from_user(&vpu_mem, (const void __user *)arg,
++                                           sizeof(vpu_mem_desc));
++                      if (ret)
++                              return -EFAULT;
++
++                      pr_debug("[FREE] mem freed cpu_addr = 0x%p\n",
++                               vpu_mem.cpu_addr);
++                      mutex_lock(&vpu_list_lock);
++                      list_for_each_entry_safe(rec, n, &head, list) {
++                              if (rec->mem.cpu_addr == vpu_mem.cpu_addr) {
++                                      /* delete from list */
++                                      list_del(&rec->list);
++                                      kfree(rec);
++                                      found = 1;
++                                      break;
++                              }
++                      }
++
++                      if (vpu_mem.cpu_addr != NULL) {
++                              dma_free_coherent(vpu_data->dev,
++                                                PAGE_ALIGN(vpu_mem.size),
++                                                vpu_mem.cpu_addr,
++                                                vpu_mem.phy_addr);
++                      }
++                      BUG_ON(!found);
++                      mutex_unlock(&vpu_list_lock);
++
++                      break;
++              }
++      case VPU_IOC_WAIT4INT:
++              {
++                      unsigned long flags;
++                      u_long timeout = arg;
++
++                      ret = wait_event_interruptible_timeout(vpu_queue,
++                                      codec_done,
++                                      msecs_to_jiffies(timeout));
++                      local_irq_save(flags);
++                      if (codec_done) {
++                              codec_done--;
++                              BUG_ON(codec_done < 0);
++                              if (codec_done > 0) {
++                                      printk(KERN_DEBUG "%s: WAIT4INT: codec_done=%d\n",
++                                             __FUNCTION__, codec_done);
++                              }
++                              ret = 0;
++                      } else if (signal_pending(current)) {
++                              if (wait_intr_cnt == 0) {
++                                      printk(KERN_WARNING "wait for VPU interrupt canceled\n");
++                              }
++                              wait_intr_cnt++;
++                      } else if (ret == 0) {
++                              if (timeout != 0) {
++                                      printk(KERN_WARNING "VPU blocking: timeout.\n");
++                              }
++                              ret = (filp->f_flags & O_NONBLOCK) ? -EAGAIN : -ETIME;
++                      }
++                      local_irq_restore(flags);
++                      break;
++              }
++/* RMW: this is not portable across platforms */
++#ifdef CONFIG_MACH_MX27
++              /* set/clear LHD (Latency Hiding Disable) bit in ESDCFG0 reg. 
++                 Tends to fix MPEG4 issue on MX27 TO2 */
++      case VPU_IOC_LHD:
++              {
++                      u_int disable = (u_int)arg;
++                      u_int reg;
++                      void __iomem *reg_addr;
++
++                      reg_addr = IO_ADDRESS(SDRAMC_BASE_ADDR + 0x10);
++                      reg = __raw_readl(reg_addr);
++                      pr_debug("ESDCFG0: [ 0x%08x ]\n", reg);
++
++                      if (disable == 0) {
++                              __raw_writel(reg & ~0x00000020, reg_addr);
++                              pr_debug("Latency Hiding Disable\n");
++                      } else {
++                              __raw_writel(reg | 0x00000020, reg_addr);
++                              pr_debug("Latency Hiding Enable\n");
++                      }
++
++                      pr_debug("ESDCFG0: [ 0x%08x ]\n",
++                               __raw_readl(reg_addr));
++
++                      break;
++              }
++#endif
++      case VPU_IOC_VL2CC_FLUSH:
++              break;
++      case VPU_IOC_REG_DUMP:
++              break;
++      case VPU_IOC_PHYMEM_DUMP:
++              break;
++      default:
++              printk(KERN_ERR "No such IOCTL, cmd is %d\n", cmd);
++              ret = -EINVAL;
++      }
++      return ret;
++}
++
++/*!
++ * @brief Release function for vpu file operation
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_release(struct inode *inode, struct file *filp)
++{
++      int ret = 0;
++      struct vpu_t *vpu_data = filp->private_data;
++
++      mutex_lock(&vpu_mutex);
++      if (open_count == 1) {
++              open_count--;
++              vpu_free_buffers(vpu_data);
++              vpu_hardware_disable();
++      } else {
++              ret = -EINVAL;
++      }
++      mutex_unlock(&vpu_mutex);
++      return ret;
++}
++
++/*!
++ * @brief fasync function for vpu file operation
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_fasync(int fd, struct file *filp, int mode)
++{
++      struct vpu_t *vpu_data = filp->private_data;
++      return fasync_helper(fd, filp, mode, &vpu_data->async_queue);
++}
++
++/*!
++ * @brief memory map function of harware registers for vpu file operation
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_map_hwregs(struct file *fp, struct vm_area_struct *vm)
++{
++      unsigned long pfn;
++
++      vm->vm_flags |= VM_IO | VM_RESERVED;
++      vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
++      pfn = VPU_BASE_ADDR >> PAGE_SHIFT;
++      pr_debug("size=0x%08lx,  page no.=0x%08lx\n",
++               vm->vm_end - vm->vm_start, pfn);
++      return remap_pfn_range(vm, vm->vm_start, pfn, vm->vm_end - vm->vm_start,
++                             vm->vm_page_prot) ? -EAGAIN : 0;
++}
++
++/*!
++ * @brief memory map function of memory for vpu file operation
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_map_mem(struct file *fp, struct vm_area_struct *vm)
++{
++      int request_size = vm->vm_end - vm->vm_start;
++
++      pr_debug(" start=0x%08lx, pgoff=0x%08lx, size=0x%08x\n",
++               vm->vm_start, vm->vm_pgoff,
++               request_size);
++
++      vm->vm_flags |= VM_IO | VM_RESERVED;
++      vm->vm_page_prot = pgprot_noncached(vm->vm_page_prot);
++
++      return remap_pfn_range(vm, vm->vm_start, vm->vm_pgoff,
++                             request_size, vm->vm_page_prot) ? -EAGAIN : 0;
++
++}
++
++/*!
++ * @brief memory map interface for vpu file operation
++ * @return  0 on success or negative error code on error
++ */
++static int vpu_mmap(struct file *fp, struct vm_area_struct *vm)
++{
++      if (vm->vm_pgoff)
++              return vpu_map_mem(fp, vm);
++      else
++              return vpu_map_hwregs(fp, vm);
++}
++
++struct file_operations vpu_fops = {
++      .owner = THIS_MODULE,
++      .open = vpu_open,
++      .ioctl = vpu_ioctl,
++      .release = vpu_release,
++      .fasync = vpu_fasync,
++      .mmap = vpu_mmap,
++};
++
++/*!
++ * This function is called by the driver framework to initialize the vpu device.
++ * @param   dev The device structure for the vpu passed in by the framework.
++ * @return   0 on success or negative error code on error
++ */
++static int vpu_dev_probe(struct platform_device *pdev)
++{
++      int err = 0;
++      struct device *temp_device;
++
++      init_waitqueue_head(&vpu_queue);
++
++      vpu_major = register_chrdev(vpu_major, "mxc_vpu", &vpu_fops);
++      if (vpu_major < 0) {
++              printk(KERN_ERR "vpu: unable to get a major for VPU\n");
++              err = vpu_major;
++              goto error;
++      }
++
++      vpu_class = class_create(THIS_MODULE, "mxc_vpu");
++      if (IS_ERR(vpu_class)) {
++              err = PTR_ERR(vpu_class);
++              goto err_out_chrdev;
++      }
++
++      temp_device = device_create(vpu_class, NULL,
++                                  MKDEV(vpu_major, 0), NULL, "mxc_vpu");
++      if (IS_ERR(temp_device)) {
++              err = PTR_ERR(temp_device);
++              goto err_out_class;
++      }
++
++      vpu_data.dev = &pdev->dev;
++      platform_set_drvdata(pdev, &vpu_data);
++
++      vpu_clk = clk_get(&pdev->dev, "vpu_clk");
++      if (IS_ERR(vpu_clk)) {
++              err = PTR_ERR(vpu_clk);
++              goto err_out_class;
++      }
++
++      err = request_irq(MXC_INT_VPU, vpu_irq_handler, 0, "VPU_CODEC_IRQ",
++                        &vpu_data);
++      if (err)
++              goto err_out_class;
++
++      printk(KERN_INFO "VPU initialized\n");
++      goto out;
++
++err_out_class:
++      device_destroy(vpu_class, MKDEV(vpu_major, 0));
++      class_destroy(vpu_class);
++err_out_chrdev:
++      unregister_chrdev(vpu_major, "mxc_vpu");
++error:
++out:
++      return err;
++}
++
++static int __devexit vpu_dev_remove(struct platform_device *pdev)
++{
++      vpu_t *vpu_data = platform_get_drvdata(pdev);
++
++      free_irq(MXC_INT_VPU, vpu_data);
++      if (vpu_major > 0) {
++              device_destroy(vpu_class, MKDEV(vpu_major, 0));
++              class_destroy(vpu_class);
++              unregister_chrdev(vpu_major, "mxc_vpu");
++              vpu_major = 0;
++      }
++
++      clk_put(vpu_clk);
++      return 0;
++}
++
++/*! Driver definition
++ *
++ */
++static struct platform_driver mxcvpu_driver = {
++      .driver = {
++              .name = "mxc_vpu",
++      },
++      .probe = vpu_dev_probe,
++      .remove = __devexit_p(vpu_dev_remove),
++};
++
++static int __init vpu_init(void)
++{
++      int ret = platform_driver_register(&mxcvpu_driver);
++
++      printk(KERN_DEBUG "%s: platform_driver_register returned %d\n", __FUNCTION__, ret);
++
++      return ret;
++}
++
++static void __exit vpu_exit(void)
++{
++      platform_driver_unregister(&mxcvpu_driver);
++      return;
++}
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("Linux VPU driver for Freescale i.MX27");
++MODULE_LICENSE("GPL");
++
++module_init(vpu_init);
++module_exit(vpu_exit);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/mxc/mxc_vpu.h linux-2.6.28-karo/drivers/mxc/mxc_vpu.h
+--- linux-2.6.28/drivers/mxc/mxc_vpu.h 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/mxc/mxc_vpu.h    2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,22 @@
++typedef struct vpu_mem_desc {
++      size_t size;
++      dma_addr_t phy_addr;
++      void *cpu_addr;         /* cpu address to free the dma mem */
++      void *virt_uaddr;               /* virtual user space address */
++} vpu_mem_desc;
++
++#define VPU_IOC_MAGIC  'V'
++
++#define VPU_IOC_PHYMEM_ALLOC  _IO(VPU_IOC_MAGIC, 0)
++#define VPU_IOC_PHYMEM_FREE   _IO(VPU_IOC_MAGIC, 1)
++#define VPU_IOC_WAIT4INT      _IO(VPU_IOC_MAGIC, 2)
++#define VPU_IOC_PHYMEM_DUMP   _IO(VPU_IOC_MAGIC, 3)
++#define VPU_IOC_REG_DUMP      _IO(VPU_IOC_MAGIC, 4)
++#define VPU_IOC_LHD           _IO(VPU_IOC_MAGIC, 5)
++#define VPU_IOC_VL2CC_FLUSH   _IO(VPU_IOC_MAGIC, 6)
++
++int vl2cc_init(u32 vl2cc_hw_base);
++void vl2cc_enable(void);
++void vl2cc_flush(void);
++void vl2cc_disable(void);
++void vl2cc_cleanup(void);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/net/Kconfig linux-2.6.28-karo/drivers/net/Kconfig
+--- linux-2.6.28/drivers/net/Kconfig   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/net/Kconfig      2009-03-11 13:16:24.000000000 +0100
+@@ -1810,11 +1810,11 @@ config 68360_ENET
+         the Motorola 68360 processor.
+ config FEC
+-      bool "FEC ethernet controller (of ColdFire CPUs)"
+-      depends on M523x || M527x || M5272 || M528x || M520x
++      tristate "FEC ethernet controller"
++      depends on M523x || M527x || M5272 || M528x || M520x || MACH_MX27
+       help
+         Say Y here if you want to use the built-in 10/100 Fast ethernet
+-        controller on some Motorola ColdFire processors.
++        controller on some Motorola/Freescale processors.
+ config FEC2
+       bool "Second FEC ethernet controller (on some ColdFire CPUs)"
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/net/fec.c linux-2.6.28-karo/drivers/net/fec.c
+--- linux-2.6.28/drivers/net/fec.c     2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/net/fec.c        2009-03-11 13:16:24.000000000 +0100
+@@ -2,6 +2,12 @@
+  * Fast Ethernet Controller (FEC) driver for Motorola MPC8xx.
+  * Copyright (c) 1997 Dan Malek (dmalek@jlc.net)
+  *
++ * This version of the driver is specific to the FADS implementation,
++ * since the board contains control registers external to the processor
++ * for the control of the LevelOne LXT970 transceiver.  The MPC860T manual
++ * describes connections using the internal parallel port I/O, which
++ * is basically all of Port D.
++ *
+  * Right now, I am very wasteful with the buffers.  I allocate memory
+  * pages and then divide them into 2K frame buffers.  This way I know I
+  * have buffers large enough to hold one frame within one buffer descriptor.
+@@ -18,48 +24,74 @@
+  * Bug fixes and cleanup by Philippe De Muyter (phdm@macqel.be)
+  * Copyright (c) 2004-2006 Macq Electronique SA.
+  */
++/*
++ * Copyright 2006-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+-#include <linux/string.h>
+-#include <linux/ptrace.h>
++#include <linux/resource.h>
+ #include <linux/errno.h>
+ #include <linux/ioport.h>
+ #include <linux/slab.h>
+ #include <linux/interrupt.h>
+-#include <linux/pci.h>
+-#include <linux/init.h>
++#include <linux/wait.h>
+ #include <linux/delay.h>
++#include <linux/platform_device.h>
+ #include <linux/netdevice.h>
+ #include <linux/etherdevice.h>
+ #include <linux/skbuff.h>
+ #include <linux/spinlock.h>
+-#include <linux/workqueue.h>
+-#include <linux/bitops.h>
++#include <linux/dma-mapping.h>
++#include <linux/clk.h>
++#include <linux/fec_enet.h>
++#include <linux/phy.h>
+ #include <asm/irq.h>
+-#include <asm/uaccess.h>
+ #include <asm/io.h>
+-#include <asm/pgtable.h>
+-#include <asm/cacheflush.h>
++#define DRV_NAME              "fec_enet"
++
++#ifdef DEBUG
++static int debug = 1;
++#define dbg_lvl(n)    ((n) < debug)
++module_param(debug, int, S_IRUGO | S_IWUSR);
++
++#define DBG(lvl, fmt...)      do { if (dbg_lvl(lvl)) printk(KERN_DEBUG fmt); } while (0)
++#else
++static int debug;
++#define dbg_lvl(n)    0
++module_param(debug, int, 0);
++
++#define DBG(lvl, fmt...)      do { } while (0)
++#endif
++
++#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || \
++    defined(CONFIG_M5272) || defined(CONFIG_M528x) || \
++    defined(CONFIG_M520x) || defined(CONFIG_M532x)
+ #include <asm/coldfire.h>
+ #include <asm/mcfsim.h>
+ #include "fec.h"
+-
+-#if defined(CONFIG_FEC2)
+-#define       FEC_MAX_PORTS   2
++#define FEC_ALIGNMENT  (0x03)          /*FEC needs 4bytes alignment*/
++#elif defined(CONFIG_ARCH_MXC)
++#include <mach/hardware.h>
++#include <mach/iim.h>
++#include "fec.h"
++#define FEC_ALIGNMENT  (0x0F)          /*FEC needs 128bits(32bytes) alignment*/       
+ #else
+-#define       FEC_MAX_PORTS   1
++#include <asm/8xx_immap.h>
++#include <asm/mpc8xx.h>
++#include "commproc.h"
++#define FEC_ALIGNMENT  (0x03)          /*FEC needs 4bytes alignment */
+ #endif
+-#if defined(CONFIG_M5272)
+-#define HAVE_mii_link_interrupt
+-#endif
++#define FEC_ADDR_ALIGNMENT(x) ((unsigned char *)(((unsigned long)(x) + (FEC_ALIGNMENT)) & (~FEC_ALIGNMENT)))
++#if 0
+ /*
+  * Define the fixed address of the FEC hardware.
+  */
++/* USE resources provided by platform_device! */
+ static unsigned int fec_hw[] = {
+ #if defined(CONFIG_M5272)
+       (MCF_MBAR + 0x840),
+@@ -72,23 +104,26 @@ static unsigned int fec_hw[] = {
+       (MCF_MBAR+0x30000),
+ #elif defined(CONFIG_M532x)
+       (MCF_MBAR+0xfc030000),
++#elif defined(CONFIG_ARCH_MXC)
++      (IO_ADDRESS(FEC_BASE_ADDR)),
+ #else
+       &(((immap_t *)IMAP_ADDR)->im_cpm.cp_fec),
+ #endif
+ };
++#endif
+-static unsigned char  fec_mac_default[] = {
+-      0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+-};
+-
++#if 0
+ /*
+  * Some hardware gets it MAC address out of local flash memory.
+  * if this is non-zero then assume it is the address to get MAC from.
+  */
++/* implemented using platform_data! */
+ #if defined(CONFIG_NETtel)
+ #define       FEC_FLASHMAC    0xf0006006
+ #elif defined(CONFIG_GILBARCONAP) || defined(CONFIG_SCALES)
+ #define       FEC_FLASHMAC    0xf0006000
++#elif defined (CONFIG_MTD_KeyTechnology)
++#define       FEC_FLASHMAC    0xffe04000
+ #elif defined(CONFIG_CANCam)
+ #define       FEC_FLASHMAC    0xf0020000
+ #elif defined (CONFIG_M5272C3)
+@@ -98,10 +133,13 @@ static unsigned char      fec_mac_default[] =
+ #else
+ #define       FEC_FLASHMAC    0
+ #endif
++#endif
++
++#define platform_func(p, args...)     ((p) ? (p)(args) : 0)
+ /* Forward declarations of some structures to support different PHYs
+ */
+-
++#ifndef CONFIG_PHYLIB
+ typedef struct {
+       uint mii_data;
+       void (*funct)(uint mii_reg, struct net_device *dev);
+@@ -116,6 +154,7 @@ typedef struct {
+       const phy_cmd_t *ack_int;
+       const phy_cmd_t *shutdown;
+ } phy_info_t;
++#endif
+ /* The number of Tx and Rx buffers.  These are allocated from the page
+  * pool.  The code may assume these are power of two, so it it best
+@@ -129,12 +168,13 @@ typedef struct {
+ #define RX_RING_SIZE          (FEC_ENET_RX_FRPPG * FEC_ENET_RX_PAGES)
+ #define FEC_ENET_TX_FRSIZE    2048
+ #define FEC_ENET_TX_FRPPG     (PAGE_SIZE / FEC_ENET_TX_FRSIZE)
+-#define TX_RING_SIZE          16      /* Must be power of two */
+-#define TX_RING_MOD_MASK      15      /*   for this to work */
++#define TX_RING_SIZE          16                      /* Must be power of two */
++#define TX_RING_MOD_MASK      (TX_RING_SIZE - 1)      /*   for this to work */
+ #if (((RX_RING_SIZE + TX_RING_SIZE) * 8) > PAGE_SIZE)
+ #error "FEC: descriptor ring size constants too large"
+ #endif
++#define CBD_BUF_SIZE          ((RX_RING_SIZE + TX_RING_SIZE) * sizeof(cbd_t))
+ /* Interrupt events/masks.
+ */
+@@ -149,6 +189,12 @@ typedef struct {
+ #define FEC_ENET_MII  ((uint)0x00800000)      /* MII interrupt */
+ #define FEC_ENET_EBERR        ((uint)0x00400000)      /* SDMA bus error */
++#ifndef CONFIG_ARCH_MXC
++#define FEC_ENET_MASK   ((uint)0xffc00000)
++#else
++#define FEC_ENET_MASK   ((uint)0xfff80000)
++#endif
++      
+ /* The FEC stores dest/src/type, data, and checksum for receive packets.
+  */
+ #define PKT_MAXBUF_SIZE               1518
+@@ -162,8 +208,8 @@ typedef struct {
+  * account when setting it.
+  */
+ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+-    defined(CONFIG_M520x) || defined(CONFIG_M532x)
+-#define       OPT_FRAME_SIZE  (PKT_MAXBUF_SIZE << 16)
++    defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC)
++#define       OPT_FRAME_SIZE  (RCR_MAX_FL_set(PKT_MAXBUF_SIZE))
+ #else
+ #define       OPT_FRAME_SIZE  0
+ #endif
+@@ -178,28 +224,44 @@ typedef struct {
+  */
+ struct fec_enet_private {
+       /* Hardware registers of the FEC device */
+-      volatile fec_t  *hwp;
+-
+-      struct net_device *netdev;
++      volatile void __iomem *reg_base;
++      struct resource *res_mem1;
++      struct resource *res_mem2;
++      int     etn_irq;
++      int     mii_irq;
++#ifndef CONFIG_PHYLIB
++      struct timer_list *phy_timer;
++#else
++      struct mii_bus *mii;
++      int mii_complete;
++#endif
++      u32 msg_enable;
+       /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+-      unsigned char *tx_bounce[TX_RING_SIZE];
++      void    *tx_bounce[TX_RING_SIZE];
+       struct  sk_buff* tx_skbuff[TX_RING_SIZE];
++      struct  sk_buff* rx_skbuff[RX_RING_SIZE];
+       ushort  skb_cur;
+       ushort  skb_dirty;
+       /* CPM dual port RAM relative addresses.
+       */
++      struct device *dma_dev;         /* pointer to (platform_)device for dma_sync*() functions */
++      void    *cbd_mem_base;          /* save the virtual base address of rx&tx buffer descriptor */
++      dma_addr_t cbd_phys_base;       /* physical address of buffer descriptor memory for access by FEC HW */
++
+       cbd_t   *rx_bd_base;            /* Address of Rx and Tx buffers. */
+       cbd_t   *tx_bd_base;
+-      cbd_t   *cur_rx, *cur_tx;               /* The next free ring entry */
+-      cbd_t   *dirty_tx;      /* The ring entries to be free()ed. */
++      cbd_t   *cur_rx, *cur_tx;       /* The next free ring entry */
++      cbd_t   *dirty_tx;              /* The ring entries to be free()ed. */
++      struct  net_device_stats stats;
+       uint    tx_full;
+-      /* hold while accessing the HW like ringbuffer for tx/rx but not MAC */
+-      spinlock_t hw_lock;
+-      /* hold while accessing the mii_list_t() elements */
+-      spinlock_t mii_lock;
++      spinlock_t lock;
++#ifdef CONFIG_PHYLIB
++      struct  phy_device *phy;
++      uint    phy_speed;
++#else
+       uint    phy_id;
+       uint    phy_id_done;
+       uint    phy_status;
+@@ -209,28 +271,41 @@ struct fec_enet_private {
+       uint    sequence_done;
+       uint    mii_phy_task_queued;
+-
++#endif
+       uint    phy_addr;
+-      int     index;
+-      int     opened;
+-      int     link;
+-      int     old_link;
+-      int     full_duplex;
++      unsigned int opened:1;
++      unsigned int phy_int_enabled:1;
++      unsigned int linkstatus:1;
++#ifndef CONFIG_PHYLIB
++      unsigned int old_linkstatus:1;
++#endif
++      unsigned int full_duplex:1;
++
++      struct clk *clk;
+ };
+-static int fec_enet_open(struct net_device *dev);
+-static int fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+-static void fec_enet_mii(struct net_device *dev);
+-static irqreturn_t fec_enet_interrupt(int irq, void * dev_id);
++#ifdef CONFIG_PHYLIB
++static int fec_connect_phy(struct net_device *dev, struct fec_enet_private *fep);
++#else
++static irqreturn_t mii_link_interrupt(int irq, void *dev_id);
++#endif
++static void fec_restart(struct net_device *dev, int duplex);
+ static void fec_enet_tx(struct net_device *dev);
+ static void fec_enet_rx(struct net_device *dev);
+-static int fec_enet_close(struct net_device *dev);
+-static void set_multicast_list(struct net_device *dev);
+-static void fec_restart(struct net_device *dev, int duplex);
++static void fec_enet_mii(struct net_device *dev);
+ static void fec_stop(struct net_device *dev);
+-static void fec_set_mac_address(struct net_device *dev);
++static void _fec_set_mac_address(struct net_device *dev);
++/*
++ *  fec_copy_threshold controls the copy when receiving ethernet frame.
++ *     If ethernet header is aligned on a 4byte boundary, the ip header and
++ *     higher level header will not be aligned.
++ *     The reason is, that an ethernet header is 14bytes long.
++ *     And the max size of tcp & ip header is 128bytes. Normally it is 40bytes.
++ *     So I set the default value between 128 to 256.
++ */
++static int fec_copy_threshold = 192;
+ /* MII processing.  We keep this as simple as possible.  Requests are
+  * placed on the list (if there is room).  When the request is finished
+@@ -242,14 +317,16 @@ typedef struct mii_list {
+       struct  mii_list *mii_next;
+ } mii_list_t;
++#ifndef CONFIG_PHYLIB
+ #define               NMII    20
+ static mii_list_t     mii_cmds[NMII];
+ static mii_list_t     *mii_free;
+ static mii_list_t     *mii_head;
+ static mii_list_t     *mii_tail;
+-static int    mii_queue(struct net_device *dev, int request,
+-                              void (*func)(uint, struct net_device *));
++static int mii_queue(struct net_device *dev, int request,
++                   void (*func)(uint, struct net_device *));
++#endif
+ /* Make MII read/write commands for the FEC.
+ */
+@@ -294,47 +371,147 @@ static int      mii_queue(struct net_device *
+ #define PHY_STAT_100HDX       0x4000  /* 100 Mbit half duplex selected */
+ #define PHY_STAT_100FDX       0x8000  /* 100 Mbit full duplex selected */
++#ifndef DEBUG
++static inline unsigned long fec_reg_read(struct fec_enet_private *fep, unsigned int reg)
++{
++      return readl(fep->reg_base + reg);
++}
++
++static inline void fec_reg_write(struct fec_enet_private *fep, unsigned int reg, unsigned long val)
++{
++      writel(val, fep->reg_base + reg);
++}
++#else
++#define fec_reg_read(fep, reg)                __fec_reg_read(fep, reg, __FUNCTION__, #reg)
++#define fec_reg_write(fep, reg, val)  __fec_reg_write(fep, reg, val, __FUNCTION__, #reg)
++
++static inline unsigned long __fec_reg_read(struct fec_enet_private *fep, unsigned int reg,
++                                         const char *func, const char *reg_name)
++{
++      unsigned long val = readl(fep->reg_base + reg);
++      DBG(3, "%s: Read %08lx from %s(%03x)\n", func, val, reg_name, reg);
++      return val;
++}
++
++static inline void __fec_reg_write(struct fec_enet_private *fep, unsigned int reg,
++                                 unsigned long val, const char *func, const char *reg_name)
++{
++      DBG(3, "%s: Writing %08lx to %s(%03x)\n", func, val, reg_name, reg);
++      writel(val, fep->reg_base + reg);
++}
++#endif
++
++static inline void fec_enet_cbd_get(struct fec_enet_private *fep)
++{
++      DBG(2, "%s: Requesting cbd area: %08lx\n", __FUNCTION__, (ulong)fep->cbd_phys_base);
++      dma_sync_single_for_cpu(fep->dma_dev, fep->cbd_phys_base, CBD_BUF_SIZE, DMA_BIDIRECTIONAL);
++}
++
++static inline void fec_enet_cbd_put(struct fec_enet_private *fep)
++{
++      DBG(2, "%s: Flushing changes to cbd area\n", __FUNCTION__);
++      dma_sync_single_for_device(fep->dma_dev, fep->cbd_phys_base,
++                                 CBD_BUF_SIZE, DMA_BIDIRECTIONAL);
++}
++
++static inline void fec_enet_rxbuf_get(struct fec_enet_private *fep, cbd_t *bdp, ushort len)
++{
++      DBG(2, "%s: Requesting RX buffer %08lx(%u)\n", __FUNCTION__, (ulong)bdp->cbd_bufaddr, len);
++      dma_sync_single_for_cpu(fep->dma_dev, bdp->cbd_bufaddr, len, DMA_FROM_DEVICE);
++}
++
++static inline void fec_enet_rxbuf_put(struct fec_enet_private *fep, cbd_t *bdp, ushort len)
++{
++      DBG(2, "%s: Releasing RX buffer %08lx(%u)\n", __FUNCTION__, (ulong)bdp->cbd_bufaddr, len);
++      dma_sync_single_for_device(fep->dma_dev, bdp->cbd_bufaddr, len, DMA_FROM_DEVICE);
++}
++
++static inline void fec_enet_rxbuf_map(struct fec_enet_private *fep, cbd_t *bdp,
++                                    void *buf, ushort len)
++{
++      BUG_ON(!dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr));
++      bdp->cbd_bufaddr = dma_map_single(fep->dma_dev, buf, len, DMA_FROM_DEVICE);
++      DBG(2, "%s: RX buffer %p(%u) mapped to %08lx\n", __FUNCTION__, buf, len,
++          (ulong)bdp->cbd_bufaddr);
++}
++
++static inline void fec_enet_rxbuf_unmap(struct fec_enet_private *fep, cbd_t *bdp, ushort len)
++{
++      DBG(2, "%s: Unmapping RX buffer %08lx(%u)\n", __FUNCTION__, (ulong)bdp->cbd_bufaddr, len);
++      BUG_ON(dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr));
++      dma_unmap_single(fep->dma_dev, bdp->cbd_bufaddr, len, DMA_FROM_DEVICE);
++      bdp->cbd_bufaddr = ~0;
++}
++
++static inline void fec_enet_txbuf_map(struct fec_enet_private *fep, cbd_t *bdp,
++                                    void *buf, ushort len)
++{
++      BUG_ON(!dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr));
++      bdp->cbd_bufaddr = dma_map_single(fep->dma_dev, buf, len, DMA_TO_DEVICE);
++      DBG(2, "%s: TX buffer %p(%u) mapped to %08lx\n", __FUNCTION__, buf, len,
++          (ulong)bdp->cbd_bufaddr);
++}
++
++static inline void fec_enet_txbuf_unmap(struct fec_enet_private *fep, cbd_t *bdp, ushort len)
++{
++      DBG(2, "%s: Unmapping TX buffer %08lx(%u)\n", __FUNCTION__, (ulong)bdp->cbd_bufaddr, len);
++      BUG_ON(dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr));
++      dma_unmap_single(fep->dma_dev, bdp->cbd_bufaddr, len, DMA_TO_DEVICE);
++      bdp->cbd_bufaddr = ~0;
++}
++
++static inline void fec_enet_txbuf_get(struct fec_enet_private *fep, cbd_t *bdp, ushort len)
++{
++      DBG(2, "%s: Requesting TX buffer %08lx(%u)\n", __FUNCTION__, (ulong)bdp->cbd_bufaddr, len);
++      dma_sync_single_for_cpu(fep->dma_dev, bdp->cbd_bufaddr, len, DMA_TO_DEVICE);
++}
++
++static inline void fec_enet_txbuf_put(struct fec_enet_private *fep, cbd_t *bdp, ushort len)
++{
++      DBG(2, "%s: Releasing TX buffer %08lx(%u)\n", __FUNCTION__, (ulong)bdp->cbd_bufaddr, len);
++      dma_sync_single_for_device(fep->dma_dev, bdp->cbd_bufaddr, len, DMA_TO_DEVICE);
++}
+ static int
+ fec_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+ {
+-      struct fec_enet_private *fep;
+-      volatile fec_t  *fecp;
+-      volatile cbd_t  *bdp;
+-      unsigned short  status;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      cbd_t *bdp;
++      unsigned short status;
+       unsigned long flags;
+-      fep = netdev_priv(dev);
+-      fecp = (volatile fec_t*)dev->base_addr;
+-
+-      if (!fep->link) {
++      if (!fep->linkstatus) {
++              DBG(0, "%s: Cannot send packet; link is down\n", __FUNCTION__);
+               /* Link is down or autonegotiation is in progress. */
+               return 1;
+       }
+-      spin_lock_irqsave(&fep->hw_lock, flags);
++      spin_lock_irqsave(&fep->lock, flags);
++
++      //WARN_ON(fec_reg_read(fep, FEC_TDAR) & TDAR_BUSY);
++      fec_enet_cbd_get(fep);
++
+       /* Fill in a Tx ring entry */
+       bdp = fep->cur_tx;
+       status = bdp->cbd_sc;
+-#ifndef final_version
++#ifdef DEBUG
+       if (status & BD_ENET_TX_READY) {
+               /* Ooops.  All transmit buffers are full.  Bail out.
+                * This should not happen, since dev->tbusy should be set.
+                */
+               printk("%s: tx queue full!.\n", dev->name);
+-              spin_unlock_irqrestore(&fep->hw_lock, flags);
++              fec_enet_cbd_put(fep);
++              spin_unlock_irqrestore(&fep->lock, flags);
+               return 1;
+       }
+ #endif
+-
+       /* Clear all of the status flags.
+        */
+       status &= ~BD_ENET_TX_STATS;
+       /* Set buffer length and buffer pointer.
+       */
+-      bdp->cbd_bufaddr = __pa(skb->data);
+       bdp->cbd_datlen = skb->len;
+       /*
+@@ -342,30 +519,25 @@ fec_enet_start_xmit(struct sk_buff *skb,
+        *      4-byte boundaries. Use bounce buffers to copy data
+        *      and get it aligned. Ugh.
+        */
+-      if (bdp->cbd_bufaddr & 0x3) {
++      if (unlikely((bdp->cbd_bufaddr) & FEC_ALIGNMENT)) {
+               unsigned int index;
+               index = bdp - fep->tx_bd_base;
+-              memcpy(fep->tx_bounce[index], (void *) bdp->cbd_bufaddr, bdp->cbd_datlen);
+-              bdp->cbd_bufaddr = __pa(fep->tx_bounce[index]);
++              memcpy(fep->tx_bounce[index], skb->data, skb->len);
++              fec_enet_txbuf_map(fep, bdp, fep->tx_bounce[index], skb->len);
++      } else {
++              fec_enet_txbuf_map(fep, bdp, skb->data, skb->len);
+       }
+       /* Save skb pointer.
+       */
+       fep->tx_skbuff[fep->skb_cur] = skb;
+-      dev->stats.tx_bytes += skb->len;
+-      fep->skb_cur = (fep->skb_cur+1) & TX_RING_MOD_MASK;
+-
+-      /* Push the data cache so the CPM does not get stale memory
+-       * data.
+-       */
+-      flush_dcache_range((unsigned long)skb->data,
+-                         (unsigned long)skb->data + skb->len);
++      fep->stats.tx_bytes += skb->len;
++      fep->skb_cur = (fep->skb_cur + 1) & TX_RING_MOD_MASK;
+       /* Send it on its way.  Tell FEC it's ready, interrupt when done,
+        * it's the last BD of the frame, and to put the CRC on the end.
+        */
+-
+       status |= (BD_ENET_TX_READY | BD_ENET_TX_INTR
+                       | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+       bdp->cbd_sc = status;
+@@ -373,7 +545,7 @@ fec_enet_start_xmit(struct sk_buff *skb,
+       dev->trans_start = jiffies;
+       /* Trigger transmission start */
+-      fecp->fec_x_des_active = 0;
++      fec_reg_write(fep, FEC_TDAR, DONT_CARE);
+       /* If this was the last BD in the ring, start at the beginning again.
+       */
+@@ -385,12 +557,14 @@ fec_enet_start_xmit(struct sk_buff *skb,
+       if (bdp == fep->dirty_tx) {
+               fep->tx_full = 1;
++              DBG(0, "TX ring full, stopping netif queue\n");
+               netif_stop_queue(dev);
+       }
+-      fep->cur_tx = (cbd_t *)bdp;
++      fep->cur_tx = bdp;
++      fec_enet_cbd_put(fep);
+-      spin_unlock_irqrestore(&fep->hw_lock, flags);
++      spin_unlock_irqrestore(&fep->lock, flags);
+       return 0;
+ }
+@@ -400,68 +574,73 @@ fec_timeout(struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      printk("%s: transmit timed out.\n", dev->name);
+-      dev->stats.tx_errors++;
+-#ifndef final_version
++      printk(KERN_WARNING "%s: transmit timed out.\n", dev->name);
++      fep->stats.tx_errors++;
++#ifdef DEBUG
+       {
+-      int     i;
+-      cbd_t   *bdp;
++              int i;
++              cbd_t *bdp;
+-      printk("Ring data dump: cur_tx %lx%s, dirty_tx %lx cur_rx: %lx\n",
+-             (unsigned long)fep->cur_tx, fep->tx_full ? " (full)" : "",
+-             (unsigned long)fep->dirty_tx,
+-             (unsigned long)fep->cur_rx);
++              fec_enet_cbd_get(fep);
+-      bdp = fep->tx_bd_base;
+-      printk(" tx: %u buffers\n",  TX_RING_SIZE);
+-      for (i = 0 ; i < TX_RING_SIZE; i++) {
+-              printk("  %08x: %04x %04x %08x\n",
+-                     (uint) bdp,
+-                     bdp->cbd_sc,
+-                     bdp->cbd_datlen,
+-                     (int) bdp->cbd_bufaddr);
+-              bdp++;
+-      }
++              printk(KERN_DEBUG "%s: Ring data dump: cur_tx %p%s, dirty_tx %p cur_rx: %p\n",
++                     __FUNCTION__,
++                     fep->cur_tx, fep->tx_full ? " (full)" : "",
++                     fep->dirty_tx,
++                     fep->cur_rx);
+-      bdp = fep->rx_bd_base;
+-      printk(" rx: %lu buffers\n",  (unsigned long) RX_RING_SIZE);
+-      for (i = 0 ; i < RX_RING_SIZE; i++) {
+-              printk("  %08x: %04x %04x %08x\n",
+-                     (uint) bdp,
+-                     bdp->cbd_sc,
+-                     bdp->cbd_datlen,
+-                     (int) bdp->cbd_bufaddr);
+-              bdp++;
+-      }
++              bdp = fep->tx_bd_base;
++              printk(" tx: %u buffers\n",  TX_RING_SIZE);
++              for (i = 0 ; i < TX_RING_SIZE; i++) {
++                      printk("  %p: %04x %04x %08x\n",
++                             bdp,
++                             bdp->cbd_sc,
++                             bdp->cbd_datlen,
++                             bdp->cbd_bufaddr);
++                      bdp++;
++              }
++
++              bdp = fep->rx_bd_base;
++              printk(" rx: %lu buffers\n", RX_RING_SIZE);
++              for (i = 0 ; i < RX_RING_SIZE; i++) {
++                      printk("  %p: %04x %04x %08x\n",
++                             bdp,
++                             bdp->cbd_sc,
++                             bdp->cbd_datlen,
++                             bdp->cbd_bufaddr);
++                      bdp++;
++              }
++              fec_enet_cbd_put(fep);
+       }
+ #endif
+       fec_restart(dev, fep->full_duplex);
+-      netif_wake_queue(dev);
++      DBG(0, "%s: Scheduling netif queue\n", __FUNCTION__);
++      //netif_schedule(dev);
+ }
+ /* The interrupt handler.
+  * This is called from the MPC core interrupt.
+  */
+ static irqreturn_t
+-fec_enet_interrupt(int irq, void * dev_id)
++fec_enet_interrupt(int irq, void *dev_id)
+ {
+-      struct  net_device *dev = dev_id;
+-      volatile fec_t  *fecp;
+-      uint    int_events;
+-      irqreturn_t ret = IRQ_NONE;
+-
+-      fecp = (volatile fec_t*)dev->base_addr;
++      struct net_device *dev = dev_id;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      uint int_events;
++      int handled = 0;
++      DBG(2, "%s: %08lx:%08lx\n", __FUNCTION__,
++          fec_reg_read(fep, FEC_EIR), fec_reg_read(fep, FEC_EIMR));
+       /* Get the interrupt events that caused us to be here.
+       */
+-      do {
+-              int_events = fecp->fec_ievent;
+-              fecp->fec_ievent = int_events;
++      while ((int_events = fec_reg_read(fep, FEC_EIR)) != 0) {
++              fec_reg_write(fep, FEC_EIR, int_events);
+               /* Handle receive event in its own function.
+                */
+-              if (int_events & FEC_ENET_RXF) {
+-                      ret = IRQ_HANDLED;
++              if (int_events & (FEC_ENET_RXF | FEC_ENET_RXB)) {
++                      DBG(2, "%s: Handling RX Interrupt\n", __FUNCTION__);
++                      handled = 1;
+                       fec_enet_rx(dev);
+               }
+@@ -469,32 +648,43 @@ fec_enet_interrupt(int irq, void * dev_i
+                  descriptors. FEC handles all errors, we just discover
+                  them as part of the transmit process.
+               */
+-              if (int_events & FEC_ENET_TXF) {
+-                      ret = IRQ_HANDLED;
++              if (int_events & (FEC_ENET_TXF | FEC_ENET_TXB)) {
++                      DBG(2, "%s: Handling TX Interrupt\n", __FUNCTION__);
++                      handled = 1;
+                       fec_enet_tx(dev);
+               }
+-              if (int_events & FEC_ENET_MII) {
+-                      ret = IRQ_HANDLED;
++              if (int_events & (FEC_ENET_MII | FEC_ENET_HBERR)) {
++                      DBG(2, "%s: Handling MII Interrupt\n", __FUNCTION__);
++                      handled = 1;
+                       fec_enet_mii(dev);
+               }
+-
+-      } while (int_events);
+-
+-      return ret;
++      }
++      return IRQ_RETVAL(handled);
+ }
++static void fec_free_skb(struct fec_enet_private *fep, cbd_t *bdp, struct sk_buff **pskb)
++{
++      struct sk_buff *skb = *pskb;
++      if (!dma_mapping_error(fep->dma_dev, bdp->cbd_bufaddr)) {
++              fec_enet_txbuf_unmap(fep, bdp, skb->len);
++      }
++      dev_kfree_skb_any(skb);
++      *pskb = NULL;
++}
+ static void
+ fec_enet_tx(struct net_device *dev)
+ {
+-      struct  fec_enet_private *fep;
+-      volatile cbd_t  *bdp;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      cbd_t *bdp;
+       unsigned short status;
+-      struct  sk_buff *skb;
++      struct sk_buff *skb;
+-      fep = netdev_priv(dev);
+-      spin_lock_irq(&fep->hw_lock);
++      spin_lock(&fep->lock);
++
++      //WARN_ON(fec_reg_read(fep, FEC_TDAR) & TDAR_BUSY);
++      fec_enet_cbd_get(fep);
+       bdp = fep->dirty_tx;
+       while (((status = bdp->cbd_sc) & BD_ENET_TX_READY) == 0) {
+@@ -505,22 +695,22 @@ fec_enet_tx(struct net_device *dev)
+               if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
+                                  BD_ENET_TX_RL | BD_ENET_TX_UN |
+                                  BD_ENET_TX_CSL)) {
+-                      dev->stats.tx_errors++;
++                      fep->stats.tx_errors++;
+                       if (status & BD_ENET_TX_HB)  /* No heartbeat */
+-                              dev->stats.tx_heartbeat_errors++;
++                              fep->stats.tx_heartbeat_errors++;
+                       if (status & BD_ENET_TX_LC)  /* Late collision */
+-                              dev->stats.tx_window_errors++;
++                              fep->stats.tx_window_errors++;
+                       if (status & BD_ENET_TX_RL)  /* Retrans limit */
+-                              dev->stats.tx_aborted_errors++;
++                              fep->stats.tx_aborted_errors++;
+                       if (status & BD_ENET_TX_UN)  /* Underrun */
+-                              dev->stats.tx_fifo_errors++;
++                              fep->stats.tx_fifo_errors++;
+                       if (status & BD_ENET_TX_CSL) /* Carrier lost */
+-                              dev->stats.tx_carrier_errors++;
++                              fep->stats.tx_carrier_errors++;
+               } else {
+-                      dev->stats.tx_packets++;
++                      fep->stats.tx_packets++;
+               }
+-#ifndef final_version
++#ifdef DEBUG
+               if (status & BD_ENET_TX_READY)
+                       printk("HEY! Enet xmit interrupt and TX_READY.\n");
+ #endif
+@@ -528,12 +718,11 @@ fec_enet_tx(struct net_device *dev)
+                * but we eventually sent the packet OK.
+                */
+               if (status & BD_ENET_TX_DEF)
+-                      dev->stats.collisions++;
++                      fep->stats.collisions++;
+               /* Free the sk buffer associated with this last transmit.
+                */
+-              dev_kfree_skb_any(skb);
+-              fep->tx_skbuff[fep->skb_dirty] = NULL;
++              fec_free_skb(fep, bdp, &fep->tx_skbuff[fep->skb_dirty]);
+               fep->skb_dirty = (fep->skb_dirty + 1) & TX_RING_MOD_MASK;
+               /* Update pointer to next buffer descriptor to be transmitted.
+@@ -548,12 +737,15 @@ fec_enet_tx(struct net_device *dev)
+                */
+               if (fep->tx_full) {
+                       fep->tx_full = 0;
+-                      if (netif_queue_stopped(dev))
++                      if (netif_queue_stopped(dev)) {
++                              DBG(0, "%s: Waking up netif queue\n", __FUNCTION__);
+                               netif_wake_queue(dev);
++                      }
+               }
+       }
+-      fep->dirty_tx = (cbd_t *)bdp;
+-      spin_unlock_irq(&fep->hw_lock);
++      fec_enet_cbd_put(fep);
++      fep->dirty_tx = bdp;
++      spin_unlock(&fep->lock);
+ }
+@@ -565,22 +757,22 @@ fec_enet_tx(struct net_device *dev)
+ static void
+ fec_enet_rx(struct net_device *dev)
+ {
+-      struct  fec_enet_private *fep;
+-      volatile fec_t  *fecp;
+-      volatile cbd_t *bdp;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      cbd_t *bdp;
+       unsigned short status;
+-      struct  sk_buff *skb;
+-      ushort  pkt_len;
+-      __u8 *data;
++      struct sk_buff *skb;
++      ushort pkt_len;
++      int rx_index;
+ #ifdef CONFIG_M532x
++      /* This is probably nonsense
++         Proper use of dma-mapping functions should make this obsolete
++      */
+       flush_cache_all();
+ #endif
+-
+-      fep = netdev_priv(dev);
+-      fecp = (volatile fec_t*)dev->base_addr;
+-
+-      spin_lock_irq(&fep->hw_lock);
++      /* reserve the dual port memory area for our use */
++      //WARN_ON(fec_reg_read(fep, FEC_RDAR) & RDAR_BUSY);
++      fec_enet_cbd_get(fep);
+       /* First, grab all of the stats for the incoming packet.
+        * These get messed up if we get called due to a busy condition.
+@@ -588,8 +780,8 @@ fec_enet_rx(struct net_device *dev)
+       bdp = fep->cur_rx;
+ while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) {
+-
+-#ifndef final_version
++      rx_index = bdp - fep->rx_bd_base;
++#ifdef DEBUG
+       /* Since we have allocated space to hold a complete frame,
+        * the last indicator should be set.
+        */
+@@ -597,23 +789,24 @@ while (!((status = bdp->cbd_sc) & BD_ENE
+               printk("FEC ENET: rcv is not +last\n");
+ #endif
+-      if (!fep->opened)
++      if (!fep->opened) {
++              DBG(0, "%s: Driver not opened; ignoring packet\n", __FUNCTION__);
+               goto rx_processing_done;
+-
++      }
+       /* Check for errors. */
+       if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH | BD_ENET_RX_NO |
+                          BD_ENET_RX_CR | BD_ENET_RX_OV)) {
+-              dev->stats.rx_errors++;
++              fep->stats.rx_errors++;
+               if (status & (BD_ENET_RX_LG | BD_ENET_RX_SH)) {
+               /* Frame too long or too short. */
+-                      dev->stats.rx_length_errors++;
++                      fep->stats.rx_length_errors++;
+               }
+               if (status & BD_ENET_RX_NO)     /* Frame alignment */
+-                      dev->stats.rx_frame_errors++;
++                      fep->stats.rx_frame_errors++;
+               if (status & BD_ENET_RX_CR)     /* CRC Error */
+-                      dev->stats.rx_crc_errors++;
++                      fep->stats.rx_crc_errors++;
+               if (status & BD_ENET_RX_OV)     /* FIFO overrun */
+-                      dev->stats.rx_fifo_errors++;
++                      fep->stats.rx_fifo_errors++;
+       }
+       /* Report late collisions as a frame error.
+@@ -621,36 +814,63 @@ while (!((status = bdp->cbd_sc) & BD_ENE
+        * have in the buffer.  So, just drop this frame on the floor.
+        */
+       if (status & BD_ENET_RX_CL) {
+-              dev->stats.rx_errors++;
+-              dev->stats.rx_frame_errors++;
++              fep->stats.rx_errors++;
++              fep->stats.rx_frame_errors++;
++              DBG(0, "%s: Collision detected; dropping packet\n", __FUNCTION__);
+               goto rx_processing_done;
+       }
+       /* Process the incoming frame.
+        */
+-      dev->stats.rx_packets++;
++      fep->stats.rx_packets++;
+       pkt_len = bdp->cbd_datlen;
+-      dev->stats.rx_bytes += pkt_len;
+-      data = (__u8*)__va(bdp->cbd_bufaddr);
++      fep->stats.rx_bytes += pkt_len;
+       /* This does 16 byte alignment, exactly what we need.
+        * The packet length includes FCS, but we don't want to
+        * include that when passing upstream as it messes up
+        * bridging applications.
+        */
+-      skb = dev_alloc_skb(pkt_len-4);
++      if ((pkt_len - 4) < fec_copy_threshold) {
++              skb = dev_alloc_skb(pkt_len);
++      } else {
++              skb = dev_alloc_skb(FEC_ENET_RX_FRSIZE);
++      }
+       if (skb == NULL) {
+               printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+-              dev->stats.rx_dropped++;
++              fep->stats.rx_dropped++;
+       } else {
+-              skb_put(skb,pkt_len-4); /* Make room */
+-              skb_copy_to_linear_data(skb, data, pkt_len-4);
+-              skb->protocol=eth_type_trans(skb,dev);
++              if ((pkt_len - 4) < fec_copy_threshold) {
++                      /* skip 2 bytes, so IP header is on a 4 bytes boundary */
++                      skb_reserve(skb, 2);
++                      skb_put(skb, pkt_len - 4); /* Make room */
++                      fec_enet_rxbuf_get(fep, bdp, pkt_len - 4);
++                      skb_copy_to_linear_data(skb,
++                                              fep->rx_skbuff[rx_index]->data,
++                                              pkt_len - 4);
++                      fec_enet_rxbuf_put(fep, bdp, pkt_len - 4);
++              } else {
++                      struct sk_buff *pskb = fep->rx_skbuff[rx_index];
++                      
++                      /* unmap the skb we are going to hand down to the network layer */
++                      fec_enet_rxbuf_unmap(fep, bdp, FEC_ENET_RX_FRSIZE);
++
++                      /* init the newly allocated skb */
++                      fep->rx_skbuff[rx_index] = skb;
++                      skb->data = FEC_ADDR_ALIGNMENT(skb->data);
++                      /* map the newly allocated skb's data buffer for DMA */
++                      fec_enet_rxbuf_map(fep, bdp, skb->data, FEC_ENET_RX_FRSIZE);
++
++                      skb_put(pskb, pkt_len - 4);        /* Make room */
++                      skb = pskb;
++
++                }
++              skb->dev = dev;
++              skb->protocol = eth_type_trans(skb, dev);
+               netif_rx(skb);
+       }
+   rx_processing_done:
+-
+       /* Clear the status flags for this buffer.
+       */
+       status &= ~BD_ENET_RX_STATS;
+@@ -660,6 +880,9 @@ while (!((status = bdp->cbd_sc) & BD_ENE
+       status |= BD_ENET_RX_EMPTY;
+       bdp->cbd_sc = status;
++      /* release the dual port memory area for use by the FEC hardware */
++      fec_enet_cbd_put(fep);
++
+       /* Update BD pointer to next entry.
+       */
+       if (status & BD_ENET_RX_WRAP)
+@@ -672,10 +895,10 @@ while (!((status = bdp->cbd_sc) & BD_ENE
+        * incoming frames.  On a heavily loaded network, we should be
+        * able to keep up at the expense of system resources.
+        */
+-      fecp->fec_r_des_active = 0;
++      fec_reg_write(fep, FEC_RDAR, DONT_CARE);
+ #endif
+    } /* while (!((status = bdp->cbd_sc) & BD_ENET_RX_EMPTY)) */
+-      fep->cur_rx = (cbd_t *)bdp;
++      fep->cur_rx = bdp;
+ #if 0
+       /* Doing this here will allow us to process all frames in the
+@@ -685,27 +908,28 @@ while (!((status = bdp->cbd_sc) & BD_ENE
+        * our way back to the interrupt return only to come right back
+        * here.
+        */
+-      fecp->fec_r_des_active = 0;
++      fec_reg_write(fep, FEC_RDAR, DONT_CARE);
+ #endif
+-
+-      spin_unlock_irq(&fep->hw_lock);
+ }
+-
++#ifdef CONFIG_PHYLIB
+ /* called from interrupt context */
++static void fec_enet_mii(struct net_device *dev)
++{
++      struct fec_enet_private *fep = netdev_priv(dev);
++      fep->mii_complete = 1;
++}
++#else
+ static void
+ fec_enet_mii(struct net_device *dev)
+ {
+-      struct  fec_enet_private *fep;
+-      volatile fec_t  *ep;
++      struct fec_enet_private *fep = netdev_priv(dev);
+       mii_list_t      *mip;
+       uint            mii_reg;
+-      fep = netdev_priv(dev);
+-      spin_lock_irq(&fep->mii_lock);
++      mii_reg = fec_reg_read(fep, FEC_MMFR);
+-      ep = fep->hwp;
+-      mii_reg = ep->fec_mii_data;
++      spin_lock(&fep->lock);
+       if ((mip = mii_head) == NULL) {
+               printk("MII and no head!\n");
+@@ -720,27 +944,27 @@ fec_enet_mii(struct net_device *dev)
+       mii_free = mip;
+       if ((mip = mii_head) != NULL)
+-              ep->fec_mii_data = mip->mii_regval;
++              fec_reg_write(fep, FEC_MMFR, mip->mii_regval);
+ unlock:
+-      spin_unlock_irq(&fep->mii_lock);
++      spin_unlock(&fep->lock);
+ }
+ static int
+ mii_queue(struct net_device *dev, int regval, void (*func)(uint, struct net_device *))
+ {
+-      struct fec_enet_private *fep;
++      struct fec_enet_private *fep = netdev_priv(dev);
+       unsigned long   flags;
+       mii_list_t      *mip;
+       int             retval;
++      retval = 0;
++
++      spin_lock_irqsave(&fep->lock,flags);
++
+       /* Add PHY address to register command.
+       */
+-      fep = netdev_priv(dev);
+-      spin_lock_irqsave(&fep->mii_lock, flags);
+-
+       regval |= fep->phy_addr << 23;
+-      retval = 0;
+       if ((mip = mii_free) != NULL) {
+               mii_free = mip->mii_next;
+@@ -752,32 +976,32 @@ mii_queue(struct net_device *dev, int re
+                       mii_tail = mip;
+               } else {
+                       mii_head = mii_tail = mip;
+-                      fep->hwp->fec_mii_data = regval;
++                      fec_reg_write(fep, FEC_MMFR, regval);
+               }
+       } else {
+               retval = 1;
+       }
+-      spin_unlock_irqrestore(&fep->mii_lock, flags);
+-      return retval;
++      spin_unlock_irqrestore(&fep->lock,flags);
++
++      return(retval);
+ }
+ static void mii_do_cmd(struct net_device *dev, const phy_cmd_t *c)
+ {
+-      if(!c)
+-              return;
++      int k;
+-      for (; c->mii_data != mk_mii_end; c++)
+-              mii_queue(dev, c->mii_data, c->funct);
++      for (k = 0; c != NULL && c[k].mii_data != mk_mii_end; k++) {
++              mii_queue(dev, c[k].mii_data, c[k].funct);
++      }
+ }
+ static void mii_parse_sr(uint mii_reg, struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile uint *s = &(fep->phy_status);
+       uint status;
+-      status = *s & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
++      status = fep->phy_status & ~(PHY_STAT_LINK | PHY_STAT_FAULT | PHY_STAT_ANC);
+       if (mii_reg & 0x0004)
+               status |= PHY_STAT_LINK;
+@@ -785,31 +1009,30 @@ static void mii_parse_sr(uint mii_reg, s
+               status |= PHY_STAT_FAULT;
+       if (mii_reg & 0x0020)
+               status |= PHY_STAT_ANC;
+-      *s = status;
++
++      fep->phy_status = status;
+ }
+ static void mii_parse_cr(uint mii_reg, struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile uint *s = &(fep->phy_status);
+       uint status;
+-      status = *s & ~(PHY_CONF_ANE | PHY_CONF_LOOP);
++      status = fep->phy_status & ~(PHY_CONF_ANE | PHY_CONF_LOOP);
+       if (mii_reg & 0x1000)
+               status |= PHY_CONF_ANE;
+       if (mii_reg & 0x4000)
+               status |= PHY_CONF_LOOP;
+-      *s = status;
++      fep->phy_status = status;
+ }
+ static void mii_parse_anar(uint mii_reg, struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile uint *s = &(fep->phy_status);
+       uint status;
+-      status = *s & ~(PHY_CONF_SPMASK);
++      status = fep->phy_status & ~(PHY_CONF_SPMASK);
+       if (mii_reg & 0x0020)
+               status |= PHY_CONF_10HDX;
+@@ -819,7 +1042,7 @@ static void mii_parse_anar(uint mii_reg,
+               status |= PHY_CONF_100HDX;
+       if (mii_reg & 0x00100)
+               status |= PHY_CONF_100FDX;
+-      *s = status;
++      fep->phy_status = status;
+ }
+ /* ------------------------------------------------------------------------- */
+@@ -834,10 +1057,9 @@ static void mii_parse_anar(uint mii_reg,
+ static void mii_parse_lxt970_csr(uint mii_reg, struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile uint *s = &(fep->phy_status);
+       uint status;
+-      status = *s & ~(PHY_STAT_SPMASK);
++      status = fep->phy_status & ~(PHY_STAT_SPMASK);
+       if (mii_reg & 0x0800) {
+               if (mii_reg & 0x1000)
+                       status |= PHY_STAT_100FDX;
+@@ -849,7 +1071,7 @@ static void mii_parse_lxt970_csr(uint mi
+               else
+                       status |= PHY_STAT_10HDX;
+       }
+-      *s = status;
++      fep->phy_status = status;
+ }
+ static phy_cmd_t const phy_cmd_lxt970_config[] = {
+@@ -905,16 +1127,15 @@ static phy_info_t const phy_info_lxt970 
+ static void mii_parse_lxt971_sr2(uint mii_reg, struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile uint *s = &(fep->phy_status);
+       uint status;
+-      status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
++      status = fep->phy_status & ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
+       if (mii_reg & 0x0400) {
+-              fep->link = 1;
++              fep->linkstatus = 1;
+               status |= PHY_STAT_LINK;
+       } else {
+-              fep->link = 0;
++              fep->linkstatus = 0;
+       }
+       if (mii_reg & 0x0080)
+               status |= PHY_STAT_ANC;
+@@ -932,7 +1153,7 @@ static void mii_parse_lxt971_sr2(uint mi
+       if (mii_reg & 0x0008)
+               status |= PHY_STAT_FAULT;
+-      *s = status;
++      fep->phy_status = status;
+ }
+ static phy_cmd_t const phy_cmd_lxt971_config[] = {
+@@ -989,10 +1210,9 @@ static phy_info_t const phy_info_lxt971 
+ static void mii_parse_qs6612_pcr(uint mii_reg, struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile uint *s = &(fep->phy_status);
+       uint status;
+-      status = *s & ~(PHY_STAT_SPMASK);
++      status = fep->phy_status & ~(PHY_STAT_SPMASK);
+       switch((mii_reg >> 2) & 7) {
+       case 1: status |= PHY_STAT_10HDX; break;
+@@ -1001,7 +1221,7 @@ static void mii_parse_qs6612_pcr(uint mi
+       case 6: status |= PHY_STAT_100FDX; break;
+ }
+-      *s = status;
++      fep->phy_status = status;
+ }
+ static phy_cmd_t const phy_cmd_qs6612_config[] = {
+@@ -1059,10 +1279,9 @@ static phy_info_t const phy_info_qs6612 
+ static void mii_parse_am79c874_dr(uint mii_reg, struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile uint *s = &(fep->phy_status);
+       uint status;
+-      status = *s & ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
++      status = fep->phy_status & ~(PHY_STAT_SPMASK | PHY_STAT_ANC);
+       if (mii_reg & 0x0080)
+               status |= PHY_STAT_ANC;
+@@ -1071,7 +1290,7 @@ static void mii_parse_am79c874_dr(uint m
+       else
+               status |= ((mii_reg & 0x0800) ? PHY_STAT_10FDX : PHY_STAT_10HDX);
+-      *s = status;
++      fep->phy_status = status;
+ }
+ static phy_cmd_t const phy_cmd_am79c874_config[] = {
+@@ -1155,33 +1374,32 @@ static phy_info_t const phy_info_ks8721b
+ static void mii_parse_dp8384x_sr2(uint mii_reg, struct net_device *dev)
+ {
+-      struct fec_enet_private *fep = dev->priv;
+-      volatile uint *s = &(fep->phy_status);
++      struct fec_enet_private *fep = netdev_priv(dev);
+-      *s &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
++      fep->phy_status &= ~(PHY_STAT_SPMASK | PHY_STAT_LINK | PHY_STAT_ANC);
+       /* Link up */
+       if (mii_reg & 0x0001) {
+-              fep->link = 1;
+-              *s |= PHY_STAT_LINK;
++              fep->linkstatus = 1;
++              fep->phy_status |= PHY_STAT_LINK;
+       } else
+-              fep->link = 0;
++              fep->linkstatus = 0;
+       /* Status of link */
+       if (mii_reg & 0x0010)   /* Autonegotioation complete */
+-              *s |= PHY_STAT_ANC;
++              fep->phy_status |= PHY_STAT_ANC;
+       if (mii_reg & 0x0002) {   /* 10MBps? */
+               if (mii_reg & 0x0004)   /* Full Duplex? */
+-                      *s |= PHY_STAT_10FDX;
++                      fep->phy_status |= PHY_STAT_10FDX;
+               else
+-                      *s |= PHY_STAT_10HDX;
++                      fep->phy_status |= PHY_STAT_10HDX;
+       } else {                  /* 100 Mbps? */
+               if (mii_reg & 0x0004)   /* Full Duplex? */
+-                      *s |= PHY_STAT_100FDX;
++                      fep->phy_status |= PHY_STAT_100FDX;
+               else
+-                      *s |= PHY_STAT_100HDX;
++                      fep->phy_status |= PHY_STAT_100HDX;
+       }
+       if (mii_reg & 0x0008)
+-              *s |= PHY_STAT_FAULT;
++              fep->phy_status |= PHY_STAT_FAULT;
+ }
+ static phy_info_t phy_info_dp83848= {
+@@ -1218,660 +1436,249 @@ static phy_info_t const * const phy_info
+       &phy_info_dp83848,
+       NULL
+ };
+-
+-/* ------------------------------------------------------------------------- */
+-#ifdef HAVE_mii_link_interrupt
+-static irqreturn_t
+-mii_link_interrupt(int irq, void * dev_id);
+ #endif
+-#if defined(CONFIG_M5272)
+ /*
+- *    Code specific to Coldfire 5272 setup.
++ * do some initializtion based architecture of this chip
++MOVED to platform_data hooks!
+  */
+-static void __inline__ fec_request_intrs(struct net_device *dev)
+-{
+-      volatile unsigned long *icrp;
+-      static const struct idesc {
+-              char *name;
+-              unsigned short irq;
+-              irq_handler_t handler;
+-      } *idp, id[] = {
+-              { "fec(RX)", 86, fec_enet_interrupt },
+-              { "fec(TX)", 87, fec_enet_interrupt },
+-              { "fec(OTHER)", 88, fec_enet_interrupt },
+-              { "fec(MII)", 66, mii_link_interrupt },
+-              { NULL },
+-      };
+-
+-      /* Setup interrupt handlers. */
+-      for (idp = id; idp->name; idp++) {
+-              if (request_irq(idp->irq, idp->handler, IRQF_DISABLED, idp->name, dev) != 0)
+-                      printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq);
+-      }
+-      /* Unmask interrupt at ColdFire 5272 SIM */
+-      icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);
+-      *icrp = 0x00000ddd;
+-      icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
+-      *icrp = 0x0d000000;
+-}
++#define PHY_POLL_LINK_ON      (1 * HZ)
++#define PHY_POLL_LINK_OFF     (HZ / 5)
+-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
++#ifdef CONFIG_PHYLIB
++static void fec_link_change(struct net_device *dev)
+ {
+-      volatile fec_t *fecp;
+-
+-      fecp = fep->hwp;
+-      fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
+-      fecp->fec_x_cntrl = 0x00;
+-
+-      /*
+-       * Set MII speed to 2.5 MHz
+-       * See 5272 manual section 11.5.8: MSCR
+-       */
+-      fep->phy_speed = ((((MCF_CLK / 4) / (2500000 / 10)) + 5) / 10) * 2;
+-      fecp->fec_mii_speed = fep->phy_speed;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      struct phy_device *phydev = fep->phy;
+-      fec_restart(dev, 0);
++      if (phydev->link != fep->linkstatus ||
++          phydev->duplex != fep->full_duplex) {
++              DBG(0, "%s: link status changed from %d to %d %s -> %s duplex\n", __FUNCTION__,
++                  fep->linkstatus, phydev->link, fep->full_duplex ? "full" : "half",
++                  phydev->duplex ? "full" : "half");
++              if (phydev->link) {
++                      fec_restart(dev, phydev->duplex);
++              } else {
++                      fec_stop(dev);
++              }
++              if (fep->linkstatus != phydev->link && netif_msg_link(fep)) {
++                      phy_print_status(phydev);
++              }
++              fep->linkstatus = phydev->link;
++      }
+ }
+-
+-static void __inline__ fec_get_mac(struct net_device *dev)
++#else
++static void fec_link_change(struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile fec_t *fecp;
+-      unsigned char *iap, tmpaddr[ETH_ALEN];
+-      fecp = fep->hwp;
++      DBG(0, "%s: link status changed from %d to %d\n", __FUNCTION__,
++          fep->old_linkstatus, fep->linkstatus);
++      if (fep->linkstatus) {
++              int duplex;
+-      if (FEC_FLASHMAC) {
+-              /*
+-               * Get MAC address from FLASH.
+-               * If it is all 1's or 0's, use the default.
+-               */
+-              iap = (unsigned char *)FEC_FLASHMAC;
+-              if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+-                  (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+-                      iap = fec_mac_default;
+-              if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+-                  (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+-                      iap = fec_mac_default;
++              duplex = 0;
++              if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) {
++                      duplex = 1;
++              }
++              fec_restart(dev, duplex);
++              if (fep->phy_timer) {
++                      mod_timer(fep->phy_timer, jiffies + PHY_POLL_LINK_ON);
++              }
+       } else {
+-              *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
+-              *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
+-              iap = &tmpaddr[0];
++              fec_stop(dev);
++              if (fep->phy_timer) {
++                      mod_timer(fep->phy_timer, jiffies + PHY_POLL_LINK_OFF);
++              }
+       }
+-      memcpy(dev->dev_addr, iap, ETH_ALEN);
+-
+-      /* Adjust MAC if using default MAC address */
+-      if (iap == fec_mac_default)
+-               dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
+-}
+-
+-static void __inline__ fec_enable_phy_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_disable_phy_intr(void)
+-{
+-      volatile unsigned long *icrp;
+-      icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
+-      *icrp = 0x08000000;
+-}
+-
+-static void __inline__ fec_phy_ack_intr(void)
+-{
+-      volatile unsigned long *icrp;
+-      /* Acknowledge the interrupt */
+-      icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
+-      *icrp = 0x0d000000;
++      fep->old_linkstatus = fep->linkstatus;
+ }
+-static void __inline__ fec_localhw_setup(void)
++static void fec_phy_timer(unsigned long data)
+ {
+-}
++      struct net_device *dev = (struct net_device *)data;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      int link_poll_interval = fep->linkstatus ? PHY_POLL_LINK_ON : PHY_POLL_LINK_OFF;
+-/*
+- *    Do not need to make region uncached on 5272.
+- */
+-static void __inline__ fec_uncache(unsigned long addr)
+-{
++      if (fep->old_linkstatus != fep->linkstatus) {
++              fec_link_change(dev);
++      }
++      mod_timer(fep->phy_timer, link_poll_interval);
+ }
+-
+-/* ------------------------------------------------------------------------- */
+-
+-#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
++#endif
+ /*
+- *    Code specific to Coldfire 5230/5231/5232/5234/5235,
+- *    the 5270/5271/5274/5275 and 5280/5282 setups.
++ * Code specific to Freescale i.MXC
+  */
+-static void __inline__ fec_request_intrs(struct net_device *dev)
++static int fec_request_intrs(struct platform_device *pdev, struct net_device *dev)
+ {
+-      struct fec_enet_private *fep;
+-      int b;
+-      static const struct idesc {
+-              char *name;
+-              unsigned short irq;
+-      } *idp, id[] = {
+-              { "fec(TXF)", 23 },
+-              { "fec(RXF)", 27 },
+-              { "fec(MII)", 29 },
+-              { NULL },
+-      };
++      int ret;
++      struct fec_enet_private *fep = netdev_priv(dev);
+-      fep = netdev_priv(dev);
+-      b = (fep->index) ? 128 : 64;
++      fep->etn_irq = platform_get_irq(pdev, 0);
++      fep->mii_irq = platform_get_irq(pdev, 1);
+       /* Setup interrupt handlers. */
+-      for (idp = id; idp->name; idp++) {
+-              if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name, dev) != 0)
+-                      printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
+-      }
+-
+-      /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */
+-      {
+-              volatile unsigned char  *icrp;
+-              volatile unsigned long  *imrp;
+-              int i, ilip;
+-
+-              b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0;
+-              icrp = (volatile unsigned char *) (MCF_IPSBAR + b +
+-                      MCFINTC_ICR0);
+-              for (i = 23, ilip = 0x28; (i < 36); i++)
+-                      icrp[i] = ilip--;
+-
+-              imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
+-                      MCFINTC_IMRH);
+-              *imrp &= ~0x0000000f;
+-              imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
+-                      MCFINTC_IMRL);
+-              *imrp &= ~0xff800001;
+-      }
+-
+-#if defined(CONFIG_M528x)
+-      /* Set up gpio outputs for MII lines */
+-      {
+-              volatile u16 *gpio_paspar;
+-              volatile u8 *gpio_pehlpar;
+-
+-              gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056);
+-              gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058);
+-              *gpio_paspar |= 0x0f00;
+-              *gpio_pehlpar = 0xc0;
++      ret = request_irq(fep->etn_irq, fec_enet_interrupt, 0, "fec", dev);
++      if (ret != 0) {
++              printk(KERN_ERR "FEC: Could not allocate FEC IRQ(%d)!\n", fep->etn_irq);
++              return ret;
++      }
++#ifndef CONFIG_PHYLIB
++      if (fep->mii_irq >= 0) {
++              /* TODO: disable now due to CPLD issue */
++              ret = request_irq(fep->mii_irq, mii_link_interrupt, 0, "fec(MII)", dev);
++              if (ret != 0) {
++                      printk(KERN_ERR "FEC: Could not allocate FEC(MII) IRQ(%d)!\n",
++                             fep->mii_irq);
++                      free_irq(fep->etn_irq, dev);
++                      return ret;
++              }
++              /*
++               * board specific workaround should be done in board specific code
++               * This is unsafe anyway. An interrupt might have been asserted
++               * already. Use IRQ_NOAUTOEN with request_irq() to have irq initially disabled.
++               */
++              fep->phy_int_enabled = 1;
++      } else {
++              fep->phy_timer = kzalloc(sizeof(struct timer_list), GFP_KERNEL);
++              if (fep->phy_timer == NULL) {
++                      free_irq(fep->etn_irq, dev);
++                      return -ENOMEM;
++              }
++              init_timer(fep->phy_timer);
++              fep->phy_timer->function = fec_phy_timer;
++              fep->phy_timer->data = (unsigned long)dev;
++              fec_link_change(dev);
+       }
+ #endif
+-#if defined(CONFIG_M527x)
+-      /* Set up gpio outputs for MII lines */
+-      {
+-              volatile u8 *gpio_par_fec;
+-              volatile u16 *gpio_par_feci2c;
+-
+-              gpio_par_feci2c = (volatile u16 *)(MCF_IPSBAR + 0x100082);
+-              /* Set up gpio outputs for FEC0 MII lines */
+-              gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100078);
+-
+-              *gpio_par_feci2c |= 0x0f00;
+-              *gpio_par_fec |= 0xc0;
++      return 0;
++}
+-#if defined(CONFIG_FEC2)
+-              /* Set up gpio outputs for FEC1 MII lines */
+-              gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100079);
++static void __inline__ fec_release_intrs(struct net_device *dev)
++{
++      struct fec_enet_private *fep = netdev_priv(dev);
+-              *gpio_par_feci2c |= 0x00a0;
+-              *gpio_par_fec |= 0xc0;
+-#endif /* CONFIG_FEC2 */
++      free_irq(fep->etn_irq, dev);
++#ifndef CONFIG_PHYLIB
++      if (fep->mii_irq >= 0) {
++              free_irq(fep->mii_irq, dev);
+       }
+-#endif /* CONFIG_M527x */
++#endif
+ }
+ static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
+ {
+-      volatile fec_t *fecp;
++      u32 rate;
++      struct clk *clk;
+-      fecp = fep->hwp;
+-      fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
+-      fecp->fec_x_cntrl = 0x00;
++      fec_reg_write(fep, FEC_RCR, OPT_FRAME_SIZE | 0x04);
++      fec_reg_write(fep, FEC_TCR, 0x00);
+-      /*
++      /*
+        * Set MII speed to 2.5 MHz
+-       * See 5282 manual section 17.5.4.7: MSCR
+        */
+-      fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
+-      fecp->fec_mii_speed = fep->phy_speed;
++      clk = clk_get(fep->dma_dev, "fec_clk");
++      rate = clk_get_rate(clk);
++      clk_put(clk);
+-      fec_restart(dev, 0);
++      fep->phy_speed = ((((rate / 2 + 4999999) / 2500000) / 2) & 0x3F) << 1;
++      fec_reg_write(fep, FEC_MSCR, fep->phy_speed);
+ }
+-static void __inline__ fec_get_mac(struct net_device *dev)
++static const unsigned char default_mac[ETH_ALEN] = {
++      0x00, 0x04, 0x9f, 0x00, 0x74, 0x4a,
++};
++
++#define FEC_IIM_BASE    IO_ADDRESS(IIM_BASE_ADDR)
++static void fec_get_mac(struct net_device *dev)
+ {
++#if 1
++      // keep bootloader assigned MAC address
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile fec_t *fecp;
+-      unsigned char *iap, tmpaddr[ETH_ALEN];
+-
+-      fecp = fep->hwp;
++      unsigned long eth_addr = fec_reg_read(fep, FEC_PALR);
++      dev->dev_addr[0] = eth_addr >> 24;
++      dev->dev_addr[1] = eth_addr >> 16;
++      dev->dev_addr[2] = eth_addr >> 8;
++      dev->dev_addr[3] = eth_addr >> 0;
++      eth_addr = fec_reg_read(fep, FEC_PAUR);
++      dev->dev_addr[5] = eth_addr >> 16;
++      dev->dev_addr[4] = eth_addr >> 24;
++#else
++      int i;
++      unsigned long fec_mac_base = FEC_IIM_BASE + MXC_IIMKEY0;
+-      if (FEC_FLASHMAC) {
+-              /*
+-               * Get MAC address from FLASH.
+-               * If it is all 1's or 0's, use the default.
+-               */
+-              iap = FEC_FLASHMAC;
+-              if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+-                  (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+-                      iap = fec_mac_default;
+-              if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+-                  (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+-                      iap = fec_mac_default;
+-      } else {
+-              *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
+-              *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
+-              iap = &tmpaddr[0];
++      if (cpu_is_mx27_rev(CHIP_REV_2_0) > 0) {
++              fec_mac_base = FEC_IIM_BASE + MXC_IIMMAC;
+       }
+-      memcpy(dev->dev_addr, iap, ETH_ALEN);
+-
+-      /* Adjust MAC if using default MAC address */
+-      if (iap == fec_mac_default)
+-              dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
++      DBG(0, "%s: Reading MAC address from %08lx\n", __FUNCTION__, fec_mac_base);
++      for (i = 0; i < ETH_ALEN; i++) {
++              dev->dev_addr[ETH_ALEN - 1 - i] = __raw_readb(fec_mac_base + i * 4);
++      }
++      //memcpy(dev->dev_addr, default_mac, ETH_ALEN);
++#endif
+ }
+-static void __inline__ fec_enable_phy_intr(void)
++#ifdef CONFIG_PHYLIB
++static void __inline__ fec_enable_phy_intr(struct fec_enet_private *fep)
+ {
+ }
+-
+-static void __inline__ fec_disable_phy_intr(void)
++static void __inline__ fec_disable_phy_intr(struct fec_enet_private *fep)
+ {
+ }
+-
+-static void __inline__ fec_phy_ack_intr(void)
++static void __inline__ fec_phy_ack_intr(struct fec_enet_private *fep)
+ {
+ }
+-
+-static void __inline__ fec_localhw_setup(void)
++#else
++static void __inline__ fec_enable_phy_intr(struct fec_enet_private *fep)
+ {
+-}
+-
+-/*
+- *    Do not need to make region uncached on 5272.
+- */
+-static void __inline__ fec_uncache(unsigned long addr)
+-{
+-}
+-
+-/* ------------------------------------------------------------------------- */
+-
+-#elif defined(CONFIG_M520x)
+-
+-/*
+- *    Code specific to Coldfire 520x
+- */
+-static void __inline__ fec_request_intrs(struct net_device *dev)
+-{
+-      struct fec_enet_private *fep;
+-      int b;
+-      static const struct idesc {
+-              char *name;
+-              unsigned short irq;
+-      } *idp, id[] = {
+-              { "fec(TXF)", 23 },
+-              { "fec(RXF)", 27 },
+-              { "fec(MII)", 29 },
+-              { NULL },
+-      };
+-
+-      fep = netdev_priv(dev);
+-      b = 64 + 13;
+-
+-      /* Setup interrupt handlers. */
+-      for (idp = id; idp->name; idp++) {
+-              if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name,dev) != 0)
+-                      printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
+-      }
+-
+-      /* Unmask interrupts at ColdFire interrupt controller */
+-      {
+-              volatile unsigned char  *icrp;
+-              volatile unsigned long  *imrp;
+-
+-              icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
+-                      MCFINTC_ICR0);
+-              for (b = 36; (b < 49); b++)
+-                      icrp[b] = 0x04;
+-              imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 +
+-                      MCFINTC_IMRH);
+-              *imrp &= ~0x0001FFF0;
++      if (!fep->phy_int_enabled) {
++              fep->phy_int_enabled = 1;
++              enable_irq(fep->mii_irq);
+       }
+-      *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FEC) |= 0xf0;
+-      *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C) |= 0x0f;
+ }
+-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
++static void __inline__ fec_disable_phy_intr(struct fec_enet_private *fep)
+ {
+-      volatile fec_t *fecp;
+-
+-      fecp = fep->hwp;
+-      fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
+-      fecp->fec_x_cntrl = 0x00;
+-
+-      /*
+-       * Set MII speed to 2.5 MHz
+-       * See 5282 manual section 17.5.4.7: MSCR
+-       */
+-      fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
+-      fecp->fec_mii_speed = fep->phy_speed;
+-
+-      fec_restart(dev, 0);
+-}
+-
+-static void __inline__ fec_get_mac(struct net_device *dev)
+-{
+-      struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile fec_t *fecp;
+-      unsigned char *iap, tmpaddr[ETH_ALEN];
+-
+-      fecp = fep->hwp;
+-
+-      if (FEC_FLASHMAC) {
+-              /*
+-               * Get MAC address from FLASH.
+-               * If it is all 1's or 0's, use the default.
+-               */
+-              iap = FEC_FLASHMAC;
+-              if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+-                 (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+-                      iap = fec_mac_default;
+-              if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+-                 (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+-                      iap = fec_mac_default;
+-      } else {
+-              *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
+-              *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
+-              iap = &tmpaddr[0];
++      if (fep->phy_int_enabled) {
++              disable_irq(fep->mii_irq);
++              fep->phy_int_enabled = 0;
+       }
+-
+-      memcpy(dev->dev_addr, iap, ETH_ALEN);
+-
+-      /* Adjust MAC if using default MAC address */
+-      if (iap == fec_mac_default)
+-              dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
+-}
+-
+-static void __inline__ fec_enable_phy_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_disable_phy_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_phy_ack_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_localhw_setup(void)
+-{
+ }
+-static void __inline__ fec_uncache(unsigned long addr)
++static void __inline__ fec_phy_ack_intr(struct fec_enet_private *fep)
+ {
+-}
+-
+-/* ------------------------------------------------------------------------- */
+-
+-#elif defined(CONFIG_M532x)
+-/*
+- * Code specific for M532x
+- */
+-static void __inline__ fec_request_intrs(struct net_device *dev)
+-{
+-      struct fec_enet_private *fep;
+-      int b;
+-      static const struct idesc {
+-              char *name;
+-              unsigned short irq;
+-      } *idp, id[] = {
+-          { "fec(TXF)", 36 },
+-          { "fec(RXF)", 40 },
+-          { "fec(MII)", 42 },
+-          { NULL },
+-      };
+-
+-      fep = netdev_priv(dev);
+-      b = (fep->index) ? 128 : 64;
+-
+-      /* Setup interrupt handlers. */
+-      for (idp = id; idp->name; idp++) {
+-              if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name,dev) != 0)
+-                      printk("FEC: Could not allocate %s IRQ(%d)!\n",
+-                              idp->name, b+idp->irq);
+-      }
+-
+-      /* Unmask interrupts */
+-      MCF_INTC0_ICR36 = 0x2;
+-      MCF_INTC0_ICR37 = 0x2;
+-      MCF_INTC0_ICR38 = 0x2;
+-      MCF_INTC0_ICR39 = 0x2;
+-      MCF_INTC0_ICR40 = 0x2;
+-      MCF_INTC0_ICR41 = 0x2;
+-      MCF_INTC0_ICR42 = 0x2;
+-      MCF_INTC0_ICR43 = 0x2;
+-      MCF_INTC0_ICR44 = 0x2;
+-      MCF_INTC0_ICR45 = 0x2;
+-      MCF_INTC0_ICR46 = 0x2;
+-      MCF_INTC0_ICR47 = 0x2;
+-      MCF_INTC0_ICR48 = 0x2;
+-
+-      MCF_INTC0_IMRH &= ~(
+-              MCF_INTC_IMRH_INT_MASK36 |
+-              MCF_INTC_IMRH_INT_MASK37 |
+-              MCF_INTC_IMRH_INT_MASK38 |
+-              MCF_INTC_IMRH_INT_MASK39 |
+-              MCF_INTC_IMRH_INT_MASK40 |
+-              MCF_INTC_IMRH_INT_MASK41 |
+-              MCF_INTC_IMRH_INT_MASK42 |
+-              MCF_INTC_IMRH_INT_MASK43 |
+-              MCF_INTC_IMRH_INT_MASK44 |
+-              MCF_INTC_IMRH_INT_MASK45 |
+-              MCF_INTC_IMRH_INT_MASK46 |
+-              MCF_INTC_IMRH_INT_MASK47 |
+-              MCF_INTC_IMRH_INT_MASK48 );
+-
+-      /* Set up gpio outputs for MII lines */
+-      MCF_GPIO_PAR_FECI2C |= (0 |
+-              MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
+-              MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
+-      MCF_GPIO_PAR_FEC = (0 |
+-              MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
+-              MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
+-}
+-
+-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
+-{
+-      volatile fec_t *fecp;
+-
+-      fecp = fep->hwp;
+-      fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
+-      fecp->fec_x_cntrl = 0x00;
+-
+-      /*
+-       * Set MII speed to 2.5 MHz
+-       */
+-      fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
+-      fecp->fec_mii_speed = fep->phy_speed;
+-
+-      fec_restart(dev, 0);
+-}
+-
+-static void __inline__ fec_get_mac(struct net_device *dev)
+-{
+-      struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile fec_t *fecp;
+-      unsigned char *iap, tmpaddr[ETH_ALEN];
+-
+-      fecp = fep->hwp;
+-
+-      if (FEC_FLASHMAC) {
+-              /*
+-               * Get MAC address from FLASH.
+-               * If it is all 1's or 0's, use the default.
+-               */
+-              iap = FEC_FLASHMAC;
+-              if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
+-                  (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
+-                      iap = fec_mac_default;
+-              if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
+-                  (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
+-                      iap = fec_mac_default;
+-      } else {
+-              *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
+-              *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
+-              iap = &tmpaddr[0];
++      if (fep->phy_int_enabled) {
++              disable_irq(fep->mii_irq);
++              fep->phy_int_enabled = 0;
+       }
+-
+-      memcpy(dev->dev_addr, iap, ETH_ALEN);
+-
+-      /* Adjust MAC if using default MAC address */
+-      if (iap == fec_mac_default)
+-              dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
+ }
+-
+-static void __inline__ fec_enable_phy_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_disable_phy_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_phy_ack_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_localhw_setup(void)
+-{
+-}
+-
+-/*
+- *    Do not need to make region uncached on 532x.
+- */
+-static void __inline__ fec_uncache(unsigned long addr)
+-{
+-}
+-
+-/* ------------------------------------------------------------------------- */
+-
+-
+-#else
+-
+-/*
+- *    Code specific to the MPC860T setup.
+- */
+-static void __inline__ fec_request_intrs(struct net_device *dev)
+-{
+-      volatile immap_t *immap;
+-
+-      immap = (immap_t *)IMAP_ADDR;   /* pointer to internal registers */
+-
+-      if (request_8xxirq(FEC_INTERRUPT, fec_enet_interrupt, 0, "fec", dev) != 0)
+-              panic("Could not allocate FEC IRQ!");
+-}
+-
+-static void __inline__ fec_get_mac(struct net_device *dev)
+-{
+-      bd_t *bd;
+-
+-      bd = (bd_t *)__res;
+-      memcpy(dev->dev_addr, bd->bi_enetaddr, ETH_ALEN);
+-}
+-
+-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
+-{
+-      extern uint _get_IMMR(void);
+-      volatile immap_t *immap;
+-      volatile fec_t *fecp;
+-
+-      fecp = fep->hwp;
+-      immap = (immap_t *)IMAP_ADDR;   /* pointer to internal registers */
+-
+-      /* Configure all of port D for MII.
+-      */
+-      immap->im_ioport.iop_pdpar = 0x1fff;
+-
+-      /* Bits moved from Rev. D onward.
+-      */
+-      if ((_get_IMMR() & 0xffff) < 0x0501)
+-              immap->im_ioport.iop_pddir = 0x1c58;    /* Pre rev. D */
+-      else
+-              immap->im_ioport.iop_pddir = 0x1fff;    /* Rev. D and later */
+-
+-      /* Set MII speed to 2.5 MHz
+-      */
+-      fecp->fec_mii_speed = fep->phy_speed =
+-              ((bd->bi_busfreq * 1000000) / 2500000) & 0x7e;
+-}
+-
+-static void __inline__ fec_enable_phy_intr(void)
+-{
+-      volatile fec_t *fecp;
+-
+-      fecp = fep->hwp;
+-
+-      /* Enable MII command finished interrupt
+-      */
+-      fecp->fec_ivec = (FEC_INTERRUPT/2) << 29;
+-}
+-
+-static void __inline__ fec_disable_phy_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_phy_ack_intr(void)
+-{
+-}
+-
+-static void __inline__ fec_localhw_setup(void)
+-{
+-      volatile fec_t *fecp;
+-
+-      fecp = fep->hwp;
+-      fecp->fec_r_hash = PKT_MAXBUF_SIZE;
+-      /* Enable big endian and don't care about SDMA FC.
+-      */
+-      fecp->fec_fun_code = 0x78000000;
+-}
+-
+-static void __inline__ fec_uncache(unsigned long addr)
+-{
+-      pte_t *pte;
+-      pte = va_to_pte(mem_addr);
+-      pte_val(*pte) |= _PAGE_NO_CACHE;
+-      flush_tlb_page(init_mm.mmap, mem_addr);
+-}
+-
+ #endif
+ /* ------------------------------------------------------------------------- */
++#ifndef CONFIG_PHYLIB
+ static void mii_display_status(struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      volatile uint *s = &(fep->phy_status);
+-      if (!fep->link && !fep->old_link) {
++      if (!fep->linkstatus && !fep->old_linkstatus) {
+               /* Link is still down - don't print anything */
+               return;
+       }
+       printk("%s: status: ", dev->name);
+-      if (!fep->link) {
++      if (!fep->linkstatus) {
+               printk("link down");
+       } else {
+               printk("link up");
+-              switch(*s & PHY_STAT_SPMASK) {
++              switch(fep->phy_status & PHY_STAT_SPMASK) {
+               case PHY_STAT_100FDX: printk(", 100MBit Full Duplex"); break;
+               case PHY_STAT_100HDX: printk(", 100MBit Half Duplex"); break;
+               case PHY_STAT_10FDX: printk(", 10MBit Full Duplex"); break;
+@@ -1880,20 +1687,19 @@ static void mii_display_status(struct ne
+                       printk(", Unknown speed/duplex");
+               }
+-              if (*s & PHY_STAT_ANC)
++              if (fep->phy_status & PHY_STAT_ANC)
+                       printk(", auto-negotiation complete");
+       }
+-      if (*s & PHY_STAT_FAULT)
++      if (fep->phy_status & PHY_STAT_FAULT)
+               printk(", remote fault");
+       printk(".\n");
+ }
+-static void mii_display_config(struct work_struct *work)
++static void mii_display_config(struct work_struct *w)
+ {
+-      struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
+-      struct net_device *dev = fep->netdev;
++      struct fec_enet_private *fep = container_of(w, struct fec_enet_private, phy_task);
+       uint status = fep->phy_status;
+       /*
+@@ -1901,7 +1707,7 @@ static void mii_display_config(struct wo
+       ** the workqueue.  It is thus safe to allow to reuse it.
+       */
+       fep->mii_phy_task_queued = 0;
+-      printk("%s: config: auto-negotiation ", dev->name);
++      //printk("%s: config: auto-negotiation ", dev->name);
+       if (status & PHY_CONF_ANE)
+               printk("on");
+@@ -1926,11 +1732,21 @@ static void mii_display_config(struct wo
+       fep->sequence_done = 1;
+ }
++#endif
++
++#ifndef CONFIG_PHYLIB
++static inline void *priv_netdev(struct fec_enet_private  *fep)
++{
++      /* ugly hack, stolen from include linux/netdevice.h */
++      return (char *)fep - ((sizeof(struct net_device)
++                             + NETDEV_ALIGN_CONST)
++                            & ~NETDEV_ALIGN_CONST);
++}
+-static void mii_relink(struct work_struct *work)
++static void mii_relink(struct work_struct *w)
+ {
+-      struct fec_enet_private *fep = container_of(work, struct fec_enet_private, phy_task);
+-      struct net_device *dev = fep->netdev;
++      struct fec_enet_private *fep = container_of(w, struct fec_enet_private, phy_task);
++      struct net_device *dev = priv_netdev(fep);
+       int duplex;
+       /*
+@@ -1938,23 +1754,19 @@ static void mii_relink(struct work_struc
+       ** the workqueue.  It is thus safe to allow to reuse it.
+       */
+       fep->mii_phy_task_queued = 0;
+-      fep->link = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;
++      fep->linkstatus = (fep->phy_status & PHY_STAT_LINK) ? 1 : 0;
+       mii_display_status(dev);
+-      fep->old_link = fep->link;
++      fep->old_linkstatus = fep->linkstatus;
+-      if (fep->link) {
++      if (fep->linkstatus) {
+               duplex = 0;
+-              if (fep->phy_status
+-                  & (PHY_STAT_100FDX | PHY_STAT_10FDX))
++              if (fep->phy_status & (PHY_STAT_100FDX | PHY_STAT_10FDX)) {
+                       duplex = 1;
++              }
+               fec_restart(dev, duplex);
+-      } else
++      } else {
+               fec_stop(dev);
+-
+-#if 0
+-      enable_irq(fep->mii_irq);
+-#endif
+-
++      }
+ }
+ /* mii_queue_relink is called in interrupt context from mii_link_interrupt */
+@@ -2004,15 +1816,14 @@ phy_cmd_t const phy_cmd_config[] = {
+ static void
+ mii_discover_phy3(uint mii_reg, struct net_device *dev)
+ {
+-      struct fec_enet_private *fep;
++      struct fec_enet_private *fep = netdev_priv(dev);
+       int i;
+-      fep = netdev_priv(dev);
+       fep->phy_id |= (mii_reg & 0xffff);
+       printk("fec: PHY @ 0x%x, ID 0x%08x", fep->phy_addr, fep->phy_id);
+-      for(i = 0; phy_info[i]; i++) {
+-              if(phy_info[i]->id == (fep->phy_id >> 4))
++      for (i = 0; phy_info[i]; i++) {
++              if (phy_info[i]->id == (fep->phy_id >> 4))
+                       break;
+       }
+@@ -2031,13 +1842,9 @@ mii_discover_phy3(uint mii_reg, struct n
+ static void
+ mii_discover_phy(uint mii_reg, struct net_device *dev)
+ {
+-      struct fec_enet_private *fep;
+-      volatile fec_t *fecp;
++      struct fec_enet_private *fep = netdev_priv(dev);
+       uint phytype;
+-      fep = netdev_priv(dev);
+-      fecp = fep->hwp;
+-
+       if (fep->phy_addr < 32) {
+               if ((phytype = (mii_reg & 0xffff)) != 0xffff && phytype != 0) {
+@@ -2045,37 +1852,41 @@ mii_discover_phy(uint mii_reg, struct ne
+                       */
+                       fep->phy_id = phytype << 16;
+                       mii_queue(dev, mk_mii_read(MII_REG_PHYIR2),
+-                                                      mii_discover_phy3);
++                                mii_discover_phy3);
+               } else {
+                       fep->phy_addr++;
+                       mii_queue(dev, mk_mii_read(MII_REG_PHYIR1),
+-                                                      mii_discover_phy);
++                                mii_discover_phy);
+               }
+       } else {
+               printk("FEC: No PHY device found.\n");
+               /* Disable external MII interface */
+-              fecp->fec_mii_speed = fep->phy_speed = 0;
+-              fec_disable_phy_intr();
++              fep->phy_speed = 0;
++              fec_reg_write(fep, FEC_MSCR, fep->phy_speed);
++              fec_disable_phy_intr(fep);
+       }
+ }
++#endif
+-/* This interrupt occurs when the PHY detects a link change.
+-*/
+-#ifdef HAVE_mii_link_interrupt
++#ifndef CONFIG_PHYLIB
+ static irqreturn_t
+-mii_link_interrupt(int irq, void * dev_id)
++mii_link_interrupt(int irq, void *dev_id)
+ {
+-      struct  net_device *dev = dev_id;
++      struct net_device *dev = dev_id;
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      fec_phy_ack_intr();
++      DBG(0, "%s: \n", __FUNCTION__);
+-#if 0
+-      disable_irq(fep->mii_irq);  /* disable now, enable later */
+-#endif
++      fec_phy_ack_intr(fep);
+-      mii_do_cmd(dev, fep->phy->ack_int);
+-      mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */
++        /*
++       * Some board will trigger phy interrupt before phy enable.
++       * And at that moment , fep->phy is not initialized.
++       */
++      if (fep->phy) {
++              mii_do_cmd(dev, fep->phy->ack_int);
++              mii_do_cmd(dev, phy_cmd_relink);  /* restart and display status */
++      }
+       return IRQ_HANDLED;
+ }
+@@ -2084,16 +1895,29 @@ mii_link_interrupt(int irq, void * dev_i
+ static int
+ fec_enet_open(struct net_device *dev)
+ {
++      int ret = 0;
+       struct fec_enet_private *fep = netdev_priv(dev);
+       /* I should reset the ring buffers here, but I don't yet know
+        * a simple way to do that.
+        */
+-      fec_set_mac_address(dev);
++      DBG(0, "%s: \n", __FUNCTION__);
++      _fec_set_mac_address(dev);
+-      fep->sequence_done = 0;
+-      fep->link = 0;
++#ifdef CONFIG_PHYLIB
++      ret = fec_connect_phy(dev, fep);
++      if (ret != 0) {
++              DBG(0, "%s: Failed to connect to PHY: %d\n", __FUNCTION__, ret);
++              return ret;
++      }
++      phy_start(fep->phy);
++      fep->linkstatus = fep->phy->link;
++      fec_restart(dev, 0);
++      DBG(0, "%s: Link status is: %d\n", __FUNCTION__, fep->linkstatus);
++#else
++      fep->linkstatus = 0;
++      fep->sequence_done = 0;
+       if (fep->phy) {
+               mii_do_cmd(dev, fep->phy->ack_int);
+               mii_do_cmd(dev, fep->phy->config);
+@@ -2115,16 +1939,16 @@ fec_enet_open(struct net_device *dev)
+                * based on this device does not implement a PHY interrupt,
+                * so we are never notified of link change.
+                */
+-              fep->link = 1;
++              fep->linkstatus = 1;
+       } else {
+-              fep->link = 1; /* lets just try it and see */
++              fep->linkstatus = 1; /* lets just try it and see */
+               /* no phy,  go full duplex,  it's most likely a hub chip */
+               fec_restart(dev, 1);
+       }
+-
+-      netif_start_queue(dev);
++      fep->old_linkstatus = fep->linkstatus;
++#endif
+       fep->opened = 1;
+-      return 0;               /* Success */
++      return ret;
+ }
+ static int
+@@ -2132,15 +1956,30 @@ fec_enet_close(struct net_device *dev)
+ {
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      /* Don't know what to do yet.
+-      */
+-      fep->opened = 0;
+-      netif_stop_queue(dev);
+-      fec_stop(dev);
++#ifdef CONFIG_PHYLIB
++      if (fep->phy) {
++              DBG(0, "%s: Stopping PHY %p\n", __FUNCTION__, fep->phy);
++              phy_stop(fep->phy);
++              DBG(0, "%s: Disconnecting PHY %p\n", __FUNCTION__, fep->phy);
++              phy_disconnect(fep->phy);
++              fep->phy = NULL;
++      }
++#endif
++      fep->opened = 0;
++      if (fep->linkstatus) {
++              fec_stop(dev);
++      }
+       return 0;
+ }
++static struct net_device_stats *fec_enet_get_stats(struct net_device *dev)
++{
++      struct fec_enet_private *fep = netdev_priv(dev);
++
++      return &fep->stats;
++}
++
+ /* Set or clear the multicast filter for this adaptor.
+  * Skeleton taken from sunlance driver.
+  * The CPM Ethernet implementation allows Multicast as well as individual
+@@ -2156,37 +1995,32 @@ fec_enet_close(struct net_device *dev)
+ static void set_multicast_list(struct net_device *dev)
+ {
+-      struct fec_enet_private *fep;
+-      volatile fec_t *ep;
++      struct fec_enet_private *fep = netdev_priv(dev);
+       struct dev_mc_list *dmi;
+       unsigned int i, j, bit, data, crc;
+       unsigned char hash;
+-      fep = netdev_priv(dev);
+-      ep = fep->hwp;
+-
+-      if (dev->flags&IFF_PROMISC) {
+-              ep->fec_r_cntrl |= 0x0008;
++      if (dev->flags & IFF_PROMISC) {
++              fec_reg_write(fep, FEC_RCR, fec_reg_read(fep, FEC_RCR) | 0x0008);
+       } else {
+-              ep->fec_r_cntrl &= ~0x0008;
++              fec_reg_write(fep, FEC_RCR, fec_reg_read(fep, FEC_RCR) & ~0x0008);
+               if (dev->flags & IFF_ALLMULTI) {
+                       /* Catch all multicast addresses, so set the
+                        * filter to all 1's.
+                        */
+-                      ep->fec_grp_hash_table_high = 0xffffffff;
+-                      ep->fec_grp_hash_table_low = 0xffffffff;
++                      fec_reg_write(fep, FEC_IAUR, 0xffffffff);
++                      fec_reg_write(fep, FEC_IALR, 0xffffffff);
+               } else {
+                       /* Clear filter and add the addresses in hash register.
+                       */
+-                      ep->fec_grp_hash_table_high = 0;
+-                      ep->fec_grp_hash_table_low = 0;
++                      fec_reg_write(fep, FEC_IAUR, 0);
++                      fec_reg_write(fep, FEC_IALR, 0);
+                       dmi = dev->mc_list;
+-                      for (j = 0; j < dev->mc_count; j++, dmi = dmi->next)
+-                      {
++                      for (j = 0; j < dev->mc_count; j++, dmi = dmi->next) {
+                               /* Only support group multicast for now.
+                               */
+                               if (!(dmi->dmi_addr[0] & 1))
+@@ -2196,11 +2030,9 @@ static void set_multicast_list(struct ne
+                               */
+                               crc = 0xffffffff;
+-                              for (i = 0; i < dmi->dmi_addrlen; i++)
+-                              {
++                              for (i = 0; i < dmi->dmi_addrlen; i++) {
+                                       data = dmi->dmi_addr[i];
+-                                      for (bit = 0; bit < 8; bit++, data >>= 1)
+-                                      {
++                                      for (bit = 0; bit < 8; bit++, data >>= 1) {
+                                               crc = (crc >> 1) ^
+                                               (((crc ^ data) & 1) ? CRC32_POLY : 0);
+                                       }
+@@ -2212,9 +2044,13 @@ static void set_multicast_list(struct ne
+                               hash = (crc >> (32 - HASH_BITS)) & 0x3f;
+                               if (hash > 31)
+-                                      ep->fec_grp_hash_table_high |= 1 << (hash - 32);
++                                      fec_reg_write(fep, FEC_IAUR,
++                                                    fec_reg_read(fep, FEC_IAUR) |
++                                                    (1 << (hash - 32)));
+                               else
+-                                      ep->fec_grp_hash_table_low |= 1 << hash;
++                                      fec_reg_write(fep, FEC_IALR,
++                                                    fec_reg_read(fep, FEC_IALR) |
++                                                    (1 << hash));
+                       }
+               }
+       }
+@@ -2223,61 +2059,211 @@ static void set_multicast_list(struct ne
+ /* Set a MAC change in hardware.
+  */
+ static void
+-fec_set_mac_address(struct net_device *dev)
++_fec_set_mac_address(struct net_device *dev)
+ {
+-      volatile fec_t *fecp;
+-
+-      fecp = ((struct fec_enet_private *)netdev_priv(dev))->hwp;
++      struct fec_enet_private *fep = netdev_priv(dev);
+       /* Set station address. */
+-      fecp->fec_addr_low = dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
+-              (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24);
+-      fecp->fec_addr_high = (dev->dev_addr[5] << 16) |
+-              (dev->dev_addr[4] << 24);
++      fec_reg_write(fep, FEC_PALR, dev->dev_addr[3] | (dev->dev_addr[2] << 8) |
++              (dev->dev_addr[1] << 16) | (dev->dev_addr[0] << 24));
++      fec_reg_write(fep, FEC_PAUR, (dev->dev_addr[5] << 16) |
++              (dev->dev_addr[4] << 24));
++}
++
++static int
++fec_set_mac_address(struct net_device *dev, void *_addr)
++{
++      struct sockaddr *addr = _addr;
++      if (!is_valid_ether_addr((const char *)&addr->sa_data)) {
++              printk(KERN_WARNING "Bad ethernet address: %02x:%02x:%02x:%02x:%02x:%02x\n",
++                     addr->sa_data[0], addr->sa_data[1], addr->sa_data[2], addr->sa_data[3],
++                     addr->sa_data[4], addr->sa_data[5]);
++              return -EINVAL;
++      }
++      printk(KERN_DEBUG "Setting MAC address to %02x:%02x:%02x:%02x:%02x:%02x\n",
++             addr->sa_data[0], addr->sa_data[1], addr->sa_data[2], addr->sa_data[3],
++             addr->sa_data[4], addr->sa_data[5]);
++
++      memcpy(&dev->dev_addr, &addr->sa_data, ETH_ALEN);
++
++      _fec_set_mac_address(dev);
++
++      return 0;
+ }
+-/* Initialize the FEC Ethernet on 860T (or ColdFire 5272).
+- */
+- /*
+-  * XXX:  We need to clean up on failure exits here.
+-  */
+-int __init fec_enet_init(struct net_device *dev)
++static void fec_enet_free_buffers(struct fec_enet_private *fep)
+ {
++      cbd_t *bdp = fep->rx_bd_base;
++      int i;
++
++      DBG(0, "%s: Freeing TX bounce buffers %p\n", __FUNCTION__, fep->tx_bounce[0]);
++      kfree(fep->tx_bounce[0]);
++      memset(fep->tx_bounce, 0, TX_RING_SIZE * sizeof(void*));
++      for (i = 0; i < RX_RING_SIZE; i++, bdp++) {
++              if (fep->rx_skbuff[i] != NULL) {
++                      DBG(0, "%s: Freeing RX skb %p\n", __FUNCTION__, fep->rx_skbuff[i]);
++                      fec_enet_rxbuf_unmap(fep, bdp, FEC_ENET_RX_FRSIZE);
++                      kfree_skb(fep->rx_skbuff[i]);
++                      fep->rx_skbuff[i] = NULL;
++              }
++      }
++}
++
++#ifdef CONFIG_PHYLIB
++/* called by the generic PHY layer in interrupt context */
++static int fec_mii_read(struct mii_bus *bus, int phy_id, int regnum)
++{
++      int ret;
++      struct net_device *dev = bus->priv;
+       struct fec_enet_private *fep = netdev_priv(dev);
+-      unsigned long   mem_addr;
+-      volatile cbd_t  *bdp;
+-      cbd_t           *cbd_base;
+-      volatile fec_t  *fecp;
+-      int             i, j;
+-      static int      index = 0;
++      unsigned long regval = mk_mii_read(regnum) | phy_id << 23;
++      unsigned long flags;
++      static int regs[32] = { [0 ... ARRAY_SIZE(regs) - 1] = -1};
+-      /* Only allow us to be probed once. */
+-      if (index >= FEC_MAX_PORTS)
+-              return -ENXIO;
++      spin_lock_irqsave(&fep->lock, flags);
++      fep->mii_complete = 0;
++      fec_reg_write(fep, FEC_MMFR, regval);
++      spin_unlock_irqrestore(&fep->lock, flags);
++
++      while (!fep->mii_complete) {
++              cpu_relax();
++      }
++
++      ret = fec_reg_read(fep, FEC_MMFR) & 0xffff;
++      if (ret < 0) {
++              DBG(0, "%s: Failed to read PHY[%02x] reg %02x: %d\n", __FUNCTION__,
++                  phy_id, regnum, ret);
++      } else if (regs[regnum] != ret) {
++              DBG(1, "%s: Read %04x from PHY[%02x] reg %02x\n", __FUNCTION__,
++                  ret, phy_id, regnum);
++              regs[regnum] = ret;
++      }
++      return ret;
++}
+-      /* Allocate memory for buffer descriptors.
+-      */
+-      mem_addr = __get_free_page(GFP_KERNEL);
+-      if (mem_addr == 0) {
+-              printk("FEC: allocate descriptor memory failed?\n");
++static int fec_mii_write(struct mii_bus *bus, int phy_id, int regnum, u16 val)
++{
++      struct net_device *dev = bus->priv;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      unsigned long regval = mk_mii_write(regnum, val) | phy_id << 23;
++      unsigned long flags;
++
++      spin_lock_irqsave(&fep->lock, flags);
++      fep->mii_complete = 0;
++      fec_reg_write(fep, FEC_MMFR, regval);
++      spin_unlock_irqrestore(&fep->lock, flags);
++
++      while (!fep->mii_complete) {
++              cpu_relax();
++      }
++      DBG(1, "%s: Wrote %04x to PHY[%02x] reg %02x\n", __FUNCTION__, val, phy_id, regnum);
++      return 0;
++}
++
++static int fec_mii_reset(struct mii_bus *bus)
++{
++      return 0;
++}
++
++static int fec_init_phy(struct net_device *dev, struct fec_enet_private *fep)
++{
++      int ret;
++      int i;
++      struct mii_bus *mii;
++
++      mii = mdiobus_alloc();
++      if (mii == NULL) {
+               return -ENOMEM;
+       }
++      mii->name = "fec mii";
++      mii->read = fec_mii_read;
++      mii->write = fec_mii_write;
++      mii->reset = fec_mii_reset;
++      mii->priv = dev;
++      snprintf(mii->id, MII_BUS_ID_SIZE, "%x", 0);
++      mii->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
++      for (i = 0; i < PHY_MAX_ADDR; i++) {
++              mii->irq[i] = fep->mii_irq >= 0 ? fep->mii_irq : PHY_POLL;
++      }
++
++      ret = mdiobus_register(mii);
++      if (ret != 0) {
++              DBG(0, "%s: Failed to register MII bus: %d\n", __FUNCTION__, ret);
++              kfree(mii->irq);
++              mdiobus_free(mii);
++              return ret;
++      }
++      fep->phy_addr = -1;
++      DBG(0, "%s: MII bus registered\n", __FUNCTION__);
++      for (i = 0; i < PHY_MAX_ADDR; i++) {
++              if (mii->phy_map[i] != NULL) {
++                      fep->phy_addr = i;
++                      break;
++              }
++      }
++      if (fep->phy_addr == -1) {
++              DBG(0, "%s: No PHY found\n", __FUNCTION__);
++              return -ENODEV;
++      }
++      DBG(0, "%s: Using PHY at addr %02x\n", __FUNCTION__, fep->phy_addr);
++      fep->mii = mii;
+-      spin_lock_init(&fep->hw_lock);
+-      spin_lock_init(&fep->mii_lock);
++      return 0;
++}
+-      /* Create an Ethernet device instance.
+-      */
+-      fecp = (volatile fec_t *) fec_hw[index];
++static int fec_connect_phy(struct net_device *dev, struct fec_enet_private *fep)
++{
++      struct mii_bus *mii = fep->mii;
++
++      fep->phy = phy_connect(dev, mii->phy_map[fep->phy_addr]->dev.bus_id,
++                             fec_link_change, 0, mii->phy_map[fep->phy_addr]->interface);
++      if (IS_ERR(fep->phy)) {
++              int ret = PTR_ERR(fep->phy);
++              printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
++              fep->phy = NULL;
++              return ret;
++      }
++      DBG(0, "%s: Registered PHY %s[%02x] IRQ %d with %s\n", __FUNCTION__,
++          fep->phy->dev.bus_id, fep->phy_addr, fep->phy->irq, dev->name);
++
++      return 0;
++}
++#else
++static int fec_init_phy(struct net_device *dev, struct fec_enet_private *fep)
++{
++      /* Queue up command to detect the PHY and initialize the
++       * remainder of the interface.
++       */
++      fep->phy_id_done = 0;
++      fep->phy_addr = 0;
++      mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
++
++      return 0;
++}
++#endif
+-      fep->index = index;
+-      fep->hwp = fecp;
+-      fep->netdev = dev;
++/* Initialize the FEC Ethernet on 860T (or ColdFire 5272).
++ */
++ /*
++  * XXX:  We need to clean up on failure exits here.
++  */
++#define res_len(r)    ((r)->end - (r)->start + 1)
++
++int __devinit fec_enet_init(struct platform_device *pdev, struct net_device *dev)
++{
++      int ret;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      cbd_t *bdp;
++      struct sk_buff *pskb;
++      int i;
++      void *mem;
++
++      spin_lock_init(&fep->lock);
+       /* Whack a reset.  We should wait for this.
+       */
+-      fecp->fec_ecntrl = 1;
++      fec_reg_write(fep, FEC_ECR, 1);
+       udelay(10);
+       /* Set the Ethernet address.  If using multiple Enets on the 8xx,
+@@ -2288,41 +2274,36 @@ int __init fec_enet_init(struct net_devi
+        */
+       fec_get_mac(dev);
+-      cbd_base = (cbd_t *)mem_addr;
+-      /* XXX: missing check for allocation failure */
+-
+-      fec_uncache(mem_addr);
+-
+-      /* Set receive and transmit descriptor base.
+-      */
+-      fep->rx_bd_base = cbd_base;
+-      fep->tx_bd_base = cbd_base + RX_RING_SIZE;
+-
+       fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
+       fep->cur_rx = fep->rx_bd_base;
+       fep->skb_cur = fep->skb_dirty = 0;
+-      /* Initialize the receive buffer descriptors.
+-      */
+-      bdp = fep->rx_bd_base;
+-      for (i=0; i<FEC_ENET_RX_PAGES; i++) {
++      /* allocate memory for TX bounce buffers */
++      mem = kzalloc(TX_RING_SIZE * FEC_ENET_TX_FRSIZE, GFP_KERNEL);
++      if (mem == NULL) {
++              return -ENOMEM;
++      }
+-              /* Allocate a page.
+-              */
+-              mem_addr = __get_free_page(GFP_KERNEL);
+-              /* XXX: missing check for allocation failure */
++      fec_enet_cbd_get(fep);
+-              fec_uncache(mem_addr);
++      /* Initialize the transmit buffer descriptors.
++      */
++      bdp = fep->tx_bd_base;
++
++      DBG(0, "%s: Allocated %d byte of TX buffer memory @ %p\n", __FUNCTION__,
++          TX_RING_SIZE * FEC_ENET_TX_FRSIZE, mem);
++      for (i = 0; i < TX_RING_SIZE; i++) {
++              fep->tx_bounce[i] = mem;
++              DBG(0, "%s: TX bounce buffer[%d]=%p\n", __FUNCTION__, i, fep->tx_bounce[i]);
++              mem = (void *)((unsigned long)(mem + FEC_ENET_TX_FRSIZE));
+               /* Initialize the BD for every fragment in the page.
+               */
+-              for (j=0; j<FEC_ENET_RX_FRPPG; j++) {
+-                      bdp->cbd_sc = BD_ENET_RX_EMPTY;
+-                      bdp->cbd_bufaddr = __pa(mem_addr);
+-                      mem_addr += FEC_ENET_RX_FRSIZE;
+-                      bdp++;
+-              }
++              /* already zeroed by kzalloc */
++              //bdp->cbd_sc = 0;
++              bdp->cbd_bufaddr = ~0;
++              bdp++;
+       }
+       /* Set the last buffer to wrap.
+@@ -2330,80 +2311,77 @@ int __init fec_enet_init(struct net_devi
+       bdp--;
+       bdp->cbd_sc |= BD_SC_WRAP;
+-      /* ...and the same for transmmit.
++      /* ...and the same for receive.
+       */
+-      bdp = fep->tx_bd_base;
+-      for (i=0, j=FEC_ENET_TX_FRPPG; i<TX_RING_SIZE; i++) {
+-              if (j >= FEC_ENET_TX_FRPPG) {
+-                      mem_addr = __get_free_page(GFP_KERNEL);
+-                      j = 1;
+-              } else {
+-                      mem_addr += FEC_ENET_TX_FRSIZE;
+-                      j++;
++      bdp = fep->rx_bd_base;
++      for (i = 0; i < RX_RING_SIZE; i++, bdp++) {
++              pskb = __dev_alloc_skb(FEC_ENET_RX_FRSIZE, GFP_KERNEL);
++              if (pskb == NULL) {
++                      DBG(0, "%s: Failed to allocate RX skb; cleaning up\n", __FUNCTION__);
++                      fec_enet_free_buffers(fep);
++                      fec_enet_cbd_put(fep);
++                      return -ENOMEM;
+               }
+-              fep->tx_bounce[i] = (unsigned char *) mem_addr;
+-
+-              /* Initialize the BD for every fragment in the page.
+-              */
+-              bdp->cbd_sc = 0;
+-              bdp->cbd_bufaddr = 0;
+-              bdp++;
++              DBG(0, "%s: RX skb allocated @ %p\n", __FUNCTION__, pskb);
++              fep->rx_skbuff[i] = pskb;
++              pskb->data = FEC_ADDR_ALIGNMENT(pskb->data);
++              bdp->cbd_sc = BD_ENET_RX_EMPTY;
++              bdp->cbd_bufaddr = ~0;
++              fec_enet_rxbuf_map(fep, bdp, pskb->data, FEC_ENET_RX_FRSIZE);
+       }
+-
+       /* Set the last buffer to wrap.
+       */
+       bdp--;
+       bdp->cbd_sc |= BD_SC_WRAP;
++      fec_enet_cbd_put(fep);
+       /* Set receive and transmit descriptor base.
+       */
+-      fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base));
+-      fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base));
+-
++      fec_reg_write(fep, FEC_ERDSR, fep->cbd_phys_base);
++      fec_reg_write(fep, FEC_ETDSR, fep->cbd_phys_base + RX_RING_SIZE * sizeof(cbd_t));
++              
+       /* Install our interrupt handlers. This varies depending on
+        * the architecture.
+       */
+-      fec_request_intrs(dev);
+-
+-      fecp->fec_grp_hash_table_high = 0;
+-      fecp->fec_grp_hash_table_low = 0;
+-      fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
+-      fecp->fec_ecntrl = 2;
+-      fecp->fec_r_des_active = 0;
+-#ifndef CONFIG_M5272
+-      fecp->fec_hash_table_high = 0;
+-      fecp->fec_hash_table_low = 0;
+-#endif
+-
+-      dev->base_addr = (unsigned long)fecp;
+-
++      ret = fec_request_intrs(pdev, dev);
++      if (ret != 0) {
++              return ret;
++      }
++      /* Clear and enable interrupts */
++      fec_reg_write(fep, FEC_EIR, fec_reg_read(fep, FEC_EIR));
++      fec_reg_write(fep, FEC_EIMR, FEC_ENET_TXF | FEC_ENET_TXB |
++                    FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
++ 
++      fec_reg_write(fep, FEC_IAUR, 0);
++      fec_reg_write(fep, FEC_IALR, 0);
++      fec_reg_write(fep, FEC_EMRBR, PKT_MAXBLR_SIZE);
++      fec_reg_write(fep, FEC_ECR, 2);
++      fec_reg_write(fep, FEC_RDAR, DONT_CARE);
++                                                              
+       /* The FEC Ethernet specific entries in the device structure. */
+       dev->open = fec_enet_open;
+       dev->hard_start_xmit = fec_enet_start_xmit;
+       dev->tx_timeout = fec_timeout;
+       dev->watchdog_timeo = TX_TIMEOUT;
+       dev->stop = fec_enet_close;
++      dev->get_stats = fec_enet_get_stats;
+       dev->set_multicast_list = set_multicast_list;
++      dev->set_mac_address = fec_set_mac_address;
+-      for (i=0; i<NMII-1; i++)
+-              mii_cmds[i].mii_next = &mii_cmds[i+1];
++#ifndef CONFIG_PHYLIB
++      for (i = 1; i < NMII; i++) {
++              mii_cmds[i - 1].mii_next = &mii_cmds[i];
++      }
+       mii_free = mii_cmds;
+-
++#endif
+       /* setup MII interface */
+       fec_set_mii(dev, fep);
+-      /* Clear and enable interrupts */
+-      fecp->fec_ievent = 0xffc00000;
+-      fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
+-
+-      /* Queue up command to detect the PHY and initialize the
+-       * remainder of the interface.
+-       */
+-      fep->phy_id_done = 0;
+-      fep->phy_addr = 0;
+-      mii_queue(dev, mk_mii_read(MII_REG_PHYIR1), mii_discover_phy);
+-
+-      index++;
++      ret = fec_init_phy(dev, fep);
++      if (ret) {
++              DBG(0, "%s: Failed to initialize PHY: %d\n", __FUNCTION__, ret);
++              return ret;
++      }
+       return 0;
+ }
+@@ -2414,62 +2392,67 @@ int __init fec_enet_init(struct net_devi
+ static void
+ fec_restart(struct net_device *dev, int duplex)
+ {
+-      struct fec_enet_private *fep;
+-      volatile cbd_t *bdp;
+-      volatile fec_t *fecp;
++      struct fec_enet_private *fep = netdev_priv(dev);
++      cbd_t *bdp;
+       int i;
++      u32 rcr = OPT_FRAME_SIZE | RCR_MII_MODE;        /* MII enable */
++      u32 tcr = TCR_HBC;
+-      fep = netdev_priv(dev);
+-      fecp = fep->hwp;
+-
++      DBG(0, "%s: Restarting FEC in %s-duplex mode\n", __FUNCTION__,
++          duplex ? "full" : "half");
+       /* Whack a reset.  We should wait for this.
+       */
+-      fecp->fec_ecntrl = 1;
++      fec_reg_write(fep, FEC_ECR, 1);
+       udelay(10);
++      /* Enable interrupts we wish to service.
++       */
++      fec_reg_write(fep, FEC_EIMR, FEC_ENET_TXF | FEC_ENET_TXB |
++                    FEC_ENET_RXF | FEC_ENET_RXB | FEC_ENET_MII);
++
+       /* Clear any outstanding interrupt.
+-      */
+-      fecp->fec_ievent = 0xffc00000;
+-      fec_enable_phy_intr();
++       *
++       */
++      fec_reg_write(fep, FEC_EIR, FEC_ENET_MASK);
++      
++      fec_enable_phy_intr(fep);
+       /* Set station address.
+       */
+-      fec_set_mac_address(dev);
++      _fec_set_mac_address(dev);
+       /* Reset all multicast.
+       */
+-      fecp->fec_grp_hash_table_high = 0;
+-      fecp->fec_grp_hash_table_low = 0;
++      fec_reg_write(fep, FEC_IAUR, 0);
++      fec_reg_write(fep, FEC_IALR, 0);
+       /* Set maximum receive buffer size.
+       */
+-      fecp->fec_r_buff_size = PKT_MAXBLR_SIZE;
+-
+-      fec_localhw_setup();
++      fec_reg_write(fep, FEC_EMRBR, PKT_MAXBLR_SIZE);
+       /* Set receive and transmit descriptor base.
+       */
+-      fecp->fec_r_des_start = __pa((uint)(fep->rx_bd_base));
+-      fecp->fec_x_des_start = __pa((uint)(fep->tx_bd_base));
+-
++      fec_reg_write(fep, FEC_ERDSR, fep->cbd_phys_base);
++      fec_reg_write(fep, FEC_ETDSR, fep->cbd_phys_base + RX_RING_SIZE * sizeof(cbd_t));
++         
+       fep->dirty_tx = fep->cur_tx = fep->tx_bd_base;
+       fep->cur_rx = fep->rx_bd_base;
+       /* Reset SKB transmit buffers.
+       */
+       fep->skb_cur = fep->skb_dirty = 0;
+-      for (i=0; i<=TX_RING_MOD_MASK; i++) {
++      bdp = fep->tx_bd_base;
++      for (i = 0; i <= TX_RING_MOD_MASK; i++) {
+               if (fep->tx_skbuff[i] != NULL) {
+-                      dev_kfree_skb_any(fep->tx_skbuff[i]);
+-                      fep->tx_skbuff[i] = NULL;
++                      fec_free_skb(fep, bdp, &fep->tx_skbuff[i]);
++                      bdp++;
+               }
+       }
+       /* Initialize the receive buffer descriptors.
+       */
+       bdp = fep->rx_bd_base;
+-      for (i=0; i<RX_RING_SIZE; i++) {
+-
++      for (i = 0; i < RX_RING_SIZE; i++) {
+               /* Initialize the BD for every fragment in the page.
+               */
+               bdp->cbd_sc = BD_ENET_RX_EMPTY;
+@@ -2484,12 +2467,11 @@ fec_restart(struct net_device *dev, int 
+       /* ...and the same for transmmit.
+       */
+       bdp = fep->tx_bd_base;
+-      for (i=0; i<TX_RING_SIZE; i++) {
+-
++      for (i = 0; i < TX_RING_SIZE; i++) {
+               /* Initialize the BD for every fragment in the page.
+               */
+               bdp->cbd_sc = 0;
+-              bdp->cbd_bufaddr = 0;
++              bdp->cbd_bufaddr = ~0;
+               bdp++;
+       }
+@@ -2501,92 +2483,321 @@ fec_restart(struct net_device *dev, int 
+       /* Enable MII mode.
+       */
+       if (duplex) {
+-              fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;/* MII enable */
+-              fecp->fec_x_cntrl = 0x04;                 /* FD enable */
++              tcr |= TCR_FDEN;        /* FD enable */
+       } else {
+-              /* MII enable|No Rcv on Xmit */
+-              fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x06;
+-              fecp->fec_x_cntrl = 0x00;
++              rcr |= RCR_DRT;         /* No Rcv on Xmit */
+       }
++      fec_reg_write(fep, FEC_RCR, rcr);
++      fec_reg_write(fep, FEC_TCR, tcr);
+       fep->full_duplex = duplex;
+       /* Set MII speed.
+       */
+-      fecp->fec_mii_speed = fep->phy_speed;
++      fec_reg_write(fep, FEC_MSCR, fep->phy_speed);
+       /* And last, enable the transmit and receive processing.
+       */
+-      fecp->fec_ecntrl = 2;
+-      fecp->fec_r_des_active = 0;
+-
+-      /* Enable interrupts we wish to service.
+-      */
+-      fecp->fec_imask = (FEC_ENET_TXF | FEC_ENET_RXF | FEC_ENET_MII);
++      fec_reg_write(fep, FEC_ECR, 2);
++      fec_reg_write(fep, FEC_RDAR, DONT_CARE);
++      
++      DBG(0, "%s: Starting netif queue\n", __FUNCTION__);
++      netif_start_queue(dev);
+ }
+ static void
+ fec_stop(struct net_device *dev)
+ {
+-      volatile fec_t *fecp;
+-      struct fec_enet_private *fep;
++      struct fec_enet_private *fep = netdev_priv(dev);
+-      fep = netdev_priv(dev);
+-      fecp = fep->hwp;
++      DBG(0, "%s: Stopping netif queue\n", __FUNCTION__);
++      netif_stop_queue(dev);
+       /*
+       ** We cannot expect a graceful transmit stop without link !!!
+       */
+-      if (fep->link)
+-              {
+-              fecp->fec_x_cntrl = 0x01;       /* Graceful transmit stop */
++      if (fep->linkstatus) {
++              fec_reg_write(fep, FEC_TCR, 0x01);      /* Graceful transmit stop */
+               udelay(10);
+-              if (!(fecp->fec_ievent & FEC_ENET_GRA))
++              if (!(fec_reg_read(fep, FEC_EIR) & FEC_ENET_GRA))
+                       printk("fec_stop : Graceful transmit stop did not complete !\n");
+-              }
++      }
+       /* Whack a reset.  We should wait for this.
+       */
+-      fecp->fec_ecntrl = 1;
++      fec_reg_write(fep, FEC_ECR, 1);
+       udelay(10);
+-      /* Clear outstanding MII command interrupts.
++      /* Mask and clear outstanding MII command interrupts.
+       */
+-      fecp->fec_ievent = FEC_ENET_MII;
+-      fec_enable_phy_intr();
++      fec_reg_write(fep, FEC_EIMR, FEC_ENET_MII);
++      fec_reg_write(fep, FEC_EIR, FEC_ENET_MII);
++      fec_enable_phy_intr(fep);
+-      fecp->fec_imask = FEC_ENET_MII;
+-      fecp->fec_mii_speed = fep->phy_speed;
++      fec_reg_write(fep, FEC_MSCR, fep->phy_speed);
+ }
+-static int __init fec_enet_module_init(void)
++static int __devinit fec_enet_probe(struct platform_device *pdev)
+ {
++      int ret;
++      struct fec_enet_private *fep;
+       struct net_device *dev;
+-      int i, err;
+-      DECLARE_MAC_BUF(mac);
++      struct fec_enet_platform_data *pdata = pdev->dev.platform_data;
++      struct resource *res_mem1;
++      struct resource *res_mem2;
++
++      res_mem1 = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res_mem1 == NULL) {
++              return -ENODEV;
++      }
++
++      res_mem1 = request_mem_region(res_mem1->start, res_len(res_mem1), DRV_NAME);
++      if (res_mem1 == NULL) {
++              return -EBUSY;
++      }
++      res_mem2 = platform_get_resource(pdev, IORESOURCE_MEM, 1);
++      if (res_mem2 != NULL) {
++              res_mem2 = request_mem_region(res_mem2->start, res_len(res_mem2), DRV_NAME);
++              if (res_mem2 == NULL) {
++                      ret = -EBUSY;
++                      goto release1;
++              }
++      }
++
++      dev = alloc_etherdev(sizeof(struct fec_enet_private));
++      if (dev == NULL) {
++              ret = -ENOMEM;
++              goto release2;
++      }
++      platform_set_drvdata(pdev, dev);
++      fep = netdev_priv(dev);
++      fep->res_mem1 = res_mem1;
++      fep->res_mem2 = res_mem2;
++
++      fep->reg_base = ioremap(res_mem1->start, res_len(res_mem1));
++      if (fep->reg_base == NULL) {
++              printk("FEC: Mapping FEC registers failed\n");
++              ret = -ENOMEM;
++              goto free_netdev;
++      }
++      DBG(0, "%s: FEC registers @ %08lx mapped to %p\n", __FUNCTION__,
++          (unsigned long)res_mem1->start, fep->reg_base);
++
++      /* Allocate memory for buffer descriptors. */
++      fep->cbd_mem_base = dma_alloc_coherent(&pdev->dev, CBD_BUF_SIZE, &fep->cbd_phys_base,
++                                             GFP_KERNEL);
++      if (fep->cbd_mem_base == NULL) {
++              printk("FEC: allocate descriptor memory failed\n");
++              ret = -ENOMEM;
++              goto unmap;
++      }
++      DBG(0, "%s: Allocated %lu [(%u + %lu) * %d] byte for CBD buffer @ %p[%08lx]\n",
++          __FUNCTION__, CBD_BUF_SIZE, TX_RING_SIZE, RX_RING_SIZE, sizeof(cbd_t),
++          fep->cbd_mem_base, (unsigned long)fep->cbd_phys_base);
++
++      /* Set receive and transmit descriptor base.
++      */
++      fep->rx_bd_base = fep->cbd_mem_base;
++      fep->tx_bd_base = fep->rx_bd_base + RX_RING_SIZE;
+       printk("FEC ENET Version 0.2\n");
++      ret = platform_func(pdata->arch_init, pdev);
++      if (ret != 0) {
++              printk(KERN_ERR "%s: platform init failed: %d\n", __FUNCTION__, ret);
++              goto free_dma;
++      }
++ 
++      ret = fec_enet_init(pdev, dev);
++      if (ret != 0) {
++              goto fec_disable;
++      }
++
++      /* Enable most messages by default */
++      fep->msg_enable = (NETIF_MSG_IFUP << 1) - 1;
++      ret = register_netdev(dev);
++      if (ret != 0) {
++              /* XXX: missing cleanup here */
++              goto free_buffers;
++      }
++
++      printk(KERN_INFO "%s: ethernet %02x:%02x:%02x:%02x:%02x:%02x\n", dev->name,
++             dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2],
++             dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
+-      for (i = 0; (i < FEC_MAX_PORTS); i++) {
+-              dev = alloc_etherdev(sizeof(struct fec_enet_private));
+-              if (!dev)
+-                      return -ENOMEM;
+-              err = fec_enet_init(dev);
+-              if (err) {
+-                      free_netdev(dev);
+-                      continue;
+-              }
+-              if (register_netdev(dev) != 0) {
+-                      /* XXX: missing cleanup here */
+-                      free_netdev(dev);
+-                      return -EIO;
++      return 0;
++
++ free_buffers:
++      fec_enet_free_buffers(fep);
++
++ fec_disable:
++      platform_func(pdata->arch_exit, pdev);
++
++ free_dma:
++      dma_free_coherent(&pdev->dev, CBD_BUF_SIZE, fep->cbd_mem_base, fep->cbd_phys_base);
++
++ unmap:
++      iounmap(fep->reg_base);
++
++ free_netdev:
++      free_netdev(dev);
++
++ release2:
++      if (res_mem2 != NULL) {
++              release_resource(res_mem2);
++      }
++
++ release1:
++      release_resource(res_mem1);
++
++      return ret;
++}
++
++static int __devexit fec_enet_remove(struct platform_device *pdev)
++{
++      struct net_device *dev = platform_get_drvdata(pdev);
++      struct fec_enet_private *fep = netdev_priv(dev);
++
++      unregister_netdev(dev);
++      free_netdev(dev);
++
++#ifdef CONFIG_PHYLIB
++      if (fep->mii != NULL) {
++              kfree(fep->mii->irq);
++              mdiobus_unregister(fep->mii);
++      }
++      mdiobus_free(fep->mii);
++#endif
++      fec_release_intrs(dev);
++
++      DBG(0, "%s: Unmapping FEC registers %p\n", __FUNCTION__, fep->reg_base);
++      iounmap(fep->reg_base);
++
++      fec_enet_free_buffers(fep);
++
++      DBG(0, "%s: Freeing CBD buffer area %p[%08lx]\n", __FUNCTION__,
++          fep->cbd_mem_base, (unsigned long)fep->cbd_phys_base);
++      dma_free_coherent(&pdev->dev, CBD_BUF_SIZE, fep->cbd_mem_base, fep->cbd_phys_base);
++
++      release_resource(fep->res_mem1);
++      if (fep->res_mem2 != NULL) {
++              release_resource(fep->res_mem2);
++      }
++      return 0;
++}
++
++static void fec_enet_shutdown(struct platform_device *pdev)
++{
++      struct fec_enet_platform_data *pdata = pdev->dev.platform_data;
++
++      DBG(0, "%s: Shutting down FEC Hardware\n", __FUNCTION__);
++      platform_func(pdata->arch_exit, pdev);
++}
++
++#ifdef CONFIG_PM
++static int fec_enet_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      int ret;
++      struct fec_enet_platform_data *pdata = pdev->dev.platform_data;
++      struct net_device *ndev = platform_get_drvdata(pdev);
++      struct fec_enet_private *fep = netdev_priv(ndev);
++
++      if (netif_running(ndev)) {
++              DBG(0, "%s: Detaching netif\n", __FUNCTION__);
++              netif_device_detach(ndev);
++#ifdef CONFIG_PHYLIB
++              DBG(0, "%s: Disconnecting PHY %p\n", __FUNCTION__, fep->phy);
++              phy_disconnect(fep->phy);
++              fep->phy = NULL;
++#endif
++      }
++#ifndef CONFIG_PHYLIB
++      if (fep->phy_timer) {
++              ret = del_timer_sync(fep->phy_timer);
++              if (ret != 0) {
++                      DBG(0, "%s: Failed to delete PHY timer: %d\n", __FUNCTION__, ret);
++                      return ret;
+               }
++      }
++#endif
++      DBG(0, "%s: Shutting down FEC Hardware %d\n", __FUNCTION__,
++          netif_running(ndev));
++      ret = platform_func(pdata->suspend, pdev);
++      if (ret != 0 && netif_running(ndev)) {
++              DBG(0, "%s: Failed to suspend: %d\n", __FUNCTION__, ret);
++              /* Undo suspend */
++#ifdef CONFIG_PHYLIB
++              DBG(0, "%s: Reconnecting PHY\n", __FUNCTION__);
++              if (fec_connect_phy(ndev, fep) != 0) {
++                      DBG(0, "%s: Failed to connect to PHY\n", __FUNCTION__);
++                      return ret;
++              }
++              phy_start(fep->phy);
++#endif
++              fec_link_change(ndev);
++              netif_device_attach(ndev);
++      }
++      return ret;
++}
+-              printk("%s: ethernet %s\n",
+-                     dev->name, print_mac(mac, dev->dev_addr));
++static int fec_enet_resume(struct platform_device *pdev)
++{
++      int ret;
++      struct fec_enet_platform_data *pdata = pdev->dev.platform_data;
++      struct net_device *ndev = platform_get_drvdata(pdev);
++
++      DBG(0, "%s: Powering up FEC Hardware %d\n", __FUNCTION__,
++          netif_running(ndev));
++      ret = platform_func(pdata->resume, pdev);
++      if (ret != 0) {
++              DBG(0, "%s: Failed to resume: %d\n", __FUNCTION__, ret);
++              return ret;
++      }
++      if (netif_running(ndev)) {
++#ifdef CONFIG_PHYLIB
++              struct fec_enet_private *fep = netdev_priv(ndev);
++
++              DBG(0, "%s: Reconnecting PHY\n", __FUNCTION__);
++              ret = fec_connect_phy(ndev, fep);
++              if (ret != 0) {
++                      DBG(0, "%s: Failed to connect to PHY: %d\n", __FUNCTION__, ret);
++                      return ret;
++              }
++              phy_start(fep->phy);
++#endif
++              fec_link_change(ndev);
++              netif_device_attach(ndev);
+       }
+       return 0;
+ }
++#else
++#define fec_enet_suspend      NULL
++#define fec_enet_resume               NULL
++#endif
++
++static struct platform_driver fec_enet_driver = {
++      .driver = {
++              .name = DRV_NAME,
++      },
++      .probe = fec_enet_probe,
++      .remove = __devexit_p(fec_enet_remove),
++      .shutdown = fec_enet_shutdown,
++      .suspend = fec_enet_suspend,
++        .resume = fec_enet_resume,
++};
++
++static int __init fec_enet_module_init(void)
++{
++      int ret;
++      ret = platform_driver_register(&fec_enet_driver);
++
++      return ret;
++}
+ module_init(fec_enet_module_init);
++static void __exit fec_enet_module_cleanup(void)
++{
++      platform_driver_unregister(&fec_enet_driver);
++}
++module_exit(fec_enet_module_cleanup);
++
+ MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/net/fec.h linux-2.6.28-karo/drivers/net/fec.h
+--- linux-2.6.28/drivers/net/fec.h     2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/net/fec.h        2009-03-11 13:16:24.000000000 +0100
+@@ -13,13 +13,50 @@
+ #define       FEC_H
+ /****************************************************************************/
++/*
++ * dummy value to write into RDAR,TDAR. FEC hardware will scan the TX/RX
++ * descriptors in memory upon any write access to those registers.
++ * The actual value written to those registers does not matter.
++*/
++#define DONT_CARE             0
++#define RDAR_BUSY             (1 << 24)
++#define TDAR_BUSY             (1 << 24)
++
+ #if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
+-    defined(CONFIG_M520x) || defined(CONFIG_M532x)
++    defined(CONFIG_M520x) || defined(CONFIG_M532x) || defined(CONFIG_ARCH_MXC)
+ /*
+  *    Just figures, Motorola would have to change the offsets for
+  *    registers in the same peripheral device on different models
+  *    of the ColdFire!
+  */
++// relying on structure alignment for hardware register is just evil
++#ifndef GARBAGE
++#define FEC_EIR                       0x004
++#define FEC_EIMR              0x008
++#define       FEC_RDAR                0x010
++#define       FEC_TDAR                0x014
++#define       FEC_ECR                 0x024
++#define       FEC_MMFR                0x040
++#define       FEC_MSCR                0x044
++#define       FEC_MIBC                0x064
++#define       FEC_RCR                 0x084
++#define       FEC_TCR                 0x0c4
++#define       FEC_PALR                0x0e4
++#define       FEC_PAUR                0x0e8
++#define       FEC_OPD                 0x0ec
++#define       FEC_IAUR                0x118
++#define       FEC_IALR                0x11c
++#define       FEC_GAUR                0x120
++#define       FEC_GALR                0x124
++#define       FEC_TFWR                0x144
++#define       FEC_FRBR                0x14c
++#define       FEC_FRSR                0x150
++#define       FEC_ERDSR               0x180
++#define       FEC_ETDSR               0x184
++#define       FEC_EMRBR               0x188
++
++#else
++
+ typedef struct fec {
+       unsigned long   fec_reserved0;
+       unsigned long   fec_ievent;             /* Interrupt event reg */
+@@ -57,6 +94,7 @@ typedef struct fec {
+       unsigned long   fec_x_des_start;        /* Transmit descriptor ring */
+       unsigned long   fec_r_buff_size;        /* Maximum receive buff size */
+ } fec_t;
++#endif
+ #else
+@@ -88,8 +126,8 @@ typedef struct fec {
+       unsigned long   fec_reserved7[158];
+       unsigned long   fec_addr_low;           /* Low 32bits MAC address */
+       unsigned long   fec_addr_high;          /* High 16bits MAC address */
+-      unsigned long   fec_grp_hash_table_high;/* High 32bits hash table */
+-      unsigned long   fec_grp_hash_table_low; /* Low 32bits hash table */
++      unsigned long   fec_hash_table_high;    /* High 32bits hash table */
++      unsigned long   fec_hash_table_low;     /* Low 32bits hash table */
+       unsigned long   fec_r_des_start;        /* Receive descriptor ring */
+       unsigned long   fec_x_des_start;        /* Transmit descriptor ring */
+       unsigned long   fec_r_buff_size;        /* Maximum receive buff size */
+@@ -103,18 +141,28 @@ typedef struct fec {
+ /*
+  *    Define the buffer descriptor structure.
+  */
++/* Please see "Receive Buffer Descriptor Field Definitions" in Specification.
++ * It's LE.
++ */
++#ifdef CONFIG_ARCH_MXC
++typedef struct bufdesc {
++      unsigned short  cbd_datlen;             /* Data length */
++      unsigned short  cbd_sc;                 /* Control and status info */
++      dma_addr_t      cbd_bufaddr;            /* Buffer address as seen by FEC Hardware */
++} cbd_t;
++#else
+ typedef struct bufdesc {
+       unsigned short  cbd_sc;                 /* Control and status info */
+       unsigned short  cbd_datlen;             /* Data length */
+-      unsigned long   cbd_bufaddr;            /* Buffer address */
++      dma_addr_t      cbd_bufaddr;            /* Buffer address */
+ } cbd_t;
+-
++#endif
+ /*
+  *    The following definitions courtesy of commproc.h, which where
+  *    Copyright (c) 1997 Dan Malek (dmalek@jlc.net).
+  */
+-#define BD_SC_EMPTY     ((ushort)0x8000)        /* Recieve is empty */
++#define BD_SC_EMPTY     ((ushort)0x8000)        /* Receive is empty */
+ #define BD_SC_READY     ((ushort)0x8000)        /* Transmit is ready */
+ #define BD_SC_WRAP      ((ushort)0x2000)        /* Last buffer descriptor */
+ #define BD_SC_INTRPT    ((ushort)0x1000)        /* Interrupt on change */
+@@ -161,5 +209,22 @@ typedef struct bufdesc {
+ #define BD_ENET_TX_STATS        ((ushort)0x03ff)        /* All status bits */
++#define RCR_LOOP              (1 << 0)
++#define RCR_DRT                       (1 << 1)
++#define RCR_MII_MODE          (1 << 2)
++#define RCR_PROM              (1 << 3)
++#define RCR_BC_REJ            (1 << 4)
++#define RCR_FCE                       (1 << 5)
++#define RCR_MAX_FL_SHIFT      16
++#define RCR_MAX_FL_MASK               (0x7ff << (RCR_MAX_FL_SHIFT))
++#define RCR_MAX_FL_set(n)     (((n) << (RCR_MAX_FL_SHIFT)) & (RCR_MAX_FL_MASK))
++#define RCR_MAX_FL_get(n)     (((n) & (RCR_MAX_FL_MASK)) >> (RCR_MAX_FL_SHIFT))
++
++#define TCR_GTS                       (1 << 0)
++#define TCR_HBC                       (1 << 1)
++#define TCR_FDEN              (1 << 2)
++#define TCR_TFCPAUSE          (1 << 3)
++#define TCR_RFCPAUSE          (1 << 4)
++
+ /****************************************************************************/
+ #endif /* FEC_H */
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/power/Kconfig linux-2.6.28-karo/drivers/power/Kconfig
+--- linux-2.6.28/drivers/power/Kconfig 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/power/Kconfig    2009-03-11 13:16:24.000000000 +0100
+@@ -68,4 +68,16 @@ config BATTERY_BQ27x00
+       help
+         Say Y here to enable support for batteries with BQ27200(I2C) chip.
++config LP3972
++      tristate "National Semiconductor LP3972 Power Management Unit"
++      depends on EXPERIMENTAL
++      depends on I2C
++      default n
++      help
++        If you say yes here you get support for the National Semiconductor
++        Power Management Chip.
++
++        This driver can also be built as a module.  If so, the module
++        will be called lp3972.
++
+ endif # POWER_SUPPLY
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/power/Makefile linux-2.6.28-karo/drivers/power/Makefile
+--- linux-2.6.28/drivers/power/Makefile        2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/power/Makefile   2009-03-11 13:16:24.000000000 +0100
+@@ -23,3 +23,5 @@ obj-$(CONFIG_BATTERY_OLPC)   += olpc_batte
+ obj-$(CONFIG_BATTERY_TOSA)    += tosa_battery.o
+ obj-$(CONFIG_BATTERY_WM97XX)  += wm97xx_battery.o
+ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
++
++obj-$(CONFIG_LP3972)          += lp3972.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/power/lp3972.c linux-2.6.28-karo/drivers/power/lp3972.c
+--- linux-2.6.28/drivers/power/lp3972.c        1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/power/lp3972.c   2009-03-11 13:52:22.000000000 +0100
+@@ -0,0 +1,267 @@
++/*
++ * Copyright (C) 2008  Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * 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 Street, Fifth Floor, Boston, MA 02110-1301
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++
++/* Addresses to scan */
++static unsigned short normal_i2c[] = { 0x34,
++                                     I2C_CLIENT_END };
++
++I2C_CLIENT_INSMOD_1(lp3972);
++
++struct lp3972_data {
++      struct i2c_client client;
++};
++
++static int lp3972_attach_adapter(struct i2c_adapter *adapter);
++static int lp3972_detect(struct i2c_adapter *adapter, int address, int kind);
++static int lp3972_detach_client(struct i2c_client *client);
++static void lp3972_init_client(struct i2c_client *client);
++
++static struct i2c_driver lp3972_driver = {
++      .driver = {
++              .name   = "lp3972",
++      },
++      //.id           = I2C_DRIVERID_LP3972,
++      .attach_adapter = lp3972_attach_adapter,
++      .detach_client  = lp3972_detach_client,
++};
++
++struct lp3972_dev_attr {
++      struct device_attribute dev_attr;
++      u8 reg;
++      u8 val;
++};
++
++#define to_lp3972_attr(d)     container_of(d, struct lp3972_dev_attr, dev_attr)
++
++static ssize_t lp3972_get_val(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      int ret;
++      struct i2c_client *client = to_i2c_client(dev);
++      struct lp3972_dev_attr *lp3972_attr = to_lp3972_attr(attr);
++
++      ret = i2c_smbus_read_byte_data(client, lp3972_attr->reg);
++      if (ret < 0) {
++              return ret;
++      }
++      lp3972_attr->val = ret;
++      return sprintf(buf, "0x%02x\n", ret);
++}
++
++static ssize_t lp3972_set_val(struct device *dev, struct device_attribute *attr, const char *buf,
++                     size_t count)
++{
++      int ret;
++      struct i2c_client *client = to_i2c_client(dev);
++      struct lp3972_dev_attr *lp3972_attr = to_lp3972_attr(attr);
++      unsigned long val = simple_strtoul(buf, NULL, 0);
++
++      if (val > 0xff) {
++              printk(KERN_WARNING "value %ld is out of range\n", val);
++              return -EINVAL;
++      }
++      if (val != lp3972_attr->val) {
++              lp3972_attr->val = val;
++              ret = i2c_smbus_write_byte_data(client, lp3972_attr->reg, lp3972_attr->val);
++              if (ret < 0) {
++                      return ret;
++              }
++      }
++      return count;
++}
++
++#define LP3972_DEV_ATTR(_name, _mode, _reg, _read, _write)    \
++      struct lp3972_dev_attr lp3972_dev_attr_##_name = {      \
++              .dev_attr = __ATTR(_name,_mode,_read,_write),   \
++              .reg = _reg,                                    \
++      }
++
++static LP3972_DEV_ATTR(scr, S_IWUSR | S_IRUGO, 0x07, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(over1, S_IWUSR | S_IRUGO, 0x10, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(ovsr1, S_IRUGO, 0x11, lp3972_get_val, NULL);
++static LP3972_DEV_ATTR(over2, S_IWUSR | S_IRUGO, 0x12, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(ovsr2, S_IRUGO, 0x13, lp3972_get_val, NULL);
++static LP3972_DEV_ATTR(vcc1, S_IWUSR | S_IRUGO, 0x20, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(adtv1, S_IWUSR | S_IRUGO, 0x23, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(adtv2, S_IWUSR | S_IRUGO, 0x24, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(avrc, S_IWUSR | S_IRUGO, 0x25, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(cdtc1, S_IWUSR, 0x26, NULL, lp3972_set_val);
++static LP3972_DEV_ATTR(cdtc2, S_IWUSR, 0x27, NULL, lp3972_set_val);
++static LP3972_DEV_ATTR(sdtv1, S_IWUSR | S_IRUGO, 0x29, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(sdtv2, S_IWUSR | S_IRUGO, 0x2a, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(mdtv1, S_IWUSR | S_IRUGO, 0x32, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(mdtv2, S_IWUSR | S_IRUGO, 0x33, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(l12vcr, S_IWUSR | S_IRUGO, 0x39, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(l34vcr, S_IWUSR | S_IRUGO, 0x3a, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(scr1, S_IWUSR | S_IRUGO, 0x80, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(scr2, S_IWUSR | S_IRUGO, 0x81, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(oen3, S_IWUSR | S_IRUGO, 0x82, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(osr3, S_IWUSR | S_IRUGO, 0x83, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(loer, S_IWUSR | S_IRUGO, 0x84, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(b2tv, S_IWUSR | S_IRUGO, 0x85, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(b3tv, S_IWUSR | S_IRUGO, 0x86, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(c32rc, S_IWUSR | S_IRUGO, 0x87, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(isra, S_IRUGO, 0x88, lp3972_get_val, NULL);
++static LP3972_DEV_ATTR(bccr, S_IWUSR | S_IRUGO, 0x89, lp3972_get_val, lp3972_set_val);
++static LP3972_DEV_ATTR(ii1rr, S_IRUGO, 0x8e, lp3972_get_val, NULL);
++static LP3972_DEV_ATTR(ii2rr, S_IRUGO, 0x8f, lp3972_get_val, NULL);
++
++static struct attribute *lp3972_attributes[] = {
++      &lp3972_dev_attr_scr.dev_attr.attr,
++      &lp3972_dev_attr_over1.dev_attr.attr,
++      &lp3972_dev_attr_ovsr1.dev_attr.attr,
++      &lp3972_dev_attr_over2.dev_attr.attr,
++      &lp3972_dev_attr_ovsr2.dev_attr.attr,
++      &lp3972_dev_attr_vcc1.dev_attr.attr,
++      &lp3972_dev_attr_adtv1.dev_attr.attr,
++      &lp3972_dev_attr_adtv2.dev_attr.attr,
++      &lp3972_dev_attr_avrc.dev_attr.attr,
++      &lp3972_dev_attr_cdtc1.dev_attr.attr,
++      &lp3972_dev_attr_cdtc2.dev_attr.attr,
++      &lp3972_dev_attr_sdtv1.dev_attr.attr,
++      &lp3972_dev_attr_sdtv2.dev_attr.attr,
++      &lp3972_dev_attr_mdtv1.dev_attr.attr,
++      &lp3972_dev_attr_mdtv2.dev_attr.attr,
++      &lp3972_dev_attr_l12vcr.dev_attr.attr,
++      &lp3972_dev_attr_l34vcr.dev_attr.attr,
++      &lp3972_dev_attr_scr1.dev_attr.attr,
++      &lp3972_dev_attr_scr2.dev_attr.attr,
++      &lp3972_dev_attr_oen3.dev_attr.attr,
++      &lp3972_dev_attr_osr3.dev_attr.attr,
++      &lp3972_dev_attr_loer.dev_attr.attr,
++      &lp3972_dev_attr_b2tv.dev_attr.attr,
++      &lp3972_dev_attr_b3tv.dev_attr.attr,
++      &lp3972_dev_attr_c32rc.dev_attr.attr,
++      &lp3972_dev_attr_isra.dev_attr.attr,
++      &lp3972_dev_attr_bccr.dev_attr.attr,
++      &lp3972_dev_attr_ii1rr.dev_attr.attr,
++      &lp3972_dev_attr_ii2rr.dev_attr.attr,
++      NULL
++};
++
++static const struct attribute_group lp3972_attr_group = {
++      .attrs = lp3972_attributes,
++};
++
++/*
++ * Real code
++ */
++
++static int lp3972_attach_adapter(struct i2c_adapter *adapter)
++{
++      return i2c_probe(adapter, &addr_data, lp3972_detect);
++}
++
++/* This function is called by i2c_probe */
++static int lp3972_detect(struct i2c_adapter *adapter, int address, int kind)
++{
++      int ret;
++      struct i2c_client *new_client;
++      struct lp3972_data *data;
++      const char *client_name = "";
++
++      if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) {
++              return -ENOTSUPP;
++      }
++
++      data = kzalloc(sizeof(struct lp3972_data), GFP_KERNEL);
++      if (data == NULL) {
++              return -ENOMEM;
++      }
++
++      new_client = &data->client;
++      i2c_set_clientdata(new_client, data);
++      new_client->addr = address;
++      new_client->adapter = adapter;
++      new_client->driver = &lp3972_driver;
++      new_client->flags = 0;
++
++      /* Now, we would do the remaining detection. But the LP3972 is plainly
++         impossible to detect! Stupid chip. */
++
++      /* Determine the chip type */
++      if (kind <= 0) {
++              kind = lp3972;
++      }
++
++      client_name = "lp3972";
++
++      /* Fill in the remaining client fields and put it into the global list */
++      strlcpy(new_client->name, client_name, I2C_NAME_SIZE);
++
++      /* Tell the I2C layer a new client has arrived */
++      ret = i2c_attach_client(new_client);
++      if (ret != 0) {
++              goto free;
++      }
++      
++      /* Initialize the LP3972 chip */
++      lp3972_init_client(new_client);
++
++      /* Register sysfs hooks */
++      ret = sysfs_create_group(&new_client->dev.kobj, &lp3972_attr_group);
++      if (ret == 0) {
++              return ret;
++      }
++
++      i2c_detach_client(new_client);
++ free:
++      kfree(data);
++      return ret;
++}
++
++static int lp3972_detach_client(struct i2c_client *client)
++{
++      int ret;
++
++      sysfs_remove_group(&client->dev.kobj, &lp3972_attr_group);
++
++      ret = i2c_detach_client(client);
++      if (ret != 0) {
++              return ret;
++      }
++
++      kfree(i2c_get_clientdata(client));
++      return 0;
++}
++
++/* Called when we have found a new LP3972. */
++static void lp3972_init_client(struct i2c_client *client)
++{
++}
++
++static int __init lp3972_init(void)
++{
++      return i2c_add_driver(&lp3972_driver);
++}
++
++static void __exit lp3972_exit(void)
++{
++      i2c_del_driver(&lp3972_driver);
++}
++
++
++MODULE_AUTHOR("Lothar Wassmann <LW@KARO-electronics.de>");
++MODULE_DESCRIPTION("LP3972 I2C PMIC driver");
++MODULE_LICENSE("GPL v2");
++
++module_init(lp3972_init);
++module_exit(lp3972_exit);
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/rtc/Kconfig linux-2.6.28-karo/drivers/rtc/Kconfig
+--- linux-2.6.28/drivers/rtc/Kconfig   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/rtc/Kconfig      2009-03-11 13:16:24.000000000 +0100
+@@ -141,6 +141,24 @@ config RTC_DRV_DS1307
+         This driver can also be built as a module. If so, the module
+         will be called rtc-ds1307.
++config RTC_DRV_DS13XX
++      tristate "Dallas/Maxim DS13xx I2C RTC chips"
++      depends on RTC_CLASS && I2C
++      help
++        If you say yes here you get support for various compatible RTC
++        chips (often with battery backup) connected with I2C.  This driver
++        should handle DS1307, DS1337, DS1338, DS1339, DS1340, ST M41T00,
++        and probably other chips. Platform specific code may provide a
++        callback function to properly initialize the chip.
++
++        The first seven registers on these chips hold an RTC, and other
++        registers may add features such as NVRAM, a trickle charger for
++        the RTC/NVRAM backup power, and alarms.  This driver may not
++        expose all those available chip features.
++
++        This driver can also be built as a module. If so, the module
++        will be called rtc-ds13xx.
++
+ config RTC_DRV_DS1374
+       tristate "Dallas/Maxim DS1374"
+       depends on RTC_CLASS && I2C
+@@ -649,6 +667,13 @@ config RTC_DRV_RS5C313
+       help
+         If you say yes here you get support for the Ricoh RS5C313 RTC chips.
++config RTC_MXC
++      tristate "Freescale MXC Real Time Clock"
++      depends on ARCH_MXC
++      depends on RTC_CLASS
++      help
++        If you say yes here you get support for the Freescale i.MX RTC
++
+ config RTC_DRV_PARISC
+       tristate "PA-RISC firmware RTC support"
+       depends on PARISC
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/rtc/Makefile linux-2.6.28-karo/drivers/rtc/Makefile
+--- linux-2.6.28/drivers/rtc/Makefile  2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/rtc/Makefile     2009-03-11 13:16:24.000000000 +0100
+@@ -28,6 +28,7 @@ obj-$(CONFIG_RTC_DRV_DS1302) += rtc-ds13
+ obj-$(CONFIG_RTC_DRV_DS1305)  += rtc-ds1305.o
+ obj-$(CONFIG_RTC_DRV_DS1307)  += rtc-ds1307.o
+ obj-$(CONFIG_RTC_DRV_DS1374)  += rtc-ds1374.o
++obj-$(CONFIG_RTC_DRV_DS13XX)  += rtc-ds13xx.o
+ obj-$(CONFIG_RTC_DRV_DS1390)  += rtc-ds1390.o
+ obj-$(CONFIG_RTC_DRV_DS1511)  += rtc-ds1511.o
+ obj-$(CONFIG_RTC_DRV_DS1553)  += rtc-ds1553.o
+@@ -62,6 +63,7 @@ obj-$(CONFIG_RTC_DRV_RX8581) += rtc-rx85
+ obj-$(CONFIG_RTC_DRV_S35390A) += rtc-s35390a.o
+ obj-$(CONFIG_RTC_DRV_S3C)     += rtc-s3c.o
+ obj-$(CONFIG_RTC_DRV_SA1100)  += rtc-sa1100.o
++obj-$(CONFIG_RTC_MXC)         += rtc-mxc.o
+ obj-$(CONFIG_RTC_DRV_SH)      += rtc-sh.o
+ obj-$(CONFIG_RTC_DRV_STK17TA8)        += rtc-stk17ta8.o
+ obj-$(CONFIG_RTC_DRV_TEST)    += rtc-test.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/rtc/rtc-ds13xx.c linux-2.6.28-karo/drivers/rtc/rtc-ds13xx.c
+--- linux-2.6.28/drivers/rtc/rtc-ds13xx.c      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/rtc/rtc-ds13xx.c 2009-03-11 18:38:58.000000000 +0100
+@@ -0,0 +1,590 @@
++/*
++ * rtc-ds13xx.c - RTC driver for some mostly-compatible I2C chips.
++ *
++ *  Copyright (C) 2005 James Chapman (ds1337 core)
++ *  Copyright (C) 2006 David Brownell
++ *  Copyright (C) 2007 Lothar Wassmann <LW@karo-electronics.de>
++ *  rewritten to support initialization via platform_device
++ *
++ * 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/init.h>
++#include <linux/slab.h>
++#include <linux/platform_device.h>
++#include <linux/i2c.h>
++#include <linux/rtc.h>
++#include <linux/bcd.h>
++#include <linux/rtc/ds13xx.h>
++
++
++/* We can't determine type by probing, but if we expect pre-Linux code
++ * to have set the chip up as a clock (turning on the oscillator and
++ * setting the date and time), Linux can ignore the non-clock features.
++ * That's a natural job for a factory or repair bench.
++ *
++ * If the I2C "force" mechanism is used, we assume the chip is a ds1337.
++ * (Much better would be board-specific tables of I2C devices, along with
++ * the platform_data drivers would use to sort such issues out.)
++ */
++
++static unsigned short normal_i2c[] = { 0x68, I2C_CLIENT_END };
++
++I2C_CLIENT_INSMOD;
++
++// the RTC epoch starts at 2000
++#define CENTURY       2000
++
++/* RTC registers don't differ much, except for the century flag */
++#define DS13XX_REG_SECS               0x00    /* 00-59 */
++#     define DS1307_BIT_CH            (1 << 7)
++#define DS13XX_REG_MIN                0x01    /* 00-59 */
++#define DS13XX_REG_HOUR               0x02    /* 00-23, or 1-12{am,pm} */
++#     define DS1340_BIT_CENTURY_EN    (1 << 7)        /* in REG_HOUR */
++#     define DS1340_BIT_CENTURY       (1 << 6)        /* in REG_HOUR */
++#define DS13XX_REG_WDAY               0x03    /* 01-07 */
++#define DS13XX_REG_MDAY               0x04    /* 01-31 */
++#define DS13XX_REG_MONTH      0x05    /* 01-12 */
++#     define DS133X_BIT_CENTURY       (1 << 7)        /* in REG_MONTH */
++#define DS13XX_REG_YEAR               0x06    /* 00-99 */
++
++/* Other registers (control, status, alarms, trickle charge, NVRAM, etc)
++ * start at 7, and they differ a lot. Only control and status matter for RTC;
++ * be careful using them.
++ */
++#define DS1307_REG_CONTROL    0x07
++#define DS1339_REG_AL1SEC     0x07
++#define DS1339_REG_AL1MIN     0x08
++#define DS1339_REG_AL1HRS     0x09
++#define DS1339_REG_AL1DAY     0x0a
++#define DS1339_REG_AL2MIN     0x0b
++#define DS1339_REG_AL2HRS     0x0c
++#define DS1339_REG_AL2DAY     0x0d
++#     define DS1339_BIT_ALMSK         (1 << 7)
++#     define DS1339_BIT_DYDT          (1 << 6)
++#define DS133X_REG_CONTROL    0x0e
++#     define DS1338_BIT_OSF           (1 << 5)
++#     define DS133X_BIT_nEOSC         (1 << 7)
++#     define DS133X_BIT_A1IE          (1 << 0)
++#     define DS133X_BIT_A2IE          (1 << 1)
++#define DS133X_REG_STATUS     0x0f
++#     define DS133X_BIT_OSF           (1 << 7)
++#     define DS133X_BIT_A1I           (1 << 0)
++#     define DS133X_BIT_A2I           (1 << 1)
++#define DS1339_REG_TRC                0x10
++#     define DS1339_TRC_MAGIC         0xa0
++#define DS1340_REG_STATUS     0x09
++#     define DS1340_BIT_OSF           (1 << 7)
++
++struct ds13xx {
++      u8                      reg_addr;
++      u8                      regs[8];
++      enum ds13xx_type        type;
++      struct i2c_msg          msg[2];
++      struct i2c_client       client;
++      struct rtc_device       *rtc;
++      int                     valid_time;
++};
++
++static const struct i2c_device_id ds13xx_id[] = {
++      { "ds1307", ds_1307 },
++      { "ds1337", ds_1337 },
++      { "ds1338", ds_1338 },
++      { "ds1339", ds_1339 },
++      { "ds1340", ds_1340 },
++      { "m41t00", m41t00 },
++      { }
++};
++MODULE_DEVICE_TABLE(i2c, ds13xx_id);
++
++static inline int ds13xx_write_reg(struct i2c_client *client, u8 regno, u8 val)
++{
++      dev_dbg(&client->dev, "Writing %02x to reg %02x\n", val, regno);
++      return i2c_smbus_write_byte_data(client, regno, val);
++}
++
++static inline int ds13xx_read_reg(struct i2c_client *client, u8 regno)
++{
++      int ret;
++
++      ret = i2c_smbus_read_byte_data(client, regno);
++
++      return ret;
++}
++
++static int __devinit ds13xx_i2c_init(struct platform_device *pdev, struct i2c_client *client)
++{
++      int ret = 0;
++      struct ds13xx_platform_data *pdata = pdev->dev.platform_data;
++      struct ds13xx *ds13xx = i2c_get_clientdata(client);
++
++      if (pdata != NULL && pdata->type > 0) {
++              ds13xx->type = pdata->type;
++              switch (ds13xx->type) {
++              case unknown:
++                      strlcpy(client->name, "unknown", I2C_NAME_SIZE);
++                      break;
++              case ds_1307:
++                      strlcpy(client->name, "ds1307", I2C_NAME_SIZE);
++                      break;
++              case ds_1337:
++                      strlcpy(client->name, "ds1337", I2C_NAME_SIZE);
++                      break;
++              case ds_1339:
++                      strlcpy(client->name, "ds1339", I2C_NAME_SIZE);
++                      break;
++              case ds_1340:
++                      strlcpy(client->name, "ds1340", I2C_NAME_SIZE);
++                      break;
++              default:
++                      return -ENODEV;
++              }
++      } else {
++              dev_dbg(&client->dev, "No platform_data\n");
++      }
++      return ret;
++}
++
++static int __devinit ds13xx_rtc_init(struct ds13xx_platform_data *pdata, struct i2c_client *client)
++{
++      int ret = 0;
++      struct ds13xx *ds13xx = i2c_get_clientdata(client);
++      int oscstart = 0;
++
++      ds13xx->valid_time = 1;
++      dev_dbg(&client->dev, "Inititialzing RTC %s\n", client->name);
++      switch (ds13xx->type) {
++      case ds_1307:
++      case m41t00:
++              if (ds13xx->regs[DS13XX_REG_SECS] & DS1307_BIT_CH) {
++                      oscstart = 1;
++                      ds13xx_write_reg(client, DS13XX_REG_SECS, 0);
++              }
++              if (pdata && pdata->ctrl >= 0) {
++                      ds13xx_write_reg(client, DS1307_REG_CONTROL, pdata->ctrl);
++              }
++              break;
++      case ds_1337:
++              ret = ds13xx_read_reg(client, DS133X_REG_CONTROL);
++              if (ret > 0 && ret & DS133X_BIT_nEOSC) {
++                      oscstart = 1;
++              }
++              if (pdata && pdata->ctrl >= 0) {
++                      ds13xx_write_reg(client, DS133X_REG_CONTROL, pdata->ctrl);
++              }
++              break;
++      case ds_1338:
++              /* clock halted?  turn it on, so clock can tick. */
++              if (ds13xx->regs[DS13XX_REG_SECS] & DS1307_BIT_CH) {
++                      ds13xx_write_reg(client, DS13XX_REG_SECS, 0);
++              }
++              /* oscillator fault?  clear flag, and warn */
++              if (ds13xx->regs[DS1307_REG_CONTROL] & DS1338_BIT_OSF) {
++                      ret = ds13xx_write_reg(client, DS1307_REG_CONTROL,
++                                             ds13xx->regs[DS1307_REG_CONTROL] &
++                                             ~DS1338_BIT_OSF);
++                      ds13xx->valid_time = 0;
++              }
++              break;
++      case ds_1339:
++              ret = ds13xx_read_reg(client, DS133X_REG_CONTROL);
++              if (ret < 0) {
++                      dev_warn(&client->dev, "failed to read DS1339 control register: %d\n",
++                               ret);
++                      break;
++              } else if (ret & DS133X_BIT_nEOSC) {
++                      oscstart = 1;
++              }
++              if (pdata && pdata->ctrl >= 0) {
++                      ds13xx_write_reg(client, DS133X_REG_CONTROL, pdata->ctrl);
++              }
++              if (pdata && pdata->trc >= 0) {
++                      ds13xx_write_reg(client, DS1339_REG_TRC, pdata->trc);
++              }
++              ret = ds13xx_read_reg(&ds13xx->client, DS133X_REG_STATUS);
++              if (ret < 0) {
++                      dev_warn(&client->dev, "failed to read DS1339 status: %d\n",
++                               ret);
++                      break;
++              } else {
++                      dev_dbg(&client->dev, "DS1339 status: %02x\n", ret);
++              }
++              if (ret > 0 && ret & DS133X_BIT_OSF) {
++                      ds13xx->valid_time = 0;
++              }
++              break;
++      case ds_1340:
++              if (ds13xx->regs[DS13XX_REG_SECS] & DS133X_BIT_nEOSC) {
++                      oscstart = 1;
++                      ds13xx_write_reg(client, DS13XX_REG_SECS, 0);
++              }
++              if (pdata && pdata->ctrl >= 0) {
++                      ds13xx_write_reg(client, DS133X_REG_CONTROL, pdata->ctrl);
++              }
++              ret = ds13xx_read_reg(&ds13xx->client, DS1340_REG_STATUS);
++              if (ret > 0 && ret & DS1340_BIT_OSF) {
++                      ds13xx->valid_time = 0;
++              }
++              break;
++      default:
++              dev_warn(&client->dev, "Unknown DS13xx chip type: %d\n", ds13xx->type);
++              break;
++      }
++      if (!ds13xx->valid_time) {
++              dev_warn(&client->dev, "%s oscillator failure; RTC time must be set!\n",
++                       client->name);
++      } else if (oscstart) {
++              ds13xx->valid_time = 0;
++              dev_warn(&client->dev, "%s oscillator has been started; RTC time must be set!\n",
++                       client->name);
++      }
++
++      return ret < 0 ? ret : 0;
++}
++
++static int ds13xx_get_time(struct device *dev, struct rtc_time *t)
++{
++      int ret;
++      struct ds13xx *ds13xx = dev_get_drvdata(dev);
++      static int once = 1;
++
++      if (!ds13xx->valid_time) {
++              if (once) {
++                      dev_warn(dev, "RTC Oscillator failure; RTC time must be set!\n");
++                      once = 0;
++              }
++      }
++
++      /* read the RTC registers all at once */
++      ds13xx->msg[1].flags = I2C_M_RD;
++      ds13xx->msg[1].len = 7;
++
++      ret = i2c_transfer(ds13xx->client.adapter, ds13xx->msg, 2);
++      if (ret != 2) {
++              dev_err(dev, "%s error %d\n", "read", ret);
++              return ret < 0 ? ret : -EIO;
++      }
++
++      dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
++                      "read",
++                      ds13xx->regs[0], ds13xx->regs[1],
++                      ds13xx->regs[2], ds13xx->regs[3],
++                      ds13xx->regs[4], ds13xx->regs[5],
++                      ds13xx->regs[6]);
++
++      t->tm_sec = bcd2bin(ds13xx->regs[DS13XX_REG_SECS] & 0x7f);
++      t->tm_min = bcd2bin(ds13xx->regs[DS13XX_REG_MIN] & 0x7f);
++      ret = ds13xx->regs[DS13XX_REG_HOUR] & 0x3f;
++      t->tm_hour = bcd2bin(ret);
++      t->tm_wday = bcd2bin(ds13xx->regs[DS13XX_REG_WDAY] & 0x07) - 1;
++      t->tm_mday = bcd2bin(ds13xx->regs[DS13XX_REG_MDAY] & 0x3f);
++      ret = ds13xx->regs[DS13XX_REG_MONTH] & 0x1f;
++      t->tm_mon = bcd2bin(ret) - 1;
++
++      t->tm_year = bcd2bin(ds13xx->regs[DS13XX_REG_YEAR]) + 100;
++      switch (ds13xx->type) {
++      case ds_1339:
++              if (ds13xx->regs[DS13XX_REG_MONTH] & DS133X_BIT_CENTURY) {
++                      t->tm_year += 100;
++              }
++      default:
++              break;
++      }
++      dev_dbg(dev, "%s secs=%d, mins=%d, "
++              "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
++              "read", t->tm_sec, t->tm_min,
++              t->tm_hour, t->tm_mday,
++              t->tm_mon, t->tm_year - 100 + CENTURY, t->tm_wday);
++
++      return 0;
++}
++
++static int ds13xx_set_time(struct device *dev, struct rtc_time *t)
++{
++      int ret;
++      struct ds13xx *ds13xx = dev_get_drvdata(dev);
++      u8 *buf = ds13xx->regs;
++
++      dev_dbg(dev, "%s secs=%d, mins=%d, "
++              "hours=%d, mday=%d, mon=%d, year=%d, wday=%d\n",
++              "write", t->tm_sec, t->tm_min,
++              t->tm_hour, t->tm_mday,
++              t->tm_mon, t->tm_year - 100 + CENTURY, t->tm_wday);
++
++      *buf++ = 0;             /* first register addr */
++      buf[DS13XX_REG_SECS] = bin2bcd(t->tm_sec);
++      buf[DS13XX_REG_MIN] = bin2bcd(t->tm_min);
++      buf[DS13XX_REG_HOUR] = bin2bcd(t->tm_hour);
++      buf[DS13XX_REG_WDAY] = bin2bcd(t->tm_wday + 1);
++      buf[DS13XX_REG_MDAY] = bin2bcd(t->tm_mday);
++      buf[DS13XX_REG_MONTH] = bin2bcd(t->tm_mon + 1);
++
++      ret = t->tm_year - 100;
++      buf[DS13XX_REG_YEAR] = bin2bcd(ret);
++
++      if (!ds13xx->valid_time) {
++              switch (ds13xx->type) {
++              case ds_1307:
++                      break;
++              case ds_1337:
++              case ds_1339:
++                      dev_dbg(dev, "Clearing OSF\n");
++                      // clear oscillator fail flag, in case it was set
++                      ret = ds13xx_write_reg(&ds13xx->client, DS133X_REG_STATUS,
++                                             (u8)~DS133X_BIT_OSF);
++                      break;
++              case ds_1340:
++                      buf[DS13XX_REG_HOUR] |= DS1340_BIT_CENTURY_EN;
++                      // clear oscillator fail flag, in case it was set
++                      ret = ds13xx_write_reg(&ds13xx->client, DS1340_REG_STATUS,
++                                             (u8)~DS1340_BIT_OSF);
++                      break;
++              default:
++                      BUG();
++              }
++      }
++      ds13xx->msg[1].flags = 0;
++      ds13xx->msg[1].len = sizeof(ds13xx->regs);
++
++      dev_dbg(dev, "%s: %02x %02x %02x %02x %02x %02x %02x\n",
++              "write", buf[0], buf[1], buf[2], buf[3],
++              buf[4], buf[5], buf[6]);
++
++      ret = i2c_transfer(ds13xx->client.adapter, &ds13xx->msg[1], 1);
++      if (ret != 1) {
++              dev_err(dev, "%s error %d\n", "write", ret);
++              return ret < 0 ? ret : -EIO;
++      }
++      ds13xx->valid_time = 1;
++      return 0;
++}
++
++static const struct rtc_class_ops ds13xx_rtc_ops = {
++      .read_time      = ds13xx_get_time,
++      .set_time       = ds13xx_set_time,
++};
++
++static struct i2c_driver ds13xx_i2c_driver;
++static struct platform_device *ds13xx_dev;
++
++static int __devinit ds13xx_detect(struct i2c_adapter *adapter, int address, int kind)
++{
++      struct ds13xx           *ds13xx;
++      int                     err = -ENODEV;
++      struct i2c_client       *client;
++      int                     ret;
++
++      if (ds13xx_dev == NULL) {
++              return -ENODEV;
++      }
++
++      ds13xx = kzalloc(sizeof(struct ds13xx), GFP_KERNEL);
++      if (ds13xx == NULL) {
++              err = -ENOMEM;
++              goto exit;
++      }
++
++      client = &ds13xx->client;
++      client->addr = address;
++      client->adapter = adapter;
++      client->driver = &ds13xx_i2c_driver;
++      client->flags = 0;
++
++      i2c_set_clientdata(client, ds13xx);
++
++      ds13xx->msg[0].addr = client->addr;
++      ds13xx->msg[0].flags = 0;
++      ds13xx->msg[0].len = 1;
++      ds13xx->msg[0].buf = &ds13xx->reg_addr;
++
++      ds13xx->msg[1].addr = client->addr;
++      ds13xx->msg[1].flags = I2C_M_RD;
++      ds13xx->msg[1].len = sizeof(ds13xx->regs);
++      ds13xx->msg[1].buf = ds13xx->regs;
++
++      /* HACK: "force" implies "needs ds1337-style-oscillator setup" */
++      if (kind >= 0) {
++              ds13xx->type = ds_1337;
++
++              ds13xx->reg_addr = DS133X_REG_CONTROL;
++              ds13xx->msg[1].len = 2;
++
++              ret = i2c_transfer(client->adapter, ds13xx->msg, 2);
++              if (ret != 2) {
++                      pr_debug("read error %d\n", ret);
++                      err = ret < 0 ? ret : -EIO;
++                      goto exit_free;
++              }
++
++              ds13xx->reg_addr = 0;
++              ds13xx->msg[1].len = sizeof(ds13xx->regs);
++
++              /* oscillator is off; need to turn it on */
++              if ((ds13xx->regs[0] & DS133X_BIT_nEOSC)
++                              || (ds13xx->regs[1] & DS133X_BIT_OSF)) {
++                      dev_err(&ds13xx_dev->dev, "no ds1337 oscillator code\n");
++                      goto exit_free;
++              }
++      } else {
++              ds13xx->type = ds_1307;
++      }
++
++      err = ds13xx_i2c_init(ds13xx_dev, client);
++      if (err) {
++              goto exit_free;
++      }
++
++read_rtc:
++      /* read RTC registers */
++
++      ret = i2c_transfer(client->adapter, ds13xx->msg, 2);
++      if (ret != 2) {
++              dev_dbg(&ds13xx_dev->dev, "read error %d\n", ret);
++              err = ret < 0 ? ret : -EIO;
++              goto exit_free;
++      }
++
++      err = ds13xx_rtc_init(ds13xx_dev->dev.platform_data, client);
++      if (err) {
++              goto exit_free;
++      }
++
++      /* minimal sanity checking; some chips (like DS1340) don't
++       * specify the extra bits as must-be-zero, but there are
++       * still a few values that are clearly out-of-range.
++       */
++      ret = ds13xx->regs[DS13XX_REG_SECS];
++      if (ret & DS1307_BIT_CH) {
++              if (ds13xx->type && ds13xx->type != ds_1307) {
++                      pr_debug("not a ds1307?\n");
++                      goto exit_free;
++              }
++              ds13xx->type = ds_1307;
++
++              /* this partial initialization should work for ds13xx,
++               * ds1338, ds1340, st m41t00, and more.
++               */
++              dev_warn(&client->dev, "oscillator started; SET TIME!\n");
++              ds13xx_write_reg(client, DS13XX_REG_SECS, 0);
++              goto read_rtc;
++      }
++      ret = bcd2bin(ret & 0x7f);
++      if (ret > 60)
++              goto exit_free;
++      ret = bcd2bin(ds13xx->regs[DS13XX_REG_MIN] & 0x7f);
++      if (ret > 60)
++              goto exit_free;
++
++      ret = bcd2bin(ds13xx->regs[DS13XX_REG_MDAY] & 0x3f);
++      if (ret == 0 || ret > 31)
++              goto exit_free;
++
++      ret = bcd2bin(ds13xx->regs[DS13XX_REG_MONTH] & 0x1f);
++      if (ret == 0 || ret > 12)
++              goto exit_free;
++
++      /* force into in 24 hour mode (most chips) or
++       * disable century bit (ds1340)
++       */
++      ret = ds13xx->regs[DS13XX_REG_HOUR];
++      if (ret & (1 << 6)) {
++              if (ret & (1 << 5))
++                      ret = bcd2bin(ret & 0x1f) + 12;
++              else
++                      ret = bcd2bin(ret);
++              ds13xx_write_reg(client,
++                               DS13XX_REG_HOUR,
++                               bin2bcd(ret));
++      }
++
++      /* Tell the I2C layer a new client has arrived */
++      if ((err = i2c_attach_client(client)))
++              goto exit_free;
++
++      dev_dbg(&client->dev, "Registering RTC %s\n", client->name);
++      ds13xx->rtc = rtc_device_register(client->name, &client->dev,
++                                        &ds13xx_rtc_ops, THIS_MODULE);
++      if (IS_ERR(ds13xx->rtc)) {
++              err = PTR_ERR(ds13xx->rtc);
++              dev_err(&client->dev,
++                      "unable to register the class device\n");
++              goto exit_detach;
++      }
++
++      return 0;
++
++exit_detach:
++      i2c_detach_client(client);
++exit_free:
++      kfree(ds13xx);
++exit:
++      return err;
++}
++
++static int __devinit ds13xx_attach_adapter(struct i2c_adapter *adapter)
++{
++      if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
++              return 0;
++      return i2c_probe(adapter, &addr_data, ds13xx_detect);
++}
++
++static int __devexit ds13xx_detach_client(struct i2c_client *client)
++{
++      int             err;
++      struct ds13xx   *ds13xx = i2c_get_clientdata(client);
++
++      rtc_device_unregister(ds13xx->rtc);
++      if ((err = i2c_detach_client(client)))
++              return err;
++      kfree(ds13xx);
++      return 0;
++}
++
++static struct i2c_driver ds13xx_i2c_driver = {
++      .driver = {
++              .name   = "ds13xx",
++              .owner  = THIS_MODULE,
++      },
++      .id_table = ds13xx_id,
++      .attach_adapter = ds13xx_attach_adapter,
++      .detach_client  = __devexit_p(ds13xx_detach_client),
++};
++
++static int __devinit ds13xx_probe(struct platform_device *pdev)
++{
++      ds13xx_dev = pdev;
++      return i2c_add_driver(&ds13xx_i2c_driver);
++}
++
++static int __devexit ds13xx_remove(struct platform_device *pdev)
++{
++      i2c_del_driver(&ds13xx_i2c_driver);
++      ds13xx_dev = NULL;
++      return 0;
++}
++
++static struct platform_driver ds13xx_driver = {
++      .probe = ds13xx_probe,
++      .remove = __devexit_p(ds13xx_remove),
++      .driver = {
++              .owner = THIS_MODULE,
++              .name = "rtc-ds13xx",
++      },
++};
++
++static int __init ds13xx_init(void)
++{
++      return platform_driver_register(&ds13xx_driver);
++}
++module_init(ds13xx_init);
++
++static void __exit ds13xx_exit(void)
++{
++      platform_driver_unregister(&ds13xx_driver);
++}
++module_exit(ds13xx_exit);
++
++MODULE_DESCRIPTION("RTC driver for DS1307,1337,1339,1340 and similar chips");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/rtc/rtc-mxc.c linux-2.6.28-karo/drivers/rtc/rtc-mxc.c
+--- linux-2.6.28/drivers/rtc/rtc-mxc.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/rtc/rtc-mxc.c    2009-03-11 18:47:09.000000000 +0100
+@@ -0,0 +1,835 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ */
++
++/*
++ * The code contained herein is licensed under the GNU General Public
++ * License. You may obtain a copy of the GNU General Public License
++ * Version 2 or later at the following locations:
++ *
++ * http://www.opensource.org/licenses/gpl-license.html
++ * http://www.gnu.org/copyleft/gpl.html
++ */
++/*
++ * Implementation based on rtc-ds1553.c
++ */
++
++/*!
++ * @defgroup RTC Real Time Clock (RTC) Driver
++ */
++/*!
++ * @file rtc-mxc.c
++ * @brief Real Time Clock interface
++ *
++ * This file contains Real Time Clock interface for Linux.
++ *
++ * @ingroup RTC
++ */
++
++#include <linux/rtc.h>
++#include <linux/module.h>
++#include <linux/fs.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/uaccess.h>
++
++#include <mach/hardware.h>
++#include <asm/io.h>
++
++#define RTC_INPUT_CLK_32768HZ (0x00 << 5)
++#define RTC_INPUT_CLK_32000HZ (0x01 << 5)
++#define RTC_INPUT_CLK_38400HZ (0x02 << 5)
++
++#define RTC_SW_BIT      (1 << 0)
++#define RTC_ALM_BIT     (1 << 2)
++#define RTC_1HZ_BIT     (1 << 4)
++#define RTC_2HZ_BIT     (1 << 7)
++#define RTC_SAM0_BIT    (1 << 8)
++#define RTC_SAM1_BIT    (1 << 9)
++#define RTC_SAM2_BIT    (1 << 10)
++#define RTC_SAM3_BIT    (1 << 11)
++#define RTC_SAM4_BIT    (1 << 12)
++#define RTC_SAM5_BIT    (1 << 13)
++#define RTC_SAM6_BIT    (1 << 14)
++#define RTC_SAM7_BIT    (1 << 15)
++#define PIT_ALL_ON      (RTC_2HZ_BIT | RTC_SAM0_BIT | RTC_SAM1_BIT | \
++                         RTC_SAM2_BIT | RTC_SAM3_BIT | RTC_SAM4_BIT | \
++                         RTC_SAM5_BIT | RTC_SAM6_BIT | RTC_SAM7_BIT)
++
++#define RTC_ENABLE_BIT  (1 << 7)
++
++#define MAX_PIE_NUM     9
++#define MAX_PIE_FREQ    512
++const u32 PIE_BIT_DEF[MAX_PIE_NUM][2] = {
++      {2, RTC_2HZ_BIT},
++      {4, RTC_SAM0_BIT},
++      {8, RTC_SAM1_BIT},
++      {16, RTC_SAM2_BIT},
++      {32, RTC_SAM3_BIT},
++      {64, RTC_SAM4_BIT},
++      {128, RTC_SAM5_BIT},
++      {256, RTC_SAM6_BIT},
++      {MAX_PIE_FREQ, RTC_SAM7_BIT},
++};
++
++/* Those are the bits from a classic RTC we want to mimic */
++#define RTC_IRQF                0x80  /* any of the following 3 is active */
++#define RTC_PF                  0x40  /* Periodic interrupt */
++#define RTC_AF                  0x20  /* Alarm interrupt */
++#define RTC_UF                  0x10  /* Update interrupt for 1Hz RTC */
++
++#define MXC_RTC_TIME            0
++#define MXC_RTC_ALARM           1
++
++#define RTC_HOURMIN    0x00   /*  32bit rtc hour/min counter reg */
++#define RTC_SECOND     0x04   /*  32bit rtc seconds counter reg */
++#define RTC_ALRM_HM    0x08   /*  32bit rtc alarm hour/min reg */
++#define RTC_ALRM_SEC   0x0C   /*  32bit rtc alarm seconds reg */
++#define RTC_RTCCTL     0x10   /*  32bit rtc control reg */
++#define RTC_RTCISR     0x14   /*  32bit rtc interrupt status reg */
++#define RTC_RTCIENR    0x18   /*  32bit rtc interrupt enable reg */
++#define RTC_STPWCH     0x1C   /*  32bit rtc stopwatch min reg */
++#define RTC_DAYR       0x20   /*  32bit rtc days counter reg */
++#define RTC_DAYALARM   0x24   /*  32bit rtc day alarm reg */
++#define RTC_TEST1      0x28   /*  32bit rtc test reg 1 */
++#define RTC_TEST2      0x2C   /*  32bit rtc test reg 2 */
++#define RTC_TEST3      0x30   /*  32bit rtc test reg 3 */
++
++struct rtc_plat_data {
++      struct rtc_device *rtc;
++      void __iomem *ioaddr;
++      unsigned long baseaddr;
++      int irq;
++      struct clk *clk;
++      unsigned int irqen;
++      int alrm_sec;
++      int alrm_min;
++      int alrm_hour;
++      int alrm_mday;
++};
++
++/*!
++ * @defgroup RTC Real Time Clock (RTC) Driver
++ */
++/*!
++ * @file rtc-mxc.c
++ * @brief Real Time Clock interface
++ *
++ * This file contains Real Time Clock interface for Linux.
++ *
++ * @ingroup RTC
++ */
++
++#if defined(CONFIG_MXC_MC13783_RTC)
++#include <asm/arch/pmic_rtc.h>
++#else
++#define pmic_rtc_get_time(args)       MXC_EXTERNAL_RTC_NONE
++#define pmic_rtc_set_time(args)       MXC_EXTERNAL_RTC_NONE
++#define pmic_rtc_loaded()             0
++#endif
++
++#define RTC_VERSION           "1.0"
++#define MXC_EXTERNAL_RTC_OK   0
++#define MXC_EXTERNAL_RTC_ERR  -1
++#define MXC_EXTERNAL_RTC_NONE -2
++
++/*!
++ * This function reads the RTC value from some external source.
++ *
++ * @param  second       pointer to the returned value in second
++ *
++ * @return 0 if successful; non-zero otherwise
++ */
++int get_ext_rtc_time(u32 * second)
++{
++      int ret = 0;
++      struct timeval tmp;
++      if (!pmic_rtc_loaded()) {
++              return MXC_EXTERNAL_RTC_NONE;
++      }
++
++      ret = pmic_rtc_get_time(&tmp);
++
++      if (0 == ret)
++              *second = tmp.tv_sec;
++      else
++              ret = MXC_EXTERNAL_RTC_ERR;
++
++      return ret;
++}
++
++/*!
++ * This function sets external RTC
++ *
++ * @param  second       value in second to be set to external RTC
++ *
++ * @return 0 if successful; non-zero otherwise
++ */
++int set_ext_rtc_time(u32 second)
++{
++      int ret = 0;
++      struct timeval tmp;
++
++      if (!pmic_rtc_loaded()) {
++              return MXC_EXTERNAL_RTC_NONE;
++      }
++
++      tmp.tv_sec = second;
++
++      ret = pmic_rtc_set_time(&tmp);
++
++      if (0 != ret)
++              ret = MXC_EXTERNAL_RTC_ERR;
++
++      return ret;
++}
++
++static u32 rtc_freq = 2;      /* minimun value for PIE */
++static unsigned long rtc_status;
++
++static struct rtc_time g_rtc_alarm = {
++      .tm_year = 0,
++      .tm_mon = 0,
++      .tm_mday = 0,
++      .tm_hour = 0,
++      .tm_mon = 0,
++      .tm_sec = 0,
++};
++
++static DEFINE_SPINLOCK(rtc_lock);
++
++/*!
++ * This function is used to obtain the RTC time or the alarm value in
++ * second.
++ *
++ * @param  time_alarm   use MXC_RTC_TIME for RTC time value; MXC_RTC_ALARM for alarm value
++ *
++ * @return The RTC time or alarm time in second.
++ */
++static u32 get_alarm_or_time(struct device *dev, int time_alarm)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++      u32 day, hr, min, sec, hr_min;
++      if (time_alarm == MXC_RTC_TIME) {
++              day = readw(ioaddr + RTC_DAYR);
++              hr_min = readw(ioaddr + RTC_HOURMIN);
++              sec = readw(ioaddr + RTC_SECOND);
++      } else if (time_alarm == MXC_RTC_ALARM) {
++              day = readw(ioaddr + RTC_DAYALARM);
++              hr_min = (0x0000FFFF) & readw(ioaddr + RTC_ALRM_HM);
++              sec = readw(ioaddr + RTC_ALRM_SEC);
++      } else {
++              panic("wrong value for time_alarm=%d\n", time_alarm);
++      }
++
++      hr = hr_min >> 8;
++      min = hr_min & 0x00FF;
++
++      return ((((day * 24 + hr) * 60) + min) * 60 + sec);
++}
++
++/*!
++ * This function sets the RTC alarm value or the time value.
++ *
++ * @param  time_alarm   the new alarm value to be updated in the RTC
++ * @param  time         use MXC_RTC_TIME for RTC time value; MXC_RTC_ALARM for alarm value
++ */
++static void set_alarm_or_time(struct device *dev, int time_alarm, u32 time)
++{
++      u32 day, hr, min, sec, temp;
++      struct platform_device *pdev = to_platform_device(dev);
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++      day = time / 86400;
++      time -= day * 86400;
++      /* time is within a day now */
++      hr = time / 3600;
++      time -= hr * 3600;
++      /* time is within an hour now */
++      min = time / 60;
++      sec = time - min * 60;
++
++      temp = (hr << 8) + min;
++
++      if (time_alarm == MXC_RTC_TIME) {
++              writew(day, ioaddr + RTC_DAYR);
++              writew(sec, ioaddr + RTC_SECOND);
++              writew(temp, ioaddr + RTC_HOURMIN);
++      } else if (time_alarm == MXC_RTC_ALARM) {
++              writew(day, ioaddr + RTC_DAYALARM);
++              writew(sec, ioaddr + RTC_ALRM_SEC);
++              writew(temp, ioaddr + RTC_ALRM_HM);
++      } else {
++              panic("wrong value for time_alarm=%d\n", time_alarm);
++      }
++}
++
++/*!
++ * This function updates the RTC alarm registers and then clears all the
++ * interrupt status bits.
++ *
++ * @param  alrm         the new alarm value to be updated in the RTC
++ *
++ * @return  0 if successful; non-zero otherwise.
++ */
++static int rtc_update_alarm(struct device *dev, struct rtc_time *alrm)
++{
++      struct rtc_time alarm_tm, now_tm;
++      unsigned long now, time;
++      int ret;
++      struct platform_device *pdev = to_platform_device(dev);
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++
++      now = get_alarm_or_time(dev, MXC_RTC_TIME);
++      rtc_time_to_tm(now, &now_tm);
++      alarm_tm.tm_year = now_tm.tm_year;
++      alarm_tm.tm_mon = now_tm.tm_mon;
++      alarm_tm.tm_mday = now_tm.tm_mday;
++      alarm_tm.tm_hour = alrm->tm_hour;
++      alarm_tm.tm_min = alrm->tm_min;
++      alarm_tm.tm_sec = alrm->tm_sec;
++      rtc_tm_to_time(&now_tm, &now);
++      rtc_tm_to_time(&alarm_tm, &time);
++      if (time < now) {
++              time += 60 * 60 * 24;
++              rtc_time_to_tm(time, &alarm_tm);
++      }
++      ret = rtc_tm_to_time(&alarm_tm, &time);
++
++      /* clear all the interrupt status bits */
++      writew(readw(ioaddr + RTC_RTCISR), ioaddr + RTC_RTCISR);
++
++      set_alarm_or_time(dev, MXC_RTC_ALARM, time);
++
++      return ret;
++}
++
++/*!
++ * This function is the RTC interrupt service routine.
++ *
++ * @param  irq          RTC IRQ number
++ * @param  dev_id       device ID which is not used
++ *
++ * @return IRQ_HANDLED as defined in the include/linux/interrupt.h file.
++ */
++static irqreturn_t mxc_rtc_interrupt(int irq, void *dev_id)
++{
++      struct platform_device *pdev = dev_id;
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++      u32 status;
++      u32 events = 0;
++      spin_lock(&rtc_lock);
++      status = readw(ioaddr + RTC_RTCISR) & readw(ioaddr + RTC_RTCIENR);
++      /* clear interrupt sources */
++      writew(status, ioaddr + RTC_RTCISR);
++
++      /* clear alarm interrupt if it has occurred */
++      if (status & RTC_ALM_BIT) {
++              status &= ~RTC_ALM_BIT;
++      }
++
++      /* update irq data & counter */
++      if (status & RTC_ALM_BIT) {
++              events |= (RTC_AF | RTC_IRQF);
++      }
++      if (status & RTC_1HZ_BIT) {
++              events |= (RTC_UF | RTC_IRQF);
++      }
++      if (status & PIT_ALL_ON) {
++              events |= (RTC_PF | RTC_IRQF);
++      }
++
++      if ((status & RTC_ALM_BIT) && rtc_valid_tm(&g_rtc_alarm)) {
++              rtc_update_alarm(&pdev->dev, &g_rtc_alarm);
++      }
++
++      spin_unlock(&rtc_lock);
++      rtc_update_irq(pdata->rtc, 1, events);
++      return IRQ_HANDLED;
++}
++
++/*!
++ * This function is used to open the RTC driver by registering the RTC
++ * interrupt service routine.
++ *
++ * @return  0 if successful; non-zero otherwise.
++ */
++static int mxc_rtc_open(struct device *dev)
++{
++      if (test_and_set_bit(1, &rtc_status))
++              return -EBUSY;
++      return 0;
++}
++
++/*!
++ * clear all interrupts and release the IRQ
++ */
++static void mxc_rtc_release(struct device *dev)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++
++      spin_lock_irq(&rtc_lock);
++      writew(0, ioaddr + RTC_RTCIENR);        /* Disable all rtc interrupts */
++      writew(0xFFFFFFFF, ioaddr + RTC_RTCISR);        /* Clear all interrupt status */
++      spin_unlock_irq(&rtc_lock);
++      rtc_status = 0;
++}
++
++/*!
++ * This function is used to support some ioctl calls directly.
++ * Other ioctl calls are supported indirectly through the
++ * arm/common/rtctime.c file.
++ *
++ * @param  cmd          ioctl command as defined in include/linux/rtc.h
++ * @param  arg          value for the ioctl command
++ *
++ * @return  0 if successful or negative value otherwise.
++ */
++static int mxc_rtc_ioctl(struct device *dev, unsigned int cmd,
++                       unsigned long arg)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++      int i;
++      switch (cmd) {
++      case RTC_PIE_OFF:
++              writew((readw(ioaddr + RTC_RTCIENR) & ~PIT_ALL_ON),
++                     ioaddr + RTC_RTCIENR);
++              return 0;
++      case RTC_IRQP_SET:
++              if (arg < 2 || arg > MAX_PIE_FREQ || (arg % 2) != 0)
++                      return -EINVAL; /* Also make sure a power of 2Hz */
++              if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
++                      return -EACCES;
++              rtc_freq = arg;
++              return 0;
++      case RTC_IRQP_READ:
++              return put_user(rtc_freq, (u32 *) arg);
++      case RTC_PIE_ON:
++              for (i = 0; i < MAX_PIE_NUM; i++) {
++                      if (PIE_BIT_DEF[i][0] == rtc_freq) {
++                              break;
++                      }
++              }
++              if (i == MAX_PIE_NUM) {
++                      return -EACCES;
++              }
++              spin_lock_irq(&rtc_lock);
++              writew((readw(ioaddr + RTC_RTCIENR) | PIE_BIT_DEF[i][1]),
++                     ioaddr + RTC_RTCIENR);
++              spin_unlock_irq(&rtc_lock);
++              return 0;
++      case RTC_AIE_OFF:
++              spin_lock_irq(&rtc_lock);
++              writew((readw(ioaddr + RTC_RTCIENR) & ~RTC_ALM_BIT),
++                     ioaddr + RTC_RTCIENR);
++              spin_unlock_irq(&rtc_lock);
++              return 0;
++
++      case RTC_AIE_ON:
++              spin_lock_irq(&rtc_lock);
++              writew((readw(ioaddr + RTC_RTCIENR) | RTC_ALM_BIT),
++                     ioaddr + RTC_RTCIENR);
++              spin_unlock_irq(&rtc_lock);
++              return 0;
++
++      case RTC_UIE_OFF:       /* UIE is for the 1Hz interrupt */
++              spin_lock_irq(&rtc_lock);
++              writew((readw(ioaddr + RTC_RTCIENR) & ~RTC_1HZ_BIT),
++                     ioaddr + RTC_RTCIENR);
++              spin_unlock_irq(&rtc_lock);
++              return 0;
++
++      case RTC_UIE_ON:
++              spin_lock_irq(&rtc_lock);
++              writew((readw(ioaddr + RTC_RTCIENR) | RTC_1HZ_BIT),
++                     ioaddr + RTC_RTCIENR);
++              spin_unlock_irq(&rtc_lock);
++              return 0;
++      }
++      return -ENOIOCTLCMD;
++}
++
++/*!
++ * This function reads the current RTC time into tm in Gregorian date.
++ *
++ * @param  tm           contains the RTC time value upon return
++ *
++ * @return  0 if successful; non-zero otherwise.
++ */
++static int mxc_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++      u32 val;
++
++      /* Avoid roll-over from reading the different registers */
++      do {
++              val = get_alarm_or_time(dev, MXC_RTC_TIME);
++      } while (val != get_alarm_or_time(dev, MXC_RTC_TIME));
++
++      rtc_time_to_tm(val, tm);
++      return 0;
++}
++
++/*!
++ * This function sets the internal RTC time based on tm in Gregorian date.
++ *
++ * @param  tm           the time value to be set in the RTC
++ *
++ * @return  0 if successful; non-zero otherwise.
++ */
++static int mxc_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++      unsigned long time;
++      int ret;
++      ret = rtc_tm_to_time(tm, &time);
++      if (ret != 0) {
++              return ret;
++      }
++
++      /* Avoid roll-over from reading the different registers */
++      do {
++              set_alarm_or_time(dev, MXC_RTC_TIME, time);
++      } while (time != get_alarm_or_time(dev, MXC_RTC_TIME));
++
++      ret = set_ext_rtc_time(time);
++
++      if (ret != MXC_EXTERNAL_RTC_OK) {
++              if (ret == MXC_EXTERNAL_RTC_NONE) {
++                      pr_info("No external RTC\n");
++                      ret = 0;
++              } else
++                      pr_info("Failed to set external RTC\n");
++      }
++
++      return ret;
++}
++
++/*!
++ * This function reads the current alarm value into the passed in \b alrm
++ * argument. It updates the \b alrm's pending field value based on the whether
++ * an alarm interrupt occurs or not.
++ *
++ * @param  alrm         contains the RTC alarm value upon return
++ *
++ * @return  0 if successful; non-zero otherwise.
++ */
++static int mxc_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++
++      rtc_time_to_tm(get_alarm_or_time(dev, MXC_RTC_ALARM), &alrm->time);
++      alrm->enabled = !!(readw(ioaddr + RTC_RTCIENR) & RTC_ALM_BIT);
++      alrm->pending = !!(readw(ioaddr + RTC_RTCISR) & RTC_ALM_BIT);
++      return 0;
++}
++
++/*!
++ * This function sets the RTC alarm based on passed in alrm.
++ *
++ * @param  alrm         the alarm value to be set in the RTC
++ *
++ * @return  0 if successful; non-zero otherwise.
++ */
++static int mxc_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++      int ret;
++
++      spin_lock_irq(&rtc_lock);
++      if (rtc_valid_tm(&alrm->time)) {
++              if (alrm->time.tm_sec > 59 ||
++                  alrm->time.tm_hour > 23 || alrm->time.tm_min > 59) {
++                      ret = -EINVAL;
++                      goto out;
++              }
++              ret = rtc_update_alarm(dev, &alrm->time);
++      } else {
++              if ((ret = rtc_valid_tm(&alrm->time)))
++                      goto out;
++              ret = rtc_update_alarm(dev, &alrm->time);
++      }
++
++      if (ret == 0) {
++              memcpy(&g_rtc_alarm, &alrm->time, sizeof(struct rtc_time));
++
++              if (alrm->enabled) {
++                      writew((readw(ioaddr + RTC_RTCIENR) | RTC_ALM_BIT),
++                             ioaddr + RTC_RTCIENR);
++              } else {
++                      writew((readw(ioaddr + RTC_RTCIENR) & ~RTC_ALM_BIT),
++                             ioaddr + RTC_RTCIENR);
++              }
++              device_set_wakeup_enable(dev, alrm->enabled);
++      }
++      out:
++      spin_unlock_irq(&rtc_lock);
++
++      return ret;
++}
++
++/*!
++ * This function is used to provide the content for the /proc/driver/rtc
++ * file.
++ *
++ * @param  buf          the buffer to hold the information that the driver wants to write
++ *
++ * @return  The number of bytes written into the rtc file.
++ */
++static int mxc_rtc_proc(struct device *dev, struct seq_file *sq)
++{
++      struct platform_device *pdev = to_platform_device(dev);
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      void __iomem *ioaddr = pdata->ioaddr;
++      char *p = sq->buf;
++
++      p += sprintf(p, "alarm_IRQ\t: %s\n",
++                   (((readw(ioaddr + RTC_RTCIENR)) & RTC_ALM_BIT) !=
++                    0) ? "yes" : "no");
++      p += sprintf(p, "update_IRQ\t: %s\n",
++                   (((readw(ioaddr + RTC_RTCIENR)) & RTC_1HZ_BIT) !=
++                    0) ? "yes" : "no");
++      p += sprintf(p, "periodic_IRQ\t: %s\n",
++                   (((readw(ioaddr + RTC_RTCIENR)) & PIT_ALL_ON) !=
++                    0) ? "yes" : "no");
++      p += sprintf(p, "periodic_freq\t: %d\n", rtc_freq);
++
++      return p - (sq->buf);
++}
++
++/*!
++ * The RTC driver structure
++ */
++static struct rtc_class_ops mxc_rtc_ops = {
++      .open = mxc_rtc_open,
++      .release = mxc_rtc_release,
++      .ioctl = mxc_rtc_ioctl,
++      .read_time = mxc_rtc_read_time,
++      .set_time = mxc_rtc_set_time,
++      .read_alarm = mxc_rtc_read_alarm,
++      .set_alarm = mxc_rtc_set_alarm,
++      .proc = mxc_rtc_proc,
++};
++
++/*! MXC RTC Power management control */
++
++static struct timespec mxc_rtc_delta;
++
++static int mxc_rtc_probe(struct platform_device *pdev)
++{
++      struct clk *clk;
++      struct timespec tv;
++      struct resource *res;
++      struct rtc_time temp_time;
++      struct rtc_device *rtc;
++      struct rtc_plat_data *pdata = NULL;
++      u32 sec, reg;
++      int ret;
++      int rtc_input_clk;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!res)
++              return -ENODEV;
++
++      pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
++      if (!pdata)
++              return -ENOMEM;
++
++      pdata->clk = clk_get(&pdev->dev, "rtc_clk");
++      clk_enable(pdata->clk);
++
++      pdata->baseaddr = res->start;
++      pdata->ioaddr = ((void *)(IO_ADDRESS(pdata->baseaddr)));
++      /* Configure and enable the RTC */
++      rtc = rtc_device_register(pdev->name, &pdev->dev, &mxc_rtc_ops,
++                                THIS_MODULE);
++      if (IS_ERR(rtc)) {
++              ret = PTR_ERR(rtc);
++              if (pdata->irq >= 0)
++                      free_irq(pdata->irq, pdev);
++              kfree(pdata);
++              return ret;
++      }
++      pdata->rtc = rtc;
++      platform_set_drvdata(pdev, pdata);
++
++      pdata->irq = platform_get_irq(pdev, 0);
++      if (pdata->irq >= 0) {
++              if (request_irq(pdata->irq, mxc_rtc_interrupt, IRQF_SHARED,
++                              pdev->name, pdev) < 0) {
++                      dev_warn(&pdev->dev, "interrupt not available.\n");
++                      pdata->irq = -1;
++              }
++      }
++      device_set_wakeup_capable(&pdev->dev, 1);
++
++      ret = get_ext_rtc_time(&sec);
++      if (ret == MXC_EXTERNAL_RTC_OK) {
++              rtc_time_to_tm(sec, &temp_time);
++              mxc_rtc_set_time(&pdev->dev, &temp_time);
++
++      } else if (ret == MXC_EXTERNAL_RTC_NONE) {
++              pr_info("No external RTC device\n");
++      } else {
++              pr_info("Reading external RTC device failed\n");
++      }
++      tv.tv_nsec = 0;
++      tv.tv_sec = get_alarm_or_time(&pdev->dev, MXC_RTC_TIME);
++      clk = clk_get(NULL, "ckil");
++      rtc_input_clk = clk_get_rate(clk);
++      if (rtc_input_clk == 32768)
++              reg = RTC_INPUT_CLK_32768HZ;
++      else if (rtc_input_clk == 32000)
++              reg = RTC_INPUT_CLK_32000HZ;
++      else if (rtc_input_clk == 38400)
++              reg = RTC_INPUT_CLK_38400HZ;
++      else {
++              printk(KERN_ALERT "rtc clock is not valid");
++              return -EINVAL;
++      }
++      clk_put(clk);
++      reg |= RTC_ENABLE_BIT;
++      writew(reg, (pdata->ioaddr + RTC_RTCCTL));
++      if (((readw(pdata->ioaddr + RTC_RTCCTL)) & RTC_ENABLE_BIT) == 0) {
++              printk(KERN_ALERT "rtc : hardware module can't be enabled!\n");
++              return -EPERM;
++      }
++      printk("Real Time clock Driver v%s %ukHz base clock\n", RTC_VERSION,
++             rtc_input_clk);
++      return 0;
++}
++
++static int __exit mxc_rtc_remove(struct platform_device *pdev)
++{
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      rtc_device_unregister(pdata->rtc);
++      if (pdata->irq >= 0) {
++              free_irq(pdata->irq, pdev);
++      }
++      clk_disable(pdata->clk);
++      clk_put(pdata->clk);
++      kfree(pdata);
++      mxc_rtc_release(NULL);
++      return 0;
++}
++
++/*!
++ * This function is called to save the system time delta relative to
++ * the MXC RTC when enterring a low power state. This time delta is
++ * then used on resume to adjust the system time to account for time
++ * loss while suspended.
++ *
++ * @param   pdev  not used
++ * @param   state Power state to enter.
++ *
++ * @return  The function always returns 0.
++ */
++static int mxc_rtc_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      struct timespec tv;
++
++      /* calculate time delta for suspend */
++      /* RTC precision is 1 second; adjust delta for avg 1/2 sec err */
++      tv.tv_nsec = NSEC_PER_SEC >> 1;
++      tv.tv_sec = get_alarm_or_time(&pdev->dev, MXC_RTC_TIME);
++      set_normalized_timespec(&mxc_rtc_delta,
++                              xtime.tv_sec - tv.tv_sec,
++                              xtime.tv_nsec - tv.tv_nsec);
++
++      if (device_may_wakeup(&pdev->dev)) {
++              int ret;
++
++              ret = enable_irq_wake(pdata->irq);
++              if (ret != 0) {
++                      dev_warn(&pdev->dev, "Failed to enable IRQ wake for IRQ %d: %d\n",
++                             pdata->irq, ret);
++                      return ret;
++              }
++      }
++      return 0;
++}
++
++/*!
++ * This function is called to correct the system time based on the
++ * current MXC RTC time relative to the time delta saved during
++ * suspend.
++ *
++ * @param   pdev  not used
++ *
++ * @return  The function always returns 0.
++ */
++static int mxc_rtc_resume(struct platform_device *pdev)
++{
++      struct rtc_plat_data *pdata = platform_get_drvdata(pdev);
++      struct timespec tv;
++      struct timespec ts;
++
++      tv.tv_nsec = 0;
++      tv.tv_sec = get_alarm_or_time(&pdev->dev, MXC_RTC_TIME);
++
++      /* restore wall clock using delta against this RTC;
++       * adjust again for avg 1/2 second RTC sampling error
++       */
++      set_normalized_timespec(&ts,
++                              tv.tv_sec + mxc_rtc_delta.tv_sec,
++                              (NSEC_PER_SEC >> 1) + mxc_rtc_delta.tv_nsec);
++      do_settimeofday(&ts);
++      if (device_may_wakeup(&pdev->dev))
++              disable_irq_wake(pdata->irq);
++      return 0;
++}
++
++/*!
++ * Contains pointers to the power management callback functions.
++ */
++static struct platform_driver mxc_rtc_driver = {
++      .driver = {
++                 .name = "mxc_rtc",
++      },
++      .probe = mxc_rtc_probe,
++      .remove = __exit_p(mxc_rtc_remove),
++      .suspend = mxc_rtc_suspend,
++      .resume = mxc_rtc_resume,
++};
++
++/*!
++ * This function creates the /proc/driver/rtc file and registers the device RTC
++ * in the /dev/misc directory. It also reads the RTC value from external source
++ * and setup the internal RTC properly.
++ *
++ * @return  -1 if RTC is failed to initialize; 0 is successful.
++ */
++static int __init mxc_rtc_init(void)
++{
++      return platform_driver_register(&mxc_rtc_driver);
++}
++
++/*!
++ * This function removes the /proc/driver/rtc file and un-registers the
++ * device RTC from the /dev/misc directory.
++ */
++static void __exit mxc_rtc_exit(void)
++{
++      platform_driver_unregister(&mxc_rtc_driver);
++
++}
++
++module_init(mxc_rtc_init);
++module_exit(mxc_rtc_exit);
++
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_DESCRIPTION("Realtime Clock Driver (RTC)");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/serial/imx.c linux-2.6.28-karo/drivers/serial/imx.c
+--- linux-2.6.28/drivers/serial/imx.c  2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/serial/imx.c     2009-03-11 13:16:24.000000000 +0100
+@@ -31,6 +31,7 @@
+ #endif
+ #include <linux/module.h>
++#include <linux/io.h>
+ #include <linux/ioport.h>
+ #include <linux/init.h>
+ #include <linux/console.h>
+@@ -42,7 +43,6 @@
+ #include <linux/serial.h>
+ #include <linux/clk.h>
+-#include <asm/io.h>
+ #include <asm/irq.h>
+ #include <mach/hardware.h>
+ #include <mach/imx-uart.h>
+@@ -66,7 +66,7 @@
+ #define ONEMS 0xb0 /* One Millisecond register */
+ #define UTS   0xb4 /* UART Test Register */
+ #endif
+-#ifdef CONFIG_ARCH_IMX
++#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
+ #define BIPR1 0xb0 /* Incremental Preset Register 1 */
+ #define BIPR2 0xb4 /* Incremental Preset Register 2 */
+ #define BIPR3 0xb8 /* Incremental Preset Register 3 */
+@@ -79,105 +79,105 @@
+ #endif
+ /* UART Control Register Bit Fields.*/
+-#define  URXD_CHARRDY    (1<<15)
+-#define  URXD_ERR        (1<<14)
+-#define  URXD_OVRRUN     (1<<13)
+-#define  URXD_FRMERR     (1<<12)
+-#define  URXD_BRK        (1<<11)
+-#define  URXD_PRERR      (1<<10)
+-#define  UCR1_ADEN       (1<<15) /* Auto dectect interrupt */
+-#define  UCR1_ADBR       (1<<14) /* Auto detect baud rate */
+-#define  UCR1_TRDYEN     (1<<13) /* Transmitter ready interrupt enable */
+-#define  UCR1_IDEN       (1<<12) /* Idle condition interrupt */
+-#define  UCR1_RRDYEN     (1<<9)        /* Recv ready interrupt enable */
+-#define  UCR1_RDMAEN     (1<<8)        /* Recv ready DMA enable */
+-#define  UCR1_IREN       (1<<7)        /* Infrared interface enable */
+-#define  UCR1_TXMPTYEN   (1<<6)        /* Transimitter empty interrupt enable */
+-#define  UCR1_RTSDEN     (1<<5)        /* RTS delta interrupt enable */
+-#define  UCR1_SNDBRK     (1<<4)        /* Send break */
+-#define  UCR1_TDMAEN     (1<<3)        /* Transmitter ready DMA enable */
+-#ifdef CONFIG_ARCH_IMX
+-#define  UCR1_UARTCLKEN  (1<<2)        /* UART clock enabled */
++#define URXD_CHARRDY  (1 << 15)
++#define URXD_ERR      (1 << 14)
++#define URXD_OVRRUN   (1 << 13)
++#define URXD_FRMERR   (1 << 12)
++#define URXD_BRK      (1 << 11)
++#define URXD_PRERR    (1 << 10)
++#define UCR1_ADEN     (1 << 15)       /* Auto dectect interrupt */
++#define UCR1_ADBR     (1 << 14)       /* Auto detect baud rate */
++#define UCR1_TRDYEN   (1 << 13)       /* Transmitter ready interrupt enable */
++#define UCR1_IDEN     (1 << 12)       /* Idle condition interrupt */
++#define UCR1_RRDYEN   (1 << 9)        /* Recv ready interrupt enable */
++#define UCR1_RDMAEN   (1 << 8)        /* Recv ready DMA enable */
++#define UCR1_IREN     (1 << 7)        /* Infrared interface enable */
++#define UCR1_TXMPTYEN (1 << 6)        /* Transimitter empty interrupt enable */
++#define UCR1_RTSDEN   (1 << 5)        /* RTS delta interrupt enable */
++#define UCR1_SNDBRK   (1 << 4)        /* Send break */
++#define UCR1_TDMAEN   (1 << 3)        /* Transmitter ready DMA enable */
++#if defined(CONFIG_ARCH_IMX) || defined(CONFIG_ARCH_MX1)
++#define UCR1_UARTCLKEN        (1 << 2)        /* UART clock enabled */
+ #endif
+ #if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
+-#define  UCR1_UARTCLKEN  (0)   /* not present on mx2/mx3 */
++#define UCR1_UARTCLKEN        0               /* not present on mx2/mx3 */
+ #endif
+-#define  UCR1_DOZE       (1<<1)        /* Doze */
+-#define  UCR1_UARTEN     (1<<0)        /* UART enabled */
+-#define  UCR2_ESCI             (1<<15) /* Escape seq interrupt enable */
+-#define  UCR2_IRTS     (1<<14) /* Ignore RTS pin */
+-#define  UCR2_CTSC     (1<<13) /* CTS pin control */
+-#define  UCR2_CTS        (1<<12) /* Clear to send */
+-#define  UCR2_ESCEN      (1<<11) /* Escape enable */
+-#define  UCR2_PREN       (1<<8)  /* Parity enable */
+-#define  UCR2_PROE       (1<<7)  /* Parity odd/even */
+-#define  UCR2_STPB       (1<<6)        /* Stop */
+-#define  UCR2_WS         (1<<5)        /* Word size */
+-#define  UCR2_RTSEN      (1<<4)        /* Request to send interrupt enable */
+-#define  UCR2_TXEN       (1<<2)        /* Transmitter enabled */
+-#define  UCR2_RXEN       (1<<1)        /* Receiver enabled */
+-#define  UCR2_SRST     (1<<0)  /* SW reset */
+-#define  UCR3_DTREN    (1<<13) /* DTR interrupt enable */
+-#define  UCR3_PARERREN   (1<<12) /* Parity enable */
+-#define  UCR3_FRAERREN   (1<<11) /* Frame error interrupt enable */
+-#define  UCR3_DSR        (1<<10) /* Data set ready */
+-#define  UCR3_DCD        (1<<9)  /* Data carrier detect */
+-#define  UCR3_RI         (1<<8)  /* Ring indicator */
+-#define  UCR3_TIMEOUTEN  (1<<7)  /* Timeout interrupt enable */
+-#define  UCR3_RXDSEN   (1<<6)  /* Receive status interrupt enable */
+-#define  UCR3_AIRINTEN   (1<<5)  /* Async IR wake interrupt enable */
+-#define  UCR3_AWAKEN   (1<<4)  /* Async wake interrupt enable */
++#define UCR1_DOZE     (1 << 1)        /* Doze */
++#define UCR1_UARTEN   (1 << 0)        /* UART enabled */
++#define UCR2_ESCI     (1 << 15)       /* Escape seq interrupt enable */
++#define UCR2_IRTS     (1 << 14)       /* Ignore RTS pin */
++#define UCR2_CTSC     (1 << 13)       /* CTS pin control */
++#define UCR2_CTS      (1 << 12)       /* Clear to send */
++#define UCR2_ESCEN    (1 << 11)       /* Escape enable */
++#define UCR2_PREN     (1 << 8)        /* Parity enable */
++#define UCR2_PROE     (1 << 7)        /* Parity odd/even */
++#define UCR2_STPB     (1 << 6)        /* Stop */
++#define UCR2_WS               (1 << 5)        /* Word size */
++#define UCR2_RTSEN    (1 << 4)        /* Request to send interrupt enable */
++#define UCR2_TXEN     (1 << 2)        /* Transmitter enabled */
++#define UCR2_RXEN     (1 << 1)        /* Receiver enabled */
++#define UCR2_SRST     (1 << 0)        /* SW reset */
++#define UCR3_DTREN    (1 << 13)       /* DTR interrupt enable */
++#define UCR3_PARERREN (1 << 12)       /* Parity enable */
++#define UCR3_FRAERREN (1 << 11)       /* Frame error interrupt enable */
++#define UCR3_DSR      (1 << 10)       /* Data set ready */
++#define UCR3_DCD      (1 << 9)        /* Data carrier detect */
++#define UCR3_RI               (1 << 8)        /* Ring indicator */
++#define UCR3_TIMEOUTEN        (1 << 7)        /* Timeout interrupt enable */
++#define UCR3_RXDSEN   (1 << 6)        /* Receive status interrupt enable */
++#define UCR3_AIRINTEN (1 << 5)        /* Async IR wake interrupt enable */
++#define UCR3_AWAKEN   (1 << 4)        /* Async wake interrupt enable */
+ #ifdef CONFIG_ARCH_IMX
+-#define  UCR3_REF25    (1<<3)  /* Ref freq 25 MHz, only on mx1 */
+-#define  UCR3_REF30    (1<<2)  /* Ref Freq 30 MHz, only on mx1 */
++#define UCR3_REF25    (1 << 3)        /* Ref freq 25 MHz, only on mx1 */
++#define UCR3_REF30    (1 << 2)        /* Ref Freq 30 MHz, only on mx1 */
+ #endif
+ #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
+-#define  UCR3_RXDMUXSEL        (1<<2)  /* RXD Muxed Input Select, on mx2/mx3 */
++#define UCR3_RXDMUXSEL        (1 << 2)        /* RXD Muxed Input Select, on mx2/mx3 */
+ #endif
+-#define  UCR3_INVT     (1<<1)  /* Inverted Infrared transmission */
+-#define  UCR3_BPEN     (1<<0)  /* Preset registers enable */
+-#define  UCR4_CTSTL_32   (32<<10) /* CTS trigger level (32 chars) */
+-#define  UCR4_INVR     (1<<9)  /* Inverted infrared reception */
+-#define  UCR4_ENIRI    (1<<8)  /* Serial infrared interrupt enable */
+-#define  UCR4_WKEN     (1<<7)  /* Wake interrupt enable */
+-#define  UCR4_REF16    (1<<6)  /* Ref freq 16 MHz */
+-#define  UCR4_IRSC     (1<<5)  /* IR special case */
+-#define  UCR4_TCEN     (1<<3)  /* Transmit complete interrupt enable */
+-#define  UCR4_BKEN     (1<<2)  /* Break condition interrupt enable */
+-#define  UCR4_OREN     (1<<1)  /* Receiver overrun interrupt enable */
+-#define  UCR4_DREN     (1<<0)  /* Recv data ready interrupt enable */
+-#define  UFCR_RXTL_SHF   0       /* Receiver trigger level shift */
+-#define  UFCR_RFDIV      (7<<7)  /* Reference freq divider mask */
+-#define  UFCR_TXTL_SHF   10      /* Transmitter trigger level shift */
+-#define  USR1_PARITYERR  (1<<15) /* Parity error interrupt flag */
+-#define  USR1_RTSS     (1<<14) /* RTS pin status */
+-#define  USR1_TRDY     (1<<13) /* Transmitter ready interrupt/dma flag */
+-#define  USR1_RTSD     (1<<12) /* RTS delta */
+-#define  USR1_ESCF     (1<<11) /* Escape seq interrupt flag */
+-#define  USR1_FRAMERR    (1<<10) /* Frame error interrupt flag */
+-#define  USR1_RRDY       (1<<9)        /* Receiver ready interrupt/dma flag */
+-#define  USR1_TIMEOUT    (1<<7)        /* Receive timeout interrupt status */
+-#define  USR1_RXDS     (1<<6)  /* Receiver idle interrupt flag */
+-#define  USR1_AIRINT   (1<<5)  /* Async IR wake interrupt flag */
+-#define  USR1_AWAKE    (1<<4)  /* Aysnc wake interrupt flag */
+-#define  USR2_ADET     (1<<15) /* Auto baud rate detect complete */
+-#define  USR2_TXFE     (1<<14) /* Transmit buffer FIFO empty */
+-#define  USR2_DTRF     (1<<13) /* DTR edge interrupt flag */
+-#define  USR2_IDLE     (1<<12) /* Idle condition */
+-#define  USR2_IRINT    (1<<8)  /* Serial infrared interrupt flag */
+-#define  USR2_WAKE     (1<<7)  /* Wake */
+-#define  USR2_RTSF     (1<<4)  /* RTS edge interrupt flag */
+-#define  USR2_TXDC     (1<<3)  /* Transmitter complete */
+-#define  USR2_BRCD     (1<<2)  /* Break condition */
+-#define  USR2_ORE        (1<<1)        /* Overrun error */
+-#define  USR2_RDR        (1<<0)        /* Recv data ready */
+-#define  UTS_FRCPERR   (1<<13) /* Force parity error */
+-#define  UTS_LOOP        (1<<12) /* Loop tx and rx */
+-#define  UTS_TXEMPTY   (1<<6)  /* TxFIFO empty */
+-#define  UTS_RXEMPTY   (1<<5)  /* RxFIFO empty */
+-#define  UTS_TXFULL    (1<<4)  /* TxFIFO full */
+-#define  UTS_RXFULL    (1<<3)  /* RxFIFO full */
+-#define  UTS_SOFTRST   (1<<0)  /* Software reset */
++#define UCR3_INVT     (1 << 1)        /* Inverted Infrared transmission */
++#define UCR3_BPEN     (1 << 0)        /* Preset registers enable */
++#define UCR4_CTSTL_32 (32 << 10)      /* CTS trigger level (32 chars) */
++#define UCR4_INVR     (1 << 9)        /* Inverted infrared reception */
++#define UCR4_ENIRI    (1 << 8)        /* Serial infrared interrupt enable */
++#define UCR4_WKEN     (1 << 7)        /* Wake interrupt enable */
++#define UCR4_REF16    (1 << 6)        /* Ref freq 16 MHz */
++#define UCR4_IRSC     (1 << 5)        /* IR special case */
++#define UCR4_TCEN     (1 << 3)        /* Transmit complete interrupt enable */
++#define UCR4_BKEN     (1 << 2)        /* Break condition interrupt enable */
++#define UCR4_OREN     (1 << 1)        /* Receiver overrun interrupt enable */
++#define UCR4_DREN     (1 << 0)        /* Recv data ready interrupt enable */
++#define UFCR_RXTL_SHF 0               /* Receiver trigger level shift */
++#define UFCR_RFDIV    (7 << 7)        /* Reference freq divider mask */
++#define UFCR_TXTL_SHF 10              /* Transmitter trigger level shift */
++#define USR1_PARITYERR        (1 << 15)       /* Parity error interrupt flag */
++#define USR1_RTSS     (1 << 14)       /* RTS pin status */
++#define USR1_TRDY     (1 << 13)       /* Transmitter ready interrupt/dma flag */
++#define USR1_RTSD     (1 << 12)       /* RTS delta */
++#define USR1_ESCF     (1 << 11)       /* Escape seq interrupt flag */
++#define USR1_FRAMERR  (1 << 10)       /* Frame error interrupt flag */
++#define USR1_RRDY     (1 << 9)        /* Receiver ready interrupt/dma flag */
++#define USR1_TIMEOUT  (1 << 7)        /* Receive timeout interrupt status */
++#define USR1_RXDS     (1 << 6)        /* Receiver idle interrupt flag */
++#define USR1_AIRINT   (1 << 5)        /* Async IR wake interrupt flag */
++#define USR1_AWAKE    (1 << 4)        /* Aysnc wake interrupt flag */
++#define USR2_ADET     (1 << 15)       /* Auto baud rate detect complete */
++#define USR2_TXFE     (1 << 14)       /* Transmit buffer FIFO empty */
++#define USR2_DTRF     (1 << 13)       /* DTR edge interrupt flag */
++#define USR2_IDLE     (1 << 12)       /* Idle condition */
++#define USR2_IRINT    (1 << 8)        /* Serial infrared interrupt flag */
++#define USR2_WAKE     (1 << 7)        /* Wake */
++#define USR2_RTSF     (1 << 4)        /* RTS edge interrupt flag */
++#define USR2_TXDC     (1 << 3)        /* Transmitter complete */
++#define USR2_BRCD     (1 << 2)        /* Break condition */
++#define USR2_ORE      (1 << 1)        /* Overrun error */
++#define USR2_RDR      (1 << 0)        /* Recv data ready */
++#define UTS_FRCPERR   (1 << 13)       /* Force parity error */
++#define UTS_LOOP      (1 << 12)       /* Loop tx and rx */
++#define UTS_TXEMPTY   (1 << 6)        /* TxFIFO empty */
++#define UTS_RXEMPTY   (1 << 5)        /* RxFIFO empty */
++#define UTS_TXFULL    (1 << 4)        /* TxFIFO full */
++#define UTS_RXFULL    (1 << 3)        /* RxFIFO full */
++#define UTS_SOFTRST   (1 << 0)        /* Software reset */
+ /* We've been assigned a range on the "Low-density serial ports" major */
+ #ifdef CONFIG_ARCH_IMX
+@@ -187,9 +187,9 @@
+ #define MAX_INTERNAL_IRQ      IMX_IRQS
+ #endif
+-#if defined CONFIG_ARCH_MX3 || defined CONFIG_ARCH_MX2
+-#define SERIAL_IMX_MAJOR        207
+-#define MINOR_START           16
++#ifdef CONFIG_ARCH_MXC
++#define SERIAL_IMX_MAJOR      207
++#define MINOR_START           16
+ #define DEV_NAME              "ttymxc"
+ #define MAX_INTERNAL_IRQ      MXC_MAX_INT_LINES
+ #endif
+@@ -200,7 +200,7 @@
+  * so we have to poll them.  We also check immediately before
+  * filling the TX fifo incase CTS has been dropped.
+  */
+-#define MCTRL_TIMEOUT (250*HZ/1000)
++#define MCTRL_TIMEOUT (250 * HZ / 1000)
+ #define DRIVER_NAME "IMX-uart"
+@@ -210,7 +210,7 @@ struct imx_port {
+       struct uart_port        port;
+       struct timer_list       timer;
+       unsigned int            old_status;
+-      int                     txirq,rxirq,rtsirq;
++      int                     txirq, rxirq, rtsirq;
+       int                     have_rtscts:1;
+       struct clk              *clk;
+ };
+@@ -268,8 +268,8 @@ static void imx_stop_tx(struct uart_port
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+-      temp = readl(sport->port.membase + UCR1);
+-      writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
++      temp = __raw_readl(sport->port.membase + UCR1);
++      __raw_writel(temp & ~UCR1_TXMPTYEN, sport->port.membase + UCR1);
+ }
+ /*
+@@ -280,8 +280,8 @@ static void imx_stop_rx(struct uart_port
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+-      temp = readl(sport->port.membase + UCR2);
+-      writel(temp &~ UCR2_RXEN, sport->port.membase + UCR2);
++      temp = __raw_readl(sport->port.membase + UCR2);
++      __raw_writel(temp & ~UCR2_RXEN, sport->port.membase + UCR2);
+ }
+ /*
+@@ -298,12 +298,12 @@ static inline void imx_transmit_buffer(s
+ {
+       struct circ_buf *xmit = &sport->port.info->xmit;
+-      while (!(readl(sport->port.membase + UTS) & UTS_TXFULL)) {
++      while (!(__raw_readl(sport->port.membase + UTS) & UTS_TXFULL)) {
+               /* send xmit->buf[xmit->tail]
+                * out the port here */
+-              writel(xmit->buf[xmit->tail], sport->port.membase + URTX0);
+-              xmit->tail = (xmit->tail + 1) &
+-                       (UART_XMIT_SIZE - 1);
++              __raw_writel(xmit->buf[xmit->tail],
++                              sport->port.membase + URTX0);
++              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+               sport->port.icount.tx++;
+               if (uart_circ_empty(xmit))
+                       break;
+@@ -321,22 +321,22 @@ static void imx_start_tx(struct uart_por
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+-      temp = readl(sport->port.membase + UCR1);
+-      writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
++      temp = __raw_readl(sport->port.membase + UCR1);
++      __raw_writel(temp | UCR1_TXMPTYEN, sport->port.membase + UCR1);
+-      if (readl(sport->port.membase + UTS) & UTS_TXEMPTY)
++      if (__raw_readl(sport->port.membase + UTS) & UTS_TXEMPTY)
+               imx_transmit_buffer(sport);
+ }
+ static irqreturn_t imx_rtsint(int irq, void *dev_id)
+ {
+       struct imx_port *sport = dev_id;
+-      unsigned int val = readl(sport->port.membase + USR1) & USR1_RTSS;
++      unsigned int val = __raw_readl(sport->port.membase + USR1) & USR1_RTSS;
+       unsigned long flags;
+       spin_lock_irqsave(&sport->port.lock, flags);
+-      writel(USR1_RTSD, sport->port.membase + USR1);
++      __raw_writel(USR1_RTSD, sport->port.membase + USR1);
+       uart_handle_cts_change(&sport->port, !!val);
+       wake_up_interruptible(&sport->port.info->delta_msr_wait);
+@@ -350,11 +350,10 @@ static irqreturn_t imx_txint(int irq, vo
+       struct circ_buf *xmit = &sport->port.info->xmit;
+       unsigned long flags;
+-      spin_lock_irqsave(&sport->port.lock,flags);
+-      if (sport->port.x_char)
+-      {
++      spin_lock_irqsave(&sport->port.lock, flags);
++      if (sport->port.x_char) {
+               /* Send next char */
+-              writel(sport->port.x_char, sport->port.membase + URTX0);
++              __raw_writel(sport->port.x_char, sport->port.membase + URTX0);
+               goto out;
+       }
+@@ -369,37 +368,37 @@ static irqreturn_t imx_txint(int irq, vo
+               uart_write_wakeup(&sport->port);
+ out:
+-      spin_unlock_irqrestore(&sport->port.lock,flags);
++      spin_unlock_irqrestore(&sport->port.lock, flags);
+       return IRQ_HANDLED;
+ }
+ static irqreturn_t imx_rxint(int irq, void *dev_id)
+ {
+       struct imx_port *sport = dev_id;
+-      unsigned int rx,flg,ignored = 0;
++      unsigned int rx, flg, ignored = 0;
+       struct tty_struct *tty = sport->port.info->port.tty;
+       unsigned long flags, temp;
+-      spin_lock_irqsave(&sport->port.lock,flags);
++      spin_lock_irqsave(&sport->port.lock, flags);
+-      while (readl(sport->port.membase + USR2) & USR2_RDR) {
++      while (__raw_readl(sport->port.membase + USR2) & USR2_RDR) {
+               flg = TTY_NORMAL;
+               sport->port.icount.rx++;
+-              rx = readl(sport->port.membase + URXD0);
++              rx = __raw_readl(sport->port.membase + URXD0);
+-              temp = readl(sport->port.membase + USR2);
++              temp = __raw_readl(sport->port.membase + USR2);
+               if (temp & USR2_BRCD) {
+-                      writel(temp | USR2_BRCD, sport->port.membase + USR2);
++                      __raw_writel(temp | USR2_BRCD,
++                                      sport->port.membase + USR2);
+                       if (uart_handle_break(&sport->port))
+                               continue;
+               }
+-              if (uart_handle_sysrq_char
+-                          (&sport->port, (unsigned char)rx))
++              if (uart_handle_sysrq_char(&sport->port, (unsigned char)rx))
+                       continue;
+-              if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR) ) {
++              if (rx & (URXD_PRERR | URXD_OVRRUN | URXD_FRMERR)) {
+                       if (rx & URXD_PRERR)
+                               sport->port.icount.parity++;
+                       else if (rx & URXD_FRMERR)
+@@ -431,7 +430,7 @@ static irqreturn_t imx_rxint(int irq, vo
+       }
+ out:
+-      spin_unlock_irqrestore(&sport->port.lock,flags);
++      spin_unlock_irqrestore(&sport->port.lock, flags);
+       tty_flip_buffer_push(tty);
+       return IRQ_HANDLED;
+ }
+@@ -441,13 +440,13 @@ static irqreturn_t imx_int(int irq, void
+       struct imx_port *sport = dev_id;
+       unsigned int sts;
+-      sts = readl(sport->port.membase + USR1);
++      sts = __raw_readl(sport->port.membase + USR1);
+       if (sts & USR1_RRDY)
+               imx_rxint(irq, dev_id);
+       if (sts & USR1_TRDY &&
+-                      readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
++                      __raw_readl(sport->port.membase + UCR1) & UCR1_TXMPTYEN)
+               imx_txint(irq, dev_id);
+       if (sts & USR1_RTSD)
+@@ -463,7 +462,8 @@ static unsigned int imx_tx_empty(struct 
+ {
+       struct imx_port *sport = (struct imx_port *)port;
+-      return (readl(sport->port.membase + USR2) & USR2_TXDC) ?  TIOCSER_TEMT : 0;
++      return (__raw_readl(sport->port.membase + USR2) & USR2_TXDC) ?
++              TIOCSER_TEMT : 0;
+ }
+ /*
+@@ -471,29 +471,29 @@ static unsigned int imx_tx_empty(struct 
+  */
+ static unsigned int imx_get_mctrl(struct uart_port *port)
+ {
+-        struct imx_port *sport = (struct imx_port *)port;
+-        unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
++      struct imx_port *sport = (struct imx_port *)port;
++      unsigned int tmp = TIOCM_DSR | TIOCM_CAR;
+-        if (readl(sport->port.membase + USR1) & USR1_RTSS)
+-                tmp |= TIOCM_CTS;
++      if (__raw_readl(sport->port.membase + USR1) & USR1_RTSS)
++              tmp |= TIOCM_CTS;
+-        if (readl(sport->port.membase + UCR2) & UCR2_CTS)
+-                tmp |= TIOCM_RTS;
++      if (__raw_readl(sport->port.membase + UCR2) & UCR2_CTS)
++              tmp |= TIOCM_RTS;
+-        return tmp;
++      return tmp;
+ }
+ static void imx_set_mctrl(struct uart_port *port, unsigned int mctrl)
+ {
+-        struct imx_port *sport = (struct imx_port *)port;
++      struct imx_port *sport = (struct imx_port *)port;
+       unsigned long temp;
+-      temp = readl(sport->port.membase + UCR2) & ~UCR2_CTS;
++      temp = __raw_readl(sport->port.membase + UCR2) & ~UCR2_CTS;
+-        if (mctrl & TIOCM_RTS)
++      if (mctrl & TIOCM_RTS)
+               temp |= UCR2_CTS;
+-      writel(temp, sport->port.membase + UCR2);
++      __raw_writel(temp, sport->port.membase + UCR2);
+ }
+ /*
+@@ -506,12 +506,12 @@ static void imx_break_ctl(struct uart_po
+       spin_lock_irqsave(&sport->port.lock, flags);
+-      temp = readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
++      temp = __raw_readl(sport->port.membase + UCR1) & ~UCR1_SNDBRK;
+-      if ( break_state != 0 )
++      if (break_state != 0)
+               temp |= UCR1_SNDBRK;
+-      writel(temp, sport->port.membase + UCR1);
++      __raw_writel(temp, sport->port.membase + UCR1);
+       spin_unlock_irqrestore(&sport->port.lock, flags);
+ }
+@@ -531,17 +531,17 @@ static int imx_setup_ufcr(struct imx_por
+       ufcr_rfdiv = (clk_get_rate(sport->clk) + sport->port.uartclk / 2)
+                       / sport->port.uartclk;
+-      if(!ufcr_rfdiv)
++      if (!ufcr_rfdiv)
+               ufcr_rfdiv = 1;
+-      if(ufcr_rfdiv >= 7)
++      if (ufcr_rfdiv >= 7)
+               ufcr_rfdiv = 6;
+       else
+               ufcr_rfdiv = 6 - ufcr_rfdiv;
+       val |= UFCR_RFDIV & (ufcr_rfdiv << 7);
+-      writel(val, sport->port.membase + UFCR);
++      __raw_writel(val, sport->port.membase + UFCR);
+       return 0;
+ }
+@@ -557,8 +557,8 @@ static int imx_startup(struct uart_port 
+       /* disable the DREN bit (Data Ready interrupt enable) before
+        * requesting IRQs
+        */
+-      temp = readl(sport->port.membase + UCR4);
+-      writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
++      temp = __raw_readl(sport->port.membase + UCR4);
++      __raw_writel(temp & ~UCR4_DREN, sport->port.membase + UCR4);
+       /*
+        * Allocate the IRQ(s) i.MX1 has three interrupts whereas later
+@@ -576,8 +576,8 @@ static int imx_startup(struct uart_port 
+                       goto error_out2;
+               retval = request_irq(sport->rtsirq, imx_rtsint,
+-                           (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
+-                             IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
++                              (sport->rtsirq < MAX_INTERNAL_IRQ) ? 0 :
++                              IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING,
+                               DRIVER_NAME, sport);
+               if (retval)
+                       goto error_out3;
+@@ -593,28 +593,28 @@ static int imx_startup(struct uart_port 
+       /*
+        * Finally, clear and enable interrupts
+        */
+-      writel(USR1_RTSD, sport->port.membase + USR1);
++      __raw_writel(USR1_RTSD, sport->port.membase + USR1);
+-      temp = readl(sport->port.membase + UCR1);
++      temp = __raw_readl(sport->port.membase + UCR1);
+       temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
+-      writel(temp, sport->port.membase + UCR1);
++      __raw_writel(temp, sport->port.membase + UCR1);
+-      temp = readl(sport->port.membase + UCR2);
++      temp = __raw_readl(sport->port.membase + UCR2);
+       temp |= (UCR2_RXEN | UCR2_TXEN);
+-      writel(temp, sport->port.membase + UCR2);
++      __raw_writel(temp, sport->port.membase + UCR2);
+ #if defined CONFIG_ARCH_MX2 || defined CONFIG_ARCH_MX3
+-      temp = readl(sport->port.membase + UCR3);
++      temp = __raw_readl(sport->port.membase + UCR3);
+       temp |= UCR3_RXDMUXSEL;
+-      writel(temp, sport->port.membase + UCR3);
++      __raw_writel(temp, sport->port.membase + UCR3);
+ #endif
+       /*
+        * Enable modem status interrupts
+        */
+-      spin_lock_irqsave(&sport->port.lock,flags);
++      spin_lock_irqsave(&sport->port.lock, flags);
+       imx_enable_ms(&sport->port);
+-      spin_unlock_irqrestore(&sport->port.lock,flags);
++      spin_unlock_irqrestore(&sport->port.lock, flags);
+       return 0;
+@@ -652,14 +652,14 @@ static void imx_shutdown(struct uart_por
+        * Disable all interrupts, port and break condition.
+        */
+-      temp = readl(sport->port.membase + UCR1);
++      temp = __raw_readl(sport->port.membase + UCR1);
+       temp &= ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN);
+-      writel(temp, sport->port.membase + UCR1);
++      __raw_writel(temp, sport->port.membase + UCR1);
+ }
+ static void
+ imx_set_termios(struct uart_port *port, struct ktermios *termios,
+-                 struct ktermios *old)
++              struct ktermios *old)
+ {
+       struct imx_port *sport = (struct imx_port *)port;
+       unsigned long flags;
+@@ -680,7 +680,7 @@ imx_set_termios(struct uart_port *port, 
+        * We only support CS7 and CS8.
+        */
+       while ((termios->c_cflag & CSIZE) != CS7 &&
+-             (termios->c_cflag & CSIZE) != CS8) {
++              (termios->c_cflag & CSIZE) != CS8) {
+               termios->c_cflag &= ~CSIZE;
+               termios->c_cflag |= old_csize;
+               old_csize = CS8;
+@@ -692,7 +692,7 @@ imx_set_termios(struct uart_port *port, 
+               ucr2 = UCR2_SRST | UCR2_IRTS;
+       if (termios->c_cflag & CRTSCTS) {
+-              if( sport->have_rtscts ) {
++              if (sport->have_rtscts) {
+                       ucr2 &= ~UCR2_IRTS;
+                       ucr2 |= UCR2_CTSC;
+               } else {
+@@ -748,17 +748,17 @@ imx_set_termios(struct uart_port *port, 
+       /*
+        * disable interrupts and drain transmitter
+        */
+-      old_ucr1 = readl(sport->port.membase + UCR1);
+-      writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
++      old_ucr1 = __raw_readl(sport->port.membase + UCR1);
++      __raw_writel(old_ucr1 & ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+                       sport->port.membase + UCR1);
+-      while ( !(readl(sport->port.membase + USR2) & USR2_TXDC))
++      while (!(__raw_readl(sport->port.membase + USR2) & USR2_TXDC))
+               barrier();
+       /* then, disable everything */
+-      old_txrxen = readl(sport->port.membase + UCR2);
+-      writel(old_txrxen & ~( UCR2_TXEN | UCR2_RXEN),
+-                      sport->port.membase + UCR2);
++      old_txrxen = __raw_readl(sport->port.membase + UCR2);
++      __raw_writel(old_txrxen & ~(UCR2_TXEN | UCR2_RXEN),
++              sport->port.membase + UCR2);
+       old_txrxen &= (UCR2_TXEN | UCR2_RXEN);
+       div = sport->port.uartclk / (baud * 16);
+@@ -780,27 +780,27 @@ imx_set_termios(struct uart_port *port, 
+       if (denom > 0)
+               denom -= 1;
+-      writel(num, sport->port.membase + UBIR);
+-      writel(denom, sport->port.membase + UBMR);
++      __raw_writel(num, sport->port.membase + UBIR);
++      __raw_writel(denom, sport->port.membase + UBMR);
+       if (div == 7)
+               div = 6; /* 6 in RFDIV means divide by 7 */
+       else
+               div = 6 - div;
+-      ufcr = readl(sport->port.membase + UFCR);
+-      ufcr = (ufcr & (~UFCR_RFDIV)) |
+-          (div << 7);
+-      writel(ufcr, sport->port.membase + UFCR);
++      ufcr = __raw_readl(sport->port.membase + UFCR);
++      ufcr = (ufcr & ~UFCR_RFDIV) | (div << 7);
++      __raw_writel(ufcr, sport->port.membase + UFCR);
+ #ifdef ONEMS
+-      writel(sport->port.uartclk / div / 1000, sport->port.membase + ONEMS);
++      __raw_writel(sport->port.uartclk / div / 1000,
++                      sport->port.membase + ONEMS);
+ #endif
+-      writel(old_ucr1, sport->port.membase + UCR1);
++      __raw_writel(old_ucr1, sport->port.membase + UCR1);
+       /* set the parity, stop bits and data size */
+-      writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
++      __raw_writel(ucr2 | old_txrxen, sport->port.membase + UCR2);
+       if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
+               imx_enable_ms(&sport->port);
+@@ -854,7 +854,7 @@ static void imx_config_port(struct uart_
+       struct imx_port *sport = (struct imx_port *)port;
+       if (flags & UART_CONFIG_TYPE &&
+-          imx_request_port(&sport->port) == 0)
++                      imx_request_port(&sport->port) == 0)
+               sport->port.type = PORT_IMX;
+ }
+@@ -912,10 +912,10 @@ static void imx_console_putchar(struct u
+ {
+       struct imx_port *sport = (struct imx_port *)port;
+-      while (readl(sport->port.membase + UTS) & UTS_TXFULL)
++      while (__raw_readl(sport->port.membase + UTS) & UTS_TXFULL)
+               barrier();
+-      writel(ch, sport->port.membase + URTX0);
++      __raw_writel(ch, sport->port.membase + URTX0);
+ }
+ /*
+@@ -930,14 +930,14 @@ imx_console_write(struct console *co, co
+       /*
+        *      First, save UCR1/2 and then disable interrupts
+        */
+-      old_ucr1 = readl(sport->port.membase + UCR1);
+-      old_ucr2 = readl(sport->port.membase + UCR2);
++      old_ucr1 = __raw_readl(sport->port.membase + UCR1);
++      old_ucr2 = __raw_readl(sport->port.membase + UCR2);
+-      writel((old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN) &
++      __raw_writel((old_ucr1 | UCR1_UARTCLKEN | UCR1_UARTEN) &
+               ~(UCR1_TXMPTYEN | UCR1_RRDYEN | UCR1_RTSDEN),
+               sport->port.membase + UCR1);
+-      writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
++      __raw_writel(old_ucr2 | UCR2_TXEN, sport->port.membase + UCR2);
+       uart_console_write(&sport->port, s, count, imx_console_putchar);
+@@ -945,10 +945,11 @@ imx_console_write(struct console *co, co
+        *      Finally, wait for transmitter to become empty
+        *      and restore UCR1/2
+        */
+-      while (!(readl(sport->port.membase + USR2) & USR2_TXDC));
++      while (!(__raw_readl(sport->port.membase + USR2) & USR2_TXDC))
++              ;
+-      writel(old_ucr1, sport->port.membase + UCR1);
+-      writel(old_ucr2, sport->port.membase + UCR2);
++      __raw_writel(old_ucr1, sport->port.membase + UCR1);
++      __raw_writel(old_ucr2, sport->port.membase + UCR2);
+ }
+ /*
+@@ -957,16 +958,15 @@ imx_console_write(struct console *co, co
+  */
+ static void __init
+ imx_console_get_options(struct imx_port *sport, int *baud,
+-                         int *parity, int *bits)
++                      int *parity, int *bits)
+ {
+-
+-      if ( readl(sport->port.membase + UCR1) | UCR1_UARTEN ) {
++      if (__raw_readl(sport->port.membase + UCR1) | UCR1_UARTEN) {
+               /* ok, the port was enabled */
+-              unsigned int ucr2, ubir,ubmr, uartclk;
++              unsigned int ucr2, ubir, ubmr, uartclk;
+               unsigned int baud_raw;
+               unsigned int ucfr_rfdiv;
+-              ucr2 = readl(sport->port.membase + UCR2);
++              ucr2 = __raw_readl(sport->port.membase + UCR2);
+               *parity = 'n';
+               if (ucr2 & UCR2_PREN) {
+@@ -981,10 +981,11 @@ imx_console_get_options(struct imx_port 
+               else
+                       *bits = 7;
+-              ubir = readl(sport->port.membase + UBIR) & 0xffff;
+-              ubmr = readl(sport->port.membase + UBMR) & 0xffff;
++              ubir = __raw_readl(sport->port.membase + UBIR) & 0xffff;
++              ubmr = __raw_readl(sport->port.membase + UBMR) & 0xffff;
+-              ucfr_rfdiv = (readl(sport->port.membase + UFCR) & UFCR_RFDIV) >> 7;
++              ucfr_rfdiv = (__raw_readl(sport->port.membase + UFCR) &
++                              UFCR_RFDIV) >> 7;
+               if (ucfr_rfdiv == 6)
+                       ucfr_rfdiv = 7;
+               else
+@@ -993,7 +994,8 @@ imx_console_get_options(struct imx_port 
+               uartclk = clk_get_rate(sport->clk);
+               uartclk /= ucfr_rfdiv;
+-              {       /*
++              {
++                      /*
+                        * The next code provides exact computation of
+                        *   baud_raw = round(((uartclk/16) * (ubir + 1)) / (ubmr + 1))
+                        * without need of float support or long long division,
+@@ -1008,7 +1010,7 @@ imx_console_get_options(struct imx_port 
+                       *baud = (baud_raw + 50) / 100 * 100;
+               }
+-              if(*baud != baud_raw)
++              if (*baud != baud_raw)
+                       printk(KERN_INFO "Serial: Console IMX rounded baud rate from %d to %d\n",
+                               baud_raw, *baud);
+       }
+@@ -1028,9 +1030,13 @@ imx_console_setup(struct console *co, ch
+        * if so, search for the first available port that does have
+        * console support.
+        */
+-      if (co->index == -1 || co->index >= ARRAY_SIZE(imx_ports))
++      if (co->index < 0 || co->index >= ARRAY_SIZE(imx_ports))
+               co->index = 0;
+-      sport = imx_ports[co->index];
++      do {
++              sport = imx_ports[co->index];
++      } while (sport == NULL && ++co->index < ARRAY_SIZE(imx_ports));
++      if (!sport)
++              return -ENODEV;
+       if (options)
+               uart_parse_options(options, &baud, &parity, &bits, &flow);
+@@ -1070,22 +1076,22 @@ static struct uart_driver imx_reg = {
+ static int serial_imx_suspend(struct platform_device *dev, pm_message_t state)
+ {
+-        struct imx_port *sport = platform_get_drvdata(dev);
++      struct imx_port *sport = platform_get_drvdata(dev);
+-        if (sport)
+-                uart_suspend_port(&imx_reg, &sport->port);
++      if (sport)
++              uart_suspend_port(&imx_reg, &sport->port);
+-        return 0;
++      return 0;
+ }
+ static int serial_imx_resume(struct platform_device *dev)
+ {
+-        struct imx_port *sport = platform_get_drvdata(dev);
++      struct imx_port *sport = platform_get_drvdata(dev);
+-        if (sport)
+-                uart_resume_port(&imx_reg, &sport->port);
++      if (sport)
++              uart_resume_port(&imx_reg, &sport->port);
+-        return 0;
++      return 0;
+ }
+ static int serial_imx_probe(struct platform_device *pdev)
+@@ -1141,7 +1147,7 @@ static int serial_imx_probe(struct platf
+       imx_ports[pdev->id] = sport;
+       pdata = pdev->dev.platform_data;
+-      if(pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
++      if (pdata && (pdata->flags & IMXUART_HAVE_RTSCTS))
+               sport->have_rtscts = 1;
+       if (pdata->init) {
+@@ -1150,13 +1156,13 @@ static int serial_imx_probe(struct platf
+                       goto clkput;
+       }
+-      uart_add_one_port(&imx_reg, &sport->port);
+       platform_set_drvdata(pdev, &sport->port);
++      uart_add_one_port(&imx_reg, &sport->port);
+       return 0;
+ clkput:
+-      clk_put(sport->clk);
+       clk_disable(sport->clk);
++      clk_put(sport->clk);
+ unmap:
+       iounmap(sport->port.membase);
+ free:
+@@ -1172,15 +1178,12 @@ static int serial_imx_remove(struct plat
+       pdata = pdev->dev.platform_data;
+-      platform_set_drvdata(pdev, NULL);
+-
+-      if (sport) {
+-              uart_remove_one_port(&imx_reg, &sport->port);
+-              clk_put(sport->clk);
+-      }
++      uart_remove_one_port(&imx_reg, &sport->port);
+       clk_disable(sport->clk);
++      clk_put(sport->clk);
++      platform_set_drvdata(pdev, NULL);
+       if (pdata->exit)
+               pdata->exit(pdev);
+@@ -1191,13 +1194,13 @@ static int serial_imx_remove(struct plat
+ }
+ static struct platform_driver serial_imx_driver = {
+-        .probe          = serial_imx_probe,
+-        .remove         = serial_imx_remove,
++      .probe          = serial_imx_probe,
++      .remove         = serial_imx_remove,
+       .suspend        = serial_imx_suspend,
+       .resume         = serial_imx_resume,
+       .driver         = {
+-              .name   = "imx-uart",
++              .name   = "imx-uart",
+               .owner  = THIS_MODULE,
+       },
+ };
+@@ -1209,14 +1212,14 @@ static int __init imx_serial_init(void)
+       printk(KERN_INFO "Serial: IMX driver\n");
+       ret = uart_register_driver(&imx_reg);
+-      if (ret)
++      if (ret != 0)
+               return ret;
+       ret = platform_driver_register(&serial_imx_driver);
+       if (ret != 0)
+               uart_unregister_driver(&imx_reg);
+-      return 0;
++      return ret;
+ }
+ static void __exit imx_serial_exit(void)
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/spi/Kconfig linux-2.6.28-karo/drivers/spi/Kconfig
+--- linux-2.6.28/drivers/spi/Kconfig   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/spi/Kconfig      2009-03-11 13:16:24.000000000 +0100
+@@ -135,6 +135,55 @@ config SPI_MPC83xx
+         technology. This driver uses a simple set of shift registers for data
+         (opposed to the CPM based descriptor model).
++config SPI_MXC
++      tristate "MXC CSPI controller as SPI Master"
++      depends on ARCH_MXC && SPI_MASTER
++      select SPI_BITBANG
++      help
++        This implements the SPI master mode using MXC CSPI.
++
++config SPI_MXC_TEST_LOOPBACK
++      bool "LOOPBACK Testing of CSPIs"
++      depends on SPI_MXC
++      default n
++
++config SPI_MXC_SELECT1
++      bool "CSPI1"
++      depends on SPI_MXC
++      default y
++
++config SPI_MXC_SELECT2
++      bool "CSPI2"
++      depends on SPI_MXC
++      default n
++
++config SPI_MXC_SELECT3
++      bool "CSPI3"
++      depends on SPI_MXC && (ARCH_MX3 || ARCH_MX2)
++      default n
++
++choice
++        prompt "SPI controller hardware revision"
++        default SPI_MXC_REV0
++        depends on SPI_MXC
++        config SPI_MXC_REV0
++                bool "Revision 0"
++                help
++                  hardware revision 0, mostly on MX27
++        config SPI_MXC_REV4
++                bool "Revision 4"
++                help
++                  hardware revision 4, mostly on MX31
++        config SPI_MXC_REV5
++                bool "Revision 5"
++                help
++                  hardware revision 5
++        config SPI_MXC_REV7
++                bool "Revision 7"
++                help
++                  hardware revision 7
++endchoice
++
+ config SPI_OMAP_UWIRE
+       tristate "OMAP1 MicroWire"
+       depends on ARCH_OMAP1
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/spi/Makefile linux-2.6.28-karo/drivers/spi/Makefile
+--- linux-2.6.28/drivers/spi/Makefile  2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/spi/Makefile     2009-03-11 13:16:24.000000000 +0100
+@@ -24,6 +24,7 @@ obj-$(CONFIG_SPI_OMAP24XX)           += omap2_mcs
+ obj-$(CONFIG_SPI_ORION)                       += orion_spi.o
+ obj-$(CONFIG_SPI_MPC52xx_PSC)         += mpc52xx_psc_spi.o
+ obj-$(CONFIG_SPI_MPC83xx)             += spi_mpc83xx.o
++obj-$(CONFIG_SPI_MXC)                 += mxc_spi.o
+ obj-$(CONFIG_SPI_S3C24XX_GPIO)                += spi_s3c24xx_gpio.o
+ obj-$(CONFIG_SPI_S3C24XX)             += spi_s3c24xx.o
+ obj-$(CONFIG_SPI_TXX9)                        += spi_txx9.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/spi/mxc_spi.c linux-2.6.28-karo/drivers/spi/mxc_spi.c
+--- linux-2.6.28/drivers/spi/mxc_spi.c 1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/spi/mxc_spi.c    2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,748 @@
++/*
++ * Copyright 2004-2007 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright (C) 2008 Juergen Beisert
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ */
++
++#include <linux/completion.h>
++#include <linux/platform_device.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/irq.h>
++#include <linux/module.h>
++#include <linux/delay.h>
++#include <linux/types.h>
++#include <linux/clk.h>
++
++#include <linux/spi/spi.h>
++#include <linux/spi/spi_bitbang.h>
++
++#include <asm/irq.h>
++#include <asm/io.h>
++#include <mach/gpio.h>
++#include <mach/imx_spi.h>
++
++#ifdef CONFIG_SPI_MXC_TEST_LOOPBACK
++struct spi_chip_info {
++      int lb_enable;
++};
++
++static struct spi_chip_info lb_chip_info = {
++      .lb_enable = 1,
++};
++
++static struct spi_board_info loopback_info[] = {
++#ifdef CONFIG_SPI_MXC_SELECT1
++      {
++       .modalias = "loopback_spi",
++       .controller_data = &lb_chip_info,
++       .irq = 0,
++       .max_speed_hz = 4000000,
++       .bus_num = 0,
++       .chip_select = 4,
++       },
++#endif
++#ifdef CONFIG_SPI_MXC_SELECT2
++      {
++       .modalias = "loopback_spi",
++       .controller_data = &lb_chip_info,
++       .irq = 0,
++       .max_speed_hz = 4000000,
++       .bus_num = 1,
++       .chip_select = 4,
++       },
++#endif
++#ifdef CONFIG_SPI_MXC_SELECT3
++      {
++       .modalias = "loopback_spi",
++       .controller_data = &lb_chip_info,
++       .irq = 0,
++       .max_speed_hz = 4000000,
++       .bus_num = 2,
++       .chip_select = 4,
++       },
++#endif
++};
++#endif
++
++static struct mxc_spi_unique_def spi_ver_0_7 = {
++      .intr_bit_shift = MXC_CSPIINT_IRQSHIFT_0_7,
++      .cs_shift = MXC_CSPICTRL_CSSHIFT_0_7,
++      .bc_shift = MXC_CSPICTRL_BCSHIFT_0_7,
++      .bc_mask = MXC_CSPICTRL_BCMASK_0_7,
++      .drctrl_shift = MXC_CSPICTRL_DRCTRLSHIFT_0_7,
++      .xfer_complete = MXC_CSPISTAT_TC_0_7,
++      .bc_overflow = MXC_CSPISTAT_BO_0_7,
++};
++
++static struct mxc_spi_unique_def spi_ver_0_5 = {
++      .intr_bit_shift = MXC_CSPIINT_IRQSHIFT_0_5,
++      .cs_shift = MXC_CSPICTRL_CSSHIFT_0_5,
++      .bc_shift = MXC_CSPICTRL_BCSHIFT_0_5,
++      .bc_mask = MXC_CSPICTRL_BCMASK_0_5,
++      .drctrl_shift = MXC_CSPICTRL_DRCTRLSHIFT_0_5,
++      .xfer_complete = MXC_CSPISTAT_TC_0_5,
++      .bc_overflow = MXC_CSPISTAT_BO_0_5,
++};
++
++static struct mxc_spi_unique_def spi_ver_0_4 = {
++      .intr_bit_shift = MXC_CSPIINT_IRQSHIFT_0_4,
++      .cs_shift = MXC_CSPICTRL_CSSHIFT_0_4,
++      .bc_shift = MXC_CSPICTRL_BCSHIFT_0_4,
++      .bc_mask = MXC_CSPICTRL_BCMASK_0_4,
++      .drctrl_shift = MXC_CSPICTRL_DRCTRLSHIFT_0_4,
++      .xfer_complete = MXC_CSPISTAT_TC_0_4,
++      .bc_overflow = MXC_CSPISTAT_BO_0_4,
++};
++
++static struct mxc_spi_unique_def spi_ver_0_0 = {
++      .intr_bit_shift = MXC_CSPIINT_IRQSHIFT_0_0,
++      .cs_shift = MXC_CSPICTRL_CSSHIFT_0_0,
++      .bc_shift = MXC_CSPICTRL_BCSHIFT_0_0,
++      .bc_mask = MXC_CSPICTRL_BCMASK_0_0,
++      .drctrl_shift = MXC_CSPICTRL_DRCTRLSHIFT_0_0,
++      .xfer_complete = MXC_CSPISTAT_TC_0_0,
++      .bc_overflow = MXC_CSPISTAT_BO_0_0,
++};
++
++struct mxc_spi;
++/*
++ * Structure to group together all the data buffers and functions
++ * used in data transfers.
++ */
++struct mxc_spi_xfer {
++      const void *tx_buf;     /* Transmit buffer. */
++      void *rx_buf;   /* Receive buffer. */
++      unsigned int count;     /* Data transfered count. */
++      void (*rx_get) (struct mxc_spi *, u32 val); /* Function to read the FIFO data to rx_buf. */
++      u32(*tx_get) (struct mxc_spi *);        /* Function to get the data to be written to FIFO. */
++};
++
++/*
++ * This structure is a way for the low level driver to define their own
++ * spi_master structure. This structure includes the core spi_master
++ * structure that is provided by Linux SPI Framework/driver as an
++ * element and has other elements that are specifically required by this
++ * low-level driver.
++ */
++struct mxc_spi {
++      struct spi_bitbang mxc_bitbang; /* SPI Master and a simple I/O queue runner. */
++      struct completion xfer_done;    /* Completion flags used in data transfers. */
++      struct mxc_spi_xfer transfer;   /* Data transfer structure. */
++      struct resource *res;   /* Resource structure, which will maintain base addresses and IRQs. */
++      void *base;     /* Base address of CSPI, used in readl and writel. */
++      int irq;        /* CSPI IRQ number. */
++      struct clk *clk;        /* CSPI Clock id. */
++      /*!
++       * CSPI input clock SCLK.
++       */
++      unsigned long spi_ipg_clk;
++      /*!
++       * CSPI registers' bit pattern.
++       */
++      struct mxc_spi_unique_def *spi_ver_def;
++};
++
++#define MXC_SPI_BUF_RX(type)  \
++void mxc_spi_buf_rx_##type(struct mxc_spi *master_drv_data, u32 val)\
++{\
++      type *rx = master_drv_data->transfer.rx_buf;\
++      *rx++ = (type)val;\
++      master_drv_data->transfer.rx_buf = rx;\
++}
++
++#define MXC_SPI_BUF_TX(type)    \
++u32 mxc_spi_buf_tx_##type(struct mxc_spi *master_drv_data)\
++{\
++      u32 val;\
++      const type *tx = master_drv_data->transfer.tx_buf;\
++      val = *tx++;\
++      master_drv_data->transfer.tx_buf = tx;\
++      return val;\
++}
++MXC_SPI_BUF_RX(u8)
++    MXC_SPI_BUF_TX(u8)
++    MXC_SPI_BUF_RX(u16)
++    MXC_SPI_BUF_TX(u16)
++    MXC_SPI_BUF_RX(u32)
++    MXC_SPI_BUF_TX(u32)
++
++static int spi_enable_interrupt(struct mxc_spi *master_data, unsigned int irqs)
++{
++      if (irqs & ~((1 << master_data->spi_ver_def->intr_bit_shift) - 1)) {
++              return -1;
++      }
++
++      writel((irqs | readl(master_data->base + MXC_CSPIINT)),
++                   master_data->base + MXC_CSPIINT);
++
++      return 0;
++}
++
++static int spi_disable_interrupt(struct mxc_spi *master_data, unsigned int irqs)
++{
++      if (irqs & ~((1 << master_data->spi_ver_def->intr_bit_shift) - 1)) {
++              return -1;
++      }
++
++      writel((~irqs & readl(master_data->base + MXC_CSPIINT)),
++              master_data->base + MXC_CSPIINT);
++      return 0;
++}
++
++static unsigned int spi_find_baudrate(struct mxc_spi *master_data,
++                                    unsigned int baud)
++{
++      unsigned int divisor;
++      unsigned int shift = 0;
++
++      /* Calculate required divisor (rounded) */
++      divisor = (master_data->spi_ipg_clk + baud / 2) / baud;
++      while (divisor >>= 1)
++              shift++;
++      MXC_CSPICTRL_ADJUST_SHIFT(shift);
++      if (shift > MXC_CSPICTRL_MAXDATRATE)
++              shift = MXC_CSPICTRL_MAXDATRATE;
++
++      return shift << MXC_CSPICTRL_DATASHIFT;
++}
++
++static unsigned int spi_get_rx_data(void *base)
++{
++      return readl(base + MXC_CSPIRXDATA);
++}
++
++static void spi_put_tx_data(void *base, unsigned int val)
++{
++      unsigned int ctrl_reg;
++
++      writel(val, base + MXC_CSPITXDATA);
++
++      ctrl_reg = readl(base + MXC_CSPICTRL);
++
++      ctrl_reg |= MXC_CSPICTRL_XCH;
++
++      writel(ctrl_reg, base + MXC_CSPICTRL);
++
++      return;
++}
++
++void mxc_spi_chipselect(struct spi_device *spi, int is_active)
++{
++      struct mxc_spi *master_drv_data;
++      struct mxc_spi_xfer *ptransfer;
++      struct mxc_spi_unique_def *spi_ver_def;
++      unsigned int ctrl_reg;
++      unsigned int ctrl_mask;
++      unsigned int xfer_len;
++
++      if (is_active == BITBANG_CS_INACTIVE) {
++              /*Need to deselect the slave */
++              return;
++      }
++
++      /* Get the master controller driver data from spi device's master */
++
++      master_drv_data = spi_master_get_devdata(spi->master);
++      spi_ver_def = master_drv_data->spi_ver_def;
++
++      xfer_len = spi->bits_per_word;
++
++      /* Control Register Settings for transfer to this slave */
++
++      ctrl_reg = readl(master_drv_data->base + MXC_CSPICTRL);
++
++      ctrl_mask =
++          (MXC_CSPICTRL_LOWPOL | MXC_CSPICTRL_PHA | MXC_CSPICTRL_HIGHSSPOL |
++           MXC_CSPICTRL_CSMASK << spi_ver_def->cs_shift |
++           MXC_CSPICTRL_DATAMASK << MXC_CSPICTRL_DATASHIFT |
++           spi_ver_def->bc_mask << spi_ver_def->bc_shift);
++      ctrl_reg &= ~ctrl_mask;
++
++      ctrl_reg |=
++          ((spi->chip_select & MXC_CSPICTRL_CSMASK) << spi_ver_def->cs_shift);
++      ctrl_reg |= spi_find_baudrate(master_drv_data, spi->max_speed_hz);
++      ctrl_reg |=
++          (((xfer_len - 1) & spi_ver_def->bc_mask) << spi_ver_def->bc_shift);
++      if (spi->mode & SPI_CPHA)
++              ctrl_reg |= MXC_CSPICTRL_PHA;
++      if (!(spi->mode & SPI_CPOL))
++              ctrl_reg |= MXC_CSPICTRL_LOWPOL;
++      if (spi->mode & SPI_CS_HIGH)
++              ctrl_reg |= MXC_CSPICTRL_HIGHSSPOL;
++
++      writel(ctrl_reg, master_drv_data->base + MXC_CSPICTRL);
++
++      /* Initialize the functions for transfer */
++      ptransfer = &master_drv_data->transfer;
++      if (xfer_len <= 8) {
++              ptransfer->rx_get = mxc_spi_buf_rx_u8;
++              ptransfer->tx_get = mxc_spi_buf_tx_u8;
++      } else if (xfer_len <= 16) {
++              ptransfer->rx_get = mxc_spi_buf_rx_u16;
++              ptransfer->tx_get = mxc_spi_buf_tx_u16;
++      } else if (xfer_len <= 32) {
++              ptransfer->rx_get = mxc_spi_buf_rx_u32;
++              ptransfer->tx_get = mxc_spi_buf_tx_u32;
++      }
++#ifdef CONFIG_SPI_MXC_TEST_LOOPBACK
++      {
++              struct spi_chip_info *lb_chip =
++                      spi->controller_data;
++              if (!lb_chip)
++                      writel(0, master_drv_data->base + MXC_CSPITEST);
++              else if (lb_chip->lb_enable)
++                      writel(MXC_CSPITEST_LBC,
++                                   master_drv_data->base + MXC_CSPITEST);
++      }
++#endif
++      return;
++}
++
++static irqreturn_t mxc_spi_isr(int irq, void *dev_id)
++{
++      struct mxc_spi *master_drv_data = dev_id;
++      irqreturn_t ret = IRQ_NONE;
++      unsigned int status;
++
++      /* Read the interrupt status register to determine the source */
++      status = readl(master_drv_data->base + MXC_CSPISTAT);
++
++      /* Rx is given higher priority - Handle it first */
++      if (status & MXC_CSPISTAT_RR) {
++              u32 rx_tmp = spi_get_rx_data(master_drv_data->base);
++
++              if (master_drv_data->transfer.rx_buf)
++                      master_drv_data->transfer.rx_get(master_drv_data,
++                                                       rx_tmp);
++
++              ret = IRQ_HANDLED;
++      }
++
++      master_drv_data->transfer.count--;
++      /* Handle the Tx now */
++      if (master_drv_data->transfer.count) {
++              if (master_drv_data->transfer.tx_buf) {
++                      u32 tx_tmp =
++                          master_drv_data->transfer.tx_get(master_drv_data);
++
++                      spi_put_tx_data(master_drv_data->base, tx_tmp);
++              }
++      } else {
++              complete(&master_drv_data->xfer_done);
++      }
++
++      return ret;
++}
++
++int mxc_spi_setup(struct spi_device *spi)
++{
++      struct mxc_spi *master_data = spi_master_get_devdata(spi->master);
++
++      if ((spi->max_speed_hz < 0)
++              || (spi->max_speed_hz > (master_data->spi_ipg_clk / 4))) {
++              dev_err(&spi->dev, "Cannot set required SPI clock speed."
++                              " Requested: %uHz, possible: %luHz\n",
++                              spi->max_speed_hz, master_data->spi_ipg_clk / 4);
++              return -EINVAL;
++      }
++
++      if (!spi->bits_per_word)
++              spi->bits_per_word = 8;
++
++      pr_debug("%s: mode %d, %u bpw, %d hz\n", __FUNCTION__,
++               spi->mode, spi->bits_per_word, spi->max_speed_hz);
++
++      return 0;
++}
++
++int mxc_spi_transfer(struct spi_device *spi, struct spi_transfer *t)
++{
++      struct mxc_spi *master_drv_data = NULL;
++
++      /* Get the master controller driver data from spi device's master */
++
++      master_drv_data = spi_master_get_devdata(spi->master);
++
++      /* Modify the Tx, Rx, Count */
++
++      master_drv_data->transfer.tx_buf = t->tx_buf;
++      master_drv_data->transfer.rx_buf = t->rx_buf;
++      master_drv_data->transfer.count = t->len;
++      INIT_COMPLETION(master_drv_data->xfer_done);
++
++      /* Enable the Rx Interrupts */
++
++      spi_enable_interrupt(master_drv_data, MXC_CSPIINT_RREN);
++
++      /* Perform single Tx transaction */
++
++      spi_put_tx_data(master_drv_data->base,
++                      master_drv_data->transfer.tx_get(master_drv_data));
++
++      /* Wait for transfer completion */
++
++      wait_for_completion(&master_drv_data->xfer_done);
++
++      /* Disable the Rx Interrupts */
++
++      spi_disable_interrupt(master_drv_data, MXC_CSPIINT_RREN);
++
++      return t->len - master_drv_data->transfer.count;
++}
++
++void mxc_spi_cleanup(struct spi_device *spi)
++{
++      return;
++}
++
++static int mxc_spi_probe(struct platform_device *pdev)
++{
++      struct mxc_spi_master *mxc_platform_info;
++      struct spi_master *master;
++      struct mxc_spi *master_drv_data;
++      unsigned int spi_ver;
++      int ret = -ENODEV;
++
++      dev_dbg(&pdev->dev, "Enter: %s\n", __FUNCTION__);
++
++      /* Get the platform specific data for this master device */
++
++      mxc_platform_info = pdev->dev.platform_data;
++      if (!mxc_platform_info) {
++              dev_err(&pdev->dev, "can't get the platform data for CSPI\n");
++              return -ENODEV;
++      }
++
++      /* Allocate SPI master controller */
++
++      master = spi_alloc_master(&pdev->dev, sizeof(struct mxc_spi));
++      if (!master) {
++              dev_err(&pdev->dev, "can't alloc for spi_master\n");
++              return -ENOMEM;
++      }
++
++      /* Set this device's driver data to master */
++
++      platform_set_drvdata(pdev, master);
++
++      /* Set this master's data from platform_info */
++
++      master->bus_num = pdev->id;
++      master->num_chipselect = mxc_platform_info->maxchipselect;
++
++      /* Set the master controller driver data for this master */
++
++      master_drv_data = spi_master_get_devdata(master);
++      if (master_drv_data == NULL)
++              goto err;
++      master_drv_data->mxc_bitbang.master = spi_master_get(master);
++
++      /* Set the master bitbang data */
++
++      master_drv_data->mxc_bitbang.chipselect = mxc_spi_chipselect;
++      master_drv_data->mxc_bitbang.txrx_bufs = mxc_spi_transfer;
++      master_drv_data->mxc_bitbang.master->setup = mxc_spi_setup;
++      master_drv_data->mxc_bitbang.master->cleanup = mxc_spi_cleanup;
++
++      /* Initialize the completion object */
++
++      init_completion(&master_drv_data->xfer_done);
++
++      /* Set the master controller register addresses and irqs */
++
++      master_drv_data->res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!master_drv_data->res) {
++              dev_err(&pdev->dev, "can't get platform resource for CSPI%d\n",
++                      master->bus_num);
++              ret = -ENOMEM;
++              goto err;
++      }
++
++      if (!request_mem_region(master_drv_data->res->start,
++                              master_drv_data->res->end -
++                              master_drv_data->res->start + 1, pdev->name)) {
++              dev_err(&pdev->dev, "request_mem_region failed for CSPI%d\n",
++                      master->bus_num);
++              ret = -EBUSY;
++              goto err;
++      }
++
++      master_drv_data->base = ioremap(master_drv_data->res->start,
++                                      master_drv_data->res->end -
++                                      master_drv_data->res->start + 1);
++
++      if (!master_drv_data->base) {
++              dev_err(&pdev->dev, "Cannot map iomem for CSPI%d\n",
++                      master->bus_num);
++              ret = -EINVAL;
++              goto err1;
++      }
++
++      ret = platform_get_irq(pdev, 0);
++      if (ret < 0) {
++              dev_err(&pdev->dev, "can't get IRQ for CSPI%d\n",
++                      master->bus_num);
++              goto err2;
++      }
++      master_drv_data->irq = ret;
++
++      /* Register for SPI Interrupt */
++
++      ret = request_irq(master_drv_data->irq, mxc_spi_isr,
++                        0, "CSPI_IRQ", master_drv_data);
++      if (ret != 0) {
++              dev_err(&pdev->dev, "request_irq failed for CSPI%d\n",
++                      master->bus_num);
++              goto err2;
++      }
++
++      /* Setup any GPIO active */
++      if (mxc_platform_info->init)
++              mxc_platform_info->init(pdev);
++
++      /* Identify SPI version */
++
++      spi_ver = mxc_platform_info->spi_version;
++      if (spi_ver == 7) {
++              master_drv_data->spi_ver_def = &spi_ver_0_7;
++      } else if (spi_ver == 5) {
++              master_drv_data->spi_ver_def = &spi_ver_0_5;
++      } else if (spi_ver == 4) {
++              master_drv_data->spi_ver_def = &spi_ver_0_4;
++      } else if (spi_ver == 0) {
++              master_drv_data->spi_ver_def = &spi_ver_0_0;
++      }
++
++      /* Enable the CSPI Clock, CSPI Module, set as a master */
++
++      master_drv_data->clk = clk_get(&pdev->dev, "cspi_clk");
++      clk_enable(master_drv_data->clk);
++      master_drv_data->spi_ipg_clk = clk_get_rate(master_drv_data->clk);
++
++      writel(0x00008000, master_drv_data->base + MXC_CSPICTRL); /* reset default */
++      writel(MXC_CSPICTRL_ENABLE | MXC_CSPICTRL_MASTER,
++                   master_drv_data->base + MXC_CSPICTRL);
++      writel(MXC_CSPIPERIOD_32KHZ,
++                   master_drv_data->base + MXC_CSPIPERIOD);
++      writel(0, master_drv_data->base + MXC_CSPIINT);
++
++      /* Start the SPI Master Controller driver */
++
++      ret = spi_bitbang_start(&master_drv_data->mxc_bitbang);
++      if (ret != 0) {
++              dev_err(&pdev->dev, "Cannot start bitbang driver\n");
++              goto err3;
++      }
++
++      printk(KERN_INFO "CSPI: %s-%d probed\n", pdev->name, pdev->id);
++
++#ifdef CONFIG_SPI_MXC_TEST_LOOPBACK
++      {
++              int i;
++              struct spi_board_info *bi = &loopback_info[0];
++              for (i = 0; i < ARRAY_SIZE(loopback_info); i++, bi++) {
++                      if (bi->bus_num != master->bus_num)
++                              continue;
++
++                      dev_info(&pdev->dev,
++                               "registering loopback device '%s'\n",
++                               bi->modalias);
++
++                      spi_new_device(master, bi);
++              }
++      }
++#endif
++      return ret;
++
++err3:
++      clk_disable(master_drv_data->clk);
++      clk_put(master_drv_data->clk);
++      if (mxc_platform_info->exit)
++              mxc_platform_info->exit(pdev);
++      free_irq(master_drv_data->irq, master_drv_data);
++err2:
++      iounmap(master_drv_data->base);
++err1:
++      release_mem_region(pdev->resource[0].start,
++                      pdev->resource[0].end - pdev->resource[0].start + 1);
++err:
++      spi_master_put(master);
++      kfree(master);
++      platform_set_drvdata(pdev, NULL);
++      return ret;
++}
++
++static int mxc_spi_remove(struct platform_device *pdev)
++{
++      struct spi_master *master = platform_get_drvdata(pdev);
++      struct mxc_spi_master *mxc_platform_info =
++              pdev->dev.platform_data;
++
++      if (master) {
++              struct mxc_spi *master_drv_data =
++                  spi_master_get_devdata(master);
++
++              if (mxc_platform_info->exit)
++                      mxc_platform_info->exit(pdev);
++              clk_disable(master_drv_data->clk);
++              /* clk_put(master_drv_data->clk); */    /* FIXME required? */
++
++              /* Disable the CSPI module */
++
++              writel(MXC_CSPICTRL_DISABLE,
++                           master_drv_data->base + MXC_CSPICTRL);
++
++              spi_bitbang_stop(&master_drv_data->mxc_bitbang);
++
++              /* free resources */
++              spi_master_put(master);
++              free_irq(master_drv_data->irq, master_drv_data);
++              iounmap(master_drv_data->base);
++              release_mem_region(master_drv_data->res->start,
++                                      master_drv_data->res->end -
++                                      master_drv_data->res->start + 1);
++      }
++
++      printk(KERN_INFO "CSPI: %s-%d removed\n", pdev->name, pdev->id);
++      platform_set_drvdata(pdev, NULL);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int suspend_devices(struct device *dev, void *pm_message)
++{
++      pm_message_t *state = pm_message;
++
++      if (dev->power.power_state.event != state->event) {
++              dev_warn(dev, "mismatch in pm state request\n");
++              return -1;
++      }
++
++      return 0;
++}
++
++static int spi_bitbang_suspend(struct spi_bitbang *bitbang)
++{
++      unsigned long flags;
++      unsigned limit = 500;
++
++      spin_lock_irqsave(&bitbang->lock, flags);
++      //bitbang->shutdown = 0;
++      while (!list_empty(&bitbang->queue) && limit--) {
++              spin_unlock_irqrestore(&bitbang->lock, flags);
++
++              dev_dbg(&bitbang->master->dev, "wait for queue\n");
++              msleep(10);
++
++              spin_lock_irqsave(&bitbang->lock, flags);
++      }
++      if (!list_empty(&bitbang->queue)) {
++              dev_err(&bitbang->master->dev, "queue didn't empty\n");
++              return -EBUSY;
++      }
++      spin_unlock_irqrestore(&bitbang->lock, flags);
++
++      //bitbang->shutdown = 1;
++
++      return 0;
++}
++
++static void spi_bitbang_resume(struct spi_bitbang *bitbang)
++{
++      spin_lock_init(&bitbang->lock);
++      INIT_LIST_HEAD(&bitbang->queue);
++
++      bitbang->busy = 0;
++      //bitbang->shutdown = 0;
++}
++
++static int mxc_spi_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      struct spi_master *master = platform_get_drvdata(pdev);
++      struct mxc_spi *master_drv_data = spi_master_get_devdata(master);
++      struct mxc_spi_master *mxc_platform_info =
++              pdev->dev.platform_data;
++      int ret = 0;
++
++      if (device_for_each_child(&pdev->dev, &state, suspend_devices) != 0) {
++              dev_warn(&pdev->dev, "suspend aborted\n");
++              return -EINVAL;
++      }
++
++      spi_bitbang_suspend(&master_drv_data->mxc_bitbang);
++      writel(MXC_CSPICTRL_DISABLE,
++                   master_drv_data->base + MXC_CSPICTRL);
++
++      clk_disable(master_drv_data->clk);
++      if (mxc_platform_info->exit)
++              mxc_platform_info->exit(pdev);
++
++      return ret;
++}
++
++static int mxc_spi_resume(struct platform_device *pdev)
++{
++      struct spi_master *master = platform_get_drvdata(pdev);
++      struct mxc_spi *master_drv_data = spi_master_get_devdata(master);
++      struct mxc_spi_master *mxc_platform_info =
++              pdev->dev.platform_data;
++
++      if (mxc_platform_info->init)
++              mxc_platform_info->init(pdev);
++      clk_enable(master_drv_data->clk);
++
++      spi_bitbang_resume(&master_drv_data->mxc_bitbang);
++      writel(MXC_CSPICTRL_ENABLE | MXC_CSPICTRL_MASTER,
++                   master_drv_data->base + MXC_CSPICTRL);
++
++      return 0;
++}
++#else
++# define mxc_spi_suspend  NULL
++# define mxc_spi_resume   NULL
++#endif /* CONFIG_PM */
++
++static struct platform_driver mxc_spi_driver = {
++      .driver = {
++              .name = "mxc_spi",
++              .owner = THIS_MODULE,
++      },
++      .probe = mxc_spi_probe,
++      .remove = mxc_spi_remove,
++      .suspend = mxc_spi_suspend,
++      .resume = mxc_spi_resume,
++};
++
++static int __init mxc_spi_init(void)
++{
++      pr_debug("Registering the SPI Controller Driver\n");
++      return platform_driver_register(&mxc_spi_driver);
++}
++
++static void __exit mxc_spi_exit(void)
++{
++      pr_debug("Unregistering the SPI Controller Driver\n");
++      platform_driver_unregister(&mxc_spi_driver);
++}
++
++subsys_initcall(mxc_spi_init);
++module_exit(mxc_spi_exit);
++
++MODULE_DESCRIPTION("SPI Master Controller driver");
++MODULE_AUTHOR("Freescale Semiconductor, Inc.");
++MODULE_LICENSE("GPL");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/usb/Kconfig linux-2.6.28-karo/drivers/usb/Kconfig
+--- linux-2.6.28/drivers/usb/Kconfig   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/usb/Kconfig      2009-03-11 13:16:24.000000000 +0100
+@@ -56,6 +56,7 @@ config USB_ARCH_HAS_EHCI
+       default y if PPC_83xx
+       default y if SOC_AU1200
+       default y if ARCH_IXP4XX
++      default y if ARCH_MXC
+       default PCI
+ # ARM SA1111 chips have a non-PCI based "OHCI-compatible" USB host interface.
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/usb/host/Kconfig linux-2.6.28-karo/drivers/usb/host/Kconfig
+--- linux-2.6.28/drivers/usb/host/Kconfig      2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/usb/host/Kconfig 2009-03-11 13:16:24.000000000 +0100
+@@ -96,6 +96,13 @@ config USB_EHCI_HCD_PPC_OF
+         Enables support for the USB controller present on the PowerPC
+         OpenFirmware platform bus.
++config USB_EHCI_MXC
++      bool "Support for Freescale on-chip EHCI USB controller"
++      depends on USB_EHCI_HCD && ARCH_MXC
++      select USB_EHCI_ROOT_HUB_TT
++      ---help---
++        Variation of ARC USB block used in some Freescale chips.
++
+ config USB_ISP116X_HCD
+       tristate "ISP116X HCD support"
+       depends on USB
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/usb/host/ehci-hcd.c linux-2.6.28-karo/drivers/usb/host/ehci-hcd.c
+--- linux-2.6.28/drivers/usb/host/ehci-hcd.c   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/usb/host/ehci-hcd.c      2009-03-11 13:16:24.000000000 +0100
+@@ -1009,6 +1009,11 @@ MODULE_LICENSE ("GPL");
+ #define       PLATFORM_DRIVER         ehci_fsl_driver
+ #endif
++#ifdef CONFIG_USB_EHCI_MXC
++#include "ehci-mxc.c"
++#define PLATFORM_DRIVER               ehci_mxc_driver
++#endif
++
+ #ifdef CONFIG_SOC_AU1200
+ #include "ehci-au1xxx.c"
+ #define       PLATFORM_DRIVER         ehci_hcd_au1xxx_driver
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/usb/host/ehci-mxc.c linux-2.6.28-karo/drivers/usb/host/ehci-mxc.c
+--- linux-2.6.28/drivers/usb/host/ehci-mxc.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/usb/host/ehci-mxc.c      2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,241 @@
++/*
++ * Copyright (c) 2008 Sascha Hauer <s.hauer@pengutronix.de>, Pengutronix
++ *
++ * 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.
++ *
++ */
++
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <mach/mxc_ehci.h>
++
++/* called during probe() after chip reset completes */
++static int ehci_mxc_setup(struct usb_hcd *hcd)
++{
++      struct ehci_hcd *ehci = hcd_to_ehci(hcd);
++      int retval;
++
++      /* EHCI registers start at offset 0x100 */
++      ehci->caps = hcd->regs + 0x100;
++      ehci->regs = hcd->regs + 0x100 +
++          HC_LENGTH(ehci_readl(ehci, &ehci->caps->hc_capbase));
++      dbg_hcs_params(ehci, "reset");
++      dbg_hcc_params(ehci, "reset");
++
++      /* cache this readonly data; minimize chip reads */
++      ehci->hcs_params = ehci_readl(ehci, &ehci->caps->hcs_params);
++
++      retval = ehci_halt(ehci);
++      if (retval)
++              return retval;
++
++      /* data structure init */
++      retval = ehci_init(hcd);
++      if (retval)
++              return retval;
++
++      hcd->has_tt = 1;
++
++      ehci->sbrn = 0x20;
++
++      ehci_reset(ehci);
++
++      ehci_port_power(ehci, 0);
++      return 0;
++}
++
++static const struct hc_driver ehci_mxc_hc_driver = {
++      .description = hcd_name,
++      .product_desc = "Freescale On-Chip EHCI Host Controller",
++      .hcd_priv_size = sizeof(struct ehci_hcd),
++
++      /*
++       * generic hardware linkage
++       */
++      .irq = ehci_irq,
++      .flags = HCD_USB2 | HCD_MEMORY,
++
++      /*
++       * basic lifecycle operations
++       */
++      .reset = ehci_mxc_setup,
++      .start = ehci_run,
++      .stop = ehci_stop,
++      .shutdown = ehci_shutdown,
++
++      /*
++       * managing i/o requests and associated device resources
++       */
++      .urb_enqueue = ehci_urb_enqueue,
++      .urb_dequeue = ehci_urb_dequeue,
++      .endpoint_disable = ehci_endpoint_disable,
++
++      /*
++       * scheduling support
++       */
++      .get_frame_number = ehci_get_frame,
++
++      /*
++       * root hub support
++       */
++      .hub_status_data = ehci_hub_status_data,
++      .hub_control = ehci_hub_control,
++      .bus_suspend = ehci_bus_suspend,
++      .bus_resume = ehci_bus_resume,
++      .relinquish_port = ehci_relinquish_port,
++      .port_handed_over = ehci_port_handed_over,
++};
++
++static int ehci_mxc_drv_probe(struct platform_device *pdev)
++{
++      struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
++      struct usb_hcd *hcd;
++      struct resource *res;
++      int irq, ret, temp;
++      struct clk *usbclk, *ahbclk;
++
++      dev_info(&pdev->dev, "initializing i.MX USB Controller\n");
++
++      /* Need platform data for setup */
++      if (!pdata) {
++              dev_err(&pdev->dev,
++                      "No platform data for %s.\n", pdev->dev.bus_id);
++              return -ENODEV;
++      }
++
++      irq = platform_get_irq(pdev, 0);
++
++      hcd = usb_create_hcd(&ehci_mxc_hc_driver, &pdev->dev, pdev->dev.bus_id);
++      if (!hcd) {
++              ret = -ENOMEM;
++              goto err1;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!res) {
++              dev_err(&pdev->dev,
++                      "Found HC with no register addr. Check %s setup!\n",
++                      pdev->dev.bus_id);
++              ret = -ENODEV;
++              goto err1;
++      }
++
++      hcd->rsrc_start = res->start;
++      hcd->rsrc_len = resource_size(res);
++
++      if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
++              dev_dbg(&pdev->dev, "controller already in use\n");
++              ret = -EBUSY;
++              goto err1;
++      }
++
++      hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++      if (!hcd->regs) {
++              dev_err(&pdev->dev, "error mapping memory\n");
++              ret = -EFAULT;
++              goto err2;
++      }
++
++      ahbclk = clk_get(NULL, "usb_ahb_clk");
++      if (IS_ERR(ahbclk)) {
++              ret = PTR_ERR(ahbclk);
++              printk(KERN_ERR "Failed to get usb_ahb_clk: %d\n", ret);
++              goto err3;
++      }
++      clk_enable(ahbclk);
++
++      usbclk = clk_get(NULL, "usb_clk");
++      if (IS_ERR(usbclk)) {
++              ret = PTR_ERR(usbclk);
++              printk(KERN_ERR "Failed to get usb_clk: %d\n", ret);
++              goto err4;
++      }
++      clk_enable(usbclk);
++
++      if (pdata->init) {
++              ret = pdata->init(pdev);
++              if (ret) {
++                      dev_err(&pdev->dev, "platform init failed\n");
++                      goto err5;
++              }
++      }
++
++      /* Set to Host mode */
++      temp = readl(hcd->regs + 0x1a8);
++      writel(temp | 0x3, hcd->regs + 0x1a8);
++
++      ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
++      if (ret)
++              goto err6;
++
++      platform_set_drvdata(pdev, hcd);
++
++      return 0;
++err6:
++      if (pdata->exit)
++              pdata->exit(pdev);
++err5:
++      clk_disable(usbclk);
++      clk_put(usbclk);
++err4:
++      clk_disable(ahbclk);
++      clk_put(ahbclk);
++err3:
++      iounmap(hcd->regs);
++err2:
++      release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++err1:
++      usb_put_hcd(hcd);
++      return ret;
++}
++
++static int ehci_mxc_drv_remove(struct platform_device *pdev)
++{
++      struct usb_hcd *hcd = platform_get_drvdata(pdev);
++      struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
++      struct clk *usbclk, *ahbclk;
++
++      usb_remove_hcd(hcd);
++      iounmap(hcd->regs);
++      release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
++      usb_put_hcd(hcd);
++      platform_set_drvdata(pdev, NULL);
++
++      if (pdata->exit)
++              pdata->exit(pdev);
++
++      usbclk = clk_get(NULL, "usb_clk");
++      if (!IS_ERR(usbclk)) {
++              clk_disable(usbclk);
++              clk_put(usbclk);
++      }
++      ahbclk = clk_get(NULL, "usb_ahb_clk");
++      if (!IS_ERR(ahbclk)) {
++              clk_disable(ahbclk);
++              clk_put(ahbclk);
++      }
++      return 0;
++}
++
++MODULE_ALIAS("platform:mxc-ehci");
++
++static struct platform_driver ehci_mxc_driver = {
++      .probe = ehci_mxc_drv_probe,
++      .remove = ehci_mxc_drv_remove,
++      .shutdown = usb_hcd_platform_shutdown,
++      .driver = {
++                 .name = "mxc-ehci",
++      },
++};
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/video/Kconfig linux-2.6.28-karo/drivers/video/Kconfig
+--- linux-2.6.28/drivers/video/Kconfig 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/video/Kconfig    2009-03-11 13:16:24.000000000 +0100
+@@ -397,7 +397,7 @@ config FB_SA1100
+ config FB_IMX
+       tristate "Motorola i.MX LCD support"
+-      depends on FB && ARM && ARCH_IMX
++      depends on FB && ARM && (ARCH_IMX || ARCH_MX2)
+       select FB_CFB_FILLRECT
+       select FB_CFB_COPYAREA
+       select FB_CFB_IMAGEBLIT
+@@ -2115,6 +2115,18 @@ config FB_PRE_INIT_FB
+         Select this option if display contents should be inherited as set by
+         the bootloader.
++config FB_MXC
++      tristate "MXC Framebuffer support"
++      depends on FB && MXC_IPU
++      select FB_CFB_FILLRECT
++      select FB_CFB_COPYAREA
++      select FB_CFB_IMAGEBLIT
++      default y
++      help
++        This is a framebuffer device for the i.MX31 LCD Controller. So
++        far only synchronous displays are supported. If you plan to use
++        an LCD display with your i.MX31 system, say Y here.
++
+ source "drivers/video/omap/Kconfig"
+ source "drivers/video/backlight/Kconfig"
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/video/Makefile linux-2.6.28-karo/drivers/video/Makefile
+--- linux-2.6.28/drivers/video/Makefile        2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/video/Makefile   2009-03-11 13:16:24.000000000 +0100
+@@ -132,6 +132,7 @@ obj-$(CONFIG_FB_VGA16)            += vga
+ obj-$(CONFIG_FB_OF)               += offb.o
+ obj-$(CONFIG_FB_BF54X_LQ043)    += bf54x-lq043fb.o
+ obj-$(CONFIG_FB_BFIN_T350MCQB)          += bfin-t350mcqb-fb.o
++obj-$(CONFIG_FB_MXC)            += mxcfb.o
+ # the test framebuffer is last
+ obj-$(CONFIG_FB_VIRTUAL)          += vfb.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/video/imxfb.c linux-2.6.28-karo/drivers/video/imxfb.c
+--- linux-2.6.28/drivers/video/imxfb.c 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/video/imxfb.c    2009-03-11 13:16:24.000000000 +0100
+@@ -1,6 +1,4 @@
+ /*
+- *  linux/drivers/video/imxfb.c
+- *
+  *  Freescale i.MX Frame Buffer device driver
+  *
+  *  Copyright (C) 2004 Sascha Hauer, Pengutronix
+@@ -16,8 +14,6 @@
+  *    linux-arm-kernel@lists.arm.linux.org.uk
+  */
+-//#define DEBUG 1
+-
+ #include <linux/module.h>
+ #include <linux/kernel.h>
+ #include <linux/errno.h>
+@@ -30,11 +26,11 @@
+ #include <linux/init.h>
+ #include <linux/ioport.h>
+ #include <linux/cpufreq.h>
++#include <linux/clk.h>
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
++#include <linux/io.h>
+-#include <mach/hardware.h>
+-#include <asm/io.h>
+ #include <mach/imxfb.h>
+ /*
+@@ -42,23 +38,170 @@
+  */
+ #define DEBUG_VAR 1
+-#include "imxfb.h"
++#define DRIVER_NAME "imx-fb"
++
++#define LCDC_SSA      0x00
++
++#define LCDC_SIZE     0x04
++#define SIZE_XMAX(x)  ((((x) >> 4) & 0x3f) << 20)
++#ifdef CONFIG_ARCH_IMX
++#define SIZE_YMAX(y)  ((y) & 0x1ff)
++#else
++#define SIZE_YMAX(y)  ((y) & 0x3ff)
++#endif
++
++#define LCDC_VPW      0x08
++#define VPW_VPW(x)    ((x) & 0x3ff)
++
++#define LCDC_CPOS     0x0C
++#define CPOS_CC1      (1<<31)
++#define CPOS_CC0      (1<<30)
++#define CPOS_OP               (1<<28)
++#define CPOS_CXP(x)   (((x) & 3ff) << 16)
++#ifdef CONFIG_ARCH_IMX
++#define CPOS_CYP(y)   ((y) & 0x1ff)
++#else
++#define CPOS_CYP(y)   ((y) & 0x3ff)
++#endif
++
++#define LCDC_LCWHB    0x10
++#define LCWHB_BK_EN   (1<<31)
++#define LCWHB_CW(w)   (((w) & 0x1f) << 24)
++#define LCWHB_CH(h)   (((h) & 0x1f) << 16)
++#define LCWHB_BD(x)   ((x) & 0xff)
++
++#define LCDC_LCHCC    0x14
++#ifdef CONFIG_ARCH_IMX
++#define LCHCC_CUR_COL_R(r) (((r) & 0x1f) << 11)
++#define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 5)
++#define LCHCC_CUR_COL_B(b) ((b) & 0x1f)
++#else
++#define LCHCC_CUR_COL_R(r) (((r) & 0x3f) << 12)
++#define LCHCC_CUR_COL_G(g) (((g) & 0x3f) << 6)
++#define LCHCC_CUR_COL_B(b) ((b) & 0x3f)
++#endif
++
++#define LCDC_PCR      0x18
++
++#define LCDC_HCR      0x1C
++#define HCR_H_WIDTH(x)        (((x) & 0x3f) << 26)
++#define HCR_H_WAIT_1(x)       (((x) & 0xff) << 8)
++#define HCR_H_WAIT_2(x)       ((x) & 0xff)
++
++#define LCDC_VCR      0x20
++#define VCR_V_WIDTH(x)        (((x) & 0x3f) << 26)
++#define VCR_V_WAIT_1(x)       (((x) & 0xff) << 8)
++#define VCR_V_WAIT_2(x)       ((x) & 0xff)
++
++#define LCDC_POS      0x24
++#define POS_POS(x)    ((x) & 1f)
++
++#define LCDC_LSCR1    0x28
++/* bit fields in imxfb.h */
++
++#define LCDC_PWMR     0x2C
++/* bit fields in imxfb.h */
++
++#define LCDC_DMACR    0x30
++/* bit fields in imxfb.h */
++
++#define LCDC_RMCR     0x34
++#define RMCR_LCDC_EN  (1<<1)
++#define RMCR_SELF_REF (1<<0)
++
++#define LCDC_LCDICR   0x38
++#define LCDICR_INT_SYN        (1<<2)
++#define LCDICR_INT_CON        (1)
++
++#define LCDC_LCDISR   0x40
++#define LCDISR_UDR_ERR        (1<<3)
++#define LCDISR_ERR_RES        (1<<2)
++#define LCDISR_EOF    (1<<1)
++#define LCDISR_BOF    (1<<0)
+-static struct imxfb_rgb def_rgb_16 = {
+-      .red    = { .offset = 8,  .length = 4, },
+-      .green  = { .offset = 4,  .length = 4, },
+-      .blue   = { .offset = 0,  .length = 4, },
+-      .transp = { .offset = 0,  .length = 0, },
++/*
++ * These are the bitfields for each
++ * display depth that we support.
++ */
++struct imxfb_rgb {
++      struct fb_bitfield      red;
++      struct fb_bitfield      green;
++      struct fb_bitfield      blue;
++      struct fb_bitfield      transp;
+ };
+-static struct imxfb_rgb def_rgb_8 = {
+-      .red    = { .offset = 0,  .length = 8, },
+-      .green  = { .offset = 0,  .length = 8, },
+-      .blue   = { .offset = 0,  .length = 8, },
+-      .transp = { .offset = 0,  .length = 0, },
++struct imxfb_info {
++      struct platform_device  *pdev;
++      void __iomem            *regs;
++      struct clk              *clk;
++      char                    enabled;
++
++      u_int                   max_bpp;
++      u_int                   max_xres;
++      u_int                   max_yres;
++
++      /*
++       * These are the addresses we mapped
++       * the framebuffer memory region to.
++       */
++      dma_addr_t              map_dma;
++      u_char                  *map_cpu;
++      u_int                   map_size;
++
++      u_char                  *screen_cpu;
++      dma_addr_t              screen_dma;
++      u_int                   palette_size;
++
++      dma_addr_t              dbar1;
++      dma_addr_t              dbar2;
++
++      u_int                   pcr;
++      u_int                   pwmr;
++      u_int                   lscr1;
++      u_int                   dmacr;
++      u_int                   cmap_inverse:1,
++                              cmap_static:1,
++                              unused:30;
++
++      void (*lcd_power)(int);
++      void (*backlight_power)(int);
+ };
+-static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info);
++#define IMX_NAME      "IMX"
++
++/*
++ * Minimum X and Y resolutions
++ */
++#define MIN_XRES      64
++#define MIN_YRES      64
++
++static struct imxfb_rgb def_rgb_18 = {
++      .red    = {.offset = 18, .length = 6,},
++      .green  = {.offset = 10, .length = 6,},
++      .blue   = {.offset = 2, .length = 6,},
++      .transp = {.offset = 0, .length = 0,},
++};
++
++static struct imxfb_rgb def_rgb_16_tft = {
++      .red    = {.offset = 11, .length = 5,},
++      .green  = {.offset = 5, .length = 6,},
++      .blue   = {.offset = 0, .length = 5,},
++      .transp = {.offset = 0, .length = 0,},
++};
++
++static struct imxfb_rgb def_rgb_16_stn = {
++      .red    = {.offset = 8, .length = 4,},
++      .green  = {.offset = 4, .length = 4,},
++      .blue   = {.offset = 0, .length = 4,},
++      .transp = {.offset = 0, .length = 0,},
++};
++
++static struct imxfb_rgb def_rgb_8 = {
++      .red    = {.offset = 0, .length = 8,},
++      .green  = {.offset = 0, .length = 8,},
++      .blue   = {.offset = 0, .length = 8,},
++      .transp = {.offset = 0, .length = 0,},
++};
+ static inline u_int chan_to_field(u_int chan, struct fb_bitfield *bf)
+ {
+@@ -67,10 +210,8 @@ static inline u_int chan_to_field(u_int 
+       return chan << bf->offset;
+ }
+-#define LCDC_PALETTE(x) __REG2(IMX_LCDC_BASE+0x800, (x)<<2)
+-static int
+-imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
+-                     u_int trans, struct fb_info *info)
++static int imxfb_setpalettereg(u_int regno, u_int red, u_int green, u_int blue,
++              u_int trans, struct fb_info *info)
+ {
+       struct imxfb_info *fbi = info->par;
+       u_int val, ret = 1;
+@@ -81,14 +222,13 @@ imxfb_setpalettereg(u_int regno, u_int r
+                     (CNVT_TOHW(green,4) << 4) |
+                     CNVT_TOHW(blue,  4);
+-              LCDC_PALETTE(regno) = val;
++              writel(val, fbi->regs + 0x800 + (regno << 2));
+               ret = 0;
+       }
+       return ret;
+ }
+-static int
+-imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
++static int imxfb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
+                  u_int trans, struct fb_info *info)
+ {
+       struct imxfb_info *fbi = info->par;
+@@ -148,11 +288,10 @@ imxfb_setcolreg(u_int regno, u_int red, 
+  *    yres, xres_virtual, yres_virtual, xoffset, yoffset, grayscale,
+  *    bitfields, horizontal timing, vertical timing.
+  */
+-static int
+-imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
++static int imxfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ {
+       struct imxfb_info *fbi = info->par;
+-      int rgbidx;
++      struct imxfb_rgb *rgb;
+       if (var->xres < MIN_XRES)
+               var->xres = MIN_XRES;
+@@ -167,24 +306,29 @@ imxfb_check_var(struct fb_var_screeninfo
+       pr_debug("var->bits_per_pixel=%d\n", var->bits_per_pixel);
+       switch (var->bits_per_pixel) {
++      case 32:
++              rgb = &def_rgb_18;
++              break;
+       case 16:
+-              rgbidx = RGB_16;
++      default:
++              if (readl(fbi->regs + LCDC_PCR) & PCR_TFT)
++                      rgb = &def_rgb_16_tft;
++              else
++                      rgb = &def_rgb_16_stn;
+               break;
+       case 8:
+-              rgbidx = RGB_8;
++              rgb = &def_rgb_8;
+               break;
+-      default:
+-              rgbidx = RGB_16;
+       }
+       /*
+        * Copy the RGB parameters for this display
+        * from the machine specific parameters.
+        */
+-      var->red    = fbi->rgb[rgbidx]->red;
+-      var->green  = fbi->rgb[rgbidx]->green;
+-      var->blue   = fbi->rgb[rgbidx]->blue;
+-      var->transp = fbi->rgb[rgbidx]->transp;
++      var->red    = rgb->red;
++      var->green  = rgb->green;
++      var->blue   = rgb->blue;
++      var->transp = rgb->transp;
+       pr_debug("RGBT length = %d:%d:%d:%d\n",
+               var->red.length, var->green.length, var->blue.length,
+@@ -206,9 +350,7 @@ static int imxfb_set_par(struct fb_info 
+       struct imxfb_info *fbi = info->par;
+       struct fb_var_screeninfo *var = &info->var;
+-      pr_debug("set_par\n");
+-
+-      if (var->bits_per_pixel == 16)
++      if (var->bits_per_pixel == 16 || var->bits_per_pixel == 32)
+               info->fix.visual = FB_VISUAL_TRUECOLOR;
+       else if (!fbi->cmap_static)
+               info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+@@ -221,49 +363,72 @@ static int imxfb_set_par(struct fb_info 
+               info->fix.visual = FB_VISUAL_STATIC_PSEUDOCOLOR;
+       }
+-      info->fix.line_length = var->xres_virtual *
+-                                var->bits_per_pixel / 8;
++      info->fix.line_length = var->xres_virtual * var->bits_per_pixel / 8;
+       fbi->palette_size = var->bits_per_pixel == 8 ? 256 : 16;
+-      imxfb_activate_var(var, info);
++      if (var->bits_per_pixel == 16)
++              fb_dealloc_cmap(&info->cmap);
++      else
++              fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);
+       return 0;
+ }
+ static void imxfb_enable_controller(struct imxfb_info *fbi)
+ {
+-      pr_debug("Enabling LCD controller\n");
+-
+-      /* initialize LCDC */
+-      LCDC_RMCR &= ~RMCR_LCDC_EN;             /* just to be safe... */
+-
+-      LCDC_SSA        = fbi->screen_dma;
+-      /* physical screen start address            */
+-      LCDC_VPW        = VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4);
++      struct imx_fb_platform_data *pdata = fbi->pdev->dev.platform_data;
++      int ret;
+-      LCDC_POS        = 0x00000000;   /* panning offset 0 (0 pixel offset)        */
++      if (!fbi->enabled) {
++              if (clk_enable(fbi->clk) != 0)
++                      printk("Warning: Could not enable clock!");
++              pr_debug("LCD clock enabled\n");
++
++              if (pdata->init) {
++                      ret = (pdata->init)(fbi->pdev);
++                      pr_debug("GPIOs enabled\n");
++                      if (ret != 0)
++                              pr_err("Failing to enable LCD pins\n");
++              }
+-      /* disable hardware cursor */
+-      LCDC_CPOS       &= ~(CPOS_CC0 | CPOS_CC1);
++              if (pdata->lcd_power) {
++                      pdata->lcd_power(1);
++                      pr_debug("Display's power enabled\n");
++              }
+-      LCDC_RMCR = RMCR_LCDC_EN;
++              if (pdata->backlight_power) {
++                      pdata->backlight_power(1);
++                      pr_debug("Backlight's power enabled\n");
++              }
+-      if(fbi->backlight_power)
+-              fbi->backlight_power(1);
+-      if(fbi->lcd_power)
+-              fbi->lcd_power(1);
++              fbi->enabled = 1;
++      }
+ }
+ static void imxfb_disable_controller(struct imxfb_info *fbi)
+ {
+-      pr_debug("Disabling LCD controller\n");
++      struct imx_fb_platform_data *pdata = fbi->pdev->dev.platform_data;
++      int ret;
++
++      if (fbi->enabled) {
++              if (pdata->backlight_power)
++                      pdata->backlight_power(0);
++              if (pdata->lcd_power)
++                      pdata->lcd_power(0);
+-      if(fbi->backlight_power)
+-              fbi->backlight_power(0);
+-      if(fbi->lcd_power)
+-              fbi->lcd_power(0);
++#ifdef CONFIG_ARCH_IMX
++              writel(0, fbi->regs + LCDC_RMCR);       /* for IMX only */
++#endif
++              clk_disable(fbi->clk);
++
++              if (pdata->exit) {
++                      ret = (pdata->exit)(fbi->pdev);
++                      if (ret != 0)
++                              pr_err("Failed to disable LCD pins\n");
++              }
+-      LCDC_RMCR = 0;
++              fbi->enabled = 0;
++      }
+ }
+ static int imxfb_blank(int blank, struct fb_info *info)
+@@ -298,114 +463,68 @@ static struct fb_ops imxfb_ops = {
+       .fb_blank       = imxfb_blank,
+ };
+-/*
+- * imxfb_activate_var():
+- *    Configures LCD Controller based on entries in var parameter.  Settings are
+- *    only written to the controller if changes were made.
+- */
+-static int imxfb_activate_var(struct fb_var_screeninfo *var, struct fb_info *info)
+-{
+-      struct imxfb_info *fbi = info->par;
+-      pr_debug("var: xres=%d hslen=%d lm=%d rm=%d\n",
+-              var->xres, var->hsync_len,
+-              var->left_margin, var->right_margin);
+-      pr_debug("var: yres=%d vslen=%d um=%d bm=%d\n",
+-              var->yres, var->vsync_len,
+-              var->upper_margin, var->lower_margin);
+-
+-#if DEBUG_VAR
+-      if (var->xres < 16        || var->xres > 1024)
+-              printk(KERN_ERR "%s: invalid xres %d\n",
+-                      info->fix.id, var->xres);
+-      if (var->hsync_len < 1    || var->hsync_len > 64)
+-              printk(KERN_ERR "%s: invalid hsync_len %d\n",
+-                      info->fix.id, var->hsync_len);
+-      if (var->left_margin > 255)
+-              printk(KERN_ERR "%s: invalid left_margin %d\n",
+-                      info->fix.id, var->left_margin);
+-      if (var->right_margin > 255)
+-              printk(KERN_ERR "%s: invalid right_margin %d\n",
+-                      info->fix.id, var->right_margin);
+-      if (var->yres < 1 || var->yres > 511)
+-              printk(KERN_ERR "%s: invalid yres %d\n",
+-                      info->fix.id, var->yres);
+-      if (var->vsync_len > 100)
+-              printk(KERN_ERR "%s: invalid vsync_len %d\n",
+-                      info->fix.id, var->vsync_len);
+-      if (var->upper_margin > 63)
+-              printk(KERN_ERR "%s: invalid upper_margin %d\n",
+-                      info->fix.id, var->upper_margin);
+-      if (var->lower_margin > 255)
+-              printk(KERN_ERR "%s: invalid lower_margin %d\n",
+-                      info->fix.id, var->lower_margin);
+-#endif
+-
+-      LCDC_HCR        = HCR_H_WIDTH(var->hsync_len) |
+-                        HCR_H_WAIT_1(var->left_margin) |
+-                        HCR_H_WAIT_2(var->right_margin);
+-
+-      LCDC_VCR        = VCR_V_WIDTH(var->vsync_len) |
+-                        VCR_V_WAIT_1(var->upper_margin) |
+-                        VCR_V_WAIT_2(var->lower_margin);
+-
+-      LCDC_SIZE       = SIZE_XMAX(var->xres) | SIZE_YMAX(var->yres);
+-      LCDC_PCR        = fbi->pcr;
+-      LCDC_PWMR       = fbi->pwmr;
+-      LCDC_LSCR1      = fbi->lscr1;
+-      LCDC_DMACR      = fbi->dmacr;
+-
+-      return 0;
+-}
+-
+-static void imxfb_setup_gpio(struct imxfb_info *fbi)
++/* enable the LCD controller with basic setup for the connected display. */
++static void imxfb_setup_display(struct imxfb_info *fbi)
+ {
+-      int width;
++      u32 pixel_clk, pcr;
++      struct imx_fb_platform_data *pinfo = fbi->pdev->dev.platform_data;
+-      LCDC_RMCR       &= ~(RMCR_LCDC_EN | RMCR_SELF_REF);
++#ifdef CONFIG_ARCH_IMX
++      writel(readl(fbi->regs + LCDC_RMCR) & ~RMCR_LCDC_EN,
++              fbi->regs + LCDC_RMCR); /* just to be safe... */
++#endif
+-      if( fbi->pcr & PCR_TFT )
+-              width = 16;
+-      else
+-              width = 1 << ((fbi->pcr >> 28) & 0x3);
++      /* physical screen start address */
++      writel(fbi->screen_dma, fbi->regs + LCDC_SSA);
+-      switch(width) {
+-      case 16:
+-              imx_gpio_mode(PD30_PF_LD15);
+-              imx_gpio_mode(PD29_PF_LD14);
+-              imx_gpio_mode(PD28_PF_LD13);
+-              imx_gpio_mode(PD27_PF_LD12);
+-              imx_gpio_mode(PD26_PF_LD11);
+-              imx_gpio_mode(PD25_PF_LD10);
+-              imx_gpio_mode(PD24_PF_LD9);
+-              imx_gpio_mode(PD23_PF_LD8);
+-      case 8:
+-              imx_gpio_mode(PD22_PF_LD7);
+-              imx_gpio_mode(PD21_PF_LD6);
+-              imx_gpio_mode(PD20_PF_LD5);
+-              imx_gpio_mode(PD19_PF_LD4);
+-      case 4:
+-              imx_gpio_mode(PD18_PF_LD3);
+-              imx_gpio_mode(PD17_PF_LD2);
+-      case 2:
+-              imx_gpio_mode(PD16_PF_LD1);
+-      case 1:
+-              imx_gpio_mode(PD15_PF_LD0);
+-      }
+-
+-      /* initialize GPIOs */
+-      imx_gpio_mode(PD6_PF_LSCLK);
+-      imx_gpio_mode(PD11_PF_CONTRAST);
+-      imx_gpio_mode(PD14_PF_FLM_VSYNC);
+-      imx_gpio_mode(PD13_PF_LP_HSYNC);
+-      imx_gpio_mode(PD12_PF_ACD_OE);
+-
+-      /* These are only needed for Sharp HR TFT displays */
+-      if (fbi->pcr & PCR_SHARP) {
+-              imx_gpio_mode(PD7_PF_REV);
+-              imx_gpio_mode(PD8_PF_CLS);
+-              imx_gpio_mode(PD9_PF_PS);
+-              imx_gpio_mode(PD10_PF_SPL_SPR);
+-      }
++      /* dimension of this display */
++      writel(SIZE_XMAX(pinfo->xres) | SIZE_YMAX(pinfo->yres),
++                      fbi->regs + LCDC_SIZE);
++
++      /* virtual page width */
++      writel(VPW_VPW(fbi->max_xres * fbi->max_bpp / 8 / 4),
++              fbi->regs + LCDC_VPW);
++
++      /* setup the pixel clock */
++      pixel_clk = clk_get_rate(fbi->clk);
++
++      pcr = (pixel_clk + ((pinfo->pixclock * 1000UL) / 2)) / (pinfo->pixclock * 1000UL);
++      if (--pcr > 0x3F) {
++              pcr = 0x3F;
++              printk("Must limit pixel clock to %luHz\n", clk_get_rate(fbi->clk) / pcr);
++      }
++
++      /* add sync polarities */
++      pcr |= fbi->pcr & ~0x3F;
++      writel(pcr, fbi->regs + LCDC_PCR);
++
++      /* setup sync behaviour */
++      writel(HCR_H_WIDTH(pinfo->hsync_len - 1) |
++              HCR_H_WAIT_1(pinfo->right_margin - 1) |
++              HCR_H_WAIT_2(pinfo->left_margin - 3),
++              fbi->regs + LCDC_HCR);
++
++      writel(VCR_V_WIDTH(pinfo->vsync_len) |
++              VCR_V_WAIT_1(pinfo->lower_margin) |
++              VCR_V_WAIT_2(pinfo->upper_margin),
++              fbi->regs + LCDC_VCR);
++
++      /* PWM contrast control register */
++      writel(fbi->pwmr, fbi->regs + LCDC_PWMR);
++
++      /* special setup for Sharp displays */
++      writel(fbi->lscr1, fbi->regs + LCDC_LSCR1);
++
++      /* dma watermarks for this mode */
++      writel(fbi->dmacr, fbi->regs + LCDC_DMACR);
++
++      /* activate refresh */
++#ifdef CONFIG_ARCH_IMX
++      writel(readl(fbi->regs + LCDC_RMCR) | RMCR_LCDC_EN,
++              fbi->regs + LCDC_RMCR);
++#else
++      writel(0x00000000, fbi->regs + LCDC_RMCR);
++#endif
+ }
+ #ifdef CONFIG_PM
+@@ -413,19 +532,23 @@ static void imxfb_setup_gpio(struct imxf
+  * Power management hooks.  Note that we won't be called from IRQ context,
+  * unlike the blank functions above, so we may sleep.
+  */
+-static int imxfb_suspend(struct platform_device *dev, pm_message_t state)
++static int imxfb_suspend(struct platform_device *pdev, pm_message_t state)
+ {
+-      struct imxfb_info *fbi = platform_get_drvdata(dev);
+-      pr_debug("%s\n",__func__);
++      struct fb_info *info = platform_get_drvdata(pdev);
++      struct imxfb_info *fbi = info->par;
++
++      pr_debug("%s\n", __func__);
+       imxfb_disable_controller(fbi);
+       return 0;
+ }
+-static int imxfb_resume(struct platform_device *dev)
++static int imxfb_resume(struct platform_device *pdev)
+ {
+-      struct imxfb_info *fbi = platform_get_drvdata(dev);
+-      pr_debug("%s\n",__func__);
++      struct fb_info *info = platform_get_drvdata(pdev);
++      struct imxfb_info *fbi = info->par;
++
++      pr_debug("%s\n", __func__);
+       imxfb_enable_controller(fbi);
+       return 0;
+@@ -435,149 +558,148 @@ static int imxfb_resume(struct platform_
+ #define imxfb_resume  NULL
+ #endif
+-static int __init imxfb_init_fbinfo(struct device *dev)
++static int __init imxfb_init_fbinfo(struct platform_device *pdev)
+ {
+-      struct imxfb_mach_info *inf = dev->platform_data;
+-      struct fb_info *info = dev_get_drvdata(dev);
++      struct imx_fb_platform_data *pdata = pdev->dev.platform_data;
++      struct fb_info *info = dev_get_drvdata(&pdev->dev);
+       struct imxfb_info *fbi = info->par;
+-      pr_debug("%s\n",__func__);
++      pr_debug("%s\n", __func__);
+-      info->pseudo_palette = kmalloc( sizeof(u32) * 16, GFP_KERNEL);
++      info->pseudo_palette = kmalloc(sizeof(u32) * 16, GFP_KERNEL);
+       if (!info->pseudo_palette)
+               return -ENOMEM;
+       memset(fbi, 0, sizeof(struct imxfb_info));
+-      fbi->dev = dev;
+       strlcpy(info->fix.id, IMX_NAME, sizeof(info->fix.id));
+-      info->fix.type  = FB_TYPE_PACKED_PIXELS;
++      info->fix.type                  = FB_TYPE_PACKED_PIXELS;
+       info->fix.type_aux              = 0;
+       info->fix.xpanstep              = 0;
+       info->fix.ypanstep              = 0;
+       info->fix.ywrapstep             = 0;
+-      info->fix.accel = FB_ACCEL_NONE;
++      info->fix.accel                 = FB_ACCEL_NONE;
+       info->var.nonstd                = 0;
+       info->var.activate              = FB_ACTIVATE_NOW;
+       info->var.height                = -1;
+       info->var.width = -1;
+       info->var.accel_flags           = 0;
+-      info->var.vmode = FB_VMODE_NONINTERLACED;
++      info->var.vmode                 = FB_VMODE_NONINTERLACED;
+       info->fbops                     = &imxfb_ops;
+-      info->flags                     = FBINFO_FLAG_DEFAULT | FBINFO_READS_FAST;
+-
+-      fbi->rgb[RGB_16]                = &def_rgb_16;
+-      fbi->rgb[RGB_8]                 = &def_rgb_8;
++      info->flags                     = FBINFO_FLAG_DEFAULT |
++                                        FBINFO_READS_FAST;
+-      fbi->max_xres                   = inf->xres;
+-      info->var.xres                  = inf->xres;
+-      info->var.xres_virtual          = inf->xres;
+-      fbi->max_yres                   = inf->yres;
+-      info->var.yres                  = inf->yres;
+-      info->var.yres_virtual          = inf->yres;
+-      fbi->max_bpp                    = inf->bpp;
+-      info->var.bits_per_pixel        = inf->bpp;
+-      info->var.nonstd                = inf->nonstd;
+-      info->var.pixclock              = inf->pixclock;
+-      info->var.hsync_len             = inf->hsync_len;
+-      info->var.left_margin           = inf->left_margin;
+-      info->var.right_margin          = inf->right_margin;
+-      info->var.vsync_len             = inf->vsync_len;
+-      info->var.upper_margin          = inf->upper_margin;
+-      info->var.lower_margin          = inf->lower_margin;
+-      info->var.sync                  = inf->sync;
+-      info->var.grayscale             = inf->cmap_greyscale;
+-      fbi->cmap_inverse               = inf->cmap_inverse;
+-      fbi->cmap_static                = inf->cmap_static;
+-      fbi->pcr                        = inf->pcr;
+-      fbi->lscr1                      = inf->lscr1;
+-      fbi->dmacr                      = inf->dmacr;
+-      fbi->pwmr                       = inf->pwmr;
+-      fbi->lcd_power                  = inf->lcd_power;
+-      fbi->backlight_power            = inf->backlight_power;
++      fbi->max_xres                   = pdata->xres;
++      info->var.xres                  = pdata->xres;
++      info->var.xres_virtual          = pdata->xres;
++      fbi->max_yres                   = pdata->yres;
++      info->var.yres                  = pdata->yres;
++      info->var.yres_virtual          = pdata->yres;
++      fbi->max_bpp                    = pdata->bpp;
++      info->var.bits_per_pixel        = pdata->bpp;
++      info->var.nonstd                = pdata->nonstd;
++      info->var.pixclock              = pdata->pixclock;
++      info->var.hsync_len             = pdata->hsync_len;
++      info->var.left_margin           = pdata->left_margin;
++      info->var.right_margin          = pdata->right_margin;
++      info->var.vsync_len             = pdata->vsync_len;
++      info->var.upper_margin          = pdata->upper_margin;
++      info->var.lower_margin          = pdata->lower_margin;
++      info->var.sync                  = pdata->sync;
++      info->var.grayscale             = pdata->cmap_greyscale;
++      fbi->cmap_inverse               = pdata->cmap_inverse;
++      fbi->cmap_static                = pdata->cmap_static;
++      fbi->pcr                        = pdata->pcr;
++      fbi->lscr1                      = pdata->lscr1;
++      fbi->dmacr                      = pdata->dmacr;
++      fbi->pwmr                       = pdata->pwmr;
++      fbi->lcd_power                  = pdata->lcd_power;
++      fbi->backlight_power            = pdata->backlight_power;
+       info->fix.smem_len              = fbi->max_xres * fbi->max_yres *
+                                         fbi->max_bpp / 8;
+       return 0;
+ }
+-/*
+- *      Allocates the DRAM memory for the frame buffer.  This buffer is
+- *    remapped into a non-cached, non-buffered, memory region to
+- *      allow pixel writes to occur without flushing the cache.
+- *      Once this area is remapped, all virtual memory access to the
+- *      video memory should occur at the new region.
+- */
+-static int __init imxfb_map_video_memory(struct fb_info *info)
+-{
+-      struct imxfb_info *fbi = info->par;
+-
+-      fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
+-      fbi->map_cpu = dma_alloc_writecombine(fbi->dev, fbi->map_size,
+-                                      &fbi->map_dma,GFP_KERNEL);
+-
+-      if (fbi->map_cpu) {
+-              info->screen_base = fbi->map_cpu;
+-              fbi->screen_cpu = fbi->map_cpu;
+-              fbi->screen_dma = fbi->map_dma;
+-              info->fix.smem_start = fbi->screen_dma;
+-      }
+-
+-      return fbi->map_cpu ? 0 : -ENOMEM;
+-}
+-
+ static int __init imxfb_probe(struct platform_device *pdev)
+ {
+       struct imxfb_info *fbi;
+       struct fb_info *info;
+-      struct imxfb_mach_info *inf;
++      struct imx_fb_platform_data *pdata;
+       struct resource *res;
+       int ret;
+       printk("i.MX Framebuffer driver\n");
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+-      if(!res)
++      if (!res)
+               return -ENODEV;
+-      inf = pdev->dev.platform_data;
+-      if(!inf) {
++      pdata = pdev->dev.platform_data;
++      if (!pdata) {
+               dev_err(&pdev->dev,"No platform_data available\n");
+               return -ENOMEM;
+       }
+       info = framebuffer_alloc(sizeof(struct imxfb_info), &pdev->dev);
+-      if(!info)
++      if (!info)
+               return -ENOMEM;
+       fbi = info->par;
+       platform_set_drvdata(pdev, info);
+-      ret = imxfb_init_fbinfo(&pdev->dev);
+-      if( ret < 0 )
++      ret = imxfb_init_fbinfo(pdev);
++      if (ret < 0)
+               goto failed_init;
+-      res = request_mem_region(res->start, res->end - res->start + 1, "IMXFB");
++      fbi->pdev = pdev;
++
++      res = request_mem_region(res->start, resource_size(res),
++                              DRIVER_NAME);
+       if (!res) {
+               ret = -EBUSY;
+-              goto failed_regs;
++              goto failed_req;
++      }
++
++      fbi->regs = ioremap(res->start, resource_size(res));
++      if (fbi->regs == NULL) {
++              printk(KERN_ERR"Cannot map frame buffer registers\n");
++              goto failed_ioremap;
+       }
+-      if (!inf->fixed_screen_cpu) {
+-              ret = imxfb_map_video_memory(info);
+-              if (ret) {
+-                      dev_err(&pdev->dev, "Failed to allocate video RAM: %d\n", ret);
++      fbi->clk = clk_get(&pdev->dev, "lcdc_clk");
++      if (IS_ERR(fbi->clk)) {
++              ret = PTR_ERR(fbi->clk);
++              dev_err(&pdev->dev,
++                      "Cannot get the clock for IMX LCD unit %d: %d\n",
++                      pdev->id, ret);
++              goto failed_getclock;
++      }
++
++      if (!pdata->fixed_screen_cpu) {
++              fbi->map_size = PAGE_ALIGN(info->fix.smem_len);
++              fbi->map_cpu = dma_alloc_writecombine(&pdev->dev,
++                              fbi->map_size, &fbi->map_dma, GFP_KERNEL);
++
++              if (!fbi->map_cpu) {
++                      dev_err(&pdev->dev, "Failed to allocate %u byte for video RAM\n",
++                              fbi->map_size);
+                       ret = -ENOMEM;
+                       goto failed_map;
+               }
++
++              info->screen_base = fbi->map_cpu;
++              fbi->screen_cpu = fbi->map_cpu;
++              fbi->screen_dma = fbi->map_dma;
++              info->fix.smem_start = fbi->screen_dma;
+       } else {
+               /* Fixed framebuffer mapping enables location of the screen in eSRAM */
+-              fbi->map_cpu = inf->fixed_screen_cpu;
+-              fbi->map_dma = inf->fixed_screen_dma;
++              fbi->map_cpu = pdata->fixed_screen_cpu;
++              fbi->map_dma = pdata->fixed_screen_dma;
+               info->screen_base = fbi->map_cpu;
+               fbi->screen_cpu = fbi->map_cpu;
+               fbi->screen_dma = fbi->map_dma;
+@@ -588,17 +710,26 @@ static int __init imxfb_probe(struct pla
+        * This makes sure that our colour bitfield
+        * descriptors are correctly initialised.
+        */
+-      imxfb_check_var(&info->var, info);
++      imxfb_setup_display(fbi);
++      ret = imxfb_check_var(&info->var, info);
++      if (ret) {
++              dev_err(&pdev->dev, "failed to get suitable mode\n");
++              goto failed_cmap;
++      }
+-      ret = fb_alloc_cmap(&info->cmap, 1<<info->var.bits_per_pixel, 0);
+-      if (ret < 0)
++      ret = imxfb_set_par(info);
++      if (ret) {
++              dev_err(&pdev->dev, "Failed to set parameters\n");
+               goto failed_cmap;
++      }
+-      imxfb_setup_gpio(fbi);
++      ret = fb_alloc_cmap(&info->cmap, 1 << info->var.bits_per_pixel, 0);
++      if (ret < 0)
++              goto failed_cmap;
+       imxfb_set_par(info);
+       ret = register_framebuffer(info);
+-      if (ret < 0) {
++      if (ret) {
+               dev_err(&pdev->dev, "failed to register framebuffer\n");
+               goto failed_register;
+       }
+@@ -610,20 +741,24 @@ static int __init imxfb_probe(struct pla
+ failed_register:
+       fb_dealloc_cmap(&info->cmap);
+ failed_cmap:
+-      if (!inf->fixed_screen_cpu)
++      if (!pdata->fixed_screen_cpu)
+               dma_free_writecombine(&pdev->dev,fbi->map_size,fbi->map_cpu,
+-                         fbi->map_dma);
++                      fbi->map_dma);
+ failed_map:
+-      kfree(info->pseudo_palette);
+-failed_regs:
++      clk_put(fbi->clk);
++failed_getclock:
++      iounmap(fbi->regs);
++failed_ioremap:
+       release_mem_region(res->start, res->end - res->start);
++failed_req:
++      kfree(info->pseudo_palette);
+ failed_init:
+       platform_set_drvdata(pdev, NULL);
+       framebuffer_release(info);
+       return ret;
+ }
+-static int imxfb_remove(struct platform_device *pdev)
++static int __devexit imxfb_remove(struct platform_device *pdev)
+ {
+       struct fb_info *info = platform_get_drvdata(pdev);
+       struct imxfb_info *fbi = info->par;
+@@ -639,7 +774,12 @@ static int imxfb_remove(struct platform_
+       kfree(info->pseudo_palette);
+       framebuffer_release(info);
++      iounmap(fbi->regs);
+       release_mem_region(res->start, res->end - res->start + 1);
++
++      clk_disable(fbi->clk);
++      clk_put(fbi->clk);
++
+       platform_set_drvdata(pdev, NULL);
+       return 0;
+@@ -653,19 +793,18 @@ void  imxfb_shutdown(struct platform_dev
+ }
+ static struct platform_driver imxfb_driver = {
+-      .probe          = imxfb_probe,
+       .suspend        = imxfb_suspend,
+       .resume         = imxfb_resume,
+-      .remove         = imxfb_remove,
++      .remove         = __devexit_p(imxfb_remove),
+       .shutdown       = imxfb_shutdown,
+       .driver         = {
+-              .name   = "imx-fb",
++              .name   = DRIVER_NAME,
+       },
+ };
+ int __init imxfb_init(void)
+ {
+-      return platform_driver_register(&imxfb_driver);
++      return platform_driver_probe(&imxfb_driver, imxfb_probe);
+ }
+ static void __exit imxfb_cleanup(void)
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/video/imxfb.h linux-2.6.28-karo/drivers/video/imxfb.h
+--- linux-2.6.28/drivers/video/imxfb.h 2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/video/imxfb.h    1970-01-01 01:00:00.000000000 +0100
+@@ -1,73 +0,0 @@
+-/*
+- * linux/drivers/video/imxfb.h
+- *
+- *  Freescale i.MX Frame Buffer device driver
+- *
+- *  Copyright (C) 2004 S.Hauer, Pengutronix
+- *
+- *  Copyright (C) 1999 Eric A. Thomas
+- *   Based on acornfb.c Copyright (C) Russell King.
+- *
+- * This file is subject to the terms and conditions of the GNU General Public
+- * License.  See the file COPYING in the main directory of this archive
+- * for more details.
+- */
+-
+-/*
+- * These are the bitfields for each
+- * display depth that we support.
+- */
+-struct imxfb_rgb {
+-      struct fb_bitfield      red;
+-      struct fb_bitfield      green;
+-      struct fb_bitfield      blue;
+-      struct fb_bitfield      transp;
+-};
+-
+-#define RGB_16        (0)
+-#define RGB_8 (1)
+-#define NR_RGB        2
+-
+-struct imxfb_info {
+-      struct device           *dev;
+-      struct imxfb_rgb        *rgb[NR_RGB];
+-
+-      u_int                   max_bpp;
+-      u_int                   max_xres;
+-      u_int                   max_yres;
+-
+-      /*
+-       * These are the addresses we mapped
+-       * the framebuffer memory region to.
+-       */
+-      dma_addr_t              map_dma;
+-      u_char *                map_cpu;
+-      u_int                   map_size;
+-
+-      u_char *                screen_cpu;
+-      dma_addr_t              screen_dma;
+-      u_int                   palette_size;
+-
+-      dma_addr_t              dbar1;
+-      dma_addr_t              dbar2;
+-
+-      u_int                   pcr;
+-      u_int                   pwmr;
+-      u_int                   lscr1;
+-      u_int                   dmacr;
+-      u_int                   cmap_inverse:1,
+-                              cmap_static:1,
+-                              unused:30;
+-
+-      void (*lcd_power)(int);
+-      void (*backlight_power)(int);
+-};
+-
+-#define IMX_NAME      "IMX"
+-
+-/*
+- * Minimum X and Y resolutions
+- */
+-#define MIN_XRES      64
+-#define MIN_YRES      64
+-
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/w1/masters/Kconfig linux-2.6.28-karo/drivers/w1/masters/Kconfig
+--- linux-2.6.28/drivers/w1/masters/Kconfig    2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/w1/masters/Kconfig       2009-03-11 13:16:24.000000000 +0100
+@@ -34,6 +34,12 @@ config W1_MASTER_DS2482
+         This driver can also be built as a module.  If so, the module
+         will be called ds2482.
++config W1_MASTER_MXC
++      tristate "Freescale MXC 1-wire busmaster"
++      depends on W1 && ARCH_MXC
++      help
++        Say Y here to enable MXC 1-wire host
++
+ config W1_MASTER_DS1WM
+       tristate "Maxim DS1WM 1-wire busmaster"
+       depends on W1 && ARM && HAVE_CLK
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/w1/masters/Makefile linux-2.6.28-karo/drivers/w1/masters/Makefile
+--- linux-2.6.28/drivers/w1/masters/Makefile   2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/drivers/w1/masters/Makefile      2009-03-11 13:16:24.000000000 +0100
+@@ -5,6 +5,8 @@
+ obj-$(CONFIG_W1_MASTER_MATROX)                += matrox_w1.o
+ obj-$(CONFIG_W1_MASTER_DS2490)                += ds2490.o
+ obj-$(CONFIG_W1_MASTER_DS2482)                += ds2482.o
++obj-$(CONFIG_W1_MASTER_MXC)           += mxc_w1.o
++
+ obj-$(CONFIG_W1_MASTER_DS1WM)         += ds1wm.o
+ obj-$(CONFIG_W1_MASTER_GPIO)          += w1-gpio.o
+ obj-$(CONFIG_HDQ_MASTER_OMAP)         += omap_hdq.o
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/drivers/w1/masters/mxc_w1.c linux-2.6.28-karo/drivers/w1/masters/mxc_w1.c
+--- linux-2.6.28/drivers/w1/masters/mxc_w1.c   1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/drivers/w1/masters/mxc_w1.c      2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,211 @@
++/*
++ * Copyright 2005-2008 Freescale Semiconductor, Inc. All Rights Reserved.
++ * Copyright 2008 Luotao Fu, kernel@pengutronix.de
++ *
++ * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++
++#include "../w1.h"
++#include "../w1_int.h"
++#include "../w1_log.h"
++
++/* According to the mx27 Datasheet the reset procedure should take up to about
++ * 1350us. We set the timeout to 500*100us = 50ms for sure */
++#define MXC_W1_RESET_TIMEOUT 500
++
++/*
++ * MXC W1 Register offsets
++ */
++#define MXC_W1_CONTROL          0x00
++#define MXC_W1_TIME_DIVIDER     0x02
++#define MXC_W1_RESET            0x04
++#define MXC_W1_COMMAND          0x06
++#define MXC_W1_TXRX             0x08
++#define MXC_W1_INTERRUPT        0x0A
++#define MXC_W1_INTERRUPT_EN     0x0C
++
++struct mxc_w1_device {
++      void __iomem *regs;
++      unsigned int clkdiv;
++      struct clk *clk;
++      struct w1_bus_master bus_master;
++};
++
++/*
++ * this is the low level routine to
++ * reset the device on the One Wire interface
++ * on the hardware
++ */
++static u8 mxc_w1_ds2_reset_bus(void *data)
++{
++      u8 reg_val;
++      unsigned int timeout_cnt = 0;
++      struct mxc_w1_device *dev = data;
++
++      __raw_writeb(0x80, (dev->regs + MXC_W1_CONTROL));
++
++      while (1) {
++              reg_val = __raw_readb(dev->regs + MXC_W1_CONTROL);
++
++              if (((reg_val >> 7) & 0x1) == 0 ||
++                  timeout_cnt > MXC_W1_RESET_TIMEOUT)
++                      break;
++              else
++                      timeout_cnt++;
++
++              udelay(100);
++      }
++      return (reg_val >> 7) & 0x1;
++}
++
++/*
++ * this is the low level routine to read/write a bit on the One Wire
++ * interface on the hardware. It does write 0 if parameter bit is set
++ * to 0, otherwise a write 1/read.
++ */
++static u8 mxc_w1_ds2_touch_bit(void *data, u8 bit)
++{
++      struct mxc_w1_device *mdev = data;
++      void __iomem *ctrl_addr = mdev->regs + MXC_W1_CONTROL;
++      unsigned int timeout_cnt = 400; /* Takes max. 120us according to
++                                       * datasheet.
++                                       */
++
++      __raw_writeb((1 << (5 - bit)), ctrl_addr);
++
++      while (timeout_cnt--) {
++              if (!((__raw_readb(ctrl_addr) >> (5 - bit)) & 0x1))
++                      break;
++
++              udelay(1);
++      }
++
++      return ((__raw_readb(ctrl_addr)) >> 3) & 0x1;
++}
++
++static int __init mxc_w1_probe(struct platform_device *pdev)
++{
++      struct mxc_w1_device *mdev;
++      struct resource *res;
++      int err = 0;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (!res)
++              return -ENODEV;
++
++      mdev = kzalloc(sizeof(struct mxc_w1_device), GFP_KERNEL);
++      if (!mdev)
++              return -ENOMEM;
++
++      mdev->clk = clk_get(&pdev->dev, "owire_clk");
++      if (!mdev->clk) {
++              err = -ENODEV;
++              goto failed_clk;
++      }
++
++      mdev->clkdiv = (clk_get_rate(mdev->clk) / 1000000) - 1;
++
++      res = request_mem_region(res->start, resource_size(res),
++                              "mxc_w1");
++      if (!res) {
++              err = -EBUSY;
++              goto failed_req;
++      }
++
++      mdev->regs = ioremap(res->start, resource_size(res));
++      if (!mdev->regs) {
++              printk(KERN_ERR "Cannot map frame buffer registers\n");
++              goto failed_ioremap;
++      }
++
++      clk_enable(mdev->clk);
++      __raw_writeb(mdev->clkdiv, mdev->regs + MXC_W1_TIME_DIVIDER);
++
++      mdev->bus_master.data = mdev;
++      mdev->bus_master.reset_bus = mxc_w1_ds2_reset_bus;
++      mdev->bus_master.touch_bit = mxc_w1_ds2_touch_bit;
++
++      err = w1_add_master_device(&mdev->bus_master);
++
++      if (err)
++              goto failed_add;
++
++      platform_set_drvdata(pdev, mdev);
++      return 0;
++
++failed_add:
++      iounmap(mdev->regs);
++failed_ioremap:
++      release_mem_region(res->start, resource_size(res));
++failed_req:
++      clk_put(mdev->clk);
++failed_clk:
++      kfree(mdev);
++      return err;
++}
++
++/*
++ * disassociate the w1 device from the driver
++ */
++static int mxc_w1_remove(struct platform_device *pdev)
++{
++      struct mxc_w1_device *mdev = platform_get_drvdata(pdev);
++      struct resource *res;
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++
++      w1_remove_master_device(&mdev->bus_master);
++
++      iounmap(mdev->regs);
++      release_mem_region(res->start, resource_size(res));
++      clk_disable(mdev->clk);
++      clk_put(mdev->clk);
++
++      platform_set_drvdata(pdev, NULL);
++
++      return 0;
++}
++
++static struct platform_driver mxc_w1_driver = {
++      .driver = {
++                 .name = "mxc_w1",
++      },
++      .probe = mxc_w1_probe,
++      .remove = mxc_w1_remove,
++};
++
++static int __init mxc_w1_init(void)
++{
++      return platform_driver_register(&mxc_w1_driver);
++}
++
++static void mxc_w1_exit(void)
++{
++      platform_driver_unregister(&mxc_w1_driver);
++}
++
++module_init(mxc_w1_init);
++module_exit(mxc_w1_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Freescale Semiconductors Inc");
++MODULE_DESCRIPTION("Driver for One-Wire on MXC");
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/include/linux/dmaengine.h linux-2.6.28-karo/include/linux/dmaengine.h
+--- linux-2.6.28/include/linux/dmaengine.h     2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/include/linux/dmaengine.h        2009-03-11 13:16:24.000000000 +0100
+@@ -285,6 +285,7 @@ struct dma_async_tx_descriptor {
+       struct list_head tx_list;
+       struct dma_chan *chan;
+       dma_cookie_t (*tx_submit)(struct dma_async_tx_descriptor *tx);
++      void (*tx_free)(struct dma_async_tx_descriptor *tx);
+       dma_async_tx_callback callback;
+       void *callback_param;
+       struct dma_async_tx_descriptor *next;
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/include/linux/fec_enet.h linux-2.6.28-karo/include/linux/fec_enet.h
+--- linux-2.6.28/include/linux/fec_enet.h      1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/include/linux/fec_enet.h 2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,26 @@
++/*
++ * Copyright (C) 2007  Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * platform_data definitions for fec_enet device
++ *
++ * 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 Street, Fifth Floor, Boston, MA 02110-1301
++ */
++
++struct fec_enet_platform_data {
++      /* callback for platform specific initialization */
++      int (*arch_init)(struct platform_device *dev);
++      void (*arch_exit)(struct platform_device *dev);
++      int (*suspend)(struct platform_device *dev);
++      int (*resume)(struct platform_device *dev);
++};
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/include/linux/mtd/mtd.h linux-2.6.28-karo/include/linux/mtd/mtd.h
+--- linux-2.6.28/include/linux/mtd/mtd.h       2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/include/linux/mtd/mtd.h  2009-03-11 13:16:24.000000000 +0100
+@@ -268,13 +268,13 @@ static inline void mtd_erase_callback(st
+ #define MTD_DEBUG_LEVEL3      (3)     /* Noisy   */
+ #ifdef CONFIG_MTD_DEBUG
+-#define DEBUG(n, args...)                             \
++#define MTD_DEBUG(n, args...)                         \
+       do {                                            \
+               if (n <= CONFIG_MTD_DEBUG_VERBOSE)      \
+                       printk(KERN_INFO args);         \
+       } while(0)
+ #else /* CONFIG_MTD_DEBUG */
+-#define DEBUG(n, args...)                             \
++#define MTD_DEBUG(n, args...)                         \
+       do {                                            \
+               if (0)                                  \
+                       printk(KERN_INFO args);         \
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/include/linux/rtc/ds13xx.h linux-2.6.28-karo/include/linux/rtc/ds13xx.h
+--- linux-2.6.28/include/linux/rtc/ds13xx.h    1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/include/linux/rtc/ds13xx.h       2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,73 @@
++/*
++ * include/linux/rtc/rtc-ds1339.h
++ *
++ * platform specific definitions for DS1339 RTC driver
++ *
++ *
++ * Copyright (C) 2007  Lothar Wassmann <LW@KARO-electronics.de>
++ *
++ * 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.
++ */
++
++enum ds13xx_type {
++      unknown,
++      ds_1307,                /* or ds1338, ... */
++      ds_1337,
++      ds_1338,
++      ds_1339,
++      ds_1340,
++      m41t00,
++      // rs5c372 too?  different address...
++};
++
++/* DS1307 control reg (0x07) bit definitions */
++#define DS1307_BIT_OUT                0x80
++#define DS1307_BIT_SQWE               0x10
++#define DS1307_BIT_RS1                0x02
++#define DS1307_BIT_RS0                0x01
++/* DS1337/DS1339 control reg (0x0e) bit definitions */
++#define DS133X_BIT_INTCN      0x04
++#define DS133X_BIT_RS1                0x08
++#define DS133X_BIT_RS2                0x10
++#define DS1339_BIT_BBSQI      0x20
++/* DS1339 trickle charge reg (0x10) bit definitions */
++#define DS1339_TRC_ENABLE     0xa0
++#define DS1339_TRC_250R               0x01
++#define DS1339_TRC_2K         0x02
++#define DS1339_TRC_4K         0x03
++#define DS1339_DIODE_DISABLE  0x04
++#define DS1339_DIODE_ENABLE   0x08
++/* DS1340 trickle charge reg (0x08) bit definitions */
++#define DS1340_TRC_ENABLE     0xa0
++#define DS1340_TRC_250R               0x01
++#define DS1340_TRC_2K         0x02
++#define DS1340_TRC_4K         0x03
++#define DS1340_DIODE_DISABLE  0x04
++#define DS1340_DIODE_ENABLE   0x08
++/* DS1340 control reg (0x09) bit definitions */
++#define DS1340_BIT_OUT                0x80
++#define DS1340_BIT_FT         0x0
++#define DS1340_CAL_SIGN               0x0
++#define DS1340_CAL_MASK               0x1f
++#define DS1340_CAL(v)         ((v) & (DS1340_CAL_MASK))
++
++struct ds13xx_platform_data {
++      /* type of DS13XX chip */
++      enum ds13xx_type type;
++      /* value for Control register on DS13xx; < 0 means don't care */
++      short ctrl;
++      /* value for Trickle charge register on DS1339; < 0 means don't care */
++      short trc;
++};
++
+diff -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/kernel/printk.c linux-2.6.28-karo/kernel/printk.c
+--- linux-2.6.28/kernel/printk.c       2008-12-25 00:26:37.000000000 +0100
++++ linux-2.6.28-karo/kernel/printk.c  2009-03-11 13:16:24.000000000 +0100
+@@ -622,6 +622,9 @@ static int recursion_bug;
+       static int new_text_line = 1;
+ static char printk_buf[1024];
++#ifdef CONFIG_DEBUG_LL
++extern void asmlinkage printascii(const char *);
++#endif
+ asmlinkage int vprintk(const char *fmt, va_list args)
+ {
+       int printed_len = 0;
+@@ -669,6 +672,9 @@ asmlinkage int vprintk(const char *fmt, 
+                                 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 -purN -X linux-2.6.28/Documentation/dontdiff linux-2.6.28/sound/arm/soc-wrapper.c linux-2.6.28-karo/sound/arm/soc-wrapper.c
+--- linux-2.6.28/sound/arm/soc-wrapper.c       1970-01-01 01:00:00.000000000 +0100
++++ linux-2.6.28-karo/sound/arm/soc-wrapper.c  2009-03-11 13:16:24.000000000 +0100
+@@ -0,0 +1,222 @@
++
++#define SOC_SHIFT_LEFT                8
++#define SOC_SHIFT_RIGHT               13
++#define SOC_SHIFT_MAX         18
++#define SOC_SHIFT_INVERT      26
++
++#define SOC_ENUM_EXT(xname, xenum, xhandler_get, xhandler_put) \
++{     .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
++      .info = snd_soc_info_enum_ext, \
++      .get = xhandler_get, .put = xhandler_put, \
++      .private_value = (unsigned long)&xenum }
++
++#define SOC_ENUM_SINGLE_EXT(xmask, xtexts) \
++{     .mask = xmask, .texts = xtexts }
++
++#define SOC_ENUM(xname, xenum) \
++{     .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname,\
++      .info = snd_soc_info_enum_double, \
++      .get = snd_soc_get_enum_double, .put = snd_soc_put_enum_double, \
++      .private_value = (unsigned long)&xenum }
++
++#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
++{     .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
++      .mask = xmask, .texts = xtexts }
++#define SOC_ENUM_SINGLE(xreg, xshift, xmask, xtexts) \
++      SOC_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xtexts)
++
++#define SOC_SINGLE_VALUE(reg, shift, max, invert) ((reg) | ((shift) << SOC_SHIFT_LEFT) |\
++      ((shift) << SOC_SHIFT_RIGHT) | ((max) << SOC_SHIFT_MAX) | ((invert) << SOC_SHIFT_INVERT))
++
++#define SOC_DOUBLE(xname, reg, shift_left, shift_right, max, invert) \
++{     .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = (xname),\
++      .info = snd_soc_info_volsw, .get = snd_soc_get_volsw, \
++      .put = snd_soc_put_volsw, \
++      .private_value = (reg) | ((shift_left) << SOC_SHIFT_LEFT) | \
++              ((shift_right) << SOC_SHIFT_RIGHT) | ((max) << SOC_SHIFT_MAX) | ((invert) << SOC_SHIFT_INVERT) }
++
++#define SOC_SINGLE_EXT(xname, xreg, xshift, xmask, xinvert,\
++       xhandler_get, xhandler_put) \
++{     .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
++      .info = snd_soc_info_volsw, \
++      .get = xhandler_get, .put = xhandler_put, \
++      .private_value = SOC_SINGLE_VALUE(xreg, xshift, xmask, xinvert) }
++
++#define SOC_SINGLE(xname, reg, shift, max, invert) \
++{     .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
++      .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
++      .put = snd_soc_put_volsw, \
++      .private_value =  SOC_SINGLE_VALUE(reg, shift, max, invert) }
++
++struct soc_enum {
++      unsigned short reg;
++      unsigned short reg2;
++      unsigned char shift_l;
++      unsigned char shift_r;
++      unsigned int mask;
++      const char **texts;
++      void *dapm;
++};
++
++static unsigned int snd_soc_read(int reg);
++static void snd_soc_write(int reg, int val);
++
++static int snd_soc_info_enum_ext(struct snd_kcontrol *kcontrol,
++      struct snd_ctl_elem_info *uinfo)
++{
++      struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
++      uinfo->count = 1;
++      uinfo->value.enumerated.items = e->mask;
++
++      if (uinfo->value.enumerated.item > e->mask - 1)
++              uinfo->value.enumerated.item = e->mask - 1;
++      strcpy(uinfo->value.enumerated.name,
++              e->texts[uinfo->value.enumerated.item]);
++      return 0;
++}
++
++static int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
++      struct snd_ctl_elem_info *uinfo)
++{
++      int max = (kcontrol->private_value >> SOC_SHIFT_MAX) & 0xff;
++      int shift = (kcontrol->private_value >> SOC_SHIFT_LEFT) & 0x1f;
++      int rshift = (kcontrol->private_value >> SOC_SHIFT_RIGHT) & 0x1f;
++
++      if (max == 1)
++              uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
++      else
++              uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
++
++      uinfo->count = shift == rshift ? 1 : 2;
++      uinfo->value.integer.min = 0;
++      uinfo->value.integer.max = max;
++      return 0;
++}
++
++static int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
++      struct snd_ctl_elem_value *ucontrol)
++{
++      int reg = kcontrol->private_value & 0xff;
++      int shift = (kcontrol->private_value >> SOC_SHIFT_LEFT) & 0x1f;
++      int rshift = (kcontrol->private_value >> SOC_SHIFT_RIGHT) & 0x1f;
++      int max = (kcontrol->private_value >> SOC_SHIFT_MAX) & 0xff;
++      int mask = (1 << fls(max)) - 1;
++      int invert = (kcontrol->private_value >> SOC_SHIFT_INVERT) & 0x01;
++
++      ucontrol->value.integer.value[0] =
++              (snd_soc_read(reg) >> shift) & mask;
++      if (shift != rshift)
++              ucontrol->value.integer.value[1] =
++                      (snd_soc_read(reg) >> rshift) & mask;
++      if (invert) {
++              ucontrol->value.integer.value[0] =
++                      max - ucontrol->value.integer.value[0];
++              if (shift != rshift)
++                      ucontrol->value.integer.value[1] =
++                              max - ucontrol->value.integer.value[1];
++      }
++
++      return 0;
++}
++
++static int snd_soc_update_bits(unsigned short reg,
++                              unsigned int mask, unsigned int value)
++{
++      int change;
++      unsigned int old, new;
++
++//    mutex_lock(&io_mutex);
++      old = snd_soc_read(reg);
++      new = (old & ~mask) | value;
++      change = old != new;
++      if (change)
++              snd_soc_write(reg, new);
++
++//    mutex_unlock(&io_mutex);
++      return change;
++}
++
++static int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
++      struct snd_ctl_elem_value *ucontrol)
++{
++      int reg = kcontrol->private_value & 0xff;
++      int shift = (kcontrol->private_value >> SOC_SHIFT_LEFT) & 0x1f;
++      int rshift = (kcontrol->private_value >> SOC_SHIFT_RIGHT) & 0x1f;
++      int max = (kcontrol->private_value >> SOC_SHIFT_MAX) & 0xff;
++      int mask = (1 << fls(max)) - 1;
++      int invert = (kcontrol->private_value >> SOC_SHIFT_INVERT) & 0x01;
++      unsigned int val, val2, val_mask;
++
++      val = (ucontrol->value.integer.value[0] & mask);
++      if (invert)
++              val = max - val;
++      val_mask = mask << shift;
++      val = val << shift;
++      if (shift != rshift) {
++              val2 = (ucontrol->value.integer.value[1] & mask);
++              if (invert)
++                      val2 = max - val2;
++              val_mask |= mask << rshift;
++              val |= val2 << rshift;
++      }
++      return snd_soc_update_bits(reg, val_mask, val);
++}
++
++static int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
++      struct snd_ctl_elem_info *uinfo)
++{
++      struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
++
++      uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
++      uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
++      uinfo->value.enumerated.items = e->mask;
++
++      if (uinfo->value.enumerated.item > e->mask - 1)
++              uinfo->value.enumerated.item = e->mask - 1;
++      strcpy(uinfo->value.enumerated.name,
++              e->texts[uinfo->value.enumerated.item]);
++      return 0;
++}
++
++static int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
++      struct snd_ctl_elem_value *ucontrol)
++{
++      struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
++      unsigned int val, bitmask;
++
++      for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
++              ;
++      val = snd_soc_read(e->reg);
++      ucontrol->value.enumerated.item[0]
++              = (val >> e->shift_l) & (bitmask - 1);
++      if (e->shift_l != e->shift_r)
++              ucontrol->value.enumerated.item[1] =
++                      (val >> e->shift_r) & (bitmask - 1);
++
++      return 0;
++}
++
++static int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
++      struct snd_ctl_elem_value *ucontrol)
++{
++      struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
++      unsigned int val;
++      unsigned int mask, bitmask;
++
++      for (bitmask = 1; bitmask < e->mask; bitmask <<= 1)
++              ;
++      if (ucontrol->value.enumerated.item[0] > e->mask - 1)
++              return -EINVAL;
++      val = ucontrol->value.enumerated.item[0] << e->shift_l;
++      mask = (bitmask - 1) << e->shift_l;
++      if (e->shift_l != e->shift_r) {
++              if (ucontrol->value.enumerated.item[1] > e->mask - 1)
++                      return -EINVAL;
++              val |= ucontrol->value.enumerated.item[1] << e->shift_r;
++              mask |= (bitmask - 1) << e->shift_r;
++      }
++
++      return snd_soc_update_bits(e->reg, mask, val);
++}
index b11bf16..bded7ed 100644 (file)
@@ -1,6 +1,6 @@
 require linux.inc
 
-PR = "r8"
+PR = "r9"
 
 # Mark archs/machines that this kernel supports
 DEFAULT_PREFERENCE = "-1"
@@ -11,6 +11,7 @@ DEFAULT_PREFERENCE_stb225 = "28"
 DEFAULT_PREFERENCE_collie = "1"
 DEFAULT_PREFERENCE_gamecube = "1"
 DEFAULT_PREFERENCE_wrap = "1"
+DEFAULT_PREFERENCE_tx27 = "1"
 
 SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.28.tar.bz2 \
            file://defconfig"
@@ -64,4 +65,9 @@ SRC_URI_append_gamecube = " \
        file://patch-2.6.28-gc;patch=1 \
        "
 
+SRC_URI_append_tx27 = " \
+       file://linux-2.6.28-karo4.diff;patch=1 \
+       "
+
+
 S = "${WORKDIR}/linux-2.6.28/"