diff options
author | Florian Boor <florian.boor@kernelconcepts.de> | 2009-05-29 19:11:19 +0200 |
---|---|---|
committer | Florian Boor <florian.boor@kernelconcepts.de> | 2009-05-29 19:14:18 +0200 |
commit | 4e9b399fb27c7bbe8a4ed54cf6259ddc494c3df0 (patch) | |
tree | df1210b1da1af555917d2ff194850c244db0098b /recipes | |
parent | 411e9f88738dae423dff7c98b3e3f3dfc712365c (diff) |
linux: Initial support for the Ka-Ro TX27 (rev. 4)
Diffstat (limited to 'recipes')
-rw-r--r-- | recipes/linux/linux-2.6.28/tx27/defconfig | 1799 | ||||
-rw-r--r-- | recipes/linux/linux-2.6.28/tx27/linux-2.6.28-karo4.diff | 40137 | ||||
-rw-r--r-- | recipes/linux/linux_2.6.28.bb | 8 |
3 files changed, 41943 insertions, 1 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(®, &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(®, &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(®, &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 = ®istered_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 = ® ++ 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(¶ms, 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, ¶ms) != 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(¶ms, 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, ¶ms) < 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(¶ms, 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, ¶ms) != 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); ++} diff --git a/recipes/linux/linux_2.6.28.bb b/recipes/linux/linux_2.6.28.bb index b11bf166c3..bded7ed03e 100644 --- a/recipes/linux/linux_2.6.28.bb +++ b/recipes/linux/linux_2.6.28.bb @@ -1,6 +1,6 @@ require linux.inc -PR = "r8" +PR = "r9" # Mark archs/machines that this kernel supports DEFAULT_PREFERENCE = "-1" @@ -11,6 +11,7 @@ DEFAULT_PREFERENCE_stb225 = "28" DEFAULT_PREFERENCE_collie = "1" DEFAULT_PREFERENCE_gamecube = "1" DEFAULT_PREFERENCE_wrap = "1" +DEFAULT_PREFERENCE_tx27 = "1" SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.28.tar.bz2 \ file://defconfig" @@ -64,4 +65,9 @@ SRC_URI_append_gamecube = " \ file://patch-2.6.28-gc;patch=1 \ " +SRC_URI_append_tx27 = " \ + file://linux-2.6.28-karo4.diff;patch=1 \ + " + + S = "${WORKDIR}/linux-2.6.28/" |