aboutsummaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux-2.6.28
diff options
context:
space:
mode:
authorFlorian Boor <florian.boor@kernelconcepts.de>2009-05-29 19:11:19 +0200
committerFlorian Boor <florian.boor@kernelconcepts.de>2009-05-29 19:14:18 +0200
commit4e9b399fb27c7bbe8a4ed54cf6259ddc494c3df0 (patch)
treedf1210b1da1af555917d2ff194850c244db0098b /recipes/linux/linux-2.6.28
parent411e9f88738dae423dff7c98b3e3f3dfc712365c (diff)
downloadopenembedded-4e9b399fb27c7bbe8a4ed54cf6259ddc494c3df0.tar.gz
linux: Initial support for the Ka-Ro TX27 (rev. 4)
Diffstat (limited to 'recipes/linux/linux-2.6.28')
-rw-r--r--recipes/linux/linux-2.6.28/tx27/defconfig1799
-rw-r--r--recipes/linux/linux-2.6.28/tx27/linux-2.6.28-karo4.diff40137
2 files changed, 41936 insertions, 0 deletions
diff --git a/recipes/linux/linux-2.6.28/tx27/defconfig b/recipes/linux/linux-2.6.28/tx27/defconfig
new file mode 100644
index 0000000000..ba5a699b98
--- /dev/null
+++ b/recipes/linux/linux-2.6.28/tx27/defconfig
@@ -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
index 0000000000..a1be6cabb4
--- /dev/null
+++ b/recipes/linux/linux-2.6.28/tx27/linux-2.6.28-karo4.diff
@@ -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);
++}