linux-rp-2.6.23: Sync with Poky in the same way as 2.6.24
authorRichard Purdie <rpurdie@rpsys.net>
Sun, 1 Jun 2008 22:51:20 +0000 (22:51 +0000)
committerRichard Purdie <rpurdie@rpsys.net>
Sun, 1 Jun 2008 22:51:20 +0000 (22:51 +0000)
17 files changed:
packages/linux/linux-rp-2.6.23/defconfig-akita
packages/linux/linux-rp-2.6.23/defconfig-bootcdx86
packages/linux/linux-rp-2.6.23/defconfig-c7x0
packages/linux/linux-rp-2.6.23/defconfig-collie
packages/linux/linux-rp-2.6.23/defconfig-htcuniversal
packages/linux/linux-rp-2.6.23/defconfig-hx2000
packages/linux/linux-rp-2.6.23/defconfig-poodle
packages/linux/linux-rp-2.6.23/defconfig-qemuarm
packages/linux/linux-rp-2.6.23/defconfig-qemux86
packages/linux/linux-rp-2.6.23/defconfig-spitz
packages/linux/linux-rp-2.6.23/defconfig-tosa
packages/linux/linux-rp-2.6.23/defconfig-zylonite
packages/linux/linux-rp-2.6.23/zylonite_keypad-r0.patch [new file with mode: 0644]
packages/linux/linux-rp-2.6.23/zylonite_mtd-r0.patch [new file with mode: 0644]
packages/linux/linux-rp-2.6.23/zylonite_touch-r0.patch [new file with mode: 0644]
packages/linux/linux-rp.inc
packages/linux/linux-rp_2.6.23.bb

index 9587fb2..ddc7ba0 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.23
-# Tue Oct 16 13:20:27 2007
+# Mon May 19 22:50:30 2008
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -34,7 +34,7 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
@@ -241,7 +241,7 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200n8 console=tty1 noinitrd root=/dev/mtdblock2 rootfstype=jffs2  fbcon=rotate:1 dyntick=enable quiet"
+CONFIG_CMDLINE="console=ttyS0,115200n8 console=tty1 noinitrd root=/dev/mtdblock2 rootfstype=jffs2  fbcon=rotate:1 dyntick=enable debug"
 # CONFIG_XIP_KERNEL is not set
 CONFIG_KEXEC=y
 CONFIG_ATAGS_PROC=y
@@ -1081,9 +1081,6 @@ CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 CONFIG_LOGO_OHAND_CLUT224=y
-# CONFIG_LOGO_OZ240_CLUT224 is not set
-# CONFIG_LOGO_OZ480_CLUT224 is not set
-# CONFIG_LOGO_OZ640_CLUT224 is not set
 
 #
 # Sound
index e885220..244df73 100644 (file)
@@ -1,10 +1,11 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.21
-# Mon Jun 11 12:01:43 2007
+# Linux kernel version: 2.6.23
+# Wed Feb  6 18:24:38 2008
 #
 CONFIG_X86_32=y
 CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CMOS_UPDATE=y
 CONFIG_CLOCKSOURCE_WATCHDOG=y
 CONFIG_GENERIC_CLOCKEVENTS=y
 CONFIG_GENERIC_CLOCKEVENTS_BROADCAST=y
@@ -14,6 +15,7 @@ CONFIG_SEMAPHORE_SLEEPERS=y
 CONFIG_X86=y
 CONFIG_MMU=y
 CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
 CONFIG_GENERIC_ISA_DMA=y
 CONFIG_GENERIC_IOMAP=y
 CONFIG_GENERIC_BUG=y
@@ -23,28 +25,24 @@ CONFIG_DMI=y
 CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
 
 #
-# Code maturity level options
+# General setup
 #
 CONFIG_EXPERIMENTAL=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
-
-#
-# General setup
-#
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
-# CONFIG_IPC_NS is not set
 CONFIG_SYSVIPC_SYSCTL=y
 CONFIG_POSIX_MQUEUE=y
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
-# CONFIG_UTS_NS is not set
+# CONFIG_USER_NS is not set
 CONFIG_AUDIT=y
 CONFIG_AUDITSYSCALL=y
 # CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=15
 # CONFIG_CPUSETS is not set
 # CONFIG_SYSFS_DEPRECATED is not set
 # CONFIG_RELAY is not set
@@ -63,31 +61,29 @@ CONFIG_BUG=y
 CONFIG_ELF_CORE=y
 CONFIG_BASE_FULL=y
 CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_SLAB=y
 CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-# CONFIG_SLOB is not set
-
-#
-# Loadable module support
-#
 CONFIG_MODULES=y
 # CONFIG_MODULE_UNLOAD is not set
 # CONFIG_MODVERSIONS is not set
 # CONFIG_MODULE_SRCVERSION_ALL is not set
 CONFIG_KMOD=y
-
-#
-# Block layer
-#
+CONFIG_STOP_MACHINE=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
 
 #
 # IO Schedulers
@@ -142,9 +138,11 @@ CONFIG_MPENTIUMII=y
 # CONFIG_MGEODE_LX is not set
 # CONFIG_MCYRIXIII is not set
 # CONFIG_MVIAC3_2 is not set
+# CONFIG_MVIAC7 is not set
 CONFIG_X86_GENERIC=y
 CONFIG_X86_CMPXCHG=y
 CONFIG_X86_L1_CACHE_SHIFT=7
+CONFIG_X86_XADD=y
 CONFIG_RWSEM_XCHGADD_ALGORITHM=y
 # CONFIG_ARCH_HAS_ILOG2_U32 is not set
 # CONFIG_ARCH_HAS_ILOG2_U64 is not set
@@ -153,11 +151,12 @@ CONFIG_X86_WP_WORKS_OK=y
 CONFIG_X86_INVLPG=y
 CONFIG_X86_BSWAP=y
 CONFIG_X86_POPAD_OK=y
-CONFIG_X86_CMPXCHG64=y
 CONFIG_X86_GOOD_APIC=y
 CONFIG_X86_INTEL_USERCOPY=y
 CONFIG_X86_USE_PPRO_CHECKSUM=y
 CONFIG_X86_TSC=y
+CONFIG_X86_CMOV=y
+CONFIG_X86_MINIMUM_CPU_FAMILY=4
 CONFIG_HPET_TIMER=y
 CONFIG_NR_CPUS=8
 CONFIG_SCHED_SMT=y
@@ -185,14 +184,17 @@ CONFIG_VM86=y
 # CONFIG_EDD is not set
 # CONFIG_DELL_RBU is not set
 # CONFIG_DCDBAS is not set
+CONFIG_DMIID=y
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
 # CONFIG_HIGHMEM64G is not set
 CONFIG_VMSPLIT_3G=y
 # CONFIG_VMSPLIT_3G_OPT is not set
 # CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_2G_OPT is not set
 # CONFIG_VMSPLIT_1G is not set
 CONFIG_PAGE_OFFSET=0xC0000000
+# CONFIG_X86_PAE is not set
 CONFIG_ARCH_FLATMEM_ENABLE=y
 CONFIG_ARCH_SPARSEMEM_ENABLE=y
 CONFIG_ARCH_SELECT_MEMORY_MODEL=y
@@ -207,6 +209,9 @@ CONFIG_SPARSEMEM_STATIC=y
 CONFIG_SPLIT_PTLOCK_CPUS=4
 # CONFIG_RESOURCES_64BIT is not set
 CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
 # CONFIG_MATH_EMULATION is not set
 CONFIG_MTRR=y
 # CONFIG_EFI is not set
@@ -218,11 +223,10 @@ CONFIG_HZ_250=y
 # CONFIG_HZ_1000 is not set
 CONFIG_HZ=250
 CONFIG_KEXEC=y
-CONFIG_ATAGS_PROC=y
 CONFIG_PHYSICAL_START=0x100000
 # CONFIG_RELOCATABLE is not set
 CONFIG_PHYSICAL_ALIGN=0x100000
-# CONFIG_HOTPLUG_CPU is not set
+CONFIG_HOTPLUG_CPU=y
 # CONFIG_COMPAT_VDSO is not set
 
 #
@@ -231,22 +235,25 @@ CONFIG_PHYSICAL_ALIGN=0x100000
 CONFIG_PM=y
 CONFIG_PM_LEGACY=y
 # CONFIG_PM_DEBUG is not set
-# CONFIG_PM_SYSFS_DEPRECATED is not set
-
-#
-# ACPI (Advanced Configuration and Power Interface) Support
-#
+CONFIG_PM_SLEEP_SMP=y
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND_SMP_POSSIBLE=y
+CONFIG_SUSPEND=y
+CONFIG_HIBERNATION_SMP_POSSIBLE=y
+# CONFIG_HIBERNATION is not set
 CONFIG_ACPI=y
+CONFIG_ACPI_SLEEP=y
 CONFIG_ACPI_PROCFS=y
+CONFIG_ACPI_PROC_EVENT=y
 CONFIG_ACPI_AC=y
 CONFIG_ACPI_BATTERY=y
 CONFIG_ACPI_BUTTON=y
 CONFIG_ACPI_FAN=y
 # CONFIG_ACPI_DOCK is not set
 CONFIG_ACPI_PROCESSOR=y
+CONFIG_ACPI_HOTPLUG_CPU=y
 CONFIG_ACPI_THERMAL=y
 # CONFIG_ACPI_ASUS is not set
-# CONFIG_ACPI_IBM is not set
 # CONFIG_ACPI_TOSHIBA is not set
 CONFIG_ACPI_BLACKLIST_YEAR=0
 # CONFIG_ACPI_DEBUG is not set
@@ -254,11 +261,8 @@ CONFIG_ACPI_EC=y
 CONFIG_ACPI_POWER=y
 CONFIG_ACPI_SYSTEM=y
 CONFIG_X86_PM_TIMER=y
-# CONFIG_ACPI_CONTAINER is not set
-
-#
-# APM (Advanced Power Management) BIOS Support
-#
+CONFIG_ACPI_CONTAINER=y
+# CONFIG_ACPI_SBS is not set
 # CONFIG_APM is not set
 
 #
@@ -279,6 +283,7 @@ CONFIG_PCI_DIRECT=y
 CONFIG_PCI_MMCONFIG=y
 CONFIG_PCIEPORTBUS=y
 CONFIG_PCIEAER=y
+CONFIG_ARCH_SUPPORTS_MSI=y
 CONFIG_PCI_MSI=y
 CONFIG_HT_IRQ=y
 CONFIG_ISA_DMA_API=y
@@ -292,10 +297,6 @@ CONFIG_K8_NB=y
 # PCCARD (PCMCIA/CardBus) support
 #
 # CONFIG_PCCARD is not set
-
-#
-# PCI Hotplug Support
-#
 # CONFIG_HOTPLUG_PCI is not set
 
 #
@@ -313,7 +314,6 @@ CONFIG_NET=y
 #
 # Networking options
 #
-# CONFIG_NETDEBUG is not set
 CONFIG_PACKET=m
 # CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
@@ -345,6 +345,7 @@ CONFIG_INET_TCP_DIAG=y
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
 # CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
@@ -374,7 +375,6 @@ CONFIG_NETFILTER_XTABLES=m
 # CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
 # CONFIG_NETFILTER_XT_MATCH_MAC is not set
 # CONFIG_NETFILTER_XT_MATCH_MARK is not set
-# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
 # CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
 # CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
 # CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
@@ -411,21 +411,8 @@ CONFIG_IP_NF_RAW=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-
-
-#
-# DCCP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_DCCP is not set
-
-#
-# SCTP Configuration (EXPERIMENTAL)
-#
 # CONFIG_IP_SCTP is not set
-
-#
-# TIPC Configuration (EXPERIMENTAL)
-#
 # CONFIG_TIPC is not set
 # CONFIG_ATM is not set
 # CONFIG_BRIDGE is not set
@@ -451,7 +438,17 @@ CONFIG_IP_NF_ARP_MANGLE=m
 # CONFIG_HAMRADIO is not set
 # CONFIG_IRDA is not set
 # CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+
+#
+# Wireless
+#
+# CONFIG_CFG80211 is not set
+# CONFIG_WIRELESS_EXT is not set
+# CONFIG_MAC80211 is not set
 # CONFIG_IEEE80211 is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
 
 #
 # Device Drivers
@@ -464,25 +461,10 @@ CONFIG_STANDALONE=y
 CONFIG_PREVENT_FIRMWARE_BUILD=y
 CONFIG_FW_LOADER=m
 # CONFIG_SYS_HYPERVISOR is not set
-
-#
-# Connector - unified userspace <-> kernelspace linker
-#
-# CONFIG_CONNECTOR is not set
-
-#
-# Memory Technology Devices (MTD)
-#
+CONFIG_CONNECTOR=y
+CONFIG_PROC_EVENTS=y
 # CONFIG_MTD is not set
-
-#
-# Parallel port support
-#
 # CONFIG_PARPORT is not set
-
-#
-# Plug and Play support
-#
 CONFIG_PNP=y
 # CONFIG_PNP_DEBUG is not set
 
@@ -492,10 +474,7 @@ CONFIG_PNP=y
 # CONFIG_ISAPNP is not set
 # CONFIG_PNPBIOS is not set
 CONFIG_PNPACPI=y
-
-#
-# Block devices
-#
+CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_FD is not set
 # CONFIG_BLK_DEV_XD is not set
 # CONFIG_BLK_CPQ_DA is not set
@@ -508,23 +487,19 @@ CONFIG_PNPACPI=y
 # CONFIG_BLK_DEV_SX8 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=65536
+CONFIG_BLK_DEV_RAM_COUNT=1
+CONFIG_BLK_DEV_RAM_SIZE=81920
 CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
-
-#
-# Misc devices
-#
+CONFIG_MISC_DEVICES=y
 # CONFIG_IBM_ASM is not set
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
 # CONFIG_SGI_IOC4 is not set
 # CONFIG_TIFM_CORE is not set
 # CONFIG_SONY_LAPTOP is not set
-
-#
-# ATA/ATAPI/MFM/RLL support
-#
+# CONFIG_THINKPAD_ACPI is not set
 # CONFIG_IDE is not set
 
 #
@@ -532,6 +507,7 @@ CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
 #
 # CONFIG_RAID_ATTRS is not set
 CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
 # CONFIG_SCSI_TGT is not set
 # CONFIG_SCSI_NETLINK is not set
 CONFIG_SCSI_PROC_FS=y
@@ -553,6 +529,7 @@ 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
@@ -560,12 +537,8 @@ CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_SPI_ATTRS is not set
 # CONFIG_SCSI_FC_ATTRS is not set
 # CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_ATTRS is not set
 # CONFIG_SCSI_SAS_LIBSAS is not set
-
-#
-# SCSI low-level drivers
-#
+CONFIG_SCSI_LOWLEVEL=y
 # CONFIG_ISCSI_TCP is not set
 # CONFIG_BLK_DEV_3W_XXXX_RAID is not set
 # CONFIG_SCSI_3W_9XXX is not set
@@ -617,20 +590,7 @@ CONFIG_SCSI_MULTI_LUN=y
 # CONFIG_SCSI_NSP32 is not set
 # CONFIG_SCSI_DEBUG is not set
 # CONFIG_SCSI_SRP is not set
-
-#
-# Serial ATA (prod) and Parallel ATA (experimental) drivers
-#
 # CONFIG_ATA is not set
-
-#
-# Old CD-ROM drivers (not SCSI, not IDE)
-#
-# CONFIG_CD_NO_IDESCSI is not set
-
-#
-# Multi-device support (RAID and LVM)
-#
 # CONFIG_MD is not set
 
 #
@@ -644,41 +604,20 @@ CONFIG_SCSI_MULTI_LUN=y
 #
 # IEEE 1394 (FireWire) support
 #
+# CONFIG_FIREWIRE is not set
 # CONFIG_IEEE1394 is not set
-
-#
-# I2O device support
-#
 # CONFIG_I2O is not set
-
-#
-# Macintosh device drivers
-#
-# CONFIG_MAC_EMUMOUSEBTN is not set
-
-#
-# Network device support
-#
+# CONFIG_MACINTOSH_DRIVERS is not set
 CONFIG_NETDEVICES=y
+# CONFIG_NETDEVICES_MULTIQUEUE is not set
 # 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_NET_SB1000 is not set
-
-#
-# ARCnet devices
-#
 # CONFIG_ARCNET is not set
-
-#
-# PHY device support
-#
 # CONFIG_PHYLIB is not set
-
-#
-# Ethernet (10 or 100Mbit)
-#
 CONFIG_NET_ETHERNET=y
 CONFIG_MII=y
 # CONFIG_HAPPYMEAL is not set
@@ -699,10 +638,6 @@ CONFIG_WD80x3=m
 CONFIG_ULTRA=m
 CONFIG_SMC9194=m
 # CONFIG_NET_VENDOR_RACAL is not set
-
-#
-# Tulip family network device support
-#
 CONFIG_NET_TULIP=y
 # CONFIG_DE2104X is not set
 CONFIG_TULIP=m
@@ -763,10 +698,7 @@ CONFIG_VIA_RHINE=m
 CONFIG_VIA_RHINE_MMIO=y
 CONFIG_VIA_RHINE_NAPI=y
 CONFIG_SC92031=m
-
-#
-# Ethernet (1000 Mbit)
-#
+CONFIG_NETDEV_1000=y
 CONFIG_ACENIC=m
 CONFIG_ACENIC_OMIT_TIGON_I=y
 CONFIG_DL2K=m
@@ -787,30 +719,31 @@ CONFIG_TIGON3=m
 CONFIG_BNX2=m
 CONFIG_QLA3XXX=m
 CONFIG_ATL1=m
-
-#
-# Ethernet (10000 Mbit)
-#
+CONFIG_NETDEV_10000=y
 # CONFIG_CHELSIO_T1 is not set
 # CONFIG_CHELSIO_T3 is not set
 # CONFIG_IXGB is not set
 # CONFIG_S2IO is not set
 # CONFIG_MYRI10GE is not set
 # CONFIG_NETXEN_NIC is not set
-
-#
-# Token Ring devices
-#
+# CONFIG_MLX4_CORE is not set
 # CONFIG_TR is not set
 
 #
-# Wireless LAN (non-hamradio)
+# Wireless LAN
 #
-# CONFIG_NET_RADIO is not set
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
 
 #
-# Wan interfaces
+# 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_MII is not set
+# CONFIG_USB_USBNET is not set
 # CONFIG_WAN is not set
 # CONFIG_FDDI is not set
 # CONFIG_HIPPI is not set
@@ -821,15 +754,7 @@ CONFIG_ATL1=m
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
 # CONFIG_NET_POLL_CONTROLLER is not set
-
-#
-# ISDN subsystem
-#
 # CONFIG_ISDN is not set
-
-#
-# Telephony Support
-#
 # CONFIG_PHONE is not set
 
 #
@@ -837,6 +762,7 @@ CONFIG_ATL1=m
 #
 CONFIG_INPUT=y
 # CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
 
 #
 # Userland interfaces
@@ -863,12 +789,20 @@ CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_STOWAWAY is not set
 CONFIG_INPUT_MOUSE=y
 CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
 # CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
 # CONFIG_MOUSE_INPORT is not set
 # CONFIG_MOUSE_LOGIBM is not set
 # CONFIG_MOUSE_PC110PAD is not set
 # CONFIG_MOUSE_VSXXXAA is not set
 # CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
 # CONFIG_INPUT_TOUCHSCREEN is not set
 # CONFIG_INPUT_MISC is not set
 
@@ -898,6 +832,7 @@ CONFIG_HW_CONSOLE=y
 #
 CONFIG_SERIAL_8250=y
 # CONFIG_SERIAL_8250_CONSOLE is not set
+CONFIG_FIX_EARLYCON_MEM=y
 CONFIG_SERIAL_8250_PCI=y
 CONFIG_SERIAL_8250_PNP=y
 CONFIG_SERIAL_8250_NR_UARTS=4
@@ -911,15 +846,7 @@ CONFIG_SERIAL_CORE=y
 # CONFIG_SERIAL_JSM is not set
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
-
-#
-# IPMI
-#
 # CONFIG_IPMI_HANDLER is not set
-
-#
-# Watchdog Cards
-#
 # CONFIG_WATCHDOG is not set
 # CONFIG_HW_RANDOM is not set
 # CONFIG_NVRAM is not set
@@ -941,8 +868,6 @@ CONFIG_AGP_SWORKS=m
 CONFIG_AGP_VIA=m
 CONFIG_AGP_EFFICEON=m
 # CONFIG_DRM is not set
-# CONFIG_DRM_I830 is not set
-# CONFIG_DRM_I915 is not set
 # CONFIG_MWAVE is not set
 # CONFIG_PC8736x_GPIO is not set
 # CONFIG_NSC_GPIO is not set
@@ -950,16 +875,9 @@ CONFIG_AGP_EFFICEON=m
 # CONFIG_RAW_DRIVER is not set
 # CONFIG_HPET is not set
 # CONFIG_HANGCHECK_TIMER is not set
-
-#
-# TPM devices
-#
 # CONFIG_TCG_TPM is not set
 # CONFIG_TELCLOCK is not set
-
-#
-# I2C support
-#
+CONFIG_DEVPORT=y
 # CONFIG_I2C is not set
 
 #
@@ -967,22 +885,16 @@ CONFIG_AGP_EFFICEON=m
 #
 # CONFIG_SPI is not set
 # CONFIG_SPI_MASTER is not set
-
-#
-# Dallas's 1-wire bus
-#
 # CONFIG_W1 is not set
-
-#
-# Hardware Monitoring support
-#
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
-# CONFIG_HWMON_VID is not set
 
 #
 # Multifunction device drivers
 #
 # CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_ASIC3 is not set
+# CONFIG_HTC_ASIC3_DS1WM is not set
 
 #
 # Multi-Function Devices
@@ -995,28 +907,74 @@ CONFIG_VIDEO_DEV=m
 CONFIG_VIDEO_V4L1=y
 CONFIG_VIDEO_V4L1_COMPAT=y
 CONFIG_VIDEO_V4L2=y
-
-#
-# Digital Video Broadcasting Devices
-#
-# CONFIG_DVB is not set
+CONFIG_VIDEO_CAPTURE_DRIVERS=y
+# CONFIG_VIDEO_ADV_DEBUG is not set
+CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
+# CONFIG_VIDEO_VIVI is not set
+# CONFIG_VIDEO_PMS is not set
+# CONFIG_VIDEO_CPIA is not set
+# CONFIG_VIDEO_CPIA2 is not set
+# CONFIG_VIDEO_STRADIS is not set
+CONFIG_V4L_USB_DRIVERS=y
+# CONFIG_USB_VICAM is not set
+# CONFIG_USB_IBMCAM is not set
+# CONFIG_USB_KONICAWC is not set
+# CONFIG_USB_QUICKCAM_MESSENGER is not set
+# CONFIG_USB_ET61X251 is not set
+# CONFIG_USB_OV511 is not set
+# CONFIG_USB_SE401 is not set
+# CONFIG_USB_SN9C102 is not set
+# CONFIG_USB_STV680 is not set
+# CONFIG_USB_ZC0301 is not set
+# CONFIG_USB_PWC is not set
+# CONFIG_USB_ZR364XX is not set
+CONFIG_RADIO_ADAPTERS=y
+# CONFIG_RADIO_CADET is not set
+# CONFIG_RADIO_RTRACK is not set
+# CONFIG_RADIO_RTRACK2 is not set
+# CONFIG_RADIO_AZTECH is not set
+# CONFIG_RADIO_GEMTEK is not set
+# CONFIG_RADIO_GEMTEK_PCI is not set
+# CONFIG_RADIO_MAXIRADIO is not set
+# CONFIG_RADIO_MAESTRO is not set
+# CONFIG_RADIO_SF16FMI is not set
+# CONFIG_RADIO_SF16FMR2 is not set
+# CONFIG_RADIO_TERRATEC is not set
+# CONFIG_RADIO_TRUST is not set
+# CONFIG_RADIO_TYPHOON is not set
+# CONFIG_RADIO_ZOLTRIX is not set
+# CONFIG_USB_DSBR is not set
+# CONFIG_DVB_CORE is not set
+CONFIG_DAB=y
 # CONFIG_USB_DABUSB is not set
 
 #
 # Graphics support
 #
 # CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+CONFIG_VGASTATE=y
+CONFIG_VIDEO_OUTPUT_CONTROL=m
 CONFIG_FB=y
-# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FIRMWARE_EDID=y
 # CONFIG_FB_DDC is not set
 CONFIG_FB_CFB_FILLRECT=y
 CONFIG_FB_CFB_COPYAREA=y
 CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_SYS_FOPS is not set
+CONFIG_FB_DEFERRED_IO=y
 # 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 is not set
+CONFIG_FB_TILEBLITTING=y
 
 #
 # Frame buffer hardware drivers
@@ -1027,17 +985,16 @@ CONFIG_FB_MODE_HELPERS=y
 # CONFIG_FB_ARC is not set
 # CONFIG_FB_ASILIANT is not set
 # CONFIG_FB_IMSTT is not set
-CONFIG_FB_VGA16=y
-CONFIG_FB_VESA=y
-# CONFIG_FB_VESA_STD is not set
-CONFIG_FB_VESA_TNG=y
-CONFIG_FB_VESA_DEFAULT_MODE="640x480-16@60"
-CONFIG_VIDEO_SELECT=y
+# CONFIG_FB_VGA16 is not set
+CONFIG_FB_UVESA=m
+# CONFIG_FB_VESA is not set
+# CONFIG_FB_HECUBA is not set
 # CONFIG_FB_HGA is not set
 # CONFIG_FB_S1D13XXX is not set
 # CONFIG_FB_NVIDIA is not set
 # CONFIG_FB_RIVA is not set
 # CONFIG_FB_I810 is not set
+# CONFIG_FB_LE80578 is not set
 # CONFIG_FB_INTEL is not set
 # CONFIG_FB_MATROX is not set
 # CONFIG_FB_RADEON is not set
@@ -1050,8 +1007,11 @@ CONFIG_VIDEO_SELECT=y
 # CONFIG_FB_KYRO is not set
 # CONFIG_FB_3DFX is not set
 # CONFIG_FB_VOODOO1 is not set
+# CONFIG_FB_VT8623 is not set
 # CONFIG_FB_CYBLA is not set
 # CONFIG_FB_TRIDENT is not set
+# CONFIG_FB_ARK is not set
+# CONFIG_FB_PM3 is not set
 # CONFIG_FB_GEODE is not set
 # CONFIG_FB_VIRTUAL is not set
 
@@ -1060,9 +1020,11 @@ CONFIG_VIDEO_SELECT=y
 #
 CONFIG_VGA_CONSOLE=y
 # CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_VIDEO_SELECT=y
 # CONFIG_MDA_CONSOLE is not set
 CONFIG_DUMMY_CONSOLE=y
 CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
 # CONFIG_FRAMEBUFFER_CONSOLE_ROTATION is not set
 CONFIG_FONTS=y
 CONFIG_FONT_8x8=y
@@ -1075,18 +1037,11 @@ CONFIG_FONT_8x16=y
 # CONFIG_FONT_SUN8x16 is not set
 # CONFIG_FONT_SUN12x22 is not set
 # CONFIG_FONT_10x18 is not set
-
-#
-# Logo configuration
-#
 CONFIG_LOGO=y
 # CONFIG_LOGO_LINUX_MONO is not set
 # CONFIG_LOGO_LINUX_VGA16 is not set
 # CONFIG_LOGO_LINUX_CLUT224 is not set
 CONFIG_LOGO_OHAND_CLUT224=y
-# CONFIG_LOGO_OZ240_CLUT224 is not set
-# CONFIG_LOGO_OZ480_CLUT224 is not set
-# CONFIG_LOGO_OZ640_CLUT224 is not set
 
 #
 # Sound
@@ -1173,6 +1128,7 @@ CONFIG_SND_AC97_CODEC=y
 # CONFIG_SND_CMIPCI is not set
 # CONFIG_SND_CS4281 is not set
 # CONFIG_SND_CS46XX is not set
+# CONFIG_SND_CS5530 is not set
 # CONFIG_SND_CS5535AUDIO is not set
 # CONFIG_SND_DARLA20 is not set
 # CONFIG_SND_GINA20 is not set
@@ -1222,27 +1178,34 @@ CONFIG_SND_AC97_POWER_SAVE=y
 #
 # CONFIG_SND_USB_AUDIO is not set
 # CONFIG_SND_USB_USX2Y is not set
+# CONFIG_SND_USB_CAIAQ is not set
 
 #
-# SoC audio support
+# System on Chip audio support
 #
 # CONFIG_SND_SOC is not set
 
 #
-# Open Sound System
+# SoC Audio support for SuperH
 #
-# CONFIG_SOUND_PRIME is not set
-CONFIG_AC97_BUS=y
 
 #
-# HID Devices
+# Open Sound System
 #
+# CONFIG_SOUND_PRIME is not set
+CONFIG_AC97_BUS=y
+CONFIG_HID_SUPPORT=y
 CONFIG_HID=y
 # CONFIG_HID_DEBUG is not set
 
 #
-# USB support
+# USB Input Devices
 #
+CONFIG_USB_HID=y
+# CONFIG_USB_HIDINPUT_POWERBOOK is not set
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV is not set
+CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 CONFIG_USB_ARCH_HAS_EHCI=y
@@ -1253,8 +1216,10 @@ CONFIG_USB=y
 # 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_PERSIST is not set
 # CONFIG_USB_OTG is not set
 
 #
@@ -1264,7 +1229,6 @@ CONFIG_USB_EHCI_HCD=y
 CONFIG_USB_EHCI_SPLIT_ISO=y
 # CONFIG_USB_EHCI_ROOT_HUB_TT is not set
 # CONFIG_USB_EHCI_TT_NEWSCHED is not set
-# CONFIG_USB_EHCI_BIG_ENDIAN_MMIO is not set
 # CONFIG_USB_ISP116X_HCD is not set
 CONFIG_USB_OHCI_HCD=y
 # CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
@@ -1272,6 +1236,7 @@ CONFIG_USB_OHCI_HCD=y
 CONFIG_USB_OHCI_LITTLE_ENDIAN=y
 CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
 
 #
 # USB Device Class drivers
@@ -1289,42 +1254,11 @@ CONFIG_USB_UHCI_HCD=y
 # CONFIG_USB_STORAGE is not set
 # CONFIG_USB_LIBUSUAL is not set
 
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=y
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-# CONFIG_USB_AIPTEK is not set
-CONFIG_USB_WACOM=y
-# CONFIG_USB_ACECAD is not set
-# CONFIG_USB_KBTAB is not set
-# CONFIG_USB_POWERMATE is not set
-# CONFIG_USB_TOUCHSCREEN is not set
-# CONFIG_USB_YEALINK is not set
-# CONFIG_USB_XPAD is not set
-# CONFIG_USB_ATI_REMOTE is not set
-# CONFIG_USB_ATI_REMOTE2 is not set
-# CONFIG_USB_KEYSPAN_REMOTE is not set
-# CONFIG_USB_APPLETOUCH is not set
-# CONFIG_USB_GTCO is not set
-
 #
 # USB Imaging devices
 #
 # CONFIG_USB_MDC800 is not set
 # CONFIG_USB_MICROTEK 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_MII is not set
-# CONFIG_USB_USBNET is not set
 # CONFIG_USB_MON is not set
 
 #
@@ -1368,38 +1302,10 @@ CONFIG_USB_WACOM=y
 # USB Gadget Support
 #
 # CONFIG_USB_GADGET is not set
-
-#
-# MMC/SD Card support
-#
 # CONFIG_MMC is not set
-
-#
-# LED devices
-#
 # CONFIG_NEW_LEDS is not set
-
-#
-# LED drivers
-#
-
-#
-# LED Triggers
-#
-
-#
-# InfiniBand support
-#
 # CONFIG_INFINIBAND is not set
-
-#
-# EDAC - error detection and reporting (RAS) (EXPERIMENTAL)
-#
 # CONFIG_EDAC is not set
-
-#
-# Real Time Clock
-#
 # CONFIG_RTC_CLASS is not set
 
 #
@@ -1414,15 +1320,13 @@ CONFIG_USB_WACOM=y
 #
 # DMA Devices
 #
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
 
 #
-# Auxiliary Display support
-#
-
-#
-# Virtualization
+# Userspace I/O
 #
-# CONFIG_KVM is not set
+# CONFIG_UIO is not set
 
 #
 # File systems
@@ -1431,7 +1335,13 @@ 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_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -1499,13 +1409,22 @@ CONFIG_RAMFS=y
 # Network File Systems
 #
 CONFIG_NFS_FS=y
+# CONFIG_NFS_V3 is not set
+# CONFIG_NFS_V4 is not set
+# CONFIG_NFS_DIRECTIO is not set
 # CONFIG_NFSD is not set
+# CONFIG_ROOT_NFS is not set
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# CONFIG_SUNRPC_BIND34 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
-# CONFIG_9P_FS is not set
 
 #
 # Partition Types
@@ -1561,10 +1480,7 @@ CONFIG_NLS_UTF8=y
 # Distributed Lock Manager
 #
 # CONFIG_DLM is not set
-
-#
-# Instrumentation Support
-#
+CONFIG_INSTRUMENTATION=y
 CONFIG_PROFILING=y
 CONFIG_OPROFILE=y
 # CONFIG_KPROBES is not set
@@ -1580,8 +1496,6 @@ CONFIG_MAGIC_SYSRQ=y
 # CONFIG_DEBUG_FS is not set
 # CONFIG_HEADERS_CHECK is not set
 # CONFIG_DEBUG_KERNEL is not set
-CONFIG_LOG_BUF_SHIFT=15
-CONFIG_TIMER_STATS=y
 # CONFIG_DEBUG_BUGVERBOSE is not set
 CONFIG_EARLY_PRINTK=y
 CONFIG_X86_FIND_SMP_CONFIG=y
@@ -1593,10 +1507,6 @@ CONFIG_DOUBLEFAULT=y
 #
 # CONFIG_KEYS is not set
 # CONFIG_SECURITY is not set
-
-#
-# Cryptographic options
-#
 CONFIG_CRYPTO=y
 CONFIG_CRYPTO_ALGAPI=m
 CONFIG_CRYPTO_BLKCIPHER=m
@@ -1616,6 +1526,7 @@ CONFIG_CRYPTO_ECB=m
 CONFIG_CRYPTO_CBC=m
 CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_LRW is not set
+# CONFIG_CRYPTO_CRYPTD is not set
 # CONFIG_CRYPTO_DES is not set
 # CONFIG_CRYPTO_FCRYPT is not set
 # CONFIG_CRYPTO_BLOWFISH is not set
@@ -1636,10 +1547,7 @@ CONFIG_CRYPTO_PCBC=m
 # CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
 # CONFIG_CRYPTO_TEST is not set
-
-#
-# Hardware crypto devices
-#
+CONFIG_CRYPTO_HW=y
 CONFIG_CRYPTO_DEV_PADLOCK=m
 CONFIG_CRYPTO_DEV_PADLOCK_AES=m
 CONFIG_CRYPTO_DEV_PADLOCK_SHA=m
@@ -1651,14 +1559,16 @@ CONFIG_CRYPTO_DEV_GEODE=m
 CONFIG_BITREVERSE=y
 CONFIG_CRC_CCITT=m
 # CONFIG_CRC16 is not set
+# CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
 CONFIG_LIBCRC32C=m
 CONFIG_AUDIT_GENERIC=y
-# CONFIG_LZO is not set
 CONFIG_ZLIB_INFLATE=m
 CONFIG_PLIST=y
 CONFIG_HAS_IOMEM=y
 CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
 CONFIG_GENERIC_HARDIRQS=y
 CONFIG_GENERIC_IRQ_PROBE=y
 CONFIG_GENERIC_PENDING_IRQ=y
@@ -1667,4 +1577,3 @@ CONFIG_X86_HT=y
 CONFIG_X86_BIOS_REBOOT=y
 CONFIG_X86_TRAMPOLINE=y
 CONFIG_KTIME_SCALAR=y
-# CONFIG_SHARPSL_RC is not set
index 4f6b8d2..f1d0295 100644 (file)
@@ -34,7 +34,7 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
index fd10d3d..64e5090 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
 # General setup
 #
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
index ead49c2..3f33b14 100644 (file)
@@ -34,7 +34,7 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
index 09ce9e5..447d26d 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
 # General setup
 #
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 # CONFIG_SWAP is not set
 CONFIG_SYSVIPC=y
 # CONFIG_IPC_NS is not set
index 210997d..5afa7c5 100644 (file)
@@ -34,7 +34,7 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
index c369657..78f08be 100644 (file)
@@ -32,7 +32,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
index c5e91d9..62bbace 100644 (file)
@@ -31,7 +31,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
index a4e849c..d3512f2 100644 (file)
@@ -34,7 +34,7 @@ CONFIG_BROKEN_ON_SMP=y
 CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
index 5173e24..d005193 100644 (file)
@@ -21,7 +21,7 @@ CONFIG_INIT_ENV_ARG_LIMIT=32
 # General setup
 #
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 # CONFIG_POSIX_MQUEUE is not set
index 8be4a3b..d989749 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
-# Linux kernel version: 2.6.23-rc4
-# Tue Sep 25 15:57:10 2007
+# Linux kernel version: 2.6.23
+# Mon Feb 18 01:42:46 2008
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -33,7 +33,7 @@ CONFIG_EXPERIMENTAL=y
 CONFIG_BROKEN_ON_SMP=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
-CONFIG_LOCALVERSION_AUTO=y
+# CONFIG_LOCALVERSION_AUTO is not set
 CONFIG_SWAP=y
 CONFIG_SYSVIPC=y
 CONFIG_SYSVIPC_SYSCTL=y
@@ -65,7 +65,6 @@ CONFIG_FUTEX=y
 CONFIG_ANON_INODES=y
 CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
-CONFIG_TIMERFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
 CONFIG_VM_EVENT_COUNTERS=y
@@ -262,6 +261,7 @@ CONFIG_BINFMT_ELF=y
 # Power management options
 #
 # CONFIG_PM is not set
+CONFIG_SUSPEND_UP_POSSIBLE=y
 
 #
 # Networking
@@ -272,6 +272,7 @@ CONFIG_NET=y
 # Networking options
 #
 CONFIG_PACKET=m
+# CONFIG_PACKET_MMAP is not set
 CONFIG_UNIX=y
 CONFIG_XFRM=y
 # CONFIG_XFRM_USER is not set
@@ -304,6 +305,7 @@ CONFIG_INET_TCP_DIAG=y
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
+# CONFIG_IP_VS is not set
 # CONFIG_IPV6 is not set
 # CONFIG_INET6_XFRM_TUNNEL is not set
 # CONFIG_INET6_TUNNEL is not set
@@ -370,7 +372,6 @@ CONFIG_IP_NF_RAW=m
 CONFIG_IP_NF_ARPTABLES=m
 CONFIG_IP_NF_ARPFILTER=m
 CONFIG_IP_NF_ARP_MANGLE=m
-
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
@@ -551,6 +552,7 @@ CONFIG_MTD_NAND=y
 CONFIG_MTD_NAND_IDS=y
 # CONFIG_MTD_NAND_DISKONCHIP is not set
 # CONFIG_MTD_NAND_SHARPSL is not set
+CONFIG_MTD_NAND_ZYLONITE=y
 # CONFIG_MTD_NAND_NANDSIM is not set
 # CONFIG_MTD_NAND_PLATFORM is not set
 # CONFIG_MTD_ONENAND is not set
@@ -727,11 +729,13 @@ CONFIG_KEYBOARD_ATKBD=y
 # CONFIG_KEYBOARD_XTKBD is not set
 # CONFIG_KEYBOARD_NEWTON is not set
 # CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_KEYBOARD_PXA27x=y
 # CONFIG_KEYBOARD_GPIO is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
 CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ZYLONITE=y
 # CONFIG_TOUCHSCREEN_FUJITSU is not set
 # CONFIG_TOUCHSCREEN_GUNZE is not set
 # CONFIG_TOUCHSCREEN_ELO is not set
@@ -964,11 +968,8 @@ CONFIG_FONT_8x16=y
 CONFIG_LOGO=y
 CONFIG_LOGO_LINUX_MONO=y
 CONFIG_LOGO_LINUX_VGA16=y
-CONFIG_LOGO_LINUX_CLUT224=y
-# CONFIG_LOGO_OHAND_CLUT224 is not set
-# CONFIG_LOGO_OZ240_CLUT224 is not set
-# CONFIG_LOGO_OZ480_CLUT224 is not set
-# CONFIG_LOGO_OZ640_CLUT224 is not set
+# CONFIG_LOGO_LINUX_CLUT224 is not set
+CONFIG_LOGO_OHAND_CLUT224=y
 
 #
 # Sound
@@ -1237,7 +1238,13 @@ 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_EXT4DEV_FS is not set
+CONFIG_JBD=m
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
diff --git a/packages/linux/linux-rp-2.6.23/zylonite_keypad-r0.patch b/packages/linux/linux-rp-2.6.23/zylonite_keypad-r0.patch
new file mode 100644 (file)
index 0000000..1889b38
--- /dev/null
@@ -0,0 +1,1187 @@
+Eric Miao's pxa keypad patchset backport.
+---
+ arch/arm/mach-pxa/devices.h                |    1 
+ arch/arm/mach-pxa/generic.c                |   31 +
+ arch/arm/mach-pxa/pxa27x.c                 |    2 
+ arch/arm/mach-pxa/pxa300.c                 |    6 
+ arch/arm/mach-pxa/pxa3xx.c                 |    1 
+ arch/arm/mach-pxa/zylonite.c               |   68 +++
+ drivers/input/keyboard/Kconfig             |    8 
+ drivers/input/keyboard/Makefile            |    2 
+ drivers/input/keyboard/pxa27x_keyboard.c   |  273 -------------
+ drivers/input/keyboard/pxa27x_keypad.c     |  575 +++++++++++++++++++++++++++++
+ include/asm-arm/arch-pxa/irqs.h            |    2 
+ include/asm-arm/arch-pxa/pxa27x_keyboard.h |   13 
+ include/asm-arm/arch-pxa/pxa27x_keypad.h   |   58 ++
+ 13 files changed, 745 insertions(+), 295 deletions(-)
+
+Index: linux-2.6.23-z-input/drivers/input/keyboard/Kconfig
+===================================================================
+--- linux-2.6.23-z-input.orig/drivers/input/keyboard/Kconfig   2008-02-18 01:43:28.000000000 +0100
++++ linux-2.6.23-z-input/drivers/input/keyboard/Kconfig        2008-02-18 01:43:28.000000000 +0100
+@@ -218,13 +218,13 @@
+         module will be called omap-keypad.
+ config KEYBOARD_PXA27x
+-      tristate "PXA27x keyboard support"
+-      depends on PXA27x
++      tristate "PXA27x/PXA3xx keypad support"
++      depends on PXA27x || PXA3xx
+       help
+-        Enable support for PXA27x matrix keyboard controller
++        Enable support for PXA27x/PXA3xx keypad controller
+         To compile this driver as a module, choose M here: the
+-        module will be called pxa27x_keyboard.
++        module will be called pxa27x_keypad.
+ config KEYBOARD_AAED2000
+       tristate "AAED-2000 keyboard"
+Index: linux-2.6.23-z-input/drivers/input/keyboard/Makefile
+===================================================================
+--- linux-2.6.23-z-input.orig/drivers/input/keyboard/Makefile  2008-02-18 01:43:28.000000000 +0100
++++ linux-2.6.23-z-input/drivers/input/keyboard/Makefile       2008-02-18 01:43:28.000000000 +0100
+@@ -18,7 +18,7 @@
+ obj-$(CONFIG_KEYBOARD_HIL)            += hil_kbd.o
+ obj-$(CONFIG_KEYBOARD_HIL_OLD)                += hilkbd.o
+ obj-$(CONFIG_KEYBOARD_OMAP)           += omap-keypad.o
+-obj-$(CONFIG_KEYBOARD_PXA27x)         += pxa27x_keyboard.o
++obj-$(CONFIG_KEYBOARD_PXA27x)         += pxa27x_keypad.o
+ obj-$(CONFIG_KEYBOARD_AAED2000)               += aaed2000_kbd.o
+ obj-$(CONFIG_KEYBOARD_GPIO)           += gpio_keys.o
+ obj-$(CONFIG_KEYBOARD_ASIC3)          += asic3_keys.o
+Index: linux-2.6.23-z-input/drivers/input/keyboard/pxa27x_keypad.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23-z-input/drivers/input/keyboard/pxa27x_keypad.c        2008-02-19 01:40:04.000000000 +0100
+@@ -0,0 +1,575 @@
++/*
++ * linux/drivers/input/keyboard/pxa27x_keypad.c
++ *
++ * Driver for the pxa27x matrix keyboard controller.
++ *
++ * Created:   Feb 22, 2007
++ * Author:    Rodolfo Giometti <giometti@linux.it>
++ *
++ * Based on a previous implementations by Kevin O'Connor
++ * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
++ * on some suggestions by Nicolas Pitre <nico@cam.org>.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ */
++
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/input.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/clk.h>
++#include <linux/err.h>
++
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/map.h>
++
++#include <asm/arch/hardware.h>
++#include <asm/arch/mfp.h>
++#include <asm/arch/pxa27x_keypad.h>
++
++#define BIT_MASK(nr)            (1UL << ((nr) % BITS_PER_LONG))
++
++/*
++ * Keypad Controller registers
++ */
++#define KPC             0x0000 /* Keypad Control register */
++#define KPDK            0x0008 /* Keypad Direct Key register */
++#define KPREC           0x0010 /* Keypad Rotary Encoder register */
++#define KPMK            0x0018 /* Keypad Matrix Key register */
++#define KPAS            0x0020 /* Keypad Automatic Scan register */
++
++/* Keypad Automatic Scan Multiple Key Presser register 0-3 */
++#define KPASMKP0        0x0028
++#define KPASMKP1        0x0030
++#define KPASMKP2        0x0038
++#define KPASMKP3        0x0040
++#define KPKDI           0x0048
++
++/* bit definitions */
++#define KPC_MKRN(n)   ((((n) - 1) & 0x7) << 26) /* matrix key row number */
++#define KPC_MKCN(n)   ((((n) - 1) & 0x7) << 23) /* matrix key column number */
++#define KPC_DKN(n)    ((((n) - 1) & 0x7) << 6)  /* direct key number */
++
++#define KPC_AS          (0x1 << 30)  /* Automatic Scan bit */
++#define KPC_ASACT       (0x1 << 29)  /* Automatic Scan on Activity */
++#define KPC_MI          (0x1 << 22)  /* Matrix interrupt bit */
++#define KPC_IMKP        (0x1 << 21)  /* Ignore Multiple Key Press */
++
++#define KPC_MS(n)     (0x1 << (13 + (n)))     /* Matrix scan line 'n' */
++#define KPC_MS_ALL      (0xff << 13)
++
++#define KPC_ME          (0x1 << 12)  /* Matrix Keypad Enable */
++#define KPC_MIE         (0x1 << 11)  /* Matrix Interrupt Enable */
++#define KPC_DK_DEB_SEL        (0x1 <<  9)  /* Direct Keypad Debounce Select */
++#define KPC_DI          (0x1 <<  5)  /* Direct key interrupt bit */
++#define KPC_RE_ZERO_DEB (0x1 <<  4)  /* Rotary Encoder Zero Debounce */
++#define KPC_REE1        (0x1 <<  3)  /* Rotary Encoder1 Enable */
++#define KPC_REE0        (0x1 <<  2)  /* Rotary Encoder0 Enable */
++#define KPC_DE          (0x1 <<  1)  /* Direct Keypad Enable */
++#define KPC_DIE         (0x1 <<  0)  /* Direct Keypad interrupt Enable */
++
++#define KPDK_DKP        (0x1 << 31)
++#define KPDK_DK(n)    ((n) & 0xff)
++
++#define KPREC_OF1       (0x1 << 31)
++#define kPREC_UF1       (0x1 << 30)
++#define KPREC_OF0       (0x1 << 15)
++#define KPREC_UF0       (0x1 << 14)
++
++#define KPREC_RECOUNT0(n)     ((n) & 0xff)
++#define KPREC_RECOUNT1(n)     (((n) >> 16) & 0xff)
++
++#define KPMK_MKP        (0x1 << 31)
++#define KPAS_SO         (0x1 << 31)
++#define KPASMKPx_SO     (0x1 << 31)
++
++#define KPAS_MUKP(n)  (((n) >> 26) & 0x1f)
++#define KPAS_RP(n)    (((n) >> 4) & 0xf)
++#define KPAS_CP(n)    ((n) & 0xf)
++
++#define KPASMKP_MKC_MASK      (0xff)
++
++#define keypad_readl(off)     __raw_readl(keypad->mmio_base + (off))
++#define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off))
++
++#define MAX_MATRIX_KEY_NUM    (8 * 8)
++
++struct pxa27x_keypad {
++      struct pxa27x_keypad_platform_data *pdata;
++
++      struct clk *clk;
++      struct input_dev *input_dev;
++      void __iomem *mmio_base;
++
++      /* matrix key code map */
++      unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
++
++      /* state row bits of each column scan */
++      uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
++      uint32_t direct_key_state;
++
++      unsigned int direct_key_mask;
++
++      int rotary_rel_code[2];
++      int rotary_up_key[2];
++      int rotary_down_key[2];
++};
++
++static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
++{
++      struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
++      struct input_dev *input_dev = keypad->input_dev;
++      unsigned int *key;
++      int i;
++
++      key = &pdata->matrix_key_map[0];
++      for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
++              int row = ((*key) >> 28) & 0xf;
++              int col = ((*key) >> 24) & 0xf;
++              int code = (*key) & 0xffffff;
++
++              keypad->matrix_keycodes[(row << 3) + col] = code;
++              set_bit(code, input_dev->keybit);
++      }
++
++      keypad->rotary_up_key[0] = pdata->rotary0_up_key;
++      keypad->rotary_up_key[1] = pdata->rotary1_up_key;
++      keypad->rotary_down_key[0] = pdata->rotary0_down_key;
++      keypad->rotary_down_key[1] = pdata->rotary1_down_key;
++      keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
++      keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
++
++      if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
++              set_bit(pdata->rotary0_up_key, input_dev->keybit);
++              set_bit(pdata->rotary0_down_key, input_dev->keybit);
++      } else
++              set_bit(pdata->rotary0_rel_code, input_dev->relbit);
++
++      if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
++              set_bit(pdata->rotary1_up_key, input_dev->keybit);
++              set_bit(pdata->rotary1_down_key, input_dev->keybit);
++      } else
++              set_bit(pdata->rotary1_rel_code, input_dev->relbit);
++}
++
++static inline unsigned int lookup_matrix_keycode(
++              struct pxa27x_keypad *keypad, int row, int col)
++{
++      return keypad->matrix_keycodes[(row << 3) + col];
++}
++
++static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
++{
++      struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
++      int row, col, num_keys_pressed = 0;
++      uint32_t new_state[MAX_MATRIX_KEY_COLS];
++      uint32_t kpas = keypad_readl(KPAS);
++
++      num_keys_pressed = KPAS_MUKP(kpas);
++
++      memset(new_state, 0, sizeof(new_state));
++
++      if (num_keys_pressed == 0)
++              goto scan;
++
++      if (num_keys_pressed == 1) {
++              col = KPAS_CP(kpas);
++              row = KPAS_RP(kpas);
++
++              /* if invalid row/col, treat as no key pressed */
++              if (col >= pdata->matrix_key_cols ||
++                  row >= pdata->matrix_key_rows)
++                      goto scan;
++
++              new_state[col] = (1 << row);
++              goto scan;
++      }
++
++      if (num_keys_pressed > 1) {
++              uint32_t kpasmkp0 = keypad_readl(KPASMKP0);
++              uint32_t kpasmkp1 = keypad_readl(KPASMKP1);
++              uint32_t kpasmkp2 = keypad_readl(KPASMKP2);
++              uint32_t kpasmkp3 = keypad_readl(KPASMKP3);
++
++              new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK;
++              new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK;
++              new_state[2] = kpasmkp1 & KPASMKP_MKC_MASK;
++              new_state[3] = (kpasmkp1 >> 16) & KPASMKP_MKC_MASK;
++              new_state[4] = kpasmkp2 & KPASMKP_MKC_MASK;
++              new_state[5] = (kpasmkp2 >> 16) & KPASMKP_MKC_MASK;
++              new_state[6] = kpasmkp3 & KPASMKP_MKC_MASK;
++              new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK;
++      }
++scan:
++      for (col = 0; col < pdata->matrix_key_cols; col++) {
++              uint32_t bits_changed;
++
++              bits_changed = keypad->matrix_key_state[col] ^ new_state[col];
++              if (bits_changed == 0)
++                      continue;
++
++              for (row = 0; row < pdata->matrix_key_rows; row++) {
++                      if ((bits_changed & (1 << row)) == 0)
++                              continue;
++
++                      input_report_key(keypad->input_dev,
++                              lookup_matrix_keycode(keypad, row, col),
++                              new_state[col] & (1 << row));
++              }
++      }
++      input_sync(keypad->input_dev);
++      memcpy(keypad->matrix_key_state, new_state, sizeof(new_state));
++}
++
++#define DEFAULT_KPREC (0x007f007f)
++
++static inline int rotary_delta(uint32_t kprec)
++{
++      if (kprec & KPREC_OF0)
++              return (kprec & 0xff) + 0x7f;
++      else if (kprec & KPREC_UF0)
++              return (kprec & 0xff) - 0x7f - 0xff;
++      else
++              return (kprec & 0xff) - 0x7f;
++}
++
++static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
++{
++      struct input_dev *dev = keypad->input_dev;
++
++      if (delta == 0)
++              return;
++
++      if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) {
++              int keycode = (delta > 0) ? keypad->rotary_up_key[r] :
++                                          keypad->rotary_down_key[r];
++
++              /* simulate a press-n-release */
++              input_report_key(dev, keycode, 1);
++              input_sync(dev);
++              input_report_key(dev, keycode, 0);
++              input_sync(dev);
++      } else {
++              input_report_rel(dev, keypad->rotary_rel_code[r], delta);
++              input_sync(dev);
++      }
++}
++
++static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
++{
++      struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
++      uint32_t kprec;
++
++      /* read and reset to default count value */
++      kprec = keypad_readl(KPREC);
++      keypad_writel(KPREC, DEFAULT_KPREC);
++
++      if (pdata->enable_rotary0)
++              report_rotary_event(keypad, 0, rotary_delta(kprec));
++
++      if (pdata->enable_rotary1)
++              report_rotary_event(keypad, 1, rotary_delta(kprec >> 16));
++}
++
++static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
++{
++      struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
++      unsigned int new_state;
++      uint32_t kpdk, bits_changed;
++      int i;
++
++      kpdk = keypad_readl(KPDK);
++
++      if (pdata->enable_rotary0 || pdata->enable_rotary1)
++              pxa27x_keypad_scan_rotary(keypad);
++
++      if (pdata->direct_key_map == NULL)
++              return;
++
++      new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
++      bits_changed = keypad->direct_key_state ^ new_state;
++
++      if (bits_changed == 0)
++              return;
++
++      for (i = 0; i < pdata->direct_key_num; i++) {
++              if (bits_changed & (1 << i))
++                      input_report_key(keypad->input_dev,
++                                      pdata->direct_key_map[i],
++                                      (new_state & (1 << i)));
++      }
++      input_sync(keypad->input_dev);
++      keypad->direct_key_state = new_state;
++}
++
++static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
++{
++      struct pxa27x_keypad *keypad = dev_id;
++      unsigned long kpc = keypad_readl(KPC);
++
++      if (kpc & KPC_DI)
++              pxa27x_keypad_scan_direct(keypad);
++
++      if (kpc & KPC_MI)
++              pxa27x_keypad_scan_matrix(keypad);
++
++      return IRQ_HANDLED;
++}
++
++static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
++{
++      struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
++      unsigned int mask = 0, direct_key_num = 0;
++      unsigned long kpc = 0;
++
++      /* enable matrix keys with automatic scan */
++      if (pdata->matrix_key_rows && pdata->matrix_key_cols) {
++              kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL;
++              kpc |= KPC_MKRN(pdata->matrix_key_rows) |
++                     KPC_MKCN(pdata->matrix_key_cols);
++      }
++
++      /* enable rotary key, debounce interval same as direct keys */
++      if (pdata->enable_rotary0) {
++              mask |= 0x03;
++              direct_key_num = 2;
++              kpc |= KPC_REE0;
++      }
++
++      if (pdata->enable_rotary1) {
++              mask |= 0x0c;
++              direct_key_num = 4;
++              kpc |= KPC_REE1;
++      }
++
++      if (pdata->direct_key_num > direct_key_num)
++              direct_key_num = pdata->direct_key_num;
++
++      keypad->direct_key_mask = ((2 << direct_key_num) - 1) & ~mask;
++
++      /* enable direct key */
++      if (direct_key_num)
++              kpc |= KPC_DE | KPC_DIE | KPC_DKN(direct_key_num);
++
++      keypad_writel(KPC, kpc | KPC_RE_ZERO_DEB);
++      keypad_writel(KPREC, DEFAULT_KPREC);
++      keypad_writel(KPKDI, pdata->debounce_interval);
++}
++
++static int pxa27x_keypad_open(struct input_dev *dev)
++{
++      struct pxa27x_keypad *keypad = input_get_drvdata(dev);
++
++      /* Enable unit clock */
++      clk_enable(keypad->clk);
++      pxa27x_keypad_config(keypad);
++
++      return 0;
++}
++
++static void pxa27x_keypad_close(struct input_dev *dev)
++{
++      struct pxa27x_keypad *keypad = input_get_drvdata(dev);
++
++      /* Disable clock unit */
++      clk_disable(keypad->clk);
++}
++
++#ifdef CONFIG_PM
++static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
++
++      clk_disable(keypad->clk);
++      return 0;
++}
++
++static int pxa27x_keypad_resume(struct platform_device *pdev)
++{
++      struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
++      struct input_dev *input_dev = keypad->input_dev;
++
++      mutex_lock(&input_dev->mutex);
++
++      if (input_dev->users) {
++              /* Enable unit clock */
++              clk_enable(keypad->clk);
++              pxa27x_keypad_config(keypad);
++      }
++
++      mutex_unlock(&input_dev->mutex);
++
++      return 0;
++}
++#else
++#define pxa27x_keypad_suspend NULL
++#define pxa27x_keypad_resume  NULL
++#endif
++
++#define res_size(res) ((res)->end - (res)->start + 1)
++
++static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
++{
++      struct pxa27x_keypad *keypad;
++      struct input_dev *input_dev;
++      struct resource *res;
++      int irq, error;
++
++      keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL);
++      if (keypad == NULL) {
++              dev_err(&pdev->dev, "failed to allocate driver data\n");
++              return -ENOMEM;
++      }
++
++      keypad->pdata = pdev->dev.platform_data;
++      if (keypad->pdata == NULL) {
++              dev_err(&pdev->dev, "no platform data defined\n");
++              error = -EINVAL;
++              goto failed_free;
++      }
++
++      irq = platform_get_irq(pdev, 0);
++      if (irq < 0) {
++              dev_err(&pdev->dev, "failed to get keypad irq\n");
++              error = -ENXIO;
++              goto failed_free;
++      }
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      if (res == NULL) {
++              dev_err(&pdev->dev, "failed to get I/O memory\n");
++              error = -ENXIO;
++              goto failed_free;
++      }
++
++      res = request_mem_region(res->start, res_size(res), pdev->name);
++      if (res == NULL) {
++              dev_err(&pdev->dev, "failed to request I/O memory\n");
++              error = -EBUSY;
++              goto failed_free;
++      }
++
++      keypad->mmio_base = ioremap(res->start, res_size(res));
++      if (keypad->mmio_base == NULL) {
++              dev_err(&pdev->dev, "failed to remap I/O memory\n");
++              error = -ENXIO;
++              goto failed_free_mem;
++      }
++
++      keypad->clk = clk_get(&pdev->dev, "KBDCLK");
++      if (IS_ERR(keypad->clk)) {
++              dev_err(&pdev->dev, "failed to get keypad clock\n");
++              error = PTR_ERR(keypad->clk);
++              goto failed_free_io;
++      }
++
++      /* Create and register the input driver. */
++      input_dev = input_allocate_device();
++      if (!input_dev) {
++              dev_err(&pdev->dev, "failed to allocate input device\n");
++              error = -ENOMEM;
++              goto failed_put_clk;
++      }
++
++      input_dev->name = pdev->name;
++      input_dev->id.bustype = BUS_HOST;
++      input_dev->open = pxa27x_keypad_open;
++      input_dev->close = pxa27x_keypad_close;
++      input_dev->dev.parent = &pdev->dev;
++
++      keypad->input_dev = input_dev;
++      input_set_drvdata(input_dev, keypad);
++
++      input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
++              BIT_MASK(EV_REL);
++
++      pxa27x_keypad_build_keycode(keypad);
++      platform_set_drvdata(pdev, keypad);
++
++      error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED,
++                          pdev->name, keypad);
++      if (error) {
++              dev_err(&pdev->dev, "failed to request IRQ\n");
++              goto failed_free_dev;
++      }
++
++      /* Register the input device */
++      error = input_register_device(input_dev);
++      if (error) {
++              dev_err(&pdev->dev, "failed to register input device\n");
++              goto failed_free_irq;
++      }
++
++      return 0;
++
++failed_free_irq:
++      free_irq(irq, pdev);
++      platform_set_drvdata(pdev, NULL);
++failed_free_dev:
++      input_free_device(input_dev);
++failed_put_clk:
++      clk_put(keypad->clk);
++failed_free_io:
++      iounmap(keypad->mmio_base);
++failed_free_mem:
++      release_mem_region(res->start, res_size(res));
++failed_free:
++      kfree(keypad);
++      return error;
++}
++
++static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
++{
++      struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
++      struct resource *res;
++
++      free_irq(platform_get_irq(pdev, 0), pdev);
++
++      clk_disable(keypad->clk);
++      clk_put(keypad->clk);
++
++      input_unregister_device(keypad->input_dev);
++      input_free_device(keypad->input_dev);
++
++      iounmap(keypad->mmio_base);
++
++      res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++      release_mem_region(res->start, res_size(res));
++
++      platform_set_drvdata(pdev, NULL);
++      kfree(keypad);
++      return 0;
++}
++
++static struct platform_driver pxa27x_keypad_driver = {
++      .probe          = pxa27x_keypad_probe,
++      .remove         = __devexit_p(pxa27x_keypad_remove),
++      .suspend        = pxa27x_keypad_suspend,
++      .resume         = pxa27x_keypad_resume,
++      .driver         = {
++              .name   = "pxa27x-keypad",
++      },
++};
++
++static int __init pxa27x_keypad_init(void)
++{
++      return platform_driver_register(&pxa27x_keypad_driver);
++}
++
++static void __exit pxa27x_keypad_exit(void)
++{
++      platform_driver_unregister(&pxa27x_keypad_driver);
++}
++
++module_init(pxa27x_keypad_init);
++module_exit(pxa27x_keypad_exit);
++
++MODULE_DESCRIPTION("PXA27x Keypad Controller Driver");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.23-z-input/include/asm-arm/arch-pxa/pxa27x_keyboard.h
+===================================================================
+--- linux-2.6.23-z-input.orig/include/asm-arm/arch-pxa/pxa27x_keyboard.h       2007-10-09 22:31:38.000000000 +0200
++++ /dev/null  1970-01-01 00:00:00.000000000 +0000
+@@ -1,13 +0,0 @@
+-#define PXAKBD_MAXROW         8
+-#define PXAKBD_MAXCOL         8
+-
+-struct pxa27x_keyboard_platform_data {
+-      int nr_rows, nr_cols;
+-      int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL];
+-      int gpio_modes[PXAKBD_MAXROW + PXAKBD_MAXCOL];
+-
+-#ifdef CONFIG_PM
+-      u32 reg_kpc;
+-      u32 reg_kprec;
+-#endif
+-};
+Index: linux-2.6.23-z-input/include/asm-arm/arch-pxa/pxa27x_keypad.h
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23-z-input/include/asm-arm/arch-pxa/pxa27x_keypad.h      2008-02-18 01:43:28.000000000 +0100
+@@ -0,0 +1,58 @@
++#ifndef __ASM_ARCH_PXA27x_KEYPAD_H
++#define __ASM_ARCH_PXA27x_KEYPAD_H
++
++#include <linux/input.h>
++
++#define MAX_MATRIX_KEY_ROWS   (8)
++#define MAX_MATRIX_KEY_COLS   (8)
++
++/* pxa3xx keypad platform specific parameters
++ *
++ * NOTE:
++ * 1. direct_key_num indicates the number of keys in the direct keypad
++ *    _plus_ the number of rotary-encoder sensor inputs,  this can be
++ *    left as 0 if only rotary encoders are enabled,  the driver will
++ *    automatically calculate this
++ *
++ * 2. direct_key_map is the key code map for the direct keys, if rotary
++ *    encoder(s) are enabled, direct key 0/1(2/3) will be ignored
++ *
++ * 3. rotary can be either interpreted as a relative input event (e.g.
++ *    REL_WHEEL/REL_HWHEEL) or specific keys (e.g. UP/DOWN/LEFT/RIGHT)
++ *
++ * 4. matrix key and direct key will use the same debounce_interval by
++ *    default, which should be sufficient in most cases
++ */
++struct pxa27x_keypad_platform_data {
++
++      /* code map for the matrix keys */
++      unsigned int    matrix_key_rows;
++      unsigned int    matrix_key_cols;
++      unsigned int    *matrix_key_map;
++      int             matrix_key_map_size;
++
++      /* direct keys */
++      int             direct_key_num;
++      unsigned int    direct_key_map[8];
++
++      /* rotary encoders 0 */
++      int             enable_rotary0;
++      int             rotary0_rel_code;
++      int             rotary0_up_key;
++      int             rotary0_down_key;
++
++      /* rotary encoders 1 */
++      int             enable_rotary1;
++      int             rotary1_rel_code;
++      int             rotary1_up_key;
++      int             rotary1_down_key;
++
++      /* key debounce interval */
++      unsigned int    debounce_interval;
++};
++
++#define KEY(row, col, val)    (((row) << 28) | ((col) << 24) | (val))
++
++extern void pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info);
++
++#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */
+Index: linux-2.6.23-z-input/drivers/input/keyboard/pxa27x_keyboard.c
+===================================================================
+--- linux-2.6.23-z-input.orig/drivers/input/keyboard/pxa27x_keyboard.c 2008-02-18 01:43:28.000000000 +0100
++++ /dev/null  1970-01-01 00:00:00.000000000 +0000
+@@ -1,273 +0,0 @@
+-/*
+- * linux/drivers/input/keyboard/pxa27x_keyboard.c
+- *
+- * Driver for the pxa27x matrix keyboard controller.
+- *
+- * Created:   Feb 22, 2007
+- * Author:    Rodolfo Giometti <giometti@linux.it>
+- *
+- * Based on a previous implementations by Kevin O'Connor
+- * <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
+- * on some suggestions by Nicolas Pitre <nico@cam.org>.
+- *
+- * This program is free software; you can redistribute it and/or modify
+- * it under the terms of the GNU General Public License version 2 as
+- * published by the Free Software Foundation.
+- */
+-
+-
+-#include <linux/kernel.h>
+-#include <linux/module.h>
+-#include <linux/init.h>
+-#include <linux/interrupt.h>
+-#include <linux/input.h>
+-#include <linux/device.h>
+-#include <linux/platform_device.h>
+-#include <linux/clk.h>
+-#include <linux/err.h>
+-
+-#include <asm/mach-types.h>
+-#include <asm/mach/arch.h>
+-#include <asm/mach/map.h>
+-
+-#include <asm/arch/hardware.h>
+-#include <asm/arch/pxa-regs.h>
+-#include <asm/arch/irqs.h>
+-#include <asm/arch/pxa27x_keyboard.h>
+-
+-#define DRIVER_NAME           "pxa27x-keyboard"
+-
+-#define KPASMKP(col)          (col/2 == 0 ? KPASMKP0 : \
+-                               col/2 == 1 ? KPASMKP1 : \
+-                               col/2 == 2 ? KPASMKP2 : KPASMKP3)
+-#define KPASMKPx_MKC(row, col)        (1 << (row + 16 * (col % 2)))
+-
+-static struct clk *pxakbd_clk;
+-
+-static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
+-{
+-      struct platform_device *pdev = dev_id;
+-      struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+-      struct input_dev *input_dev = platform_get_drvdata(pdev);
+-      unsigned long kpc = KPC;
+-      int p, row, col, rel;
+-
+-      if (kpc & KPC_DI) {
+-              unsigned long kpdk = KPDK;
+-
+-              if (!(kpdk & KPDK_DKP)) {
+-                      /* better luck next time */
+-              } else if (kpc & KPC_REE0) {
+-                      unsigned long kprec = KPREC;
+-                      KPREC = 0x7f;
+-
+-                      if (kprec & KPREC_OF0)
+-                              rel = (kprec & 0xff) + 0x7f;
+-                      else if (kprec & KPREC_UF0)
+-                              rel = (kprec & 0xff) - 0x7f - 0xff;
+-                      else
+-                              rel = (kprec & 0xff) - 0x7f;
+-
+-                      if (rel) {
+-                              input_report_rel(input_dev, REL_WHEEL, rel);
+-                              input_sync(input_dev);
+-                      }
+-              }
+-      }
+-
+-      if (kpc & KPC_MI) {
+-              /* report the status of every button */
+-              for (row = 0; row < pdata->nr_rows; row++) {
+-                      for (col = 0; col < pdata->nr_cols; col++) {
+-                              p = KPASMKP(col) & KPASMKPx_MKC(row, col) ?
+-                                      1 : 0;
+-                              pr_debug("keycode %x - pressed %x\n",
+-                                              pdata->keycodes[row][col], p);
+-                              input_report_key(input_dev,
+-                                              pdata->keycodes[row][col], p);
+-                      }
+-              }
+-              input_sync(input_dev);
+-      }
+-
+-      return IRQ_HANDLED;
+-}
+-
+-static int pxakbd_open(struct input_dev *dev)
+-{
+-      /* Set keypad control register */
+-      KPC |= (KPC_ASACT |
+-              KPC_MS_ALL |
+-              (2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL |
+-              KPC_ME | KPC_MIE | KPC_DE | KPC_DIE);
+-
+-      KPC &= ~KPC_AS;         /* disable automatic scan */
+-      KPC &= ~KPC_IMKP;       /* do not ignore multiple keypresses */
+-
+-      /* Set rotary count to mid-point value */
+-      KPREC = 0x7F;
+-
+-      /* Enable unit clock */
+-      clk_enable(pxakbd_clk);
+-
+-      return 0;
+-}
+-
+-static void pxakbd_close(struct input_dev *dev)
+-{
+-      /* Disable clock unit */
+-      clk_disable(pxakbd_clk);
+-}
+-
+-#ifdef CONFIG_PM
+-static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
+-{
+-      struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+-
+-      /* Save controller status */
+-      pdata->reg_kpc = KPC;
+-      pdata->reg_kprec = KPREC;
+-
+-      return 0;
+-}
+-
+-static int pxakbd_resume(struct platform_device *pdev)
+-{
+-      struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+-      struct input_dev *input_dev = platform_get_drvdata(pdev);
+-
+-      mutex_lock(&input_dev->mutex);
+-
+-      if (input_dev->users) {
+-              /* Restore controller status */
+-              KPC = pdata->reg_kpc;
+-              KPREC = pdata->reg_kprec;
+-
+-              /* Enable unit clock */
+-              clk_disable(pxakbd_clk);
+-              clk_enable(pxakbd_clk);
+-      }
+-
+-      mutex_unlock(&input_dev->mutex);
+-
+-      return 0;
+-}
+-#else
+-#define pxakbd_suspend        NULL
+-#define pxakbd_resume NULL
+-#endif
+-
+-static int __devinit pxakbd_probe(struct platform_device *pdev)
+-{
+-      struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
+-      struct input_dev *input_dev;
+-      int i, row, col, error;
+-
+-      pxakbd_clk = clk_get(&pdev->dev, "KBDCLK");
+-      if (IS_ERR(pxakbd_clk)) {
+-              error = PTR_ERR(pxakbd_clk);
+-              goto err_clk;
+-      }
+-
+-      /* Create and register the input driver. */
+-      input_dev = input_allocate_device();
+-      if (!input_dev) {
+-              printk(KERN_ERR "Cannot request keypad device\n");
+-              error = -ENOMEM;
+-              goto err_alloc;
+-      }
+-
+-      input_dev->name = DRIVER_NAME;
+-      input_dev->id.bustype = BUS_HOST;
+-      input_dev->open = pxakbd_open;
+-      input_dev->close = pxakbd_close;
+-      input_dev->dev.parent = &pdev->dev;
+-
+-      input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP) | BIT(EV_REL);
+-      input_dev->relbit[LONG(REL_WHEEL)] = BIT(REL_WHEEL);
+-      for (row = 0; row < pdata->nr_rows; row++) {
+-              for (col = 0; col < pdata->nr_cols; col++) {
+-                      int code = pdata->keycodes[row][col];
+-                      if (code > 0)
+-                              set_bit(code, input_dev->keybit);
+-              }
+-      }
+-
+-      error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, IRQF_DISABLED,
+-                          DRIVER_NAME, pdev);
+-      if (error) {
+-              printk(KERN_ERR "Cannot request keypad IRQ\n");
+-              goto err_free_dev;
+-      }
+-
+-      platform_set_drvdata(pdev, input_dev);
+-
+-      /* Register the input device */
+-      error = input_register_device(input_dev);
+-      if (error)
+-              goto err_free_irq;
+-
+-      /* Setup GPIOs. */
+-      for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++)
+-              pxa_gpio_mode(pdata->gpio_modes[i]);
+-
+-      /*
+-       * Store rows/cols info into keyboard registers.
+-       */
+-
+-      KPC |= (pdata->nr_rows - 1) << 26;
+-      KPC |= (pdata->nr_cols - 1) << 23;
+-
+-      for (col = 0; col < pdata->nr_cols; col++)
+-              KPC |= KPC_MS0 << col;
+-
+-      return 0;
+-
+- err_free_irq:
+-      platform_set_drvdata(pdev, NULL);
+-      free_irq(IRQ_KEYPAD, pdev);
+- err_free_dev:
+-      input_free_device(input_dev);
+- err_alloc:
+-      clk_put(pxakbd_clk);
+- err_clk:
+-      return error;
+-}
+-
+-static int __devexit pxakbd_remove(struct platform_device *pdev)
+-{
+-      struct input_dev *input_dev = platform_get_drvdata(pdev);
+-
+-      input_unregister_device(input_dev);
+-      free_irq(IRQ_KEYPAD, pdev);
+-      clk_put(pxakbd_clk);
+-      platform_set_drvdata(pdev, NULL);
+-
+-      return 0;
+-}
+-
+-static struct platform_driver pxakbd_driver = {
+-      .probe          = pxakbd_probe,
+-      .remove         = __devexit_p(pxakbd_remove),
+-      .suspend        = pxakbd_suspend,
+-      .resume         = pxakbd_resume,
+-      .driver         = {
+-              .name   = DRIVER_NAME,
+-      },
+-};
+-
+-static int __init pxakbd_init(void)
+-{
+-      return platform_driver_register(&pxakbd_driver);
+-}
+-
+-static void __exit pxakbd_exit(void)
+-{
+-      platform_driver_unregister(&pxakbd_driver);
+-}
+-
+-module_init(pxakbd_init);
+-module_exit(pxakbd_exit);
+-
+-MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver");
+-MODULE_LICENSE("GPL");
+Index: linux-2.6.23-z-input/arch/arm/mach-pxa/zylonite.c
+===================================================================
+--- linux-2.6.23-z-input.orig/arch/arm/mach-pxa/zylonite.c     2008-02-18 01:43:28.000000000 +0100
++++ linux-2.6.23-z-input/arch/arm/mach-pxa/zylonite.c  2008-02-19 01:31:33.000000000 +0100
+@@ -25,6 +25,7 @@
+ #include <asm/arch/gpio.h>
+ #include <asm/arch/pxafb.h>
+ #include <asm/arch/zylonite.h>
++#include <asm/arch/pxa27x_keypad.h>
+ #include "generic.h"
+@@ -173,6 +174,72 @@
+ static inline void zylonite_init_lcd(void) {}
+ #endif
++#if defined(CONFIG_KEYBOARD_PXA27x) || defined(CONFIG_KEYBOARD_PXA27x_MODULES)
++static unsigned int zylonite_matrix_key_map[] = {
++       /* KEY(row, col, key_code) */
++       KEY(0, 0, KEY_A), KEY(0, 1, KEY_B), KEY(0, 2, KEY_C), KEY(0, 5, KEY_D),
++       KEY(1, 0, KEY_E), KEY(1, 1, KEY_F), KEY(1, 2, KEY_G), KEY(1, 5, KEY_H),
++       KEY(2, 0, KEY_I), KEY(2, 1, KEY_J), KEY(2, 2, KEY_K), KEY(2, 5, KEY_L),
++       KEY(3, 0, KEY_M), KEY(3, 1, KEY_N), KEY(3, 2, KEY_O), KEY(3, 5, KEY_P),
++       KEY(5, 0, KEY_Q), KEY(5, 1, KEY_R), KEY(5, 2, KEY_S), KEY(5, 5, KEY_T),
++       KEY(6, 0, KEY_U), KEY(6, 1, KEY_V), KEY(6, 2, KEY_W), KEY(6, 5, KEY_X),
++       KEY(7, 1, KEY_Y), KEY(7, 2, KEY_Z),
++
++       KEY(4, 4, KEY_0), KEY(1, 3, KEY_1), KEY(4, 1, KEY_2), KEY(1, 4, KEY_3),
++       KEY(2, 3, KEY_4), KEY(4, 2, KEY_5), KEY(2, 4, KEY_6), KEY(3, 3, KEY_7),
++       KEY(4, 3, KEY_8), KEY(3, 4, KEY_9),
++
++       KEY(4, 5, KEY_SPACE),
++       KEY(5, 3, KEY_KPASTERISK),      /* * */
++       KEY(5, 4, KEY_KPDOT),           /* #" */
++
++       KEY(0, 7, KEY_UP),
++       KEY(1, 7, KEY_DOWN),
++       KEY(2, 7, KEY_LEFT),
++       KEY(3, 7, KEY_RIGHT),
++       KEY(2, 6, KEY_HOME),
++       KEY(3, 6, KEY_END),
++       KEY(6, 4, KEY_DELETE),
++       KEY(6, 6, KEY_BACK),
++       KEY(6, 3, KEY_CAPSLOCK),        /* KEY_LEFTSHIFT), */
++
++       KEY(4, 6, KEY_ENTER),           /* scroll push */
++       KEY(5, 7, KEY_ENTER),           /* keypad action */
++
++       KEY(0, 4, KEY_EMAIL),
++       KEY(5, 6, KEY_SEND),
++       KEY(4, 0, KEY_CALENDAR),
++       KEY(7, 6, KEY_RECORD),
++       KEY(6, 7, KEY_VOLUMEUP),
++       KEY(7, 7, KEY_VOLUMEDOWN),
++
++       KEY(0, 6, KEY_F22),     /* soft1 */
++       KEY(1, 6, KEY_F23),     /* soft2 */
++       KEY(0, 3, KEY_AUX),     /* contact */
++};
++
++static struct pxa27x_keypad_platform_data zylonite_keypad_info = {
++       .matrix_key_rows        = 8,
++       .matrix_key_cols        = 8,
++       .matrix_key_map         = zylonite_matrix_key_map,
++       .matrix_key_map_size    = ARRAY_SIZE(zylonite_matrix_key_map),
++
++       .enable_rotary0         = 1,
++       .rotary0_up_key         = KEY_UP,
++       .rotary0_down_key       = KEY_DOWN,
++
++       .debounce_interval      = 30,
++};
++
++static void __init zylonite_init_keypad(void)
++{
++       pxa_set_keypad_info(&zylonite_keypad_info);
++}
++#else
++static inline void zylonite_init_keypad(void) {}
++#endif
++
++
+ static void __init zylonite_init(void)
+ {
+       /* board-processor specific initialization */
+@@ -190,6 +257,7 @@
+       platform_device_register(&touch_device);
+       zylonite_init_lcd();
++      zylonite_init_keypad();
+ }
+ MACHINE_START(ZYLONITE, "PXA3xx Platform Development Kit (aka Zylonite)")
+Index: linux-2.6.23-z-input/arch/arm/mach-pxa/devices.h
+===================================================================
+--- linux-2.6.23-z-input.orig/arch/arm/mach-pxa/devices.h      2008-02-18 01:43:28.000000000 +0100
++++ linux-2.6.23-z-input/arch/arm/mach-pxa/devices.h   2008-02-18 01:43:28.000000000 +0100
+@@ -12,3 +12,4 @@
+ extern struct platform_device pxa27x_device_i2c_power;
+ extern struct platform_device pxa27x_device_ohci;
++extern struct platform_device pxa27x_device_keypad;
+Index: linux-2.6.23-z-input/arch/arm/mach-pxa/generic.c
+===================================================================
+--- linux-2.6.23-z-input.orig/arch/arm/mach-pxa/generic.c      2008-02-18 01:43:28.000000000 +0100
++++ linux-2.6.23-z-input/arch/arm/mach-pxa/generic.c   2008-02-18 01:43:28.000000000 +0100
+@@ -450,3 +450,34 @@
+       .name           = "sa1100-rtc",
+       .id             = -1,
+ };
++
++static struct resource pxa27x_resource_keypad[] = {
++       [0] = {
++               .start  = 0x41500000,
++               .end    = 0x4150004c,
++               .flags  = IORESOURCE_MEM,
++       },
++       [1] = {
++               .start  = IRQ_KEYPAD,
++               .end    = IRQ_KEYPAD,
++               .flags  = IORESOURCE_IRQ,
++       },
++};
++
++struct platform_device pxa27x_device_keypad = {
++       .name           = "pxa27x-keypad",
++       .id             = -1,
++       .resource       = pxa27x_resource_keypad,
++       .num_resources  = ARRAY_SIZE(pxa27x_resource_keypad),
++};
++
++void __init pxa_set_keypad_info(struct pxa27x_keypad_platform_data *info)
++{
++      int ret;
++
++      pxa27x_device_keypad.dev.platform_data = info;
++
++      ret = platform_device_register(&pxa27x_device_keypad);
++      if (ret)
++              dev_err(&pxa27x_device_keypad.dev, "unable to register device: %d\n", ret);
++}
+Index: linux-2.6.23-z-input/arch/arm/mach-pxa/pxa27x.c
+===================================================================
+--- linux-2.6.23-z-input.orig/arch/arm/mach-pxa/pxa27x.c       2008-02-18 01:43:28.000000000 +0100
++++ linux-2.6.23-z-input/arch/arm/mach-pxa/pxa27x.c    2008-02-18 01:43:28.000000000 +0100
+@@ -148,7 +148,7 @@
+       INIT_CKEN("USBCLK", USB,    48000000, 0, &pxa27x_device_ohci.dev),
+       INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev),
+-      INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL),
++      INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, &pxa27x_device_keypad.dev),
+       /*
+       INIT_CKEN("PWMCLK",  PWM0, 13000000, 0, NULL),
+Index: linux-2.6.23-z-input/arch/arm/mach-pxa/pxa3xx.c
+===================================================================
+--- linux-2.6.23-z-input.orig/arch/arm/mach-pxa/pxa3xx.c       2008-02-18 01:43:28.000000000 +0100
++++ linux-2.6.23-z-input/arch/arm/mach-pxa/pxa3xx.c    2008-02-19 01:32:40.000000000 +0100
+@@ -159,6 +159,7 @@
+ static struct clk pxa3xx_clks[] = {
+       INIT_CK("LCDCLK", LCD,    &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
+       INIT_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_ops, NULL),
++      INIT_CK("KBDCLK", KEYPAD, &clk_pxa3xx_hsio_ops, &pxa27x_device_keypad.dev),
+       INIT_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
+       INIT_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
+Index: linux-2.6.23-z-input/include/asm-arm/arch-pxa/irqs.h
+===================================================================
+--- linux-2.6.23-z-input.orig/include/asm-arm/arch-pxa/irqs.h  2008-02-18 01:43:28.000000000 +0100
++++ linux-2.6.23-z-input/include/asm-arm/arch-pxa/irqs.h       2008-02-18 01:43:28.000000000 +0100
+@@ -13,7 +13,7 @@
+ #define PXA_IRQ(x)    (x)
+-#ifdef CONFIG_PXA27x
++#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
+ #define IRQ_SSP3      PXA_IRQ(0)      /* SSP3 service request */
+ #define IRQ_MSL               PXA_IRQ(1)      /* MSL Interface interrupt */
+ #define IRQ_USBH2     PXA_IRQ(2)      /* USB Host interrupt 1 (OHCI) */
+Index: linux-2.6.23-z-input/arch/arm/mach-pxa/pxa300.c
+===================================================================
+--- linux-2.6.23-z-input.orig/arch/arm/mach-pxa/pxa300.c       2008-02-19 01:33:58.000000000 +0100
++++ linux-2.6.23-z-input/arch/arm/mach-pxa/pxa300.c    2008-02-19 01:34:35.000000000 +0100
+@@ -23,8 +23,10 @@
+       MFP_ADDR_X(GPIO0,   GPIO2,   0x00b4),
+       MFP_ADDR_X(GPIO3,   GPIO26,  0x027c),
+-      MFP_ADDR_X(GPIO27,  GPIO127, 0x0400),
+-      MFP_ADDR_X(GPIO0_2, GPIO6_2, 0x02ec),
++      MFP_ADDR_X(GPIO27,  GPIO98,  0x0400),
++      MFP_ADDR_X(GPIO99,  GPIO127, 0x0600),
++      MFP_ADDR_X(GPIO0_2, GPIO1_2, 0x0674),
++      MFP_ADDR_X(GPIO2_2, GPIO6_2, 0x02dc),
+       MFP_ADDR(nBE0, 0x0204),
+       MFP_ADDR(nBE1, 0x0208),
diff --git a/packages/linux/linux-rp-2.6.23/zylonite_mtd-r0.patch b/packages/linux/linux-rp-2.6.23/zylonite_mtd-r0.patch
new file mode 100644 (file)
index 0000000..cb5a9c5
--- /dev/null
@@ -0,0 +1,4093 @@
+Gross hacks to make the Zylonite boot from flash in VGA.
+
+Flash driver forward ported to 2.6.14
+
+Index: linux-2.6.23/drivers/mtd/nand/Kconfig
+===================================================================
+--- linux-2.6.23.orig/drivers/mtd/nand/Kconfig 2007-10-09 21:31:38.000000000 +0100
++++ linux-2.6.23/drivers/mtd/nand/Kconfig      2008-02-13 00:59:45.000000000 +0000
+@@ -223,6 +223,10 @@
+       tristate "Support for NAND Flash on Sharp SL Series (C7xx + others)"
+       depends on ARCH_PXA
++config MTD_NAND_ZYLONITE
++      tristate "Support for NAND Flash on Zylonite"
++      depends on ARCH_PXA
++
+ config MTD_NAND_BASLER_EXCITE
+       tristate  "Support for NAND Flash on Basler eXcite"
+       depends on BASLER_EXCITE
+Index: linux-2.6.23/drivers/mtd/nand/Makefile
+===================================================================
+--- linux-2.6.23.orig/drivers/mtd/nand/Makefile        2007-10-09 21:31:38.000000000 +0100
++++ linux-2.6.23/drivers/mtd/nand/Makefile     2008-02-13 00:59:45.000000000 +0000
+@@ -19,6 +19,7 @@
+ obj-$(CONFIG_MTD_NAND_H1900)          += h1910.o
+ obj-$(CONFIG_MTD_NAND_RTC_FROM4)      += rtc_from4.o
+ obj-$(CONFIG_MTD_NAND_SHARPSL)                += sharpsl.o
++obj-$(CONFIG_MTD_NAND_ZYLONITE)               += mhn_nand.o
+ obj-$(CONFIG_MTD_NAND_TS7250)         += ts7250.o
+ obj-$(CONFIG_MTD_NAND_NANDSIM)                += nandsim.o
+ obj-$(CONFIG_MTD_NAND_CS553X)         += cs553x_nand.o
+Index: linux-2.6.23/drivers/mtd/nand/mhn_nand.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23/drivers/mtd/nand/mhn_nand.c   2008-02-13 00:59:45.000000000 +0000
+@@ -0,0 +1,3869 @@
++/*
++ *  drivers/mtd/nand/mhn_nand.c
++ *
++ *  Copyright (C) 2005 Intel Coporation (chao.xie@intel.com)
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ *  Overview:
++ *   This is a device driver for the NAND flash device on zylonite board
++ *   which utilizes the Samsung K9K1216Q0C parts. This is a 64Mibit NAND
++ *   flash device.
++
++ *(C) Copyright 2006 Marvell International Ltd.
++ * All Rights Reserved
++ */
++
++#include <linux/slab.h>
++#include <linux/module.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
++#include <linux/interrupt.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <asm/delay.h>
++#include <asm/dma.h>
++#include <asm/arch/mfp.h>
++//#include <asm/arch/cpu-freq-voltage-mhn.h>
++
++//#define NDCR 0xf0000000
++//#define NDCR        (*((volatile u32 *)0xf0000000))
++//#define NDCR              __REG_2(0x43100000)  /* Data Flash Control register */
++#define NDCR_SPARE_EN             (0x1<<31)
++#define NDCR_ECC_EN               (0x1<<30)
++#define NDCR_DMA_EN               (0x1<<29)
++#define NDCR_ND_RUN               (0x1<<28)
++#define NDCR_DWIDTH_C             (0x1<<27)
++#define NDCR_DWIDTH_M             (0x1<<26)
++#define NDCR_PAGE_SZ              (0x1<<24)
++#define NDCR_NCSX         (0x1<<23)
++#define NDCR_ND_MODE              (0x3<<21)
++#define NDCR_NAND_MODE    0x0
++#define NDCR_CLR_PG_CNT           (0x1<<20)
++#define NDCR_CLR_ECC      (       0x1<<19)
++#define NDCR_RD_ID_CNT_MASK       (0x7<<16)
++#define NDCR_RD_ID_CNT(x)       (((x) << 16) & NDCR_RD_ID_CNT_MASK)
++#define NDCR_RA_START     (0x1<<15)
++#define NDCR_PG_PER_BLK   (0x1<<14)
++#define NDCR_ND_ARB_EN    (0x1<<12)
++
++//#define NDSR        (*((volatile u32 *)0xf0000014))
++//#define NDSR              __REG_2(0x43100014)  /* Data Controller Status Register */
++#define NDSR_RDY  (0x1<<11)
++#define NDSR_CS0_PAGED    (0x1<<10)
++#define NDSR_CS1_PAGED    (0x1<<9)
++#define NDSR_CS0_CMDD     (0x1<<8)
++#define NDSR_CS1_CMDD     (0x1<<7)
++#define NDSR_CS0_BBD      (0x1<<6)
++#define NDSR_CS1_BBD      (0x1<<5)
++#define NDSR_DBERR        (0x1<<4)
++#define NDSR_SBERR        (0x1<<3)
++#define NDSR_WRDREQ       (0x1<<2)
++#define NDSR_RDDREQ       (0x1<<1)
++#define NDSR_WRCMDREQ     (0x1)
++
++#define OSCR              __REG(0x40A00010)  /* OS Timer Counter Register */
++//#define NDCB0             __REG_2(0x43100048)  /* Data Controller Command Buffer0 */
++//#define NDCB1             __REG_2(0x4310004C)  /* Data Controller Command Buffer1 */
++//#define NDCB2             __REG_2(0x43100050)  /* Data Controller Command Buffer2 */
++#define NDCB0_AUTO_RS             (0x1<<25)
++#define NDCB0_CSEL                (0x1<<24)
++#define NDCB0_CMD_TYPE_MASK       (0x7<<21)
++#define   NDCB0_CMD_TYPE(x)       (((x) << 21) & NDCB0_CMD_TYPE_MASK)
++#define NDCB0_NC          (0x1<<20)
++#define NDCB0_DBC         (0x1<<19)
++#define NDCB0_ADDR_CYC_MASK       (0x7<<16)
++#define   NDCB0_ADDR_CYC(x)       (((x) << 16) & NDCB0_ADDR_CYC_MASK)
++#define NDCB0_CMD2_MASK           (0xff<<8)
++#define NDCB0_CMD1_MASK           (0xff)
++#define NDCB0_ADDR_CYC_SHIFT      (16)
++#define DCMD0             __REG(0x4000020c)  /* DMA Command Address Register Channel 0 */
++#define DCMD1             __REG(0x4000021c)  /* DMA Command Address Register Channel 1 */
++#define DCMD2             __REG(0x4000022c)  /* DMA Command Address Register Channel 2 */
++#define DCMD3             __REG(0x4000023c)  /* DMA Command Address Register Channel 3 */
++#define DCMD4             __REG(0x4000024c)  /* DMA Command Address Register Channel 4 */
++#define DCMD5             __REG(0x4000025c)  /* DMA Command Address Register Channel 5 */
++#define DCMD6             __REG(0x4000026c)  /* DMA Command Address Register Channel 6 */
++#define DCMD7             __REG(0x4000027c)  /* DMA Command Address Register Channel 7 */
++#define DCMD8             __REG(0x4000028c)  /* DMA Command Address Register Channel 8 */
++#define DCMD9             __REG(0x4000029c)  /* DMA Command Address Register Channel 9 */
++#define DCMD10            __REG(0x400002ac)  /* DMA Command Address Register Channel 10 */
++#define DCMD11            __REG(0x400002bc)  /* DMA Command Address Register Channel 11 */
++#define DCMD12            __REG(0x400002cc)  /* DMA Command Address Register Channel 12 */
++#define DCMD13            __REG(0x400002dc)  /* DMA Command Address Register Channel 13 */
++#define DCMD14            __REG(0x400002ec)  /* DMA Command Address Register Channel 14 */
++#define DCMD15            __REG(0x400002fc)  /* DMA Command Address Register Channel 15 */
++#define DCMD(x)           __REG2(0x4000020c, (x) << 4)
++#define DCMD_INCSRCADDR   (1 << 31)       /* Source Address Increment Setting. */
++#define DCMD_INCTRGADDR   (1 << 30)       /* Target Address Increment Setting. */
++#define DCMD_FLOWSRC      (1 << 29)       /* Flow Control by the source. */
++#define DCMD_FLOWTRG      (1 << 28)       /* Flow Control by the target. */
++#define DCMD_STARTIRQEN   (1 << 22)       /* Start Interrupt Enable */
++#define DCMD_ENDIRQEN     (1 << 21)       /* End Interrupt Enable */
++#define DCMD_ENDIAN       (1 << 18)       /* Device Endian-ness. */
++#define DCMD_BURST8       (1 << 16)       /* 8 byte burst */
++#define DCMD_BURST16      (2 << 16)       /* 16 byte burst */
++#define DCMD_BURST32      (3 << 16)       /* 32 byte burst */
++#define DCMD_WIDTH1       (1 << 14)       /* 1 byte width */
++#define DCMD_WIDTH2       (2 << 14)       /* 2 byte width (HalfWord) */
++#define DCMD_WIDTH4       (3 << 14)       /* 4 byte width (Word) */
++#define DCMD_LENGTH       0x01fff         /* length mask (max = 8K - 1) */
++#define DCMD_RXPCDR       (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
++#define DCMD_RXMCDR       (DCMD_INCTRGADDR|DCMD_FLOWSRC|DCMD_BURST32|DCMD_WIDTH4)
++#define DCMD_TXPCDR       (DCMD_INCSRCADDR|DCMD_FLOWTRG|DCMD_BURST32|DCMD_WIDTH4)
++#define DRCMR(n)  __REG2(0x40000100, (n)<<2)
++#define DRCMR97           __REG(0x40001184)  /* Request to Channel Map Register for NAND interface data transmit & receive Request */
++#define DRCMR98           __REG(0x40001188)  /* Reserved */
++#define DRCMR99           __REG(0x4000118C)  /* Request to Channel Map Register for NAND interface command transmit Request */
++#define DRCMRRXSADR       DRCMR2
++#define DRCMRTXSADR       DRCMR3
++#define DRCMRRXBTRBR      DRCMR4
++#define DRCMRTXBTTHR      DRCMR5
++#define DRCMRRXFFRBR      DRCMR6
++#define DRCMRTXFFTHR      DRCMR7
++#define DRCMRRXMCDR       DRCMR8
++#define DRCMRRXMODR       DRCMR9
++#define DRCMRTXMODR       DRCMR10
++#define DRCMRRXPCDR       DRCMR11
++#define DRCMRTXPCDR       DRCMR12
++#define DRCMRRXSSDR       DRCMR13
++#define DRCMRTXSSDR       DRCMR14
++#define DRCMRRXICDR       DRCMR17
++#define DRCMRTXICDR       DRCMR18
++#define DRCMRRXSTRBR      DRCMR19
++#define DRCMRTXSTTHR      DRCMR20
++#define DRCMRRXMMC        DRCMR21
++#define DRCMRTXMMC        DRCMR22
++#define DRCMRRXMMC2       DRCMR93
++#define DRCMRTXMMC2       DRCMR94
++#define DRCMRRXMMC3       DRCMR100
++#define DRCMRTXMMC3       DRCMR101
++#define DRCMRUDC(x)       DRCMR((x) + 24)
++#define DRCMR_MAPVLD      (1 << 7)        /* Map Valid (read / write) */
++#define DRCMR_CHLNUM      0x1f            /* mask for Channel Number (read / write) */
++#define DCSR0             __REG(0x40000000)  /* DMA Control / Status Register for Channel 0 */
++#define DCSR1             __REG(0x40000004)  /* DMA Control / Status Register for Channel 1 */
++#define DCSR2             __REG(0x40000008)  /* DMA Control / Status Register for Channel 2 */
++#define DCSR3             __REG(0x4000000c)  /* DMA Control / Status Register for Channel 3 */
++#define DCSR4             __REG(0x40000010)  /* DMA Control / Status Register for Channel 4 */
++#define DCSR5             __REG(0x40000014)  /* DMA Control / Status Register for Channel 5 */
++#define DCSR6             __REG(0x40000018)  /* DMA Control / Status Register for Channel 6 */
++#define DCSR7             __REG(0x4000001c)  /* DMA Control / Status Register for Channel 7 */
++#define DCSR8             __REG(0x40000020)  /* DMA Control / Status Register for Channel 8 */
++#define DCSR9             __REG(0x40000024)  /* DMA Control / Status Register for Channel 9 */
++#define DCSR10            __REG(0x40000028)  /* DMA Control / Status Register for Channel 10 */
++#define DCSR11            __REG(0x4000002c)  /* DMA Control / Status Register for Channel 11 */
++#define DCSR12            __REG(0x40000030)  /* DMA Control / Status Register for Channel 12 */
++#define DCSR13            __REG(0x40000034)  /* DMA Control / Status Register for Channel 13 */
++#define DCSR14            __REG(0x40000038)  /* DMA Control / Status Register for Channel 14 */
++#define DCSR15            __REG(0x4000003c)  /* DMA Control / Status Register for Channel 15 */
++#define DCSR16            __REG(0x40000040)  /* DMA Control / Status Register for Channel 16 */
++#define DCSR17            __REG(0x40000044)  /* DMA Control / Status Register for Channel 17 */
++#define DCSR18            __REG(0x40000048)  /* DMA Control / Status Register for Channel 18 */
++#define DCSR19            __REG(0x4000004c)  /* DMA Control / Status Register for Channel 19 */
++#define DCSR20            __REG(0x40000050)  /* DMA Control / Status Register for Channel 20 */
++#define DCSR21            __REG(0x40000054)  /* DMA Control / Status Register for Channel 21 */
++#define DCSR22            __REG(0x40000058)  /* DMA Control / Status Register for Channel 22 */
++#define DCSR23            __REG(0x4000005c)  /* DMA Control / Status Register for Channel 23 */
++#define DCSR24            __REG(0x40000060)  /* DMA Control / Status Register for Channel 24 */
++#define DCSR25            __REG(0x40000064)  /* DMA Control / Status Register for Channel 25 */
++#define DCSR26            __REG(0x40000068)  /* DMA Control / Status Register for Channel 26 */
++#define DCSR27            __REG(0x4000006c)  /* DMA Control / Status Register for Channel 27 */
++#define DCSR28            __REG(0x40000070)  /* DMA Control / Status Register for Channel 28 */
++#define DCSR29            __REG(0x40000074)  /* DMA Control / Status Register for Channel 29 */
++#define DCSR30            __REG(0x40000078)  /* DMA Control / Status Register for Channel 30 */
++#define DCSR31            __REG(0x4000007c)  /* DMA Control / Status Register for Channel 31 */
++#define DCSR(x)           __REG2(0x40000000, (x) << 2)
++#define DCSR_RUN  (1 << 31)       /* Run Bit (read / write) */
++#define DCSR_NODESC       (1 << 30)       /* No-Descriptor Fetch (read / write) */
++#define DCSR_STOPIRQEN    (1 << 29)       /* Stop Interrupt Enable (read / write) */
++#define DCSR_EORIRQEN     (1 << 28)       /* End of Receive Interrupt Enable (R/W) */
++#define DCSR_EORJMPEN     (1 << 27)       /* Jump to next descriptor on EOR */
++#define DCSR_EORSTOPEN    (1 << 26)       /* STOP on an EOR */
++#define DCSR_SETCMPST     (1 << 25)       /* Set Descriptor Compare Status */
++#define DCSR_CLRCMPST     (1 << 24)       /* Clear Descriptor Compare Status */
++#define DCSR_CMPST        (1 << 10)       /* The Descriptor Compare Status */
++#define DCSR_EORINTR      (1 << 9)        /* The end of Receive */
++#define DCSR_REQPEND      (1 << 8)        /* Request Pending (read-only) */
++#define DCSR_RASINTR      (1 << 4)        /* Request After Channel Stopped */
++#define DCSR_STOPSTATE    (1 << 3)        /* Stop State (read-only) */
++#define DCSR_ENDINTR      (1 << 2)        /* End Interrupt (read / write) */
++#define DCSR_STARTINTR    (1 << 1)        /* Start Interrupt (read / write) */
++#define DCSR_BUSERR       (1 << 0)        /* Bus Error Interrupt (read / write) */
++#define DDADR(x)  __REG2(0x40000200, (x) << 4)
++//#define __REG_2(x)        (*((volatile u32 *)io_p2v_2(x)))
++#define IRQ_NAND      PXA_IRQ(45)
++#define   CKEN_NAND       4       ///< NAND Flash Controller Clock Enable
++
++/* #define CONFIG_MTD_NAND_MONAHANS_DEBUG */
++#ifdef CONFIG_MTD_NAND_MONAHANS_DEBUG
++#define D1(x) do { \
++              printk(KERN_DEBUG "%s: ", __FUNCTION__); \
++              x; \
++      }while(0)
++
++#define       DPRINTK(fmt,args...) printk(KERN_DEBUG fmt, ##args )
++#define PRINT_BUF(buf, num)   print_buf(buf, num)
++#else
++#define D1(x)
++#define DPRINTK(fmt,args...)
++#define PRINT_BUF(buf, num)
++#endif
++
++/* DFC timing 0 register */
++#define DFC_TIMING_tRP                0
++#define DFC_TIMING_tRH                3
++#define DFC_TIMING_tWP                8
++#define DFC_TIMING_tWH                11
++#define DFC_TIMING_tCS                16
++#define DFC_TIMING_tCH                19
++
++/* DFC timing 1 register */
++#define DFC_TIMING_tAR                0
++#define DFC_TIMING_tWHR               4
++#define DFC_TIMING_tR         16
++
++/* max value for each timing setting in DFC */
++#define DFC_TIMING_MAX_tCH    7
++#define DFC_TIMING_MAX_tCS    7
++#define DFC_TIMING_MAX_tWH    7
++#define DFC_TIMING_MAX_tWP    7
++#define DFC_TIMING_MAX_tRH    7
++#define DFC_TIMING_MAX_tRP    7
++#define DFC_TIMING_MAX_tR     65535
++#define DFC_TIMING_MAX_tWHR   15
++#define DFC_TIMING_MAX_tAR    15
++
++/*
++ * The Data Flash Controller Flash timing structure
++ * For NAND flash used on Zylonite board(Samsung K9K1216Q0C),
++ * user should use value at end of each row of following member
++ * bracketed.
++ */
++struct dfc_flash_timing {
++      uint32_t   tCH; /* Enable signal hold time */
++      uint32_t   tCS; /* Enable signal setup time */
++      uint32_t   tWH; /* ND_nWE high duration */
++      uint32_t   tWP; /* ND_nWE pulse time */
++      uint32_t   tRH; /* ND_nRE high duration */
++      uint32_t   tRP; /* ND_nRE pulse width */
++      uint32_t   tR;  /* ND_nWE high to ND_nRE low for read */
++      uint32_t   tWHR;/* ND_nWE high to ND_nRE low delay for status read */
++      uint32_t   tAR; /* ND_ALE low to ND_nRE low delay */
++};
++
++/* DFC command type */
++enum {
++      DFC_CMD_READ            = 0x00000000,
++      DFC_CMD_PROGRAM         = 0x00200000,
++      DFC_CMD_ERASE           = 0x00400000,
++      DFC_CMD_READ_ID         = 0x00600000,
++      DFC_CMD_STATUS_READ     = 0x00800000,
++      DFC_CMD_RESET           = 0x00a00000
++};
++
++/*
++ * The Data Flash Controller Flash specification structure
++ * For NAND flash used on Zylonite board(Samsung K9K1216Q0C),
++ * user should use value at end of each row of following member
++ * bracketed.
++ */
++struct dfc_flash_info {
++      struct dfc_flash_timing timing; /* NAND Flash timing */
++
++      int      enable_arbiter;/* Data flash bus arbiter enable (ND_ARB_EN) */
++      uint32_t page_per_block;/* Pages per block (PG_PER_BLK) */
++      uint32_t row_addr_start;/* Row address start position (RA_START) */
++      uint32_t read_id_bytes; /* returned ID bytes(RD_ID_CNT) */
++      uint32_t dfc_mode;      /* NAND, CARBONDALE, PIXLEY... (ND_MODE) */
++      uint32_t ncsx;          /* Chip select don't care bit (NCSX) */
++      uint32_t page_size;     /* Page size in bytes (PAGE_SZ) */
++      uint32_t oob_size;      /* OOB size */
++      uint32_t flash_width;   /* Width of Flash memory (DWIDTH_M) */
++      uint32_t dfc_width;     /* Width of flash controller(DWIDTH_C) */
++      uint32_t num_blocks;    /* Number of physical blocks in Flash */
++      uint32_t chip_id;
++
++      /* command codes */
++      uint32_t read1;         /* Read */
++      uint32_t read2;         /* unused, DFC don't support yet */
++      uint32_t program;       /* two cycle command */
++      uint32_t read_status;
++      uint32_t read_id;
++      uint32_t erase;         /* two cycle command */
++      uint32_t reset;
++      uint32_t lock;          /* lock whole flash */
++      uint32_t unlock;        /* two cycle command, supporting partial unlock */
++      uint32_t lock_status;   /* read block lock status */
++
++      /* addr2ndcb1 - encode address cycles into register NDCB1 */
++      /* ndbbr2addr - convert register NDBBR to bad block address */
++      int (*addr2ndcb1)(uint16_t cmd, uint32_t addr, uint32_t *p);
++      int (*ndbbr2addr)(uint16_t cmd, uint32_t ndbbr,uint32_t *p);
++};
++
++enum {
++      DFC_FLASH_NULL = 0 ,
++      DFC_FLASH_Samsung_512Mb_X_16 = 1,
++      DFC_FLASH_Micron_1Gb_X_8 = 2,
++      DFC_FLASH_Micron_1Gb_X_16 = 3,
++      DFC_FLASH_STM_1Gb_X_16 = 4,
++      DFC_FLASH_STM_2Gb_X_16 = 5,
++      DFC_FLASH_END,
++};
++
++static int dfc_get_flash_info(int type, struct dfc_flash_info **flash_info);
++
++#define               DFC_NDCR        0
++#define               DFC_NDTR0CS0    1
++#define               DFC_NDTR1CS0    3
++#define               DFC_NDSR        5
++#define               DFC_NDPCR       6
++#define               DFC_NDBDR0      7
++#define               DFC_NDBDR1      8
++#define               DFC_NDDB        16
++#define               DFC_NDCB0       18
++#define               DFC_NDCB1       19
++#define               DFC_NDCB2       20
++
++/* The Data Flash Controller Mode structure */
++struct dfc_mode {
++      int   enable_dma;       /* DMA, or nonDMA mode */
++      int   enable_ecc;       /* ECC on/off */
++      int   enable_spare;     /* Spare enable */
++      int   chip_select;      /* CS0 or CS1 */
++};
++
++/* The Data Flash Controller Context structure */
++struct dfc_context {
++      unsigned char __iomem   *membase;       /* DFC register base */
++      struct dfc_mode         *dfc_mode;      /* DFC mode */
++      int                     data_dma_ch;    /* Data DMA channel number */
++      int                     cmd_dma_ch;     /* CMD  DMA channel number */
++      struct dfc_flash_info   *flash_info; /* Flash Spec */
++      struct mtd_info         *mtd;
++};
++
++#define NDCB0_DMA_ADDR        0x43100048
++#define NDDB_DMA_ADDR 0x43100040
++
++#define NDSR_MASK     0xFFF
++
++/* The following data is a rough evaluation */
++
++/* microsecond, for readID/readStatus/reset */
++#define NAND_OTHER_TIMEOUT            10
++/* microsecond, for readID/readStatus/reset */
++#define NAND_CMD_TIMEOUT              10
++
++#define BBT_BLOCK_BAD 0x03
++#define BBT_BLOCK_GOOD        0x00
++#define BBT_BLOCK_REV1        0x01
++#define BBT_BLOCK_REV2        0x02
++
++#define BUFLEN                (2048 + 64)
++
++/*
++ * DFC data size enumeration transfered from/to controller,
++ * including padding (zero)to be a multiple of 32.
++ */
++enum {
++      DFC_DATA_SIZE_STATUS = 8,       /* ReadStatus/ReadBlockLockStatus */
++      DFC_DATA_SIZE_ID = 7,   /* ReadID */
++
++      DFC_DATA_SIZE_32 = 32,
++      DFC_DATA_SIZE_512 = 512,        /* R/W disabling spare area */
++      DFC_DATA_SIZE_520 = 520,        /* Spare=1, ECC=1 */
++      DFC_DATA_SIZE_528 = 528,        /* Spare=1, ECC=0 */
++      DFC_DATA_SIZE_544 = 544,        /* R/W enabling spare area.(DMA mode)*/
++
++      DFC_DATA_SIZE_64 = 64,
++      DFC_DATA_SIZE_2048 = 2048,      /* R/W disabling spare area */
++      DFC_DATA_SIZE_2088 = 2088,      /* R/W enabling spare area with ecc */
++      DFC_DATA_SIZE_2112 = 2112,      /* R/W enabling spare area without ecc*/
++      DFC_DATA_SIZE_2096 = 2096,      /* R/W enabling spare area */
++      DFC_DATA_SIZE_UNUSED = 0xFFFF
++};
++
++/* DFC padding size enumeration transfered from/to controller */
++enum {
++      /*
++       * ReadStatus/ReadBlockLockStatus/ReadID/
++       * Read/Program disabling spare area(Both 512 and 2048)
++       * Read/Program enabling spare area, disabling ECC
++       */
++      DFC_PADDING_SIZE_0 = 0,
++
++      /* Read/program with SPARE_EN=1, ECC_EN=0, pgSize=512 */
++      DFC_PADDING_SIZE_16 = 16,
++      /* for read/program with SPARE_EN=1, ECC_EN=1, pgSize=512 and 2048 */
++      DFC_PADDING_SIZE_24 = 24,
++      DFC_PADDING_SIZE_UNUSED = 0xFFFF
++};
++
++static unsigned int flash_config = DFC_FLASH_NULL;
++
++void dfc_set_timing(struct dfc_context *context, struct dfc_flash_timing *t);
++void dfc_set_dma(struct dfc_context *context);
++void dfc_set_ecc(struct dfc_context *context);
++void dfc_set_spare(struct dfc_context *context);
++
++int dfc_get_pattern(struct dfc_context *context, uint16_t cmd,
++                      int *data_size, int *padding);
++
++static int dfc_wait_event(struct dfc_context *context, uint32_t event,
++              uint32_t *event_out, uint32_t timeout, int enable_int);
++
++int dfc_send_cmd(struct dfc_context *context, uint16_t cmd,
++              uint32_t addr, int num_pages);
++
++void dfc_stop(struct dfc_context *context);
++void dfc_read_fifo_partial(struct dfc_context *context, uint8_t *buffer,
++                      int nbytes, int data_size);
++void dfc_write_fifo_partial(struct dfc_context *context, uint8_t *buffer,
++                      int nbytes, int data_size);
++
++void dfc_read_fifo(struct dfc_context *context, uint8_t *buffer, int nbytes);
++void dfc_write_fifo(struct dfc_context *context, uint8_t *buffer, int nbytes);
++
++void dfc_read_badblock_addr(struct dfc_context *context, uint32_t *bbaddr);
++
++void dfc_clear_int(struct dfc_context *context, uint32_t int_mask);
++void dfc_enable_int(struct dfc_context *context, uint32_t int_mask);
++void dfc_disable_int(struct dfc_context *context, uint32_t int_mask);
++
++/* high level primitives */
++int dfc_init(struct dfc_context *context, int type);
++int dfc_init_no_gpio(struct dfc_context *context, int type);
++
++int dfc_reset_flash(struct dfc_context *context);
++
++int dfc_setup_cmd_dma(struct dfc_context *context,
++              uint16_t cmd, uint32_t addr, int num_pages,
++              uint32_t *buf, uint32_t buf_phys,
++              uint32_t next_desc_phys, uint32_t dma_int_en,
++              struct pxa_dma_desc *dma_desc);
++
++int dfc_setup_data_dma(struct dfc_context *context,
++              uint16_t cmd, uint32_t buf_phys,
++              uint32_t next_desc_phys, uint32_t dma_int_en,
++              struct pxa_dma_desc *dma_desc);
++
++void dfc_start_cmd_dma(struct dfc_context *context,
++                      struct pxa_dma_desc *dma_desc);
++void dfc_start_data_dma(struct dfc_context *context,
++                      struct pxa_dma_desc *dma_desc);
++static int monahans_df_dev_ready(struct mtd_info *mtd);
++
++#ifdef CONFIG_DVFM
++static int mhn_nand_dvfm_notifier(unsigned cmd, void *client_data, void *info);
++static struct mhn_fv_notifier dvfm_notifier = {
++      .name           = "monahans-nand-flash",
++      .priority       = 0,
++      .notifier_call  = mhn_nand_dvfm_notifier,
++};
++#endif
++
++static unsigned short search_rel_block(int block, struct mtd_info *mtd);
++
++/*****************************************************************************
++ * The DFC registers read/write routines
++ *****************************************************************************/
++static inline void dfc_write(struct dfc_context *context, int offset,
++              unsigned long value)
++{
++      offset <<= 2;
++      writel(value, context->membase + offset);
++}
++
++static inline unsigned int dfc_read(struct dfc_context *context, int offset)
++{
++      offset <<= 2;
++      return __raw_readl(context->membase + offset);
++}
++
++/****************************************************************************
++ * Flash Information
++ ***************************************************************************/
++
++static int Samsung512MbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int Samsung512MbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info samsung512MbX16 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 0,       /* tCS, Enable signal setup time */
++              .tWH = 20,      /* tWH, ND_nWE high duration */
++              .tWP = 40,      /* tWP, ND_nWE pulse time */
++              .tRH = 30,      /* tRH, ND_nRE high duration */
++              .tRP = 40,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 11123,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 110,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 32,   /* Pages per block */
++      .row_addr_start = 0,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 2,     /* 2 bytes, returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 512,       /* Page size in bytes */
++      .oob_size = 16,         /* OOB size in bytes */
++      .flash_width = 16,      /* Width of Flash memory */
++      .dfc_width = 16,        /* Width of flash controller */
++      .num_blocks = 4096,     /* Number of physical blocks in Flash */
++      .chip_id =  0x46ec,
++
++      /* command codes */
++      .read1 = 0x0000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = Samsung512MbX16Addr2NDCB1,
++      .ndbbr2addr = Samsung512MbX16NDBBR2Addr,
++};
++
++static int Samsung512MbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++
++      if (addr >= 0x4000000) return -EINVAL;
++
++      if (cmd == samsung512MbX16.read1 || cmd == samsung512MbX16.program) {
++              ndcb1 = (addr & 0xFF) | ((addr >> 1) & 0x01FFFF00);
++      } else if (cmd == samsung512MbX16.erase) {
++              ndcb1 = ((addr >> 9) & 0x00FFFFFF);
++      }
++
++      *p = ndcb1;
++      return 0;
++
++}
++
++static int Samsung512MbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      *p = ndbbr << 9;
++      return 0;
++}
++
++static int Micron1GbX8Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int Micron1GbX8NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info micron1GbX8 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 25,      /* tCS, Enable signal setup time */
++              .tWH = 15,      /* tWH, ND_nWE high duration */
++              .tWP = 25,      /* tWP, ND_nWE pulse time */
++              .tRH = 15,      /* tRH, ND_nRE high duration */
++              .tRP = 25,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 25000,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 60,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 64,   /* Pages per block */
++      .row_addr_start = 1,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 4,     /* Returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 2048,      /* Page size in bytes */
++      .oob_size = 64,         /* OOB size in bytes */
++      .flash_width = 8,       /* Width of Flash memory */
++      .dfc_width = 8,         /* Width of flash controller */
++      .num_blocks = 1024,     /* Number of physical blocks in Flash */
++      .chip_id =  0xa12c,
++      /* command codes */
++      .read1 = 0x3000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = Micron1GbX8Addr2NDCB1,
++      .ndbbr2addr = Micron1GbX8NDBBR2Addr,
++};
++
++static int Micron1GbX8Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++      uint32_t page;
++
++      if (addr >= 0x8000000)
++              return -EINVAL;
++      page = addr / micron1GbX8.page_size;
++      addr =  (page / micron1GbX8.page_per_block) << 18 |
++              (page % micron1GbX8.page_per_block) << 12;
++
++      if (cmd == micron1GbX8.read1 || cmd == micron1GbX8.program) {
++              ndcb1 = (addr & 0xFFF) | ((addr << 4) & 0xFFFF0000);
++      }
++      else if (cmd == micron1GbX8.erase) {
++              ndcb1 = ((addr >> 18) << 6) & 0xFFFF;
++      }
++
++      *p = ndcb1;
++      return 0;
++}
++
++static int Micron1GbX8NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      if (cmd == micron1GbX8.read1 || cmd == micron1GbX8.program) {
++              *p = ((ndbbr & 0xF) << 8) | ((ndbbr >> 8) << 16);
++      }
++      else if (cmd == micron1GbX8.erase) {
++              *p = (ndbbr >> 6) << 18;
++      }
++
++
++      return 0;
++}
++
++
++static int Micron1GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int Micron1GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info micron1GbX16 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 25,      /* tCS, Enable signal setup time */
++              .tWH = 15,      /* tWH, ND_nWE high duration */
++              .tWP = 25,      /* tWP, ND_nWE pulse time */
++              .tRH = 15,      /* tRH, ND_nRE high duration */
++              .tRP = 25,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 25000,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 60,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 64,   /* Pages per block */
++      .row_addr_start = 1,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 4,     /* Returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 2048,      /* Page size in bytes */
++      .oob_size = 64,         /* OOB size in bytes */
++      .flash_width = 16,      /* Width of Flash memory */
++      .dfc_width = 16,        /* Width of flash controller */
++      .num_blocks = 1024,     /* Number of physical blocks in Flash */
++      .chip_id =  0xb12c,
++
++      /* command codes */
++      .read1 = 0x3000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = Micron1GbX16Addr2NDCB1,
++      .ndbbr2addr = Micron1GbX16NDBBR2Addr,
++};
++
++static int Micron1GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++      uint32_t page;
++
++      if (addr >= 0x8000000)
++              return -EINVAL;
++      page = addr / micron1GbX16.page_size;
++      addr =  (page / micron1GbX16.page_per_block) << 17 |
++              (page % micron1GbX16.page_per_block) << 11;
++
++      if (cmd == micron1GbX16.read1 || cmd == micron1GbX16.program) {
++              ndcb1 = (addr & 0x7FF) | ((addr << 5) & 0xFFFF0000);
++      }
++      else if (cmd == micron1GbX16.erase) {
++              ndcb1 = ((addr >> 17) << 6) & 0xFFFF;
++      }
++      *p = ndcb1;
++      return 0;
++}
++
++static int Micron1GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      if (cmd == micron1GbX16.read1 || cmd == micron1GbX16.program) {
++              *p = ((ndbbr & 0x7) << 8) | ((ndbbr >> 8) << 16);
++      }
++      else if (cmd == micron1GbX16.erase) {
++              *p = (ndbbr >> 6) << 17;
++      }
++
++      return 0;
++}
++
++static int STM1GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int STM1GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info stm1GbX16 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 10,      /* tCS, Enable signal setup time */
++              .tWH = 20,      /* tWH, ND_nWE high duration */
++              .tWP = 25,      /* tWP, ND_nWE pulse time */
++              .tRH = 20,      /* tRH, ND_nRE high duration */
++              .tRP = 25,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 25000,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 60,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 64,   /* Pages per block */
++      .row_addr_start = 1,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 4,     /* Returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 2048,      /* Page size in bytes */
++      .oob_size = 64,         /* OOB size in bytes */
++      .flash_width = 16,      /* Width of Flash memory */
++      .dfc_width = 16,        /* Width of flash controller */
++      .num_blocks = 1024,     /* Number of physical blocks in Flash */
++      .chip_id =  0xb120,
++
++      /* command codes */
++      .read1 = 0x3000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = STM1GbX16Addr2NDCB1,
++      .ndbbr2addr = STM1GbX16NDBBR2Addr,
++};
++
++static int STM1GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++      uint32_t page;
++
++      if (addr >= 0x8000000)
++              return -EINVAL;
++      page = addr / stm1GbX16.page_size;
++      addr =  (page / stm1GbX16.page_per_block) << 17 |
++              (page % stm1GbX16.page_per_block) << 11;
++
++      if (cmd == stm1GbX16.read1 || cmd == stm1GbX16.program) {
++              ndcb1 = (addr & 0x7FF) | ((addr << 5) & 0xFFFF0000);
++      }
++      else if (cmd == stm1GbX16.erase) {
++              ndcb1 = ((addr >> 17) << 6) & 0xFFFF;
++      }
++      *p = ndcb1;
++      return 0;
++}
++
++static int STM1GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      if (cmd == stm1GbX16.read1 || cmd == stm1GbX16.program) {
++              *p = ((ndbbr & 0x7) << 8) | ((ndbbr >> 8) << 16);
++      }
++      else if (cmd == stm1GbX16.erase) {
++              *p = (ndbbr >> 6) << 17;
++      }
++
++      return 0;
++}
++
++static int STM2GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p);
++static int STM2GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p);
++
++static struct dfc_flash_info stm2GbX16 =
++{
++      .timing = {
++              .tCH = 10,      /* tCH, Enable signal hold time */
++              .tCS = 10,      /* tCS, Enable signal setup time */
++              .tWH = 20,      /* tWH, ND_nWE high duration */
++              .tWP = 25,      /* tWP, ND_nWE pulse time */
++              .tRH = 20,      /* tRH, ND_nRE high duration */
++              .tRP = 25,      /* tRP, ND_nRE pulse width */
++              /* tR = tR+tRR+tWB+1, ND_nWE high to ND_nRE low for read */
++              .tR = 25000,
++              /* tWHR, ND_nWE high to ND_nRE low delay for status read */
++              .tWHR = 60,
++              .tAR = 10,      /* tAR, ND_ALE low to ND_nRE low delay */
++      },
++      .enable_arbiter = 1,    /* Data flash bus arbiter enable */
++      .page_per_block = 64,   /* Pages per block */
++      .row_addr_start = 1,    /* Second cycle start, Row address start position */
++      .read_id_bytes = 4,     /* Returned ID bytes */
++      .dfc_mode = 0,          /* NAND mode */
++      .ncsx = 0,
++      .page_size = 2048,      /* Page size in bytes */
++      .oob_size = 64,         /* OOB size in bytes */
++      .flash_width = 16,      /* Width of Flash memory */
++      .dfc_width = 16,        /* Width of flash controller */
++      .num_blocks = 2048,     /* Number of physical blocks in Flash */
++      .chip_id =  0xca20,
++
++      /* command codes */
++      .read1 = 0x3000,        /* Read */
++      .read2 = 0x0050,        /* Read1 unused, current DFC don't support */
++      .program = 0x1080,      /* Write, two cycle command */
++      .read_status = 0x0070,  /* Read status */
++      .read_id = 0x0090,      /* Read ID */
++      .erase =  0xD060,       /* Erase, two cycle command */
++      .reset = 0x00FF,        /* Reset */
++      .lock = 0x002A,         /* Lock whole flash */
++      .unlock = 0x2423,       /* Unlock, two cycle command, supporting partial unlock */
++      .lock_status = 0x007A,  /* Read block lock status */
++      .addr2ndcb1 = STM2GbX16Addr2NDCB1,
++      .ndbbr2addr = STM2GbX16NDBBR2Addr,
++};
++
++static int STM2GbX16Addr2NDCB1(uint16_t cmd, uint32_t addr, uint32_t *p)
++{
++      uint32_t ndcb1 = 0;
++      uint32_t page;
++
++      if (addr >= 0x8000000)
++              return -EINVAL;
++      page = addr / stm2GbX16.page_size;
++      addr =  (page / stm2GbX16.page_per_block) << 17 |
++              (page % stm2GbX16.page_per_block) << 11;
++
++      if (cmd == stm2GbX16.read1 || cmd == stm2GbX16.program) {
++              ndcb1 = (addr & 0x7FF) | ((addr << 5) & 0xFFFF0000);
++      }
++      else if (cmd == stm2GbX16.erase) {
++              ndcb1 = ((addr >> 17) << 6) & 0xFFFF;
++      }
++      *p = ndcb1;
++      return 0;
++}
++
++static int STM2GbX16NDBBR2Addr(uint16_t cmd, uint32_t ndbbr, uint32_t *p)
++{
++      if (cmd == stm2GbX16.read1 || cmd == stm2GbX16.program) {
++              *p = ((ndbbr & 0x7) << 8) | ((ndbbr >> 8) << 16);
++      }
++      else if (cmd == stm2GbX16.erase) {
++              *p = (ndbbr >> 6) << 17;
++      }
++
++      return 0;
++}
++
++static struct {
++      int type;
++      struct dfc_flash_info *flash_info;
++} type_info[] = {
++      { DFC_FLASH_Samsung_512Mb_X_16, &samsung512MbX16},
++      { DFC_FLASH_Micron_1Gb_X_8, &micron1GbX8},
++      { DFC_FLASH_Micron_1Gb_X_16, &micron1GbX16},
++      { DFC_FLASH_STM_1Gb_X_16, &stm1GbX16},
++      { DFC_FLASH_STM_2Gb_X_16, &stm2GbX16},
++      { DFC_FLASH_NULL, NULL},
++};
++
++int dfc_get_flash_info(int type, struct dfc_flash_info **flash_info)
++{
++      uint32_t i = 0;
++
++      while(type_info[i].type != DFC_FLASH_NULL) {
++              if (type_info[i].type == type) {
++                      *flash_info = type_info[i].flash_info;
++                      return 0;
++              }
++              i++;
++      }
++      *flash_info = NULL;
++      return -EINVAL;
++}
++
++/******************************************************************************
++  dfc_set_timing
++
++  Description:
++      This function sets flash timing property in DFC timing register
++      according to input timing value embodied in context structure.
++      It is called once during the hardware initialization.
++  Input Parameters:
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++//#if defined(CONFIG_CPU_MONAHANS_L) || defined(CONFIG_CPU_MONAHANS_LV)
++#define DFC_CLOCK     208
++//#else
++//#define DFC_CLOCK   104
++//#endif
++#define CLOCK_NS      DFC_CLOCK/1000
++
++void dfc_set_timing(struct dfc_context *context, struct dfc_flash_timing *t)
++{
++      struct dfc_flash_timing timing = *t;
++
++      uint32_t  r0 = 0;
++      uint32_t  r1 = 0;
++
++      /*
++       * num of clock cycles = time (ns) / one clock sycle (ns) + 1
++       * - integer division will truncate the result, so add a 1 in all cases
++       * - subtract the extra 1 cycle added to all register timing values
++       */
++      timing.tCH = min(((int) (timing.tCH * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tCH);
++      timing.tCS = min(((int) (timing.tCS * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tCS);
++      timing.tWH = min(((int) (timing.tWH * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tWH);
++      timing.tWP = min(((int) (timing.tWP * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tWP);
++      timing.tRH = min(((int) (timing.tRH * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tRH);
++      timing.tRP = min(((int) (timing.tRP * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tRP);
++
++      r0 = (timing.tCH << DFC_TIMING_tCH) |
++           (timing.tCS << DFC_TIMING_tCS) |
++           (timing.tWH << DFC_TIMING_tWH) |
++           (timing.tWP << DFC_TIMING_tWP) |
++           (timing.tRH << DFC_TIMING_tRH) |
++           (timing.tRP << DFC_TIMING_tRP);
++
++      dfc_write(context, DFC_NDTR0CS0, r0);
++
++      timing.tR   = min(((int) (timing.tR   * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tR);
++      timing.tWHR = min(((int) (timing.tWHR * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tWHR);
++      timing.tAR  = min(((int) (timing.tAR  * CLOCK_NS) + 1),
++                      DFC_TIMING_MAX_tAR);
++
++      r1 = (timing.tR   << DFC_TIMING_tR)   |
++           (timing.tWHR << DFC_TIMING_tWHR) |
++           (timing.tAR  << DFC_TIMING_tAR);
++
++      dfc_write(context, DFC_NDTR1CS0, r1);
++      return;
++}
++
++/******************************************************************************
++  dfc_set_dma
++
++  Description:
++              Enables or Disables DMA in line with setting in DFC mode of context
++              structure. DMA mode of DFC. Performs a read-modify-write operation that
++              only changes the driven DMA_EN bit field In DMA mode, all commands and
++              data are transferred by DMA.  DMA can be enable/disable on the fly.
++  Input Parameters:
++      context -Pointer to DFC context structure
++      Output Parameters:
++              None
++      Returns:
++              None
++*******************************************************************************/
++void
++dfc_set_dma(struct dfc_context* context)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      if (context->dfc_mode->enable_dma)
++              ndcr |= NDCR_DMA_EN;
++      else
++              ndcr &= ~NDCR_DMA_EN;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      /* Read again to make sure write work */
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++
++/******************************************************************************
++  dfc_set_ecc
++
++  Description:
++              This function enables or disables hardware ECC capability of DFC in line
++              with setting in DFC mode of context structure.
++  Input Parameters:
++      context -Pointer to DFC context structure
++      Output Parameters:
++              None
++      Returns:
++              None
++*******************************************************************************/
++void
++dfc_set_ecc(struct dfc_context* context)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      if (context->dfc_mode->enable_ecc)
++              ndcr |= NDCR_ECC_EN;
++      else
++              ndcr &= ~NDCR_ECC_EN;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      /* Read again to make sure write work */
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++/******************************************************************************
++  dfc_set_spare
++
++  Description:
++              This function enables or disables accesses to spare area of NAND Flash
++              through DFC in line with setting in DFC mode of context structure.
++  Input Parameters:
++      context -Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void
++dfc_set_spare(struct dfc_context* context)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      if (context->dfc_mode->enable_spare)
++              ndcr |= NDCR_SPARE_EN;
++      else
++              ndcr &= ~NDCR_SPARE_EN;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      /* Read again to make sure write work */
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++static unsigned int get_delta (unsigned int start)
++{
++    unsigned int stop = OSCR;
++    return (stop - start);
++}
++
++static int dfc_wait_event(struct dfc_context *context, uint32_t event,
++              uint32_t *event_out, uint32_t timeout, int enable_int)
++{
++      uint32_t ndsr;
++      uint32_t to = 3 * timeout;      /* 3 ticks ~ 1us */
++      int status;
++      int start = OSCR;
++
++      if (enable_int)
++              dfc_enable_int(context, event);
++
++      while (1) {
++              ndsr = dfc_read(context, DFC_NDSR);
++              ndsr &= NDSR_MASK;
++              if (ndsr & event) {
++                      /* event happened */
++                      *event_out = ndsr & event;
++                      dfc_clear_int(context, *event_out);
++                      status = 0;
++                      break;
++              } else if (get_delta(start) > to) {
++                      status = -ETIME;
++                      break;
++              }
++      }
++
++      if (enable_int)
++              dfc_disable_int(context, event);
++      return status;
++}
++
++/******************************************************************************
++  dfc_get_pattern
++
++  Description:
++      This function is used to retrieve buffer size setting for a transaction
++      based on cmd.
++  Input Parameters:
++      context - Pointer to DFC context structure
++      cmd
++        Specifies type of command to be sent to NAND flash .The LSB of this
++        parameter defines the first command code for 2-cycles command. The
++        MSB defines the second command code for 2-cycles command. If MSB is
++        set to zero, this indicates that one cycle command
++      Output Parameters:
++      data_size
++        It is used to retrieve  length of data transferred to/from DFC,
++        which includes padding bytes
++      padding
++        It is used to retrieve how many padding bytes there should be
++        in buffer of data_size.
++      Returns:
++      0
++        If size setting is returned successfully
++      -EINVAL
++        If page size specified in flash spec of context structure is not 512 or
++        2048;If specified command index is not read1/program/erase/reset/readID/
++        readStatus.
++*******************************************************************************/
++int dfc_get_pattern(struct dfc_context *context, uint16_t cmd,
++                      int *data_size, int *padding)
++{
++      struct dfc_mode* dfc_mode = context->dfc_mode;
++      struct dfc_flash_info * flash_info = context->flash_info;
++      uint32_t page_size = context->flash_info->page_size; /* 512 or 2048 */
++
++      if (cmd == flash_info->read1 ||
++              cmd == flash_info->program) {
++              if (512 == page_size) {
++                      /* add for DMA */
++                      if (dfc_mode->enable_dma) {
++                              *data_size = DFC_DATA_SIZE_544;
++                              if (dfc_mode->enable_ecc)
++                                      *padding = DFC_PADDING_SIZE_24;
++                              else
++                                      *padding = DFC_PADDING_SIZE_16;
++                      } else if (!dfc_mode->enable_spare) {
++                              *data_size = DFC_DATA_SIZE_512;
++                              *padding = DFC_PADDING_SIZE_0;
++                      } else {
++
++                              if (dfc_mode->enable_ecc)
++                                      *data_size = DFC_DATA_SIZE_520;
++                              else
++                                      *data_size = DFC_DATA_SIZE_528;
++
++                              *padding = DFC_PADDING_SIZE_0;
++                      }
++              } else if (2048 == page_size) {
++                      /* add for DMA */
++                      if (dfc_mode->enable_dma) {
++                              *data_size = DFC_DATA_SIZE_2112;
++                              if (dfc_mode->enable_ecc)
++                                      *padding = DFC_PADDING_SIZE_24;
++                              else
++                                      *padding = DFC_PADDING_SIZE_0;
++                      } else if (!dfc_mode->enable_spare) {
++                              *data_size = DFC_DATA_SIZE_2048;
++                              *padding = DFC_PADDING_SIZE_0;
++                      } else {
++
++                              if (dfc_mode->enable_ecc)
++                                      *data_size = DFC_DATA_SIZE_2088;
++                              else
++                                      *data_size = DFC_DATA_SIZE_2112;
++
++                              *padding = DFC_PADDING_SIZE_0;
++                      }
++              } else /* if the page_size is neither 512 or 2048 */
++                      return -EINVAL;
++      } else if (cmd == flash_info->read_id) {
++              *data_size = DFC_DATA_SIZE_ID;
++              *padding = DFC_PADDING_SIZE_0;
++      } else if(cmd == flash_info->read_status) {
++              *data_size = DFC_DATA_SIZE_STATUS;
++              *padding = DFC_PADDING_SIZE_0;
++      } else if (cmd == flash_info->erase || cmd == flash_info->reset) {
++              *data_size = DFC_DATA_SIZE_UNUSED;
++              *padding = DFC_PADDING_SIZE_UNUSED;
++      } else
++              return -EINVAL;
++      return 0;
++}
++
++
++/******************************************************************************
++  dfc_send_cmd
++
++  Description:
++      This function configures DFC to send command through DFC to NAND flash
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      cmd
++        Specifies type of command to be sent to NAND flash .The LSB of this
++        parameter defines the first command code for 2-cycles command. The
++        MSB defines the second command code for 2-cycles command. If MSB is
++        set to zero, this indicates that one cycle command
++      addr
++        Address sent out to the flash device withthis command. For page read/
++        program commands , 4-cycles address is sent. For erase command only
++        3-cycles address is sent. If it is equal to 0xFFFFFFFF, the address
++        should not be used.
++      num_pages
++        It specifies the number of pages of data to be transferred for
++        a program or read commands. Unused for any other commands than
++        read/program.
++
++  Output Parameters:
++      None
++  Returns:
++      0
++        If size setting is returned successfully
++      -EINVAL
++        If specified command index is not read1/program/erase/reset/readID/
++        readStatus.
++*******************************************************************************/
++int dfc_send_cmd(struct dfc_context *context, uint16_t cmd,
++                      uint32_t addr, int num_pages)
++{
++      struct dfc_flash_info *flash_info = context->flash_info;
++      struct dfc_mode *dfc_mode = context->dfc_mode;
++      uint8_t  cmd2;
++      uint32_t event_out;
++      uint32_t ndcb0=0, ndcb1=0, ndcb2=0, ndcr;
++      int status;
++
++      /* It is a must to set ND_RUN firstly, then write command buffer
++       * If conversely,it does not work
++       */
++      dfc_write(context, DFC_NDSR, NDSR_MASK);
++
++      /* Set ND_RUN */
++      ndcr = dfc_read(context, DFC_NDCR);
++      dfc_write(context, DFC_NDCR, (ndcr | NDCR_ND_RUN));
++
++      // Wait for write command request
++      status = dfc_wait_event(context, NDSR_WRCMDREQ,
++              &event_out, NAND_CMD_TIMEOUT, 0);
++
++      if (status) /* Timeout */
++              return status;
++
++      cmd2 = (cmd>>8) & 0xFF;
++      ndcb0 = cmd | (dfc_mode->chip_select<<24) | ((cmd2?1:0)<<19);
++
++      if (cmd == flash_info->read1) {
++              if (0xFFFFFFFF != addr) {
++                      ndcb0 |= NDCB0_ADDR_CYC(4);
++                      status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++                      if (status)
++                              return status;
++                      ndcb2 = (num_pages - 1) << 8;
++              }
++      } else if (cmd == flash_info->program) {
++              ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
++              ndcb0 |= NDCB0_ADDR_CYC(4);
++              status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++              if (status)
++                      return status;
++              ndcb2 = (num_pages-1) << 8;
++      } else if (cmd == flash_info->erase) {
++              ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS;
++              ndcb0 |= NDCB0_ADDR_CYC(3);
++              status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++              if (status)
++                      return status;
++      } else if (cmd == flash_info->read_id) {
++              ndcb0 |= NDCB0_CMD_TYPE(3);
++      } else if(cmd == flash_info->read_status) {
++              ndcb0 |= NDCB0_CMD_TYPE(4);
++      } else if(cmd == flash_info->reset) {
++              ndcb0 |= NDCB0_CMD_TYPE(5);
++      } else if (cmd == flash_info->lock) {
++              ndcb0 |= NDCB0_CMD_TYPE(5);
++      } else
++              return -EINVAL;
++
++      /* Write to DFC command register */
++      dfc_write(context, DFC_NDCB0, ndcb0);
++      dfc_write(context, DFC_NDCB0, ndcb1);
++      dfc_write(context, DFC_NDCB0, ndcb2);
++
++      return 0;
++}
++
++/******************************************************************************
++  dfc_stop
++
++  Description:
++      This function clears ND_RUN bit of NDCR.
++  Input Parameters:
++      context--Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_stop(struct dfc_context *context)
++{
++      unsigned int ndcr;
++      ndcr = dfc_read(context, DFC_NDCR);
++      dfc_write(context, DFC_NDCR, (ndcr & ~NDCR_ND_RUN));
++      ndcr = dfc_read(context, DFC_NDCR);
++
++      return;
++}
++
++int dfc_setup_cmd_dma(struct dfc_context *context,
++              uint16_t cmd, uint32_t addr, int num_pages,
++              uint32_t *buf, uint32_t buf_phys,
++              uint32_t next_desc_phys, uint32_t dma_int_en,
++              struct pxa_dma_desc *dma_desc)
++{
++      struct dfc_flash_info *flash_info = context->flash_info;
++      struct dfc_mode *dfc_mode = context->dfc_mode;
++      uint8_t  cmd2;
++      uint32_t event_out;
++      uint32_t ndcb0=0, ndcb1=0, ndcb2=0, ndcr;
++      int status;
++
++      /*
++       * It is a must to set ND_RUN firstly, then write command buffer
++       * If conversely,it does not work
++       */
++      dfc_write(context, DFC_NDSR, NDSR_MASK);
++
++      /* Set ND_RUN */
++      ndcr = dfc_read(context, DFC_NDCR);
++      ndcr |= NDCR_ND_RUN;
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      /* Wait for write command request */
++      status = dfc_wait_event(context, NDSR_WRCMDREQ,
++              &event_out, NAND_CMD_TIMEOUT, 0);
++
++      if (status)
++              return status; /* Timeout */
++
++      cmd2 = (cmd>>8) & 0xFF;
++      ndcb0 = cmd | (dfc_mode->chip_select<<24) | ((cmd2?1:0)<<19);
++
++      if (cmd == flash_info->read1) {
++              if (0xFFFFFFFF != addr) {
++                      ndcb0 |= NDCB0_ADDR_CYC(4);
++                      status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++                      if (status)
++                              return status;
++                      ndcb2 = (num_pages-1) << 8;
++              }
++      } else if (cmd == flash_info->program) {
++              ndcb0 |= NDCB0_CMD_TYPE(1) | NDCB0_AUTO_RS;
++              ndcb0 |= NDCB0_ADDR_CYC(4);
++
++              status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++              if (status)
++                      return status;
++              ndcb2 = (num_pages-1) << 8;
++      } else if (cmd == flash_info->erase) {
++              ndcb0 |= NDCB0_CMD_TYPE(2) | NDCB0_AUTO_RS;
++              ndcb0 |= NDCB0_ADDR_CYC(3);
++
++              status = flash_info->addr2ndcb1(cmd, addr, &ndcb1);
++              if (status)
++                      return status;
++      } else if (cmd == flash_info->read_id) {
++              ndcb0 |= NDCB0_CMD_TYPE(3);
++      } else if (cmd == flash_info->read_status) {
++              ndcb0 |= NDCB0_CMD_TYPE(4);
++      } else if (cmd == flash_info->reset) {
++              ndcb0 |= NDCB0_CMD_TYPE(5);
++      } else if (cmd == flash_info->lock) {
++              ndcb0 |= NDCB0_CMD_TYPE(5);
++      } else
++              return -EINVAL;
++
++      *((uint32_t *)buf) = ndcb0;
++      *((uint32_t *)buf + 1) = ndcb1;
++      *((uint32_t *)buf + 2) = ndcb2;
++
++      dma_int_en &= (DCMD_STARTIRQEN | DCMD_ENDIRQEN);
++
++      dma_desc->ddadr = next_desc_phys;
++      dma_desc->dsadr = buf_phys;
++      dma_desc->dtadr = NDCB0_DMA_ADDR;
++      dma_desc->dcmd  = DCMD_INCSRCADDR | DCMD_FLOWTRG | dma_int_en |
++                        DCMD_WIDTH4 | DCMD_BURST16 | 12;
++      return 0;
++}
++
++int dfc_setup_data_dma(struct dfc_context* context,
++              uint16_t cmd, uint32_t buf_phys,
++              uint32_t next_desc_phys, uint32_t dma_int_en,
++              struct pxa_dma_desc* dma_desc)
++{
++      struct dfc_flash_info * flash_info = context->flash_info;
++      int data_size, padding;
++
++      dfc_get_pattern(context, cmd, &data_size, &padding);
++
++      dma_desc->ddadr = next_desc_phys;
++      dma_int_en &= (DCMD_STARTIRQEN | DCMD_ENDIRQEN);
++
++      if (cmd == flash_info->program) {
++
++              dma_desc->dsadr = buf_phys;
++              dma_desc->dtadr = NDDB_DMA_ADDR;
++              dma_desc->dcmd  = DCMD_INCSRCADDR | DCMD_FLOWTRG | dma_int_en |
++                                DCMD_WIDTH4 | DCMD_BURST32 | data_size;
++
++      } else if (cmd == flash_info->read1 || cmd == flash_info->read_id ||
++                 cmd == flash_info->read_status) {
++
++              dma_desc->dsadr = NDDB_DMA_ADDR;
++              dma_desc->dtadr = buf_phys;
++              dma_desc->dcmd  = DCMD_INCTRGADDR | DCMD_FLOWSRC | dma_int_en |
++                                DCMD_WIDTH4 | DCMD_BURST32 | data_size;
++      }
++      else
++              return -EINVAL;
++      return 0;
++}
++
++void dfc_start_cmd_dma(struct dfc_context* context, struct pxa_dma_desc* dma_desc)
++{
++      DRCMR99 = DRCMR_MAPVLD | context->cmd_dma_ch;   /* NAND CMD DRCMR */
++      DDADR(context->cmd_dma_ch) = (uint32_t)dma_desc;
++      DCSR(context->cmd_dma_ch) |= DCSR_RUN;
++}
++
++void dfc_start_data_dma(struct dfc_context* context, struct pxa_dma_desc* dma_desc)
++{
++      DRCMR97 = DRCMR_MAPVLD | context->data_dma_ch;
++      DDADR(context->data_dma_ch) = (uint32_t)dma_desc;
++      DCSR(context->data_dma_ch) |= DCSR_RUN;
++}
++
++/******************************************************************************
++  dfc_read_fifo_partial
++
++  Description:
++      This function reads data from data buffer of DFC.Bytes can be any less than
++      or equal to data_size, the left is ignored by ReadFIFO though they will be
++      read from NDDB to clear data buffer.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      nbytes
++        Indicating how much data should be read into buffer.
++      data_size
++        Specifing length of data transferred to/from DFC, which includes
++        padding bytes
++  Output Parameters:
++      pBuffer
++        Pointer to the data buffer where data should be placed.
++      Returns:
++        None
++*******************************************************************************/
++void dfc_read_fifo_partial(struct dfc_context *context, uint8_t *buffer,
++              int nbytes, int data_size)
++{
++      uint32_t data = 0;
++      uint32_t i = 0;
++      uint32_t bytes_multi;
++      uint32_t bytes_remain;
++
++
++      if (1 == data_size) {
++              data = dfc_read(context, DFC_NDDB) & 0xFF;
++              *buffer++ = (uint8_t)data;
++      } else if (2 == data_size) {
++              data = dfc_read(context, DFC_NDDB) & 0xFFFF;
++              *buffer++ = data & 0xFF;
++              *buffer++ = (data >> 8) & 0xFF;
++      } else {
++              bytes_multi = (nbytes & 0xFFFFFFFC);
++              bytes_remain = nbytes & 0x03;
++
++              i = 0;
++              /* Read the bytes_multi*4 bytes data */
++              while (i < bytes_multi) {
++                      data = dfc_read(context, DFC_NDDB);
++                      /* FIXME: we don't know whether the buffer
++                       * align to 4 bytes or not. Cast the buffer
++                       * to int is not safe here. Especially under
++                       * gcc 4.x. Used memcpy here. But the memcpy
++                       * may be not correct on BE architecture.
++                       * --by Yin, Fengwei
++                       */
++                      memcpy(buffer, &data, sizeof(data));
++                      i += sizeof(data);
++                      buffer += sizeof(data);
++              }
++
++              /* Read the left bytes_remain bytes data */
++              if (bytes_remain) {
++                      data = dfc_read(context, DFC_NDDB);
++                      for (i = 0; i < bytes_remain; i++)
++                              *buffer++ = (uint8_t)((data >> (8*i)) & 0xFF);
++              }
++
++              /* When read the remain bytes, we always read 4 bytes data
++               * to DFC. So the data_size should subtract following number.
++               */
++              data_size -= bytes_multi + (bytes_remain ? sizeof(data) : 0);
++
++              /* We need Read data_size bytes data totally */
++              while (data_size > 0) {
++                      data = dfc_read(context, DFC_NDDB);
++                      data_size -= sizeof(data);
++              }
++
++/*
++              while(i < ((uint32_t)data_size) ) {
++                      if (i < bytes_multi) {
++                              temp = (uint32_t *)buffer;
++                              *temp = dfc_reg->nddb;
++                      } else if (i == bytes_multi && bytes_remain){
++                              uint32_t j = 0;
++                              data = dfc_reg->nddb;
++                              while (j++ < bytes_remain) {
++                                      *buffer++ = (uint8_t)   \
++                                              ((data>>(8*j)) & 0xFF);
++                              }
++                      } else {
++                              data = dfc_reg->nddb;
++                      }
++                      i += 4;
++                      buffer += 4;
++              }
++*/
++      }
++      return;
++}
++
++/******************************************************************************
++  dfc_write_fifo_partial
++
++  Description:
++      Write to data buffer of DFC from a buffer. Bytes can be same as
++      data_size, also can be data_size-padding, but can¡¯t be random value,
++      the left will be automatically padded by WriteFIFO.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      bytes
++        Indicating how much data should be read into buffer.
++      data_size
++        Specifing length of data transferred to/from DFC, which includes
++        padding bytes
++      buffer
++        Pointer to the data buffer where data will be taken from to be written
++        to DFC data buffer
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_write_fifo_partial(struct dfc_context *context, uint8_t *buffer,
++              int nbytes, int data_size)
++{
++      uint32_t i = 0;
++
++      uint32_t bytes_multi = (nbytes & 0xFFFFFFFC);
++      uint32_t bytes_remain = nbytes & 0x03;
++      uint32_t temp;
++      /*
++       * caller guarantee buffer contains appropriate data thereby
++       * it is impossible for nbytes not to be a multiple of 4 byte
++       */
++
++      /* Write the bytes_multi*4 bytes data */
++      while (i < bytes_multi) {
++              temp = buffer[0] | buffer[1] << 8 |
++                              buffer[2] << 16 | buffer[3] << 24;
++              dfc_write(context, DFC_NDDB, temp);
++              buffer += 4;
++              i += 4;
++      }
++
++      /* Write the left bytes_remain bytes data */
++      if (bytes_remain) {
++              temp = 0xFFFFFFFF;
++              for (i = 0; i < bytes_remain; i++)
++                      temp &= *buffer++ << i*8;
++
++              dfc_write(context, DFC_NDDB, temp);
++      }
++
++      /* When write the remain bytes, we always write 4 bytes data
++       * to DFC. So the data_size should subtract following number.
++       */
++      data_size -= bytes_multi + (bytes_remain ? sizeof(temp) : 0);
++
++      while (data_size > 0) {
++              dfc_write(context, DFC_NDDB, 0xFFFFFFFF);
++              data_size -= 4;
++      }
++
++/*
++      while (i < ((uint32_t)data_size)) {
++              if (i < bytes_multi) {
++                      temp = (uint32_t *)buffer;
++                      dfc_reg->nddb = *temp;
++              }
++              else if (i == bytes_multi && bytes_remain) {
++                              uint32_t j = 0, data = 0xFFFFFFFF;
++                              while (j < bytes_remain) {
++                                data &= (uint8_t)(*buffer) << j;
++                                buffer++;
++                                j++;
++                              }
++                      dfc_reg->nddb = data;
++              }
++              else {
++                      dfc_reg->nddb = 0xFFFFFFFF;
++              }
++              i += 4;
++              buffer += 4;
++      }
++*/
++
++      return;
++}
++
++/******************************************************************************
++  dfc_read_fifo
++  Description:
++      This function reads data from data buffer of DFC.Bytes can be any less
++      than or equal to data_size, the left is ignored by ReadFIFO though they
++      will be read from NDDB to clear data buffer.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      nbytes
++        Indicating how much data should be read into buffer.
++      data_size
++        Specifing length of data transferred to/from DFC, which includes
++        padding bytes
++  Output Parameters:
++      buffer
++        Pointer to the data buffer where data should be placed.
++  Returns:
++      None
++*******************************************************************************/
++
++void dfc_read_fifo(struct dfc_context *context, uint8_t *buffer, int nbytes)
++{
++      uint32_t i = 0;
++
++      uint32_t bytes_multi = (nbytes & 0xFFFFFFFC);
++      uint32_t bytes_remain = nbytes & 0x03;
++      uint32_t temp;
++
++      /* Read the bytes_multi*4 bytes data */
++      while (i < bytes_multi) {
++              temp = dfc_read(context, DFC_NDDB);
++              /* FIXME: we don't know whether the buffer
++               * align to 4 bytes or not. Cast the buffer
++               * to int is not safe here. Especially under
++               * gcc 4.x. Used memcpy here. But the memcpy
++               * may be not correct on BE architecture.
++               * --by Yin, Fengwei
++               */
++              memcpy(buffer, &temp, sizeof(temp));
++              i += sizeof(temp);
++              buffer += sizeof(temp);
++      }
++
++      /* Read the left bytes_remain bytes data */
++      temp = dfc_read(context, DFC_NDDB);
++      for (i = 0; i < bytes_remain; i++) {
++              *buffer++ = (uint8_t)((temp >> (8*i)) & 0xFF);
++      }
++
++/*
++      while (i < bytes_multi) {
++          temp = (uint32_t *)buffer;
++          *temp = dfc_reg->nddb;
++          i += 4;
++          buffer += 4;
++      }
++
++      if (bytes_remain) {
++              data = dfc_reg->nddb;
++              for (i = 0; i < bytes_remain; i++) {
++                      *buffer++ = (uint8_t)((data>>(8*i)) & 0xFF);
++              }
++      }
++*/
++
++      return;
++}
++
++/******************************************************************************
++  dfc_write_fifo
++  Description:
++      Write to data buffer of DFC from a buffer.Bytes can be same as data_size,
++      also can be data_size-padding, but can¡¯t be random value, the left will
++      be automatically padded by WriteFIFO.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      nbytes
++        Indicating how much data should be read into buffer.
++      data_size
++        Specifing length of data transferred to/from DFC, which includes
++        padding bytes
++      buffer
++        Pointer to the data buffer where data will be taken from to be written to
++        DFC data buffer
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_write_fifo(struct dfc_context *context, uint8_t *buffer, int nbytes)
++{
++      uint32_t bytes_multi = (nbytes & 0xFFFFFFFC);
++      uint32_t bytes_remain = nbytes & 0x03;
++      uint32_t i=0;
++      uint32_t temp;
++
++      /* Write the bytes_multi*4 bytes data */
++      while (i < bytes_multi) {
++              temp = buffer[0] | buffer[1] << 8 |
++                              buffer[2] << 16 | buffer[3] << 24;
++              dfc_write(context, DFC_NDDB, temp);
++              buffer += 4;
++              i += 4;
++      }
++
++      /* Write the left bytes_remain bytes data */
++      temp = 0xFFFFFFFF;
++      for (i = 0; i < bytes_remain; i++)
++              temp &= *buffer++ << i*8;
++      dfc_write(context, DFC_NDDB, temp);
++
++/*
++      while (i < nbytes) {
++          temp = (uint32_t *)buffer;
++          dfc_reg->nddb = *temp;
++          i += 4;
++          buffer += 4;
++      }
++*/
++}
++
++/******************************************************************************
++  dfc_read_badblock_addr
++
++  Description:
++      This function reads bad block address in units of block starting from 0
++      if bad block is detected. It takes into the account if the operation is
++      for CS0 or CS1  depending on settings of chip_select parameter of DFC
++      Mode structure.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++  Output Parameters:
++      pBadBlockAddr
++        Used to retrieve bad block address back to caller if bad block is
++        detected
++  Returns:
++      None
++*******************************************************************************/
++void dfc_read_badblock_addr(struct dfc_context *context, uint32_t *bbaddr)
++{
++      uint32_t ndbdr;
++      if (0 == context->dfc_mode->chip_select)
++              ndbdr = dfc_read(context, DFC_NDBDR0);
++      else
++              ndbdr = dfc_read(context, DFC_NDBDR1);
++
++      if (512 == context->flash_info->page_size) {
++              ndbdr = (ndbdr >> 5) & 0xFFF;
++              *bbaddr = ndbdr;
++      } else if (2048 == context->flash_info->page_size) {
++              /* 16 bits LB */
++              ndbdr = (ndbdr >> 8);
++              *bbaddr = ndbdr;
++      }
++      return;
++}
++
++/******************************************************************************
++  dfc_enable_int
++
++  Description:
++      This function is used to enable DFC interrupts. The bits in int_mask
++      will be used to unmask NDCR register to enable corresponding interrupts.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      int_mask
++        Specifies what interrupts to enable
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_enable_int(struct dfc_context *context, uint32_t int_mask)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      ndcr &= ~int_mask;
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++/******************************************************************************
++  dfc_disable_int
++
++  Description:
++      This function is used to disable DFC interrupts.
++      The bits inint_mask will be used to mask NDCR register to disable
++      corresponding interrupts.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      int_mask
++        Specifies what interrupts to disable
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_disable_int(struct dfc_context *context, uint32_t int_mask)
++{
++      uint32_t ndcr;
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      ndcr |= int_mask;
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      ndcr = dfc_read(context, DFC_NDCR);
++      return;
++}
++
++/******************************************************************************
++  dfc_clear_int
++
++  Description:
++      This function is used to disable DFC interrupts.
++      The bits in int_mask will be used to clear corresponding interrupts
++      in NDCR register
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++      int_mask
++        Specifies what interrupts to clear
++  Output Parameters:
++      None
++  Returns:
++      None
++*******************************************************************************/
++void dfc_clear_int(struct dfc_context *context, uint32_t int_mask)
++{
++      dfc_write(context, DFC_NDSR, int_mask);
++
++      dfc_read(context, DFC_NDSR);
++      return;
++}
++
++/*
++ * high level primitives
++ */
++
++/******************************************************************************
++  dfc_init
++
++  Description:
++      This function does entire DFC initialization according to the NAND
++      flash type currently used with platform, including setting MFP, set
++      flash timing, set DFC mode, configuring specified flash parameters
++      in DFC, clear ECC logic and page count register.
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      0
++        if MFPRs are set correctly
++      -EINVAL
++        if specified flash is not support by check bytes per page and pages per
++        block
++******************************************************************************/
++
++static mfp_cfg_t pxa300_nand_cfg[] = {
++      /* NAND */
++      MFP_CFG_X(DF_INT_RnB, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nRE_nOE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nWE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_CLE_nOE, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nADV1_ALE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nCS0, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nCS1, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_IO0, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO1, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO2, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO3, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO4, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO5, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO6, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO7, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO8, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO9, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO10, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO11, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO12, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO13, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO14, AF1, DS08X, PULL_LOW),
++};
++
++#define ARRAY_AND_SIZE(x)     (x), ARRAY_SIZE(x)
++
++int dfc_init(struct dfc_context* context, int type)
++{
++      int status;
++      struct dfc_flash_info * flash_info;
++      uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
++
++      status = dfc_get_flash_info(type, &flash_info);
++      if (status)
++              return status;
++      context->flash_info = flash_info;
++
++      pxa3xx_mfp_config(ARRAY_AND_SIZE(pxa300_nand_cfg));
++      //enable_dfc_pins();
++
++      dfc_set_timing(context, &context->flash_info->timing);
++
++      if (flash_info->enable_arbiter)
++              ndcr |= NDCR_ND_ARB_EN;
++
++      if (64 == flash_info->page_per_block)
++              ndcr |= NDCR_PG_PER_BLK;
++      else if (32 != flash_info->page_per_block)
++              return -EINVAL;
++
++      if (flash_info->row_addr_start)
++              ndcr |= NDCR_RA_START;
++
++      ndcr |=  (flash_info->read_id_bytes)<<16;
++
++      ndcr |= (flash_info->dfc_mode) << 21;
++
++      if (flash_info->ncsx)
++              ndcr |= NDCR_NCSX;
++
++      if (2048 == flash_info->page_size)
++              ndcr |= NDCR_PAGE_SZ;
++      else if (512 != flash_info->page_size)
++              return -EINVAL;
++
++      if (16 == flash_info->flash_width)
++              ndcr |= NDCR_DWIDTH_M;
++      else if (8 != flash_info->flash_width)
++              return -EINVAL;
++
++      if (16 == flash_info->dfc_width)
++              ndcr |= NDCR_DWIDTH_C;
++      else if (8 != flash_info->dfc_width)
++              return -EINVAL;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      dfc_set_dma(context);
++      dfc_set_ecc(context);
++      dfc_set_spare(context);
++
++      return 0;
++}
++
++/******************************************************************************
++  dfc_init_no_gpio
++
++  Description:
++      This function does entire DFC initialization according to the NAND
++      flash type currently used with platform, including set flash timing,
++      set DFC mode, configuring specified flash parameters in DFC, clear
++      ECC logic and page count register. The only difference with dfc_init
++      is that it does not set MFP&GPIO, very useful in OS loader
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      0
++        if MFPRs are set correctly
++      -EINVAL
++        if specified flash is not support by check bytes per page and pages
++        per block
++******************************************************************************/
++int dfc_init_no_gpio(struct dfc_context* context, int type)
++{
++      struct dfc_flash_info * flash_info;
++      uint32_t ndcr = 0x00000FFF; /* disable all interrupts */
++      int status;
++
++      status = dfc_get_flash_info(type, &flash_info);
++      if (status)
++              return status;
++      context->flash_info = flash_info;
++
++      dfc_set_timing(context, &context->flash_info->timing);
++
++      if (flash_info->enable_arbiter)
++              ndcr |= NDCR_ND_ARB_EN;
++
++      if (64 == flash_info->page_per_block)
++              ndcr |= NDCR_PG_PER_BLK;
++      else if (32 != flash_info->page_per_block)
++              return -EINVAL;
++
++      if (flash_info->row_addr_start)
++              ndcr |= NDCR_RA_START;
++
++      ndcr |=  (flash_info->read_id_bytes)<<16;
++
++      ndcr |= (flash_info->dfc_mode) << 21;
++
++      if (flash_info->ncsx)
++              ndcr |= NDCR_NCSX;
++
++      if (2048 == flash_info->page_size)
++              ndcr |= NDCR_PAGE_SZ;
++      else if (512 != flash_info->page_size)
++              return -EINVAL;
++
++      if (16 == flash_info->flash_width)
++              ndcr |= NDCR_DWIDTH_M;
++      else if (8 != flash_info->flash_width)
++              return -EINVAL;
++
++      if (16 == flash_info->dfc_width)
++              ndcr |= NDCR_DWIDTH_C;
++      else if (8 != flash_info->dfc_width)
++              return -EINVAL;
++
++      dfc_write(context, DFC_NDCR, ndcr);
++
++      dfc_set_dma(context);
++      dfc_set_ecc(context);
++      dfc_set_spare(context);
++
++      return 0;
++}
++
++/*
++ * This macro will be used in following NAND operation functions.
++ * It is used to clear command buffer to ensure cmd buffer is empty
++ * in case of operation is timeout
++ */
++#define ClearCMDBuf()         do {                                    \
++                              dfc_stop(context);              \
++                              udelay(NAND_OTHER_TIMEOUT);     \
++                      } while (0)
++
++/******************************************************************************
++  dfc_reset_flash
++
++  Description:
++      It reset the flash. The function can be called at any time when the
++      device is in Busy state during random read/program/erase mode and
++      reset operation will abort all these operations. After reset operation
++      the device is ready to wait for next command
++  Input Parameters:
++      context
++        Pointer to DFC context structure
++  Output Parameters:
++      None
++  Returns:
++      0
++        execution succeeds
++      -ETIME
++        if timeout
++*******************************************************************************/
++int dfc_reset_flash(struct dfc_context *context)
++{
++      struct dfc_flash_info *flash_info = context->flash_info;
++      uint32_t event, event_out;
++      unsigned long timeo;
++      int status;
++
++      /* Send command */
++      dfc_send_cmd(context, (uint16_t)flash_info->reset, 0xFFFFFFFF, 0);
++
++      event = (context->dfc_mode->chip_select)? \
++                      NDSR_CS1_CMDD : NDSR_CS0_CMDD;
++
++      /* Wait for CMDDM(command done successfully) */
++      status = dfc_wait_event(context, event, &event_out,
++              NAND_OTHER_TIMEOUT, 0);
++
++      if (status) {
++              ClearCMDBuf();
++              return status;
++      }
++
++
++      /* Wait until flash device is stable or timeout (10ms) */
++      timeo = jiffies + HZ;
++      do {
++              if (monahans_df_dev_ready(context->mtd))
++                      break;
++      } while (time_before(jiffies, timeo));
++
++      return 0;
++}
++
++int dfc_readid(struct dfc_context *context, uint32_t *id)
++{
++      struct dfc_flash_info *flash_info = context->flash_info;
++      uint32_t event_out;
++      int status;
++      char tmp[DFC_DATA_SIZE_ID];
++
++      /* Send command */
++      status = dfc_send_cmd(context, (uint16_t)flash_info->read_id,
++                      0xFFFFFFFF, 0);
++      if (status) {
++              ClearCMDBuf();
++              return status;
++      }
++
++      /* Wait for CMDDM(command done successfully) */
++      status = dfc_wait_event(context, NDSR_RDDREQ, &event_out,
++              NAND_OTHER_TIMEOUT, 0);
++      if (status) {
++              ClearCMDBuf();
++              return status;
++      }
++      dfc_read_fifo_partial(context, (unsigned char *)tmp,
++                      context->flash_info->read_id_bytes, DFC_DATA_SIZE_ID);
++
++      *id = tmp[0] | (tmp[1] << 8);
++      return 0;
++}
++
++#define ERR_NONE              0x0
++#define ERR_DMABUSERR         (-0x01)
++#define ERR_SENDCMD           (-0x02)
++#define ERR_DBERR             (-0x03)
++#define ERR_BBERR             (-0x04)
++#define ERR_BUSY              (-0x05)
++
++#define STATE_CMD_SEND                0x1
++#define STATE_CMD_HANDLE      0x2
++#define STATE_DMA_TRANSFER    0x3
++#define STATE_DMA_DONE                0x4
++#define STATE_READY           0x5
++#define STATE_SUSPENDED               0x6
++#define       STATE_DATA_TRANSFER     0x7
++
++#define NAND_RELOC_MAX                127
++#define NAND_RELOC_HEADER     0x524e
++#define MAX_CHIP              1
++#define NAND_CMD_DMA_LEN      12
++
++#define MAX_TIM_SIZE  0x1000
++#define MAX_BBT_SLOTS 24
++
++struct reloc_item {
++      unsigned short from;
++      unsigned short to;
++};
++
++struct reloc_table {
++      unsigned short header;
++      unsigned short total;
++      struct reloc_item reloc[NAND_RELOC_MAX];
++};
++
++struct monahans_dfc_info {
++      unsigned int            state;
++      struct dfc_context      *context;
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      dma_addr_t              data_buf_addr;
++      char                    *data_buf;
++      int                     data_dma;
++      struct pxa_dma_desc     *data_desc;
++      dma_addr_t              data_desc_addr;
++      dma_addr_t              cmd_buf_addr;
++      char                    *cmd_buf;
++      int                     cmd_dma;
++      struct pxa_dma_desc     *cmd_desc;
++      dma_addr_t              cmd_desc_addr;
++      u64                     dma_mask;
++#else
++      char                    *data_buf;
++#endif
++      u32                     current_slot;
++      struct reloc_table      table;
++      unsigned int            table_init;
++      /* relate to the command */
++      unsigned int            cmd;
++      unsigned int            addr;
++      unsigned int            column;
++      int                     retcode;
++      unsigned int            buf_count;
++      struct completion       cmd_complete;
++};
++
++static struct dfc_mode dfc_mode =
++{
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      1,      /* enable DMA */
++#else
++      0,
++#endif
++      1,      /* enable ECC */
++      1,      /* enable SPARE */
++      0,      /* CS0 */
++};
++
++
++struct dfc_context dfc_context =
++{
++      0,      /* Initialized at function monahans_df_init() */
++      &dfc_mode,
++      0,      /* data dma channel */
++      0,      /* cmd dma channel */
++      NULL,   /* &zylonite_flashinfo */
++};
++
++
++/*
++ * MTD structure for Zylonite board
++ */
++static struct mtd_info *monahans_mtd = NULL;
++
++/*
++ * BootRom and XDB will use last 127 block, and they will keep all the status
++ * of the bootloader and image, so skip the first 2M size and last 2M size
++ */
++static struct mtd_partition partition_info[] = {
++      {
++              name:           "Bootloader",
++//#ifdef      CONFIG_CPU_MONAHANS_LV
++              size:           0x00060000,
++//#else
++//            size:           0x00040000,
++//#endif
++              offset:         0,
++              mask_flags:     MTD_WRITEABLE  /* force read-only */
++      },{
++              name:           "Kernel",
++              size:           0x00200000,
++//#ifdef      CONFIG_CPU_MONAHANS_LV
++              offset:         0x00060000,
++//#else
++//            offset:         0x00040000,
++//#endif
++              mask_flags:     MTD_WRITEABLE  /* force read-only */
++      },{
++              name:           "Filesystem",
++              size:           0x05000000,
++//#ifdef      CONFIG_CPU_MONAHANS_LV
++              offset:         0x00260000,
++//#else
++//            offset:         0x00240000,
++//#endif
++      }, {
++              name:           "MassStorage",
++              size:           0x0, /* It will be set at probe function */
++              offset:         MTDPART_OFS_APPEND /* Append after fs section */
++      }, {
++              name:           "BBT",
++              size:           0x0, /* It will be set at probe function */
++              offset:         MTDPART_OFS_APPEND,/* Append after fs section */
++              mask_flags:     MTD_WRITEABLE  /* force read-only */
++      }
++};
++
++#define               PART_NUM        ARRAY_SIZE(partition_info)
++
++/* MHN_OBM_V2 is related to BBT in MOBM V2
++ * MHN_OBM_V3 is related to BBT in MOBM V3
++ */
++enum {
++      MHN_OBM_NULL = 0,
++      MHN_OBM_V1,
++      MHN_OBM_V2,
++      MHN_OBM_V3,
++      MHN_OBM_INVAL
++} MHN_OBM_TYPE;
++
++static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
++static uint8_t scan_main_bbt_pattern[] = { 'p', 'x', 'a', '1' };
++static uint8_t scan_mirror_bbt_pattern[] = { '0', 'a', 'x', 'p' };
++
++static struct nand_bbt_descr monahans_bbt_default = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .maxblocks = 2,
++      .len = 2,
++      .offs = 0,
++      .pattern = scan_ff_pattern,
++};
++
++static struct nand_bbt_descr monahans_bbt_main = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .veroffs = 6,
++      .maxblocks = 2,
++        .offs = 2,
++        .len = 4,
++        .pattern = scan_main_bbt_pattern,
++};
++
++static struct nand_bbt_descr monahans_bbt_mirror = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .veroffs = 6,
++      .maxblocks = 2,
++        .offs = 2,
++        .len = 4,
++        .pattern = scan_mirror_bbt_pattern,
++};
++
++#if 0
++static struct nand_bbt_descr monahans_bbt_main = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .veroffs = 2,
++      .maxblocks = 2,
++        .offs =               0x0,
++        .len =                        2,
++        .pattern =            scan_ff_pattern
++};
++static struct nand_bbt_descr monahans_bbt_mirror = {
++      .options = NAND_BBT_LASTBLOCK | NAND_BBT_CREATE | NAND_BBT_WRITE
++                      | NAND_BBT_2BIT | NAND_BBT_VERSION,
++      .veroffs = 2,
++      .maxblocks = 2,
++        .offs = 0x0,
++        .len = 2,
++        .pattern = scan_ff_pattern
++};
++#endif
++
++static struct nand_ecclayout monahans_lb_nand_oob = {
++      .eccbytes = 24,
++      .eccpos = {
++              40, 41, 42, 43, 44, 45, 46, 47,
++              48, 49, 50, 51, 52, 53, 54, 55,
++              56, 57, 58, 59, 60, 61, 62, 63},
++      .oobfree = { {2, 38} }
++};
++
++/*
++ * Monahans OOB size is only 8 bytes, and the rest 8 bytes is controlled by
++ * hardware for ECC. We construct virutal ECC buffer. Acutally, ECC is 6 bytes
++ * and the remain 2 bytes are reserved.
++ */
++static struct nand_ecclayout monahans_sb_nand_oob = {
++      .eccbytes = 6,
++      .eccpos = {8, 9, 10, 11, 12, 13 },
++      .oobfree = { {2, 6} }
++};
++
++
++static inline int is_buf_blank(u8 * buf, int size)
++{
++      int i = 0;
++      while(i < size) {
++              if (*((unsigned long *)(buf + i)) != 0xFFFFFFFF)
++                      return 0;
++              i += 4;
++      }
++      if (i > size) {
++              i -= 4;
++              while( i < size) {
++                      if(*(buf + i) != 0xFF)
++                              return 0;
++                      i++;
++              }
++      }
++      return 1;
++}
++
++static void print_buf(char *buf, int num)
++{
++      int i = 0;
++
++      while (i < num) {
++              printk(KERN_ERR "0x%08x: %02x %02x %02x %02x %02x %02x %02x"
++              " %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
++              (unsigned int) (i),  buf[i], buf[i+1], buf[i+2],
++              buf[i+3], buf[i+4], buf[i+5], buf[i+6], buf[i+7],
++              buf[i+8], buf[i+9], buf[i+10],buf[i+11], buf[i+12],
++              buf[i+13], buf[i+14], buf[i+15]);
++              i += 16;
++      }
++}
++
++static int inline enable_dfc_dma(struct dfc_context *context, int enable)
++{
++      int ret = dfc_mode.enable_dma;
++      unsigned long ndcr;
++
++      if (!enable) {
++              ndcr = dfc_read(context, DFC_NDCR);
++              ndcr &= ~NDCR_DMA_EN;
++              dfc_write(context, DFC_NDCR, ndcr);
++              dfc_mode.enable_dma = 0;
++      } else {
++              ndcr = dfc_read(context, DFC_NDCR);
++              ndcr |= NDCR_DMA_EN;
++              dfc_write(context, DFC_NDCR, ndcr);
++              dfc_mode.enable_dma = 1;
++      }
++      return ret;
++}
++
++
++static void inline dump_info(struct monahans_dfc_info *info)
++{
++      if (!info)
++              return;
++
++      printk(KERN_ERR "cmd:0x%x; addr:0x%x; retcode:%d; state:%d \n",
++              info->cmd, info->addr, info->retcode, info->state);
++}
++
++static void inline  enable_hw_ecc(struct dfc_context* context, int enable)
++{
++      unsigned long ndcr;
++
++      if (!enable) {
++              ndcr = dfc_read(context, DFC_NDCR);
++              ndcr &= ~NDCR_ECC_EN;
++              dfc_write(context, DFC_NDCR, ndcr);
++              dfc_mode.enable_ecc = 0;
++      }
++      else {
++              ndcr = dfc_read(context, DFC_NDCR);
++              ndcr |= NDCR_ECC_EN;
++              dfc_write(context, DFC_NDCR, ndcr);
++              dfc_mode.enable_ecc = 1;
++      }
++}
++
++/*
++ * Now, we are not sure that the NDSR_RDY mean the flash is ready.
++ * Need more test.
++ */
++static int monahans_df_dev_ready(struct mtd_info *mtd)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++
++      struct dfc_context* context = info->context;
++
++      return ((dfc_read(context, DFC_NDSR) & NDSR_RDY));
++}
++
++/* each read, we can only read 4bytes from NDDB, we must buffer it */
++static u_char monahans_df_read_byte(struct mtd_info *mtd)
++{
++      char retval = 0xFF;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++
++      if (info->column < info->buf_count) {
++              /* Has just send a new command? */
++              retval = info->data_buf[info->column++];
++      }
++      return retval;
++}
++
++static void monahans_df_write_byte(struct mtd_info *mtd, u8 byte)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++      info->data_buf[info->column++] = byte;
++}
++
++static u16 monahans_df_read_word(struct mtd_info *mtd)
++{
++      u16 retval = 0xFFFF;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++
++      if (!(info->column & 0x01) && info->column < info->buf_count) {
++              retval = *((u16 *)(info->data_buf+info->column));
++              info->column += 2;
++      }
++      return retval;
++}
++
++static void monahans_df_write_word(struct mtd_info *mtd, u16 word)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++
++      if (!(info->column & 0x01) && info->column < info->buf_count) {
++              *((u16 *)(info->data_buf+info->column)) = word;
++              info->column += 2;
++      }
++}
++
++static void monahans_df_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++      int real_len = min((unsigned int)len, info->buf_count - info->column);
++
++      memcpy(buf, info->data_buf + info->column, real_len);
++      info->column += real_len;
++}
++
++static void monahans_df_write_buf(struct mtd_info *mtd,
++              const u_char *buf, int len)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                              (((struct nand_chip *)(mtd->priv))->priv);
++      int real_len = min((unsigned int)len, info->buf_count - info->column);
++
++      memcpy(info->data_buf + info->column, buf, real_len);
++      info->column += real_len;
++}
++
++static int monahans_df_verify_buf(struct mtd_info *mtd,
++              const u_char *buf, int len)
++{
++      return 0;
++}
++
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++static void monahans_dfc_cmd_dma_irq(int channel, void *data,
++              struct pt_regs *regs)
++{
++      unsigned int dcsr;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)data;
++      struct dfc_context* context = info->context;
++      struct dfc_mode* dfc_mode = context->dfc_mode;
++      unsigned int intm;
++
++      dcsr = DCSR(channel);
++      DCSR(channel) = dcsr;
++
++      intm = (dfc_mode->chip_select) ? \
++              (NDSR_CS1_BBD | NDSR_CS1_CMDD) : (NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++      D1(printk("cmd dma interrupt, channel:%d, DCSR:0x%08x\n", \
++                      channel, dcsr));
++
++      if (dcsr & DCSR_BUSERR) {
++              info->retcode = ERR_DMABUSERR;
++              complete(&info->cmd_complete);
++      } else {
++              if ((info->cmd == NAND_CMD_READ0) ||
++                              (info->cmd == NAND_CMD_READOOB)|| \
++                              (info->cmd == NAND_CMD_READID) || \
++                              (info->cmd == NAND_CMD_STATUS)) {
++                      dfc_enable_int(context, NDSR_RDDREQ | NDSR_DBERR);
++              } else if (info->cmd == NAND_CMD_PAGEPROG)
++                      dfc_enable_int(context, NDSR_WRDREQ);
++              else if (info->cmd == NAND_CMD_ERASE1)
++                      dfc_enable_int(context, intm);
++      }
++
++      return;
++}
++
++
++static void monahans_dfc_data_dma_irq(int channel, void *data,
++              struct pt_regs *regs)
++{
++      unsigned int dcsr, intm;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)data;
++      struct dfc_context* context = info->context;
++      struct dfc_mode* dfc_mode = context->dfc_mode;
++
++      dcsr = DCSR(channel);
++      DCSR(channel) = dcsr;
++
++      intm = (dfc_mode->chip_select) ? \
++              (NDSR_CS1_BBD | NDSR_CS1_CMDD) : (NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++      D1(printk("data dma interrupt, channel:%d, DCSR:0x%08x\n",
++                      channel, dcsr));
++      if (dcsr & DCSR_BUSERR) {
++              info->retcode = ERR_DMABUSERR;
++              complete(&info->cmd_complete);
++      }
++
++      if (info->cmd == NAND_CMD_PAGEPROG) {
++              /* DMA interrupt may be interrupted by other IRQs*/
++              info->state = STATE_DMA_DONE;
++              dfc_enable_int(context, intm);
++      } else {
++              info->state = STATE_READY;
++              complete(&info->cmd_complete);
++      }
++
++}
++#endif
++
++static irqreturn_t monahans_dfc_irq(int irq, void *devid)
++{
++      unsigned int status, event, intm, cmd;
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)devid;
++      struct dfc_context* context = info->context;
++      struct dfc_mode* dfc_mode = context->dfc_mode;
++
++      intm =  (dfc_mode->chip_select) ? \
++              (NDSR_CS1_BBD | NDSR_CS1_CMDD) : (NDSR_CS0_BBD | NDSR_CS0_CMDD);
++      event = (dfc_mode->chip_select) ? \
++              (NDSR_CS1_BBD | NDSR_CS1_CMDD) : (NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++      status = dfc_read(context, DFC_NDSR);
++      D1(printk("DFC irq, NDSR:0x%x\n", status));
++      if (status & (NDSR_RDDREQ | NDSR_DBERR)) {
++              if (status & NDSR_DBERR) {
++                      info->retcode = ERR_DBERR;
++              }
++
++              dfc_disable_int(context, NDSR_RDDREQ | NDSR_DBERR);
++              dfc_clear_int(context, NDSR_RDDREQ | NDSR_DBERR);
++              if (info->cmd == NAND_CMD_READID)
++                      cmd = context->flash_info->read_id;
++              else if (info->cmd == NAND_CMD_STATUS)
++                      cmd = context->flash_info->read_status;
++              else if (info->cmd == NAND_CMD_READ0 ||
++                              info->cmd == NAND_CMD_READOOB)
++                      cmd = context->flash_info->read1;
++              else {
++                      printk(KERN_ERR "No according command:0x%x happens\n",
++                                      info->cmd);
++                      goto out;
++              }
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++              info->state = STATE_DMA_TRANSFER;
++              dfc_start_data_dma(context,
++                              (struct pxa_dma_desc*)info->data_desc_addr);
++#else
++              info->state = STATE_DATA_TRANSFER;
++              complete(&info->cmd_complete);
++#endif
++      } else if (status & NDSR_WRDREQ) {
++              dfc_disable_int(context, NDSR_WRDREQ);
++              dfc_clear_int(context, NDSR_WRDREQ);
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++              info->state = STATE_DMA_TRANSFER;
++              dfc_start_data_dma(context,
++                              (struct pxa_dma_desc*)info->data_desc_addr);
++#else
++              info->state = STATE_DATA_TRANSFER;
++              complete(&info->cmd_complete);
++#endif
++      } else if (status & event) {
++              if (status & NDSR_CS0_BBD) {
++                      info->retcode = ERR_BBERR;
++              }
++
++              dfc_disable_int(context, intm);
++              dfc_clear_int(context, event);
++              info->state = STATE_READY;
++              complete(&info->cmd_complete);
++      }
++out:
++      return IRQ_HANDLED;
++}
++
++static int dfc_send_command(struct mtd_info *mtd, unsigned int cmd,
++                              unsigned int addr, unsigned int num_pages,
++                              unsigned int event)
++{
++
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++      struct dfc_context* context = info->context;
++      int status;
++      int ret;
++
++      D1(printk("ready send command, cmd:0x%x, at address:0x%x,"
++              " num_pages:%d, wait event:0x%x\n", cmd, addr, num_pages, event));
++
++      info->state = STATE_CMD_SEND;
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      status = dfc_setup_cmd_dma(context, cmd, addr, num_pages,
++                      (uint32_t *)info->cmd_buf, info->cmd_buf_addr,
++                      DDADR_STOP, DCMD_ENDIRQEN, info->cmd_desc);
++#else
++      status = dfc_send_cmd(context, cmd, addr, num_pages);
++#endif
++      if (status) {
++              info->retcode = ERR_SENDCMD;
++              dfc_stop(context);
++              udelay(20);
++              printk(KERN_ERR "fail send command\n");
++              return info->retcode;
++      }
++      info->state = STATE_CMD_HANDLE;
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      dfc_setup_data_dma(context, cmd, info->data_buf_addr,
++                      DDADR_STOP, DCMD_ENDIRQEN, info->data_desc);
++      dfc_start_cmd_dma(context, (struct pxa_dma_desc*)info->cmd_desc_addr);
++#endif
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++      dfc_enable_int(context, event);
++#endif
++      ret = wait_for_completion_timeout(&info->cmd_complete, 2*HZ);
++      if (!ret){
++              printk(KERN_ERR "Command time out\n");
++              dump_info(info);
++      }
++      D1(printk("command return, cmd:0x%x, retcode:%d\n",
++                      info->cmd, info->retcode));
++      return 0;
++}
++
++static void monahans_df_command(struct mtd_info *mtd, unsigned command,
++              int column, int page_addr )
++{
++      struct nand_chip *this = (struct nand_chip *)(mtd->priv);
++      struct monahans_dfc_info *info =
++                      (struct monahans_dfc_info *)(this->priv);
++      struct dfc_context *context = info->context;
++      struct dfc_flash_info * flash_info = context->flash_info;
++      int ret, pages_shift;
++      int status;
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++      int datasize;
++              int paddingsize;
++#endif
++      unsigned int to;
++
++      D1(printk("command:0x%x at address:0x%x, column:0x%x\n",
++                      command, page_addr, column));
++
++      if (info->state != STATE_READY) {
++              printk(KERN_ERR "CHIP is not ready.\n");
++              dump_info(info);
++              info->retcode = ERR_BUSY;
++              return;
++      }
++      info->retcode = ERR_NONE;
++      pages_shift = this->phys_erase_shift - this->page_shift;
++      if (info->table_init) {
++              to = search_rel_block((page_addr >> pages_shift), mtd);
++      if (to) {
++                      page_addr = (to << pages_shift) | (page_addr
++                                      & ((1 << pages_shift) - 1));
++              }
++      }
++
++      switch ( command ) {
++      case NAND_CMD_READOOB:
++              /*
++               * DFC has mark the last 8 bytes OOB data if HARDEARE_ECC is
++               * enabled. We must first disable the HARDWARE_ECC for getting
++               * all the 16 bytes OOB
++               */
++              enable_hw_ecc(context, 0);
++              info->buf_count = mtd->writesize + mtd->oobsize;
++              info->column = mtd->writesize + column;
++              info->cmd = command;
++              info->addr = page_addr << this->page_shift;
++              ret = dfc_send_command(mtd, flash_info->read1, info->addr,
++                              1, NDSR_RDDREQ | NDSR_DBERR);
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              dfc_get_pattern(info->context, flash_info->read1, &datasize,
++                              &paddingsize);
++              dfc_read_fifo_partial(info->context, info->data_buf,
++                              min(info->buf_count, datasize), datasize);
++              info->state = STATE_READY;
++#endif
++              /* We only are OOB, so if the data has error, does not matter */
++              if (info->retcode == ERR_DBERR)
++                      info->retcode = ERR_NONE;
++              enable_hw_ecc(context, 1);
++              break;
++
++      case NAND_CMD_READ0:
++              enable_hw_ecc(context, 1);
++              info->column = column;
++              info->cmd = command;
++              info->buf_count = mtd->writesize + mtd->oobsize;
++              memset(info->data_buf, 0xFF, info->buf_count);
++              info->addr = page_addr << this->page_shift;
++
++              ret = dfc_send_command(mtd, flash_info->read1, info->addr,
++                              1, NDSR_RDDREQ | NDSR_DBERR);
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              dfc_get_pattern(info->context, flash_info->read1, &datasize,
++                              &paddingsize);
++              dfc_read_fifo_partial(info->context, info->data_buf,
++                              min(info->buf_count, datasize), datasize);
++              info->state = STATE_READY;
++#endif
++              /* When the data buf is blank, the DFC will report DB error */
++              if (info->retcode == ERR_DBERR && is_buf_blank(info->data_buf,
++                              mtd->writesize))
++                      info->retcode = ERR_NONE;
++
++              if (info->retcode == ERR_DBERR) {
++                      printk(KERN_ERR "DB error at address 0x%x\n",
++                              info->addr);
++                      print_buf(info->data_buf, info->buf_count);
++              }
++              break;
++      case NAND_CMD_SEQIN:
++              /* Write only OOB? */
++
++              info->cmd = command;
++              if (column >= mtd->writesize) {
++                      info->buf_count = mtd->writesize + mtd->oobsize;
++                      enable_hw_ecc(context, 0);
++              } else {
++                      info->buf_count = mtd->writesize + mtd->oobsize;
++                      enable_hw_ecc(context, 1);
++              }
++              memset(info->data_buf, 0xFF, mtd->writesize + mtd->oobsize);
++              info->column = column;
++              info->addr = page_addr << this->page_shift;
++              break;
++      case NAND_CMD_PAGEPROG:
++              /* prevois command is NAND_CMD_SEIN ?*/
++              if (info->cmd != NAND_CMD_SEQIN) {
++                      info->cmd = command;
++                      info->retcode = ERR_SENDCMD;
++                      printk(KERN_ERR "Monahans NAND device: "
++                              "No NAND_CMD_SEQIN executed before.\n");
++                      enable_hw_ecc(context, 1);
++                      break;
++              }
++              info->cmd = command;
++              ret = dfc_send_command(mtd, flash_info->program, info->addr,
++                              1, NDSR_WRDREQ);
++
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              if (ret != 0)
++                      break;
++
++              dfc_get_pattern(info->context, flash_info->program, &datasize,
++                              &paddingsize);
++              dfc_write_fifo_partial(info->context, info->data_buf, datasize,
++                              datasize);
++
++              if (info->context->dfc_mode->chip_select)
++                      dfc_enable_int(info->context,
++                              NDSR_CS1_BBD | NDSR_CS1_CMDD);
++              else
++                      dfc_enable_int(info->context,
++                              NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++              ret = wait_for_completion_timeout(&info->cmd_complete, 2*HZ);
++              if (!ret){
++                      printk(KERN_ERR "Programm Command time out\n");
++                      dump_info(info);
++              }
++
++              if (info->retcode == ERR_BBERR) {
++                      mtd->block_markbad(mtd, info->addr);
++              }
++#endif
++              break;
++      case NAND_CMD_ERASE1:
++              info->cmd = command;
++              info->addr = (page_addr >> pages_shift) << this->phys_erase_shift;
++
++              if (info->context->dfc_mode->chip_select)
++                      ret = dfc_send_command(mtd, flash_info->erase,
++                              info->addr, 0, NDSR_CS1_BBD | NDSR_CS1_CMDD);
++              else
++                      ret = dfc_send_command(mtd, flash_info->erase,
++                              info->addr, 0, NDSR_CS0_BBD | NDSR_CS0_CMDD);
++
++              if (info->retcode == ERR_BBERR) {
++                      mtd->block_markbad(mtd, info->addr);
++              }
++              break;
++      case NAND_CMD_ERASE2:
++              break;
++      case NAND_CMD_READID:
++              info->cmd = command;
++              info->buf_count = flash_info->read_id_bytes;
++              info->column = 0;
++              info->addr = 0xFFFFFFFF;
++              ret = dfc_send_command(mtd, flash_info->read_id, info->addr,
++                              0, NDSR_RDDREQ);
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              dfc_get_pattern(info->context, flash_info->read_id, &datasize,
++                              &paddingsize);
++              dfc_read_fifo_partial(info->context, info->data_buf,
++                              info->buf_count, datasize);
++              info->state = STATE_READY;
++#endif
++              D1(printk("ReadID, [1]:0x%x, [2]:0x%x\n",
++                      info->data_buf[0], info->data_buf[1]));
++              break;
++      case NAND_CMD_STATUS:
++              info->cmd = command;
++              info->buf_count = 1;
++              info->column = 0;
++              info->addr = 0xFFFFFFFF;
++              ret = dfc_send_command(mtd, flash_info->read_status,
++                      info->addr, 0, NDSR_RDDREQ);
++#ifndef CONFIG_MTD_NAND_MONAHANS_DMA
++              dfc_get_pattern(info->context, flash_info->read_status,
++                      &datasize, &paddingsize);
++              dfc_read_fifo_partial(info->context, info->data_buf,
++                      info->buf_count, datasize);
++              info->state = STATE_READY;
++#endif
++              break;
++
++      case NAND_CMD_RESET:
++              status = dfc_reset_flash(&dfc_context);
++              if (status) {
++                      printk(KERN_WARNING "Monahans NAND device:"
++                              "NAND_CMD_RESET error\n");
++              }
++              break;
++      default:
++              printk(KERN_WARNING "Monahans NAND device:"
++                      "Non-support the command.\n");
++              break;
++      }
++
++      if (info->retcode != ERR_NONE)
++              dfc_stop(info->context);
++}
++
++static void monahans_df_select_chip(struct mtd_info *mtd, int chip)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++
++      if (chip <= MAX_CHIP)
++              info->context->dfc_mode->chip_select = chip;
++      else
++              printk(KERN_ERR "Monahans NAND device:"
++                      "not select the NAND chips!\n");
++}
++
++static int monahans_df_waitfunc(struct mtd_info *mtd,
++              struct nand_chip *this)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++
++      /* monahans_df_send_command has waited for command complete */
++      if (this->state == FL_WRITING || this->state == FL_ERASING) {
++              if (info->retcode == ERR_NONE)
++                      return 0;
++              else {
++                      /*
++                       * any error make it return 0x01 which will tell
++                       * the caller the erase and write fail
++                       */
++                      return 0x01;
++              }
++      }
++
++      return 0;
++}
++
++static int monahans_df_calculate_ecc(struct mtd_info *mtd,
++              const u_char *dat, u_char *ecc_code)
++{
++      return 0;
++}
++
++static int monahans_df_correct_data(struct mtd_info *mtd,
++              u_char *dat, u_char *read_ecc, u_char *calc_ecc)
++{
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++
++      /*
++       * Any error include ERR_SEND_CMD, ERR_DBERR, ERR_BUSERR, we
++       * consider it as a ecc error which will tell the caller the
++       * read fail We have distinguish all the errors, but the
++       * nand_read_ecc only check this function return value
++       */
++      if (info->retcode != ERR_NONE)
++              return -1;
++
++      return 0;
++}
++
++static void monahans_df_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++      return;
++}
++
++/*
++ * The relocation table management is different between MOBM V2 and V3.
++ *
++ * MOBM V2 is applied on chips taped out before MhnLV A0.
++ * MOBM V3 is applied on chips taped out after MhnLV A0. It's also applied
++ * on MhnLV A0.
++ */
++static int calc_obm_ver(void)
++{
++      unsigned int    cpuid;
++      /* read CPU ID */
++      __asm__ (
++              "mrc p15, 0, %0, c0, c0, 0\n"
++              : "=r" (cpuid)
++      );
++      /* It's not xscale chip. */
++      if ((cpuid & 0xFFFF0000) != 0x69050000)
++              return MHN_OBM_INVAL;
++      /* It's MhnP Ax */
++      if ((cpuid & 0x0000FFF0) == 0x00006420)
++              return MHN_OBM_V2;
++      /* It's MhnP Bx */
++      if ((cpuid & 0x0000FFF0) == 0x00006820) {
++              if ((cpuid & 0x0F) <= 5)
++                      return MHN_OBM_V2;
++              else
++                      return MHN_OBM_V3;
++      }
++      /* It's MhnL Ax */
++      if ((cpuid & 0x0000FFF0) == 0x00006880) {
++              if ((cpuid & 0x0F) == 0)
++                      return MHN_OBM_V2;
++              else
++                      return MHN_OBM_V3;
++      }
++      /* It's MhnLV Ax */
++      if ((cpuid & 0x0000FFF0) == 0x00006890)
++              return MHN_OBM_V3;
++      return MHN_OBM_INVAL;
++}
++
++
++/*
++ * MOBM maintains a relocation table. It's used to replace bad blocks.
++ * If block A is bad, it will use block B instead.
++ * There're 127 relocated blocks. All of them reside in the bottom of NAND
++ * flash. So they're reserved and can't be calculated in mtd size and chip
++ * size.
++ */
++static int read_reloc_table(struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      struct dfc_context *context = NULL;
++      struct reloc_table *table = NULL;
++      int page, maxslot;
++      int obm, valid;
++
++      obm = calc_obm_ver();
++      this = (struct nand_chip *)(mtd->priv);
++      info = (struct monahans_dfc_info *)(this->priv);
++      context = info->context;
++
++      mtd->size -= (NAND_RELOC_MAX * mtd->erasesize);
++      this->chipsize -= (NAND_RELOC_MAX << this->phys_erase_shift);
++      page = (1 << (this->phys_erase_shift - this->page_shift)) - 1;
++
++      this->select_chip(mtd, 0);
++      valid = 0;
++      if (obm == MHN_OBM_V2) {
++              /* On MOBM V2, the relocation table resides in the last page
++               * of the first block.
++               */
++              memset(info->data_buf, 0, BUFLEN);
++              monahans_df_command(mtd, NAND_CMD_READ0, 0, page);
++      memcpy(((unsigned char *)&(info->table)), info->data_buf,
++                      sizeof(struct reloc_table));
++              if (info->table.header == NAND_RELOC_HEADER)
++                      valid = 1;
++      } else if (obm == MHN_OBM_V3) {
++              /* On MOBM V3, there're several relocation tables in the first
++               * block.
++               * When new bad blocks are found, a new relocation table will
++               * be generated and written back to the first block. But the
++               * original relocation table won't be erased. Even if the new
++               * relocation table is written wrong, system can still find an
++               * old one.
++               * One page contains one slot.
++               */
++              maxslot = 1 << (this->phys_erase_shift - this->page_shift);
++              page = maxslot - MAX_BBT_SLOTS;
++              for (; page < maxslot; page++) {
++                      monahans_df_command(mtd, NAND_CMD_READ0, 0, page);
++                      table = (struct reloc_table *)info->data_buf;
++                      if (info->retcode == ERR_NONE) {
++                              if (table->header != NAND_RELOC_HEADER) {
++                                      continue;
++      } else {
++                                      memcpy(((unsigned char *)&(info->table)),
++                                              table, sizeof(struct reloc_table));
++                                      valid = 1;
++                                      break;
++                              }
++                      }
++      }
++
++      } else {
++              printk(KERN_ERR "The version of MOBM isn't supported\n");
++      }
++      if (valid) {
++              memcpy(((unsigned char *)&(info->table)), info->data_buf,
++                      sizeof(struct reloc_table));
++              printk(KERN_DEBUG "relocation table at page:%d\n", page);
++              PRINT_BUF((unsigned char *)&(info->table),
++                      sizeof(struct reloc_table));
++      info->table_init = 1;
++      } else {
++              /* There should be a valid relocation table slot at least. */
++              printk(KERN_ERR "NO VALID relocation table can be \
++                              recognized\n");
++              printk(KERN_ERR "CAUTION: It may cause unpredicated error\n");
++              printk(KERN_ERR "Please re-initialize the NAND flash.\n");
++              memset((unsigned char *)&(info->table), 0,
++                              sizeof(struct reloc_table));
++              info->table_init = 0;
++              return -EINVAL;
++      }
++      return 0;
++}
++
++/* add the relocation entry into the relocation table
++ * It's valid on MOBM V3.
++ * If the relocated block is bad, an new entry will be added into the
++ * bottom of the relocation table.
++ */
++static int update_rel_table(struct mtd_info *mtd, int block)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      struct reloc_table *table = NULL;
++      int obm, reloc_block;
++
++      this = (struct nand_chip *)(mtd->priv);
++      info = (struct monahans_dfc_info *)(this->priv);
++      obm = calc_obm_ver();
++      if (obm == MHN_OBM_V3) {
++              table = &info->table;
++              if (info->table_init == 0) {
++                      printk(KERN_ERR "Error: the initial relocation \
++                                      table can't be read\n");
++                      memset(table, 0, sizeof(struct reloc_table));
++                      table->header = NAND_RELOC_HEADER;
++                      info->table_init = 1;
++              }
++              if (table->total == 0) {
++                      /* Point to the first relocated block.
++                       * It resides in the last block of flash.
++                       * the relocation entry has calculated in
++                       * chipsize
++                       */
++                      reloc_block = (this->chipsize
++                                      >> this->phys_erase_shift)
++                                      + NAND_RELOC_MAX - 1;
++              } else if (table->total < NAND_RELOC_MAX) {
++                      reloc_block = table->reloc[table->total - 1].to - 1;
++              } else {
++                      printk(KERN_ERR "Relocation table exceed max number, \
++                              cannot mark block 0x%x as bad block\n", block);
++                      return -ENOSPC;
++              }
++              /* Make sure that reloc_block is pointing to a valid block */
++              for (; ; reloc_block--) {
++                      /* The relocate table is full */
++                      if (reloc_block < (this->chipsize
++                                      >> this->phys_erase_shift))
++                              return -ENOSPC;
++                      this->cmdfunc(mtd, NAND_CMD_ERASE1, 0, reloc_block
++                                      << (this->phys_erase_shift
++                                      - this->page_shift));
++                      if (info->retcode == ERR_NONE)
++                              break;
++              }
++              /* Create the relocated block information in the table */
++              table->reloc[table->total].from = block;
++              table->reloc[table->total].to = reloc_block;
++              table->total++;
++      }
++      return 0;
++}
++
++/* Write the relocation table back to device, if there's room. */
++static int sync_rel_table(struct mtd_info *mtd, int *idx)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      int obm, start_page, len;
++
++      if (*idx >= MAX_BBT_SLOTS) {
++              printk(KERN_ERR "Can't write relocation table to device \
++                              any more.\n");
++              return -1;
++      }
++      if (*idx < 0) {
++              printk(KERN_ERR "Wrong Slot is specified.\n");
++              return -1;
++      }
++      this = (struct nand_chip *)(mtd->priv);
++      info = (struct monahans_dfc_info *)(this->priv);
++      len = 4;
++      len += info->table.total << 2;
++      obm = calc_obm_ver();
++      if (obm == MHN_OBM_V3) {
++              /* write to device */
++              start_page = 1 << (this->phys_erase_shift - this->page_shift);
++              start_page = start_page - 1 - *idx;
++              memset(&(info->data_buf), 0xFF, BUFLEN);
++              memcpy(&(info->data_buf), &(info->table), len);
++
++              printk(KERN_DEBUG "DUMP relocation table before write. \
++                              page:0x%x\n", start_page);
++              monahans_df_command(mtd, NAND_CMD_SEQIN, 0, start_page);
++              monahans_df_command(mtd, NAND_CMD_PAGEPROG, 0, start_page);
++              /* write to idx */
++              (*idx)++;
++              /* dump it */
++              memset(&(info->data_buf), 0, BUFLEN);
++              monahans_df_command(mtd, NAND_CMD_READOOB, 0, start_page);
++              PRINT_BUF(info->data_buf, len);
++      }
++      return 0;
++}
++
++
++/* Find the relocated block of the bad one.
++ * If it's a good block, return 0. Otherwise, return a relocated one.
++ * idx points to the next relocation entry
++ * If the relocated block is bad, an new entry will be added into the
++ * bottom of the relocation table.
++ */
++static unsigned short search_rel_block(int block, struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      struct reloc_table *table = NULL;
++      int i, max, reloc_block = 0;
++
++      this = (struct nand_chip *)(mtd->priv);
++      info = (struct monahans_dfc_info *)(this->priv);
++      table = &(info->table);
++      if ((block <= 0) || (block > this->chipsize)
++                      || (info->table_init == 0) || (table->total == 0))
++              return 0;
++      if (table->total > NAND_RELOC_MAX)
++              table->total = NAND_RELOC_MAX;
++      max = table->total;
++      for (i = 0; i < max; i++) {
++              if (block == table->reloc[i].from)
++                      reloc_block = table->reloc[i].to;
++      }
++      return reloc_block;
++}
++
++/*
++ * Check whether the block is a bad one.
++ * At first, it will search the relocation table.
++ * If necessary, it will search the BBT. Because relocation table can only
++ * maintain limited record. If there're more bad blocks, they can't be
++ * recorded in relocation table. They can only be recorded in BBT.
++ */
++static int monahans_df_block_bad(struct mtd_info *mtd, loff_t ofs, int getchip)
++{
++      struct nand_chip *this = NULL;
++      int page, block, reloc_block, chipnr, res = 0;
++      u16 bad;
++
++      /* At here, we only support one flash chip */
++      this = (struct nand_chip *)mtd->priv;
++      block = (int)(ofs >> this->phys_erase_shift);
++      /* search the block in the relocation table */
++      reloc_block = search_rel_block(block, mtd);
++      if (reloc_block) {
++              ofs = ((reloc_block << this->phys_erase_shift) |
++                      (ofs & ((1 << this->phys_erase_shift) - 1)));
++      }
++
++      /* search BBT
++       * Maybe the relocation table is full, but some bad blocks aren't
++       * recordered in it.
++       * The below code are copied from nand_block_bad().
++       */
++      if (getchip) {
++              page = (int)(ofs >> this->page_shift);
++              chipnr = (int)(ofs >> this->chip_shift);
++
++              /* Select the NAND chips */
++              this->select_chip(mtd, chipnr);
++      } else
++              page = (int)ofs;
++
++      if (this->options & NAND_BUSWIDTH_16) {
++              this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos & 0xFE,
++                              page & this->pagemask);
++              bad = cpu_to_le16(this->read_word(mtd));
++              if (this->badblockpos & 0x1)
++                      bad >>= 1;
++              if ((bad & 0xFF) != 0xFF)
++                      res = 1;
++      } else {
++              this->cmdfunc(mtd, NAND_CMD_READOOB, this->badblockpos,
++                              page & this->pagemask);
++              if (this->read_byte(mtd) != 0xFF)
++                      res = 1;
++      }
++
++      return res;
++}
++
++static int monahans_df_block_markbad(struct mtd_info *mtd, loff_t ofs)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      unsigned char buf[2] = {0, 0};
++      int block, reloc_block, page, ret;
++
++      this = (struct nand_chip *)mtd->priv;
++      info = (struct monahans_dfc_info *)(this->priv);
++      /* Get block number */
++      block = ((int)ofs) >> this->bbt_erase_shift;
++      ret = update_rel_table(mtd, block);
++      if (!ret) {
++              sync_rel_table(mtd, &(info->current_slot));
++              return 0;
++              } else {
++              reloc_block = search_rel_block(block, mtd);
++              if (reloc_block)
++                      block = reloc_block;
++              if (this->bbt)
++                      this->bbt[block >> 2] |= 0x01 << ((block & 0x03) << 1);
++      }
++
++      /* Do we have a flash based bad block table ? */
++      if (this->options & NAND_USE_FLASH_BBT)
++              return nand_update_bbt(mtd, ofs);
++
++      /* mark the bad block flag at the first two pages */
++      page = block << (this->phys_erase_shift - this->page_shift);
++      ofs = mtd->writesize + this->badblockpos;
++      this->cmdfunc(mtd, NAND_CMD_SEQIN, ofs, page);
++      this->write_buf(mtd, buf, 2);
++      this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++      page++;
++      this->cmdfunc(mtd, NAND_CMD_SEQIN, ofs, page);
++      this->write_buf(mtd, buf, 2);
++      this->cmdfunc(mtd, NAND_CMD_PAGEPROG, -1, -1);
++      return 0;
++}
++
++static int dump_bbt_flash(struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++      struct monahans_dfc_info *info = NULL;
++      int block, page, totlen;
++
++      this = (struct nand_chip *)mtd->priv;
++      info = (struct monahans_dfc_info *)this->priv;
++      block = (this->chipsize >> this->phys_erase_shift) - 1;
++      totlen = (this->chipsize >> this->phys_erase_shift) >> 2;
++      printk(KERN_ERR "totlen:0x%x\n", totlen);
++      this->select_chip(mtd, 0);
++      if (this->bbt_td) {
++              printk(KERN_ERR "BBT page:0x%x\n", this->bbt_td->pages[0]);
++              page = this->bbt_td->pages[0];
++              if (this->bbt_td->pages[0] <= 0) {
++                      page = block << (this->phys_erase_shift
++                              - this->page_shift);
++              }
++              while (totlen > 0) {
++                      printk(KERN_ERR "page:0x%x\n", page);
++                      monahans_df_command(mtd, NAND_CMD_READ0, 0, page);
++                      printk(KERN_ERR "read result:0x%x\n", info->retcode);
++                      PRINT_BUF(info->data_buf, BUFLEN);
++                      totlen -= (1 << this->page_shift);
++                      page++;
++              }
++      }
++      if (this->bbt_md) {
++              printk(KERN_ERR "BBT page:0x%x\n", this->bbt_md->pages[0]);
++              page = this->bbt_md->pages[0];
++              if (this->bbt_td->pages[0] <= 0) {
++                      page = block << (this->phys_erase_shift
++                              - this->page_shift);
++                      }
++              while (totlen > 0) {
++                      printk(KERN_ERR "page:0x%x\n", page);
++                      monahans_df_command(mtd, NAND_CMD_READ0, 0, page);
++                      printk(KERN_ERR "read result:0x%x\n", info->retcode);
++                      PRINT_BUF(info->data_buf, BUFLEN);
++                      totlen -= (1 << this->page_shift);
++                      page++;
++              }
++
++      }
++      return 0;
++}
++
++static int dump_bbt_mem(struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++
++      this = (struct nand_chip *)mtd->priv;
++      PRINT_BUF(this->bbt, 225);
++      return 0;
++}
++
++static int monahans_df_scan_bbt(struct mtd_info *mtd)
++{
++      struct nand_chip *this = NULL;
++      int ret;
++
++      this = (struct nand_chip *)mtd->priv;
++      ret = read_reloc_table(mtd);
++      if (ret) {
++              printk(KERN_ERR "Failed to get relocation table\n");
++              printk(KERN_ERR "Try to build a new BBT. It may result \
++                              unpredicated error.\n");
++              /* Create new memory based and flash based BBT */
++      }
++      nand_scan_bbt(mtd, &monahans_bbt_default);
++      //dump_bbt_flash(mtd);
++      dump_bbt_mem(mtd);
++      return 0;
++#if 0
++      /* Read flashed based BBT from device */
++      return (nand_scan_bbt(mtd, &monahans_bbt_main));
++#endif
++}
++
++
++static int monahans_df_probe(struct platform_device *pdev)
++{
++      struct nand_chip *this;
++      struct monahans_dfc_info *info;
++      int status = -1;
++      unsigned int data_buf_len;
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      unsigned int buf_len;
++#endif
++      int i, ret = 0;
++
++      printk(KERN_ERR "Nand driver probe\n");
++
++      dfc_context.membase = ioremap_nocache(0x43100000, 0x100000);
++      if (!dfc_context.membase)
++              printk(KERN_ERR "Couldn't ioremap\n");
++
++      pxa_set_cken(CKEN_NAND, 1);
++
++      for (i = DFC_FLASH_NULL + 1; i < DFC_FLASH_END; i++)
++      {
++              uint32_t id;
++
++              status = dfc_init(&dfc_context, i);
++              if (status)
++                      continue;
++              status = dfc_readid(&dfc_context, &id);
++              if (status)
++                      continue;
++              printk(KERN_DEBUG "id:0x%x, chipid:0x%x\n",
++                      id, dfc_context.flash_info->chip_id);
++              if (id == dfc_context.flash_info->chip_id)
++                      break;
++      }
++
++      if(i == DFC_FLASH_END) {
++              printk(KERN_ALERT "Monahans NAND device:"
++                      "Nand Flash initialize failure!\n");
++              ret = -ENXIO;
++              goto out;
++      }
++      flash_config = i;
++
++      monahans_mtd = kzalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip) +
++                      sizeof(struct monahans_dfc_info) , GFP_KERNEL);
++      if (!monahans_mtd) {
++              printk (KERN_ERR "Monahans NAND device:"
++                      "Unable to allocate NAND MTD device structure.\n");
++              ret = -ENOMEM;
++              goto out;
++        }
++
++      /* Get pointer to private data */
++      this = (struct nand_chip *)((void *)monahans_mtd + sizeof(struct mtd_info));
++      info = (struct monahans_dfc_info *)((void *)this + sizeof(struct nand_chip));
++      dfc_context.mtd = monahans_mtd;
++
++      monahans_mtd->priv = this;
++      this->priv = info;
++      data_buf_len = dfc_context.flash_info->page_size +
++              dfc_context.flash_info->oob_size;
++      info->state = STATE_READY;
++      init_completion(&info->cmd_complete);
++      info->table_init = 0;
++      memset(&info->table, 0x0, sizeof(struct reloc_table));
++      printk(KERN_DEBUG "%s: this->controller: 0x%x, &this->controller: 0x%x\n",__func__, (unsigned int)this->controller, (unsigned int)&(this->controller));
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      info->dma_mask = 0xffffffffUL;
++
++      dev->dma_mask = &info->dma_mask;
++      dev->coherent_dma_mask = 0xffffffffUL;
++
++      /* alloc dma data buffer for data
++       * buffer + 2*descriptor + command buffer
++       */
++      buf_len = ALIGN(2*sizeof(struct pxa_dma_desc), 32) +
++              ALIGN(data_buf_len, 32) + ALIGN(NAND_CMD_DMA_LEN, 32);
++
++      printk(KERN_INFO "Try to allocate dma buffer(len:%d)"
++              "for data buffer + 2*descriptor + command buffer\n", buf_len);
++      info->data_desc = (struct pxa_dma_desc*)dma_alloc_writecombine(dev,
++                      buf_len, &info->data_desc_addr, GFP_KERNEL);
++      if (!info->data_desc) {
++              printk(KERN_ERR "Monahans NAND device:"
++                      "Unable to alloc dma buffer\n");
++              ret = -ENOMEM;
++              goto free_mtd;
++      }
++
++      info->cmd_desc = (struct pxa_dma_desc*)((char *)info->data_desc +
++                      sizeof(struct pxa_dma_desc));
++      info->cmd_desc_addr = (dma_addr_t)((char *)info->data_desc_addr +
++                      sizeof(struct pxa_dma_desc));
++      info->data_buf = (char *)info->data_desc +
++              ALIGN(2*sizeof(struct pxa_dma_desc), 32);
++      info->data_buf_addr = (dma_addr_t)((char *)info->data_desc_addr +
++              ALIGN(2*sizeof(struct pxa_dma_desc), 32));
++      info->cmd_buf = (char *)info->data_buf + ALIGN(data_buf_len, 32);
++      info->cmd_buf_addr = (dma_addr_t)((char *)info->data_buf_addr +
++                      ALIGN(data_buf_len, 32));
++
++      D1(printk("Get dma buffer for data dma descriptor, virt:0x%x, phys0x:%x\n",
++              (unsigned int)info->data_desc, info->data_desc_addr));
++      D1(printk("Get dma buffer for command dma descriptors, virt:0x%x,"
++              "phys0x:%x\n", (unsigned int)info->cmd_desc, info->cmd_desc_addr));
++      D1(printk("Get dma buffer for data, virt:0x%x, phys0x:%x\n",
++              (unsigned int)info->data_buf, info->data_buf_addr));
++      D1(printk("Get dma buffer for command, virt:0x%x, phys0x:%x\n",
++              (unsigned int)info->cmd_buf, info->cmd_buf_addr));
++
++      D1(printk("Try to allocate dma channel for data\n"));
++
++      info->data_dma = pxa_request_dma("NAND DATA", DMA_PRIO_LOW,
++                      monahans_dfc_data_dma_irq, info);
++      if (info->data_dma < 0) {
++              printk(KERN_ERR "Monahans NAND device:"
++                      "Unable to alloc dma channel for data\n");
++              ret = info->data_dma;
++              goto free_buf;
++      }
++      D1(printk("Get dma channel:%d for data\n", info->data_dma));
++
++      D1(printk("Try to allocate dma channel for command\n"));
++      info->cmd_dma = pxa_request_dma("NAND CMD", DMA_PRIO_LOW,
++                      monahans_dfc_cmd_dma_irq, info);
++      if (info->cmd_dma < 0) {
++              printk(KERN_ERR "Monahans NAND device:"
++                      "Unable to alloc dma channel for command\n");
++              ret = info->cmd_dma;
++              goto free_data_dma;
++      }
++      D1(printk("Get dma channel:%d for command\n", info->cmd_dma));
++
++      dfc_context.cmd_dma_ch  = info->cmd_dma;
++      dfc_context.data_dma_ch = info->data_dma;
++#else
++      printk(KERN_DEBUG "Try to allocate data buffer(len:%d)\n", data_buf_len);
++      info->data_buf = kmalloc(data_buf_len, GFP_KERNEL);
++      if (!info->data_buf) {
++              printk(KERN_ERR "Monahans NAND device:"
++                      "Unable to alloc data buffer\n");
++              ret = -ENOMEM;
++              goto free_mtd;
++      }
++#endif
++
++      D1(printk("Try to request irq:%d\n", IRQ_NAND));
++      ret = request_irq(IRQ_NAND, monahans_dfc_irq, 0, pdev->name, info);
++      if (ret < 0) {
++              printk(KERN_ERR "Monahans NAND device: Unable to request irq\n");
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++              goto free_cmd_dma;
++#else
++              goto free_buf;
++#endif
++      }
++
++      D1(printk("Success request irq\n"));
++
++      /* set address of NAND IO lines */
++      this->options = (dfc_context.flash_info->flash_width == 16)? \
++                      NAND_BUSWIDTH_16: 0 | NAND_USE_FLASH_BBT;
++
++      /* this->IO_ADDR_R = this->IO_ADDR_W = NDDB */
++      this->waitfunc = monahans_df_waitfunc;
++      this->select_chip = monahans_df_select_chip;
++      this->dev_ready = monahans_df_dev_ready;
++      this->cmdfunc = monahans_df_command;
++      this->read_word= monahans_df_read_word;
++      /*this->write_word= monahans_df_write_word;*/
++      this->read_byte = monahans_df_read_byte;
++      this->read_buf = monahans_df_read_buf;
++      this->write_buf = monahans_df_write_buf;
++      this->verify_buf = monahans_df_verify_buf;
++      this->ecc.hwctl = monahans_df_enable_hwecc;
++      this->ecc.calculate = monahans_df_calculate_ecc;
++      this->ecc.correct = monahans_df_correct_data;
++      this->block_bad = monahans_df_block_bad;
++      this->block_markbad = monahans_df_block_markbad;
++      this->scan_bbt = monahans_df_scan_bbt;
++      this->chip_delay= 25;
++      this->bbt_td = &monahans_bbt_main;
++      this->bbt_md = &monahans_bbt_mirror;
++
++      /* If the NAND flash is small block flash, only 512-byte pagesize
++       * is supported.
++       * Adjust parameters of BBT what is depended on large block nand
++       * flash or small block nand flash.
++       */
++      if (dfc_context.flash_info->oob_size > 16) {
++              this->ecc.layout = &monahans_lb_nand_oob;
++              this->ecc.mode = NAND_ECC_HW;
++              this->ecc.size = 2048;
++              this->ecc.bytes = 24;
++              this->bbt_td->offs = 2;
++              this->bbt_td->veroffs = 6;
++              this->bbt_md->offs = 2;
++              this->bbt_md->veroffs = 6;
++              this->badblockpos = NAND_LARGE_BADBLOCK_POS;
++              monahans_bbt_default.offs = NAND_LARGE_BADBLOCK_POS;
++              monahans_bbt_default.len = 2;
++              /* when scan_bbt() is executed, bbt version can get */
++              monahans_bbt_default.veroffs = 2;
++      } else {
++              this->ecc.layout = &monahans_sb_nand_oob;
++              this->ecc.mode = NAND_ECC_HW;
++              this->ecc.size = 512;
++              this->ecc.bytes = 6;
++              this->bbt_td->offs = 8;
++              this->bbt_td->veroffs = 12;
++              this->bbt_md->offs = 8;
++              this->bbt_md->veroffs = 12;
++              this->badblockpos = NAND_SMALL_BADBLOCK_POS;
++              monahans_bbt_default.offs = NAND_SMALL_BADBLOCK_POS;
++              monahans_bbt_default.len = 1;
++              monahans_bbt_default.veroffs = 8;
++      }
++
++      info->context = &dfc_context;
++      /* TODO: allocate dma buffer and channel */
++
++      platform_set_drvdata(pdev, monahans_mtd);
++
++      if (nand_scan(monahans_mtd, 1)) {
++              printk(KERN_ERR "Nand scan failed\n");
++              ret = -ENXIO;
++              goto free_irq;
++      }
++
++      /* There is a potential limitation that no more partition can be
++       * added between MassStorage and BBT(last block).
++       *
++       * The last 127 blocks is reserved for relocation table, they aren't
++       * statistical data of mtd size and chip size.
++       *
++       * BBT partitions contains 4 blocks. Two blocks are used to store
++       * main descriptor, the other two are used to store mirror descriptor.
++       */
++      partition_info[PART_NUM - 1].size = (monahans_bbt_main.maxblocks
++                                      + monahans_bbt_mirror.maxblocks)
++                                      << this->phys_erase_shift;
++      partition_info[PART_NUM - 1].offset = this->chipsize
++                                      - partition_info[PART_NUM - 1].size;
++      partition_info[PART_NUM - 2].offset = partition_info[PART_NUM - 3].offset
++                                      + partition_info[PART_NUM - 3].size;
++      partition_info[PART_NUM - 2].size = this->chipsize
++                                      - partition_info[PART_NUM - 2].offset
++                                      - partition_info[PART_NUM - 1].size;
++      add_mtd_partitions(monahans_mtd, partition_info, PART_NUM);
++
++#ifdef CONFIG_DVFM
++        dvfm_notifier.client_data = info;
++        mhn_fv_register_notifier(&dvfm_notifier);
++#endif
++
++      return 0;
++
++free_irq:
++      free_irq(IRQ_NAND, info);
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++free_cmd_dma:
++      pxa_free_dma(info->cmd_dma);
++free_data_dma:
++      pxa_free_dma(info->data_dma);
++free_buf:
++      dma_free_writecombine(dev, buf_len, info->data_desc, info->data_desc_addr);
++#else
++free_buf:
++      kfree(info->data_buf);
++#endif
++free_mtd:
++      kfree(monahans_mtd);
++out:
++      return ret;
++
++}
++
++static int __devexit monahans_df_remove(struct platform_device *dev)
++{
++      struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(dev);
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      unsigned int data_buf_len = dfc_context.flash_info->page_size +
++                      dfc_context.flash_info->oob_size;
++      unsigned int buf_len = ALIGN(2*sizeof(struct pxa_dma_desc), 32) +
++                      ALIGN(data_buf_len, 32) + ALIGN(NAND_CMD_DMA_LEN, 32);
++#endif
++
++#ifdef CONFIG_DVFM
++        mhn_fv_unregister_notifier(&dvfm_notifier);
++#endif
++
++      platform_set_drvdata(dev, NULL);
++
++      del_mtd_device(mtd);
++      del_mtd_partitions(mtd);
++      free_irq(IRQ_NAND, info);
++#ifdef CONFIG_MTD_NAND_MONAHANS_DMA
++      pxa_free_dma(info->cmd_dma);
++      pxa_free_dma(info->data_dma);
++      dma_free_writecombine(dev, buf_len, info->data_desc,
++              info->data_desc_addr);
++#else
++      kfree(info->data_buf);
++#endif
++      kfree(mtd);
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int monahans_df_suspend(struct platform_device *dev, pm_message_t state, u32 level)
++{
++      struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(dev);
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++
++      if( SUSPEND_DISABLE == level){ /*SUSPEND_NOTIFY*/
++              if (info->state != STATE_READY) {
++                      printk(KERN_ERR "current state is %d\n", info->state);
++                      return -EAGAIN;
++              }
++              info->state = STATE_SUSPENDED;
++              /*
++               * The PM code need read the mobm from NAND.
++               * So the NAND clock can't be stop here.
++               * The PM code will cover this.
++               */
++              /* pxa_set_cken(CKEN_NAND, 0); */
++      }
++      return 0;
++}
++
++static int monahans_df_resume(struct platform_device *dev, u32 level)
++{
++      struct mtd_info *mtd = (struct mtd_info *)platform_get_drvdata(dev);
++      struct monahans_dfc_info *info = (struct monahans_dfc_info *)
++                      (((struct nand_chip *)(mtd->priv))->priv);
++      int status;
++
++      if(RESUME_ENABLE == level){
++              if (info->state != STATE_SUSPENDED)
++                      printk(KERN_WARNING "Error State after resume back\n");
++
++              info->state = STATE_READY;
++
++              pxa_set_cken(CKEN_NAND, 1);
++
++              status = dfc_init(&dfc_context, flash_config);
++              if (status) {
++                      printk(KERN_ALERT "Monahans NAND device:"
++                              "Nand Flash initialize failure!\n");
++                      return -ENXIO;
++              }
++      }
++      return 0;
++}
++#endif
++
++#ifdef CONFIG_DVFM
++static int mhn_nand_dvfm_notifier(unsigned cmd, void *client_data, void *info)
++{
++      struct monahans_dfc_info *dfc_info =
++                      (struct monahans_dfc_info *)client_data;
++
++      switch (cmd) {
++      case FV_NOTIFIER_QUERY_SET :
++              if (dfc_info->state != STATE_READY)
++                      return -1;
++              break;
++
++      case FV_NOTIFIER_PRE_SET :
++              break;
++
++      case FV_NOTIFIER_POST_SET :
++              break;
++      }
++
++      return 0;
++}
++#endif
++
++static struct platform_driver monahans_df_driver = {
++      .probe          = monahans_df_probe,
++      .remove         = __devexit_p(monahans_df_remove),
++#ifdef CONFIG_PM
++      .suspend        = monahans_df_suspend,
++      .resume         = monahans_df_resume,
++#endif
++      .driver         = {
++              .name           = "monahans-nand-flash",
++      }
++};
++
++static void __exit monahans_df_cleanup(void)
++{
++      printk(KERN_ERR "Nand driver registered\n");
++      platform_driver_unregister(&monahans_df_driver);
++}
++
++static int __init monahans_df_init(void)
++{
++      return platform_driver_register(&monahans_df_driver);
++}
++
++module_init(monahans_df_init);
++module_exit(monahans_df_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Jingqing.xu (jingqing.xu@intel.com)");
++MODULE_DESCRIPTION("Glue logic layer for NAND flash on monahans DFC");
++
++
+Index: linux-2.6.23/arch/arm/mach-pxa/zylonite.c
+===================================================================
+--- linux-2.6.23.orig/arch/arm/mach-pxa/zylonite.c     2008-02-13 00:59:45.000000000 +0000
++++ linux-2.6.23/arch/arm/mach-pxa/zylonite.c  2008-02-13 09:11:02.000000000 +0000
+@@ -29,6 +29,8 @@
+ #include "generic.h"
+ int gpio_backlight;
++int gpio_vsync;
++int gpio_vsync1;
+ int gpio_eth_irq;
+ int lcd_id;
+@@ -54,6 +56,16 @@
+       .resource       = smc91x_resources,
+ };
++static struct platform_device nand_device = {
++      .name           = "monahans-nand-flash",
++      .id             = -1,
++};
++
++static struct platform_device touch_device = {
++      .name           = "pxa2xx-touch",
++      .id             = -1,
++};
++
+ #if defined(CONFIG_FB_PXA) || (CONFIG_FB_PXA_MODULES)
+ static void zylonite_backlight_power(int on)
+ {
+@@ -96,7 +108,7 @@
+ };
+ static struct pxafb_mode_info sharp_ls037_modes[] = {
+-      [0] = {
++      [1] = {
+               .pixclock       = 158000,
+               .xres           = 240,
+               .yres           = 320,
+@@ -109,8 +121,8 @@
+               .lower_margin   = 3,
+               .sync           = 0,
+       },
+-      [1] = {
+-              .pixclock       = 39700,
++      [0] = {
++              .pixclock       = 45000,
+               .xres           = 480,
+               .yres           = 640,
+               .bpp            = 16,
+@@ -137,6 +149,11 @@
+       /* backlight GPIO: output, default on */
+       gpio_direction_output(gpio_backlight, 1);
++      gpio_direction_output(gpio_vsync, 0);
++      gpio_direction_output(gpio_vsync1, 0);
++
++      printk(KERN_ERR "LCD ID is %x\n", lcd_id);
++
+       if (lcd_id & 0x20) {
+               set_pxa_fb_info(&zylonite_sharp_lcd_info);
+               return;
+@@ -169,6 +186,8 @@
+       smc91x_resources[1].start = gpio_to_irq(gpio_eth_irq);
+       smc91x_resources[1].end   = gpio_to_irq(gpio_eth_irq);
+       platform_device_register(&smc91x_device);
++      platform_device_register(&nand_device);
++      platform_device_register(&touch_device);
+       zylonite_init_lcd();
+ }
+Index: linux-2.6.23/arch/arm/mach-pxa/zylonite_pxa300.c
+===================================================================
+--- linux-2.6.23.orig/arch/arm/mach-pxa/zylonite_pxa300.c      2008-02-13 00:59:45.000000000 +0000
++++ linux-2.6.23/arch/arm/mach-pxa/zylonite_pxa300.c   2008-02-13 14:01:13.000000000 +0000
+@@ -62,12 +62,12 @@
+       GPIO110_UART3_RXD,
+       /* AC97 */
+-      GPIO23_AC97_nACRESET,
++      /*GPIO23_AC97_nACRESET,
+       GPIO24_AC97_SYSCLK,
+       GPIO29_AC97_BITCLK,
+       GPIO25_AC97_SDATA_IN_0,
+       GPIO27_AC97_SDATA_OUT,
+-      GPIO28_AC97_SYNC,
++      GPIO28_AC97_SYNC,*/
+       /* Keypad */
+       GPIO107_KP_DKIN_0,
+@@ -104,6 +104,41 @@
+       /* Ethernet */
+       GPIO2_nCS3,
+       GPIO99_GPIO,
++
++      /* NAND */
++      MFP_CFG_X(DF_INT_RnB, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nRE_nOE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nWE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_CLE_nOE, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nADV1_ALE, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nCS0, AF1, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_nCS1, AF0, DS10X, PULL_LOW),
++      MFP_CFG_X(DF_IO0, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO1, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO2, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO3, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO4, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO5, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO6, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO7, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO8, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO9, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO10, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO11, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO12, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO13, AF1, DS08X, PULL_LOW),
++      MFP_CFG_X(DF_IO14, AF1, DS08X, PULL_LOW),
++
++      /* AC97 */
++      MFP_CFG_X(GPIO23, AF1, DS03X, PULL_LOW),
++      MFP_CFG_X(GPIO27, AF1, DS03X, PULL_LOW),
++      MFP_CFG_X(GPIO28, AF1, DS03X, PULL_LOW),
++      MFP_CFG_X(GPIO29, AF1, DS03X, PULL_LOW),
++      MFP_CFG_X(GPIO25, AF1, DS03X, PULL_LOW),
++
++      MFP_CFG_X(GPIO26, AF0, DS01X, PULL_LOW), /* Interrupt */
++      MFP_CFG_X(GPIO24, AF0, DS03X, PULL_LOW), /*SYSCLK external */
++      MFP_CFG_X(GPIO11, AF0, DS01X, PULL_LOW),
+ };
+ static mfp_cfg_t pxa310_mfp_cfg[] __initdata = {
+@@ -163,6 +198,9 @@
+               pxa3xx_mfp_write(lcd_detect_pins[i], mfpr_save[i]);
+ }
++extern int gpio_vsync;
++extern int gpio_vsync1;
++
+ void __init zylonite_pxa300_init(void)
+ {
+       if (cpu_is_pxa300() || cpu_is_pxa310()) {
+@@ -174,6 +212,8 @@
+               /* GPIO pin assignment */
+               gpio_backlight = mfp_to_gpio(MFP_PIN_GPIO20);
++              gpio_vsync = mfp_to_gpio(GPIO76_LCD_VSYNC);
++              gpio_vsync1 = mfp_to_gpio(GPIO71_LCD_LDD_17);
+       }
+       if (cpu_is_pxa300()) {
+Index: linux-2.6.23/drivers/video/pxafb.c
+===================================================================
+--- linux-2.6.23.orig/drivers/video/pxafb.c    2008-02-13 00:59:45.000000000 +0000
++++ linux-2.6.23/drivers/video/pxafb.c 2008-02-13 00:59:45.000000000 +0000
+@@ -1543,9 +1543,9 @@
+         if (inf->lccr0 & LCCR0_INVALID_CONFIG_MASK)
+                 dev_warn(&dev->dev, "machine LCCR0 setting contains illegal bits: %08x\n",
+                         inf->lccr0 & LCCR0_INVALID_CONFIG_MASK);
+-        if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
+-                dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
+-                        inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
++        //if (inf->lccr3 & LCCR3_INVALID_CONFIG_MASK)
++        //        dev_warn(&dev->dev, "machine LCCR3 setting contains illegal bits: %08x\n",
++        //                inf->lccr3 & LCCR3_INVALID_CONFIG_MASK);
+         if (inf->lccr0 & LCCR0_DPD &&
+           ((inf->lccr0 & LCCR0_PAS) != LCCR0_Pas ||
+            (inf->lccr0 & LCCR0_SDS) != LCCR0_Sngl ||
+Index: linux-2.6.23/include/asm-arm/arch-pxa/mfp-pxa300.h
+===================================================================
+--- linux-2.6.23.orig/include/asm-arm/arch-pxa/mfp-pxa300.h    2008-02-13 00:59:45.000000000 +0000
++++ linux-2.6.23/include/asm-arm/arch-pxa/mfp-pxa300.h 2008-02-13 00:59:45.000000000 +0000
+@@ -175,13 +175,13 @@
+ #define GPIO68_LCD_LDD_14     MFP_CFG_DRV(GPIO68, AF1, DS01X)
+ #define GPIO69_LCD_LDD_15     MFP_CFG_DRV(GPIO69, AF1, DS01X)
+ #define GPIO70_LCD_LDD_16     MFP_CFG_DRV(GPIO70, AF1, DS01X)
+-#define GPIO71_LCD_LDD_17     MFP_CFG_DRV(GPIO71, AF1, DS01X)
++#define GPIO71_LCD_LDD_17     MFP_CFG_DRV(GPIO71, AF0, DS01X)
+ #define GPIO62_LCD_CS_N               MFP_CFG_DRV(GPIO62, AF2, DS01X)
+ #define GPIO72_LCD_FCLK               MFP_CFG_DRV(GPIO72, AF1, DS01X)
+ #define GPIO73_LCD_LCLK               MFP_CFG_DRV(GPIO73, AF1, DS01X)
+ #define GPIO74_LCD_PCLK               MFP_CFG_DRV(GPIO74, AF1, DS01X)
+ #define GPIO75_LCD_BIAS               MFP_CFG_DRV(GPIO75, AF1, DS01X)
+-#define GPIO76_LCD_VSYNC      MFP_CFG_DRV(GPIO76, AF2, DS01X)
++#define GPIO76_LCD_VSYNC      MFP_CFG_DRV(GPIO76, AF0, DS01X)
+ #define GPIO15_LCD_CS_N               MFP_CFG_DRV(GPIO15,  AF2, DS01X)
+ #define GPIO127_LCD_CS_N      MFP_CFG_DRV(GPIO127, AF1, DS01X)
diff --git a/packages/linux/linux-rp-2.6.23/zylonite_touch-r0.patch b/packages/linux/linux-rp-2.6.23/zylonite_touch-r0.patch
new file mode 100644 (file)
index 0000000..1c00696
--- /dev/null
@@ -0,0 +1,1548 @@
+Index: linux-2.6.23/drivers/input/touchscreen/Kconfig
+===================================================================
+--- linux-2.6.23.orig/drivers/input/touchscreen/Kconfig        2008-02-13 01:12:29.000000000 +0000
++++ linux-2.6.23/drivers/input/touchscreen/Kconfig     2008-02-13 01:13:20.000000000 +0000
+@@ -54,6 +54,12 @@
+         To compile this driver as a module, choose M here: the
+         module will be called corgi_ts.
++config TOUCHSCREEN_ZYLONITE
++      tristate "Zylonite touchscreen driver"
++      default y
++      help
++        Say Y here for the Zylonite touchscreen driver
++
+ config TOUCHSCREEN_FUJITSU
+       tristate "Fujitsu serial touchscreen"
+       select SERIO
+Index: linux-2.6.23/drivers/input/touchscreen/Makefile
+===================================================================
+--- linux-2.6.23.orig/drivers/input/touchscreen/Makefile       2008-02-13 01:12:29.000000000 +0000
++++ linux-2.6.23/drivers/input/touchscreen/Makefile    2008-02-13 01:13:38.000000000 +0000
+@@ -19,3 +19,4 @@
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)    += touchwin.o
+ obj-$(CONFIG_TOUCHSCREEN_UCB1400)     += ucb1400_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_TSC2101)     += tsc2101_ts.o
++obj-$(CONFIG_TOUCHSCREEN_ZYLONITE)    += zylonite-ts.o
+Index: linux-2.6.23/drivers/input/touchscreen/zylonite-ts.c
+===================================================================
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.23/drivers/input/touchscreen/zylonite-ts.c       2008-02-13 16:19:15.000000000 +0000
+@@ -0,0 +1,1517 @@
++/*
++ *  drivers/input/touchscreen/mhn_audio_touch.c.
++ *
++ *  Author:   bridge.wu@marvell.com
++ *  Created:  Nov 17, 2006
++ *  Copyright:        Marvell Corporation.
++ *
++ *  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/module.h>
++#include <linux/kernel.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/initval.h>
++
++#include <asm/semaphore.h>
++#include <asm/hardware.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/gpio.h>
++#include <asm/arch/mfp.h>
++//#include <asm/arch/ipmc.h>
++#include <linux/suspend.h>
++#include <linux/spinlock.h>
++
++//#include <asm/arch/codec/acodec.h>
++//#include <asm/arch/mhn_audio_plat.h>
++
++#define OSCC               __REG(0x41350000)  /* Oscillator Configuration Register */
++#define AC97_DIV      __REG(0x41340014)
++
++#define ALSA_ZY_CARD_DEBUG
++#undef ALSA_ZY_CARD_DEBUG
++
++#define WM_9713_ID  0x4C13 /* this should be the 7E register value */
++
++#ifdef ALSA_ZY_CARD_DEBUG
++#define dbg(format, arg...) printk(KERN_DEBUG format, ##arg)
++#else
++#define dbg(format, arg...)
++#endif
++
++#define DEBUG
++#undef DEBUG
++#ifdef DEBUG
++unsigned int start_time;
++unsigned int end_time;
++unsigned int time;
++#define PRINT_TIME() do {\
++        time = ((end_time > start_time))?\
++                (end_time - start_time)*100/325:\
++                (0xffffffff - start_time + end_time)*100/325;\
++        printk("\n%s:%dus\n", __FUNCTION__, time);\
++} while(0)
++#endif
++
++
++
++
++/* 9713 specific
++ *    Register Name                   Index
++ */
++#define RESET                         0X00
++#define SPEAKER_VOLUME                        0X02
++#define HEADPHONE_VOLUME              0X04
++#define OUT3_OUT4_VOLUME              0X06
++#define MONOVOL_MONOINPGA_ROUTE               0X08
++#define LINE_IN_PGA_VOL_ROUTE         0X0A
++#define DAC_PGA_VOL_ROUTE             0X0C
++#define MIC_PGA_VOLUME                        0X0E
++#define MIC_ROUTING                   0X10
++#define REC_PGA_VOL                   0X12
++#define REC_ROUTE_MUX_SEL             0X14
++#define PCBEEP_VOL_ROUTE              0X16
++#define VXDAC_VOLUME_ROUTE            0X18
++#define AUX_DAC_VOL_ROUTE             0X1A
++#define OUTPUT_PGA_MUX                        0X1C
++#define DAC_3D_CTRL_INV_MUX_SEL               0X1E
++#define DAC_TONE_CTRL                 0X20
++#define MIC_BIAS                      0X22
++#define OUTPUT_VOL_MAPPING_JACK               0X24
++#define POWERDOWN_CTRL_STAT           0X26
++#define EXTENDED_AUD_ID                       0X28
++#define EXTENDED_AUD_STAT_CTRL        0X2A
++#define AUDIO_DAC_RATE                        0X2C
++#define AUX_DAC_RATE                  0X2E
++#define AUDIO_ADC_RATE                        0X32
++#define PCM_CODEC_CTRL                        0X36
++#define SPDIF_CTRL                    0X3A
++#define POWER_DOWN_1                  0X3C
++#define POWER_DOWN_2                  0X3E
++#define GENERAL_PURPOSE_WM_13         0X40
++#define FAST_POWERUP_CTRL             0X42
++#define MCLK_PLL_CTRL_1                       0X44
++#define MCLK_PLL_CTRL_2                       0X46
++#define GPIO_PIN_CFG                  0X4C
++#define GPIO_PIN_POL_TYPE             0X4E
++#define GPIO_PIN_STICKY               0X50
++#define GPIO_PIN_WAKEUP                       0X52
++#define GPIO_PIN_STATUS                       0X54
++#define GPIO_PIN_SHARING              0X56
++#define GPIO_PULL_UP_DOWN_CTRL                0X58
++#define ADD_FUNC_1                    0X5A
++#define ADD_FUNC_2                    0X5C
++#define ALC_CTRL                      0X60
++#define ALC_NOISE_GATE_CTRL           0X62
++#define AUX_DAC_INPUT_CTRL            0X64
++#define TEST_REG_1                    0X68
++#define TEST_REG_2                    0X6A
++#define TEST_REG_3                    0X6C
++#define TEST_REG_4                    0X6E
++#define DIGITIZER_1_WM13              0x74
++#define DIGITIZER_2_WM13              0x76
++#define DIGITIZER_3_WM13              0x78
++#define DIGITIZER_READ_BACK           0x7a
++#define VENDOR_ID1                    0x7c
++#define VENDOR_ID2                    0x7e
++
++#define ZY_TOUCH_SAMPLE_X 1
++#define ZY_TOUCH_SAMPLE_Y 2
++
++#define ZY_EVENT_TYPE_NONE                    0
++#define ZY_EVENT_TYPE_PDN                     1
++
++
++typedef enum _zy_acodec_error_t {
++    ZY_ACODEC_SUCCESS = 0,    /* successful completion of a function */
++    ZY_ACODEC_GENERAL_SW_ERR, /* null pointer to registers or other software error */
++    ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT, /* time-out for waiting for respponse */
++    ZY_ACODEC_SAMPLERATE_NOT_SUPPORTED, /* the sample rate is not supported either in controller or codec */
++    ZY_ACODEC_FEATURE_NO_SUPPORTED, /* this codec feature is not supported  */
++    ZY_ACODEC_GENERAL_HW_ERR ,/* other hardware error besides time out */
++    ZY_ACODEC_ROUTE_NO_SUPPORTED, /* the codec can not set the route required */
++    ZY_ACODEC_SLEEP /* the codec is sleep */
++} zy_acodec_error_t;
++
++typedef unsigned int zy_acodec_device_id_t;
++
++typedef enum _codec_state {
++      ZY_CODEC_SLEEP  = 0,
++      ZY_CODEC_WAKEUP = 1
++} acodec_state_t;
++
++typedef enum {
++       ZY_FM = 0,
++       ZY_MIC1 = 1,
++       ZY_MIC2 = 2,
++       ZY_SPEAKER =3,
++       ZY_HEADSET =4,
++       ZY_HANDSET =5,
++} vol_port_type_t;
++
++typedef struct _context_t {
++      int  use_count;                 /* probe/remove and suspend/resume usage count, sync among multiple devices */
++      zy_acodec_device_id_t acodec_id;/* - an ID that uniquely identifies the codec to be used */
++      unsigned long init_number;      /* used by driver to track whether it is inited or not */
++
++      void *p_voice_reg;              /* pointer to Monahans registers that has PCM interface to codec */
++      void *p_hifi_reg;               /* pointer to Monahans registers that has hifi interface to codec */
++      void *p_ctrl_reg;               /* pointer to Monahans registers that has control interface to codec */
++      int  *p_ost_regs;               /* needed for time out */
++      void *p_save_memory;            /* pointer to a memory region to save context while suspend */
++      void *p_zy_scenario;            /* pointer to the scenario data structure  */
++      long u_max_read_write_time_out_ms;/* input the max time to wait in milliseconds before giving up on a read or write operation */
++      long u_max_setup_time_out_ms;   /* input the maximum time in milliseconds to wait during initial setup of the ACODEC controller and codec */
++
++      /* member functions these pointers must be set by */
++      zy_acodec_error_t (* g_pfn_codec_specific_init)      (struct _context_t *p_device_context);
++      zy_acodec_error_t (* g_pfn_codec_specific_dinit)    (struct _context_t *p_device_context);
++      zy_acodec_error_t (* g_pfn_acodec_read)             (struct _context_t *p_dev_context, unsigned short reg_addr, unsigned short *p_reg_value);
++      zy_acodec_error_t (* g_pfn_acodec_write)            (struct _context_t *p_dev_context, unsigned short reg_addr, unsigned short reg_value);
++
++      /* add for route */
++      zy_acodec_error_t (* g_pfn_set_route)           (struct _context_t *p_device_context, unsigned short * rout_map ,unsigned short* current_map);
++      /* add for sleep the codec */
++      zy_acodec_error_t (* g_pfn_sleep_codec)           (struct _context_t *p_device_context);
++      /* add for Wake up the codec */
++      zy_acodec_error_t (* g_pfn_wake_codec)           (struct _context_t *p_device_context);
++      /* add for get codec state */
++      zy_acodec_error_t (* g_pfn_get_state)           (struct _context_t *p_device_context, acodec_state_t *p_state);
++      /* add for volume */
++      zy_acodec_error_t (* g_pfn_get_vol)(struct _context_t *p_device_context, vol_port_type_t port,  unsigned short *gain_in_db);
++      zy_acodec_error_t (* g_pfn_set_vol)(struct _context_t *p_device_context, vol_port_type_t port,  unsigned short gain_in_db);
++
++        void (* g_pfn_get_event)(struct _context_t *p_device_context, unsigned char * event_type);
++        void (* g_pfn_event_ack)(struct _context_t *p_device_context, unsigned char event_type);
++        zy_acodec_error_t (* g_pfn_enable_touch)(struct _context_t *p_device_context);
++        zy_acodec_error_t (* g_pfn_disable_touch)(struct _context_t *p_device_context);
++} zy_acocec_context_t, *p_zy_acocec_context_t;
++
++
++
++
++
++static p_zy_acocec_context_t p_zy_codec_ctxt = NULL;
++
++#include <linux/input.h>
++//#include <asm/arch/codec/wm9713.h>
++
++#define PEN_DOWN              1
++#define PEN_UP                        0
++#define TS_SAMPLE_INTERVAL    1
++
++typedef struct {
++      struct input_dev *idev;
++      struct timer_list *timer;
++      int  use_count;
++} codec_zy_ts_t;
++
++codec_zy_ts_t codec_zy_ts;
++
++static struct input_dev *codec_zy_ts_input;
++
++#ifdef CONFIG_PM
++static volatile int touch_suspend = 0 ;
++#endif
++
++#define ZY_AC97_CODEC_REGS_NUM        0x40
++
++typedef struct
++{  //   Register symbol     // Usage
++    volatile unsigned long pocr;           // PCM Out Control Register
++    volatile unsigned long picr;           // PCM In Control Register
++    volatile unsigned long mccr;           // Mic In Control Register
++    volatile unsigned long gcr;            // Global Control Register
++    volatile unsigned long posr;           // PCM Out Status Register
++    volatile unsigned long pisr;           // PCM In Status Register
++    volatile unsigned long mcsr;           // Mic In Status Register
++    volatile unsigned long gsr;            // Global Status Register
++    volatile unsigned long car;            // CODEC Access Register
++    volatile unsigned long pcscr;          // PCM Surround Out Control
++    volatile unsigned long pcssr;          // PCM Surround Out Status
++    volatile unsigned long pcsdr;          // PCM Surround Out Data
++    volatile unsigned long pcclcr;         // PCM Center/LFE Out Control
++    volatile unsigned long pcclsr;         // PCM Center/LFE Out Status
++    volatile unsigned long pccldr;         // PCM Center/LFE Out Data
++    volatile unsigned long reserved1;       //
++    volatile unsigned long pcdr;           // PCM FIFO Data Register
++    volatile unsigned long reserved2 [0x7];      // 0x4050-0044 through 0x4050-005C
++    volatile unsigned long mcdr;           // Mic-in FIFO Data Register
++    volatile unsigned long reserved3 [0x27];   // 0x4050-0064 through 0x4050-00FC
++    volatile unsigned long mocr;           // MODEM Out Control Register
++    volatile unsigned long reserved4;
++    volatile unsigned long micr;           // MODEM In Control Register
++    volatile unsigned long reserved5;
++    volatile unsigned long mosr;           // MODEM Out Status Register
++    volatile unsigned long reserved6;
++    volatile unsigned long misr;           // MODEM In Status Register
++    volatile unsigned long reserved7 [0x9];      // 0x4050-011C through 0x4050-013C
++    volatile unsigned long modr;           // MODEM FIFO Data Register
++    volatile unsigned long reserved8 [0x2F];   // 0x4050-0144 through 0x4050-01FC
++                            // Primary Audio CODEC registers access
++    volatile unsigned long codec_regs_primary_aud   [ZY_AC97_CODEC_REGS_NUM];
++                            // Secondary ID 01 Audio CODEC registers access
++    volatile unsigned long codec_regs_secondary_aud [ZY_AC97_CODEC_REGS_NUM];
++                            // Primary MODEM CODEC registers access
++    volatile unsigned long codec_regs_primary_mdm   [ZY_AC97_CODEC_REGS_NUM];
++                            // Secondary ID 01 MODEM CODEC registers access
++    volatile unsigned long codec_regs_secondary_mdm [ZY_AC97_CODEC_REGS_NUM];
++                            // Secondary ID 10 MODEM CODEC registers access
++    volatile unsigned long codec_regs_third_mdm [ZY_AC97_CODEC_REGS_NUM];
++                            // Secondary ID 11 MODEM CODEC registers access
++    volatile unsigned long codec_regs_fouth_mdm [ZY_AC97_CODEC_REGS_NUM];
++                            // Secondary ID 10 Audio CODEC registers access
++    volatile unsigned long codec_regs_third_aud [ZY_AC97_CODEC_REGS_NUM];
++                            // Secondary ID 11 Audio CODEC registers access
++    volatile unsigned long codec_regs_fouth_aud [ZY_AC97_CODEC_REGS_NUM];
++}  zy_ac97_acodec_t, *p_zy_ac97acodec_t ;
++
++
++/* Constants for the Global Control Register and Global Status Register */
++
++// AC97 Global Control Register bit mask constants
++
++#define ZY_AC97_GCR_GIE_MSK          (1u << 0 )
++#define ZY_AC97_GCR_COLD_RESET_MSK   (1u << 1 )
++#define ZY_AC97_GCR_WARM_RESET_MSK   (1u << 2 )
++#define ZY_AC97_GCR_LINK_OFF_MSK     (1u << 3 )
++#define ZY_AC97_GCR_PCRSM_IEN_MSK    (1u << 4 )
++#define ZY_AC97_GCR_SCRSM_IEN_MSK    (1u << 5 )
++#define ZY_AC97_GCR_PCRDY_IEN_MSK    (1u << 8 )
++#define ZY_AC97_GCR_SCRDY_IEN_MSK    (1u << 9 )
++#define ZY_AC97_GCR_SDONE_IE_MSK     (1u << 18)
++#define ZY_AC97_GCR_CDONE_IE_MSK     (1u << 19)
++#define ZY_AC97_GCR_nDMAEN_MSK       (1u << 24)
++#define ZY_AC97_GCR_CLKBPB_MSK       (1u << 31)
++#define ZY_AC97_GCR_FRCRST_MSK       (1u << 30)
++// Global Status Register bit mask constants
++
++#define ZY_AC97_GSR_GSCI_MSK       (1u << 0 )
++#define ZY_AC97_GSR_MIINT_MSK      (1u << 1 )
++#define ZY_AC97_GSR_MOINT_MSK      (1u << 2 )
++#define ZY_AC97_GSR_ACOFFD_MSK     (1u << 3 )
++#define ZY_AC97_GSR_PIINT_MSK      (1u << 5 )
++#define ZY_AC97_GSR_POINT_MSK      (1u << 6 )
++#define ZY_AC97_GSR_MINT_MSK       (1u << 7 )
++#define ZY_AC97_GSR_PCRDY_MSK      (1u << 8 )
++#define ZY_AC97_GSR_SCRDY_MSK      (1u << 9 )
++#define ZY_AC97_GSR_PCRSM_MSK      (1u << 10)
++#define ZY_AC97_GSR_SCRSM_MSK      (1u << 11)
++#define ZY_AC97_GSR_SLT12_BITS_MSK (7u << 12)
++#define ZY_AC97_GSR_RCS_ERR_MSK    (1u << 15)
++#define ZY_AC97_GSR_SDONE_MSK      (1u << 18)
++#define ZY_AC97_GSR_CDONE_MSK      (1u << 19)
++
++
++// Bit mask and values for CAIP bit in car register.
++#define ZY_AC97_CAR_CAIP_MSK       (0x1<<0)
++#define ZY_AC97_CAR_CAIP_LOCKED    (0x1<<0)
++#define ZY_AC97_CAR_CAIP_CLEAR     (0<<0)
++
++/* Constants for FIFO status reporting and control */
++
++// One bit location is used to report FIFO error conditions and clear
++//  interrupts on those conditions in the various non-global status registers.
++
++// ZY_AC97_FIFOSTAT_FIFOE is used in:
++                                                // posr
++                                                // pisr
++                                                // mcsr
++                                                // mosr
++                                                // misr
++
++#define ZY_AC97_FIFOSTAT_FIFOE  (1u << 4)
++#define ZY_AC97_FIFOSTAT_EOC    (1u << 3)
++#define ZY_AC97_FIFOSTAT_FSR    (1u << 2)
++
++// A different bit location is used to enable or disable interrupts based on
++//  FIFO error conditions in the various non-global control registers.
++
++// ZY_AC97_FIFOCTRL_FEIE is used in:
++                                                // pocr
++                                                // picr
++                                                // mccr
++                                                // mocr
++                                                // micr
++
++#define ZY_AC97_FIFOCTRL_FEIE  (1u << 3)
++#define ZY_AC97_FIFOCTRL_FSRIE (1u << 1)
++
++/*
++*******************************************************************************
++    AC'97 Codec Registers Location and Bit Definition
++*******************************************************************************
++*/
++
++/* */
++
++    // Includes symbolic values for certain proprietary register asssignments
++    //   in AC'97 devices that might be used with ZY_AC97.
++
++    // Valid for subset of R 2.1 specification.
++    // Leading "e" in comment means it is an "expanded" register definition as
++    //  found in one or more of the Appendices A-D of the R 2.1 specification.
++    //  Appendix identifier will immediately follow the "e", such as "eA"
++    // R/O indicates read-only
++    // Registers not supported by the assumed controller will be commented out.
++
++#define    ZY_AC97_CR_RESET_ID             0x00  // RESET CODEC TO DEFAULT, get ID info
++#define    ZY_AC97_CR_MASTER_VOLUME        0x02  // LINE OUT VOLUME
++#define    ZY_AC97_CR_HEADPHONE_VOLUME     0x04  //
++#define    ZY_AC97_CR_MASTER_VOLUME_MONO   0x06  //
++#define    ZY_AC97_CR_MASTER_TONE_R_L      0x08  //
++#define    ZY_AC97_CR_PC_BEEP_VOLUME       0x0A  //
++#define    ZY_AC97_CR_PHONE_VOLUME         0x0C  //
++#define    ZY_AC97_CR_MIC_VOLUME           0x0E  //   micrOPHONE VOLUME/ AGC
++#define    ZY_AC97_CR_LINE_IN_VOLUME       0x10  //   LINE IN VOLUME
++#define    ZY_AC97_CR_CD_VOLUME            0x12  //
++#define    ZY_AC97_CR_VIDEO_VOLUME         0x14  //
++#define    ZY_AC97_CR_AUX_VOLUME           0x16  //
++#define    ZY_AC97_CR_PCM_OUT_VOLUME       0x18  //
++#define    ZY_AC97_CR_RECORD_SELECT        0x1A  //   SELECT LINE IN OR micrOPHONE
++#define    ZY_AC97_CR_RECORD_GAIN          0x1C  //
++#define    ZY_AC97_CR_RECORD_GAIN_MIC      0x1E  //
++#define    ZY_AC97_CR_GENERAL_PURPOSE      0x20  //
++#define    ZY_AC97_CR_CONTROL_3D           0x22  //
++#define    ZY_AC97_CR_POWERDOWN_CTRL_STAT  0x26  //   POWER MANAGEMENT
++#define    ZY_AC97_CR_E_AUDIO_ID           0x28  // eA Extended audio sprt info, R/O
++#define    ZY_AC97_CR_E_AUDIO_CTRL_STAT    0x2A  // eA Extended audio stat + control
++
++//
++// Audio Sample Rate Control Registers, 0x2C - 0x34
++//
++                                           // eA PCM Front DAC rate control
++#define    ZY_AC97_CR_E_ASR_PCM_FRNT_DAC_RT 0x2C  //  (output slots 3, 4, 6)
++#define    ZY_AC97_CR_E_ASR_PCM_LR_ADC_RT   0x32  // eA PCM L+R ADC rate control (3+4)
++#define    ZY_AC97_CR_E_ASR_MIC_ADC_RT      0x34  // eA PCM Mic ADC rate control (5)
++
++
++#define    ZY_AC97_CR_E_MDM_GPIO_PIN_STAT     0x54
++//
++// 5Ah-7Ah: Vendor Reserved
++//
++//
++// 7Ch-7Eh: Vendor ID registers.  Optional but standardized for Plug'n'Play
++//
++#define    ZY_AC97_CR_VENDOR_ID1         0x7C
++#define    ZY_AC97_CR_VENDOR_ID2         0x7E
++
++#define    ZY_AC97_CR_MAX               ZY_AC97_CR_VENDOR_ID2
++
++#define    ZY_AC97_CR_END_OF_LIST       (ZY_AC97_CR_MAX +  2)
++
++
++
++/* Other Constants */
++
++// For accessing the Codec mixer registers, each increment of one 32-bit word
++//  in processor space increments the addressed mixer register by two.
++// This does not cause any ambiguities because only even mixer register
++//  addresses are currently supported (AC '97 spec, R 2.2)
++#define ZY_AC97_CODEC_REGS_PER_WORD           2
++
++/* Default timeout and holdtime settings */
++
++// timeout in reading and writing codec registers through AC link
++#define ZY_AC97_RW_TIMEOUT_DEF                200     //unit is us
++
++// timeout in waiting for codec's ready signal during setup process
++#define ZY_AC97_SETUP_TIMEOUT_DEF             500     //unit is us
++
++// timeout in waiting for locking the link successfully
++#define ZY_AC97_LOCK_TIMEOUT_DEF              300     //unit is us
++
++// timeout in shutting down the link
++#define ZY_AC97_LINKOFF_TIMEOUT_DEF           500     //unit is us
++
++// holdtime for keeping nReset signal active(low) in AC link
++#define ZY_AC97_COLD_HOLDTIME                 100     //unit is us
++
++/*
++*******************************************************************************
++  ZY AC97 data structure used in function interface
++*******************************************************************************
++*/
++
++typedef struct
++{
++    unsigned long pocr;           // PCM Out Control Register
++    unsigned long picr;           // PCM In Control Register
++    unsigned long mccr;           // Mic In Control Register
++    unsigned long gcr;            // Global Control Register
++    unsigned long pcscr;          // PCM Surround Out Control
++    unsigned long pcclcr;         // PCM Center/LFE Out Control
++    unsigned long mocr;           // MODEM Out Control Register
++    unsigned long micr;           // MODEM In Control Register
++}zy_ac97_save_context_t;
++
++
++#define AC97_SAVE_CONTEXT_SIZE (sizeof(zy_ac97_save_context_t))
++
++static int zy_ac97_acodec_link_lock(p_zy_ac97acodec_t p_ac97_reg)
++{
++      int             status = 1;
++      volatile unsigned long  car_tmp;
++
++      car_tmp = p_ac97_reg->car;
++      if (car_tmp & ZY_AC97_CAR_CAIP_MSK)     /*  "1" in CAIP bit means lock failed. */
++      {
++              status = 0;
++      }
++      return (status);
++}
++
++
++zy_acodec_error_t zy_ac97_acodec_write (zy_acocec_context_t *p_dev_context, unsigned short offset, unsigned short data)
++{
++      zy_acodec_error_t       status = ZY_ACODEC_SUCCESS;
++      int                     got_link;
++      unsigned long           time_remaining;
++      volatile unsigned long *        p_codec_reg;
++      p_zy_ac97acodec_t p_ac97_reg = (p_zy_ac97acodec_t)(p_dev_context->p_ctrl_reg);
++      unsigned long max_rw_time_out_us = (p_dev_context->u_max_read_write_time_out_ms) * 1000;
++
++
++      if(offset == ZY_AC97_CR_E_MDM_GPIO_PIN_STAT)
++      {/* it is a special register and sent out on slot 12 */
++              p_codec_reg = &(p_ac97_reg->codec_regs_primary_mdm[0]);
++              p_codec_reg += offset / ZY_AC97_CODEC_REGS_PER_WORD;
++              /*  The data will be sent out on slot 12. */
++              *p_codec_reg = (unsigned long)data;
++              goto done;
++      }
++
++      /*  Point to specified register within area mapped to target codec regs */
++      p_codec_reg = &(p_ac97_reg->codec_regs_primary_aud[0]);
++      p_codec_reg += offset / ZY_AC97_CODEC_REGS_PER_WORD;
++
++
++      /* Lock the ACLINK */
++      time_remaining = ZY_AC97_LOCK_TIMEOUT_DEF;
++      do
++      {
++              got_link = zy_ac97_acodec_link_lock(p_ac97_reg);
++              if (0 == got_link)      /*  1 usec is a long time.  Skip delay if possible. */
++              {
++                      udelay(1);
++              }
++      }               /*  Wait while time remaining and ACLINK not available */
++      while (time_remaining-- && (0 == got_link));
++
++      if (0 == got_link)      /*  Didn't get the ACLINK */
++      {
++              status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
++              printk(KERN_ERR "AC97 Write Link Timeout\n");
++      }
++      else    /*  We got the link. Perform the write operation and don't wait. */
++      {
++              /*  First, clear old write status indication CDONE by writing a ONE to that bit. */
++              p_ac97_reg->gsr = ZY_AC97_GSR_CDONE_MSK;
++
++              *p_codec_reg = (unsigned long)data;        /*  Now the write! */
++
++              /* Wait until write cycle is complete. There should be a way
++               * to do this speculatively at the beginning of the procedure.
++               * Need to discover it. Too inefficient to always wait.
++               */
++
++              time_remaining = max_rw_time_out_us;
++              do
++              {
++                      udelay(1);
++              }        /*  Wait while time remaining and command I/O still incomplete. */
++              while ( (time_remaining--) && !(p_ac97_reg->gsr & ZY_AC97_GSR_CDONE_MSK));
++              if (!(p_ac97_reg->gsr & ZY_AC97_GSR_CDONE_MSK))
++              {
++                      status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
++                      p_ac97_reg->car = ZY_AC97_CAR_CAIP_CLEAR;
++              }
++      }  /*  Got AC link */
++
++done:
++      return(status);
++} /*  Ac97CtrlCodecWrite() */
++
++#define CKENA         __REG(0x4134000C)       /* A Clock Enable Register */
++#define CKENB         __REG(0x41340010)
++
++zy_acodec_error_t zy_ac97_acodec_read  (zy_acocec_context_t *p_dev_context, unsigned short offset,  unsigned short *pdata)
++{
++      zy_acodec_error_t       status = ZY_ACODEC_SUCCESS;
++      int                     got_link;
++      unsigned long           time_remaining;
++      volatile unsigned long *        p_codec_reg;
++      p_zy_ac97acodec_t p_ac97_reg = (p_zy_ac97acodec_t)(p_dev_context->p_ctrl_reg);
++      unsigned long max_rw_time_out_us = (p_dev_context->u_max_read_write_time_out_ms) * 1000;
++
++      /*  Point to specified register within area mapped to target codec regs */
++      p_codec_reg = &(p_ac97_reg->codec_regs_primary_aud[0]);
++      p_codec_reg += offset / ZY_AC97_CODEC_REGS_PER_WORD;
++
++      /* Lock the ACLINK */
++      time_remaining = ZY_AC97_LOCK_TIMEOUT_DEF;
++      do
++      {
++              got_link = zy_ac97_acodec_link_lock(p_ac97_reg);
++              if (0 == got_link)      /*  1 usec is a long time.  Skip delay if possible. */
++              {
++                      udelay(1);
++              }
++      }               /*  Wait while time remaining and ACLINK not available */
++      while (time_remaining-- && (0 == got_link));
++
++      if (0 == got_link)      /*  Didn't get the ACLINK */
++      {
++              status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
++              printk(KERN_ERR "AC97 Read Link Timeout\n");
++      }
++      else    /*  We got the link. Perform the write operation and don't wait. */
++      {
++               /*  First, clear old read status indications. */
++              p_ac97_reg->gsr = ZY_AC97_GSR_SDONE_MSK | ZY_AC97_GSR_RCS_ERR_MSK;
++
++              *pdata = (unsigned short)(*p_codec_reg); /*  This is THE DUMMY READ. */
++
++               /*  Wait for read I/O with codec to complete before doing real read. */
++              time_remaining = max_rw_time_out_us;
++              do
++              {
++                      udelay(1);
++              }   /*  Wait while time remaining and read I/O still incomplete */
++              while( (time_remaining--) && (!(p_ac97_reg->gsr & ZY_AC97_GSR_SDONE_MSK)) );
++
++              if ((p_ac97_reg->gsr & ZY_AC97_GSR_SDONE_MSK) && (!(p_ac97_reg->gsr & ZY_AC97_GSR_RCS_ERR_MSK)) )
++              {
++                      if (p_ac97_reg->gsr & ZY_AC97_GSR_RCS_ERR_MSK)
++                      {/* timeout indicated by RCS bit */
++                              status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
++                      }
++                      /*  succeed in reading. clear status bits first. */
++                      p_ac97_reg->gsr = ZY_AC97_GSR_SDONE_MSK | ZY_AC97_GSR_RCS_ERR_MSK;
++                      *pdata = (unsigned short)(*p_codec_reg);        /*  THE REAL READ. */
++                      if (*pdata == 0xffff)
++                      {/* timeout indicated by returned value */
++                              status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
++                      }
++                      /* check later: is second waiting really needed? */
++                      time_remaining = max_rw_time_out_us;
++                      do
++                      {
++                              udelay(1);
++                      }   /*  Wait while time remaining and read I/O still incomplete */
++                      while( (time_remaining--) && (!(p_ac97_reg->gsr & ZY_AC97_GSR_SDONE_MSK)) );
++                      //printk(KERN_ERR "AC97 Read Result %d\n", (p_ac97_reg->gsr & ZY_AC97_GSR_SDONE_MSK) );
++              }
++              else    /*  failed */
++              {
++                      status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
++                      p_ac97_reg->car = ZY_AC97_CAR_CAIP_CLEAR;
++                      //printk(KERN_ERR "AC97 Read Link Timeout2 %x %x %x\n", CKENA, OSCC, CKENB);
++              } /*  else  (OK to do real read) */
++
++      } /*  else  (We got the link.  Perform the read operations.) */
++
++      return (status);
++}
++
++
++
++zy_acodec_error_t zy_acodec_get_adc_sample(zy_acocec_context_t *p_device_context, unsigned short *p_sample_data, unsigned short adc_type, int *p_pen_down)
++{
++      zy_acodec_error_t       status = ZY_ACODEC_SUCCESS;
++      unsigned short value;
++      unsigned long wait;
++
++      if (adc_type == ZY_TOUCH_SAMPLE_X)
++      {
++              value = 0x202;
++      }
++      else
++      {/* Y sample */
++              value = 0x204;
++      }
++
++      status = zy_ac97_acodec_write(p_device_context, DIGITIZER_1_WM13, value);
++
++      wait = 0;
++      do
++      {
++              status = zy_ac97_acodec_read(p_device_context, DIGITIZER_1_WM13, &value);
++              if ( !(value & 0x200 ) )
++              {
++                      break;
++              }
++      }while ( 100 > wait++ );
++
++      status = zy_ac97_acodec_read(p_device_context, DIGITIZER_READ_BACK, &value);
++      if (value & 0x8000)
++      {/* means pen down */
++              *p_pen_down = 1;
++      }
++      else
++      {
++              *p_pen_down = 0;
++      }
++      *p_sample_data = value & 0xfff;
++
++      return status;
++}
++
++
++
++/*
++ * add a touch event
++ */
++static int codec_zy_ts_evt_add(codec_zy_ts_t* ts, u16 pressure, u16 x, u16 y)
++{
++        /* add event and remove adc src bits */
++        static u16 pre_press = 0;
++
++        input_report_abs(ts->idev, ABS_X, x & 0xfff);
++        input_report_abs(ts->idev, ABS_Y, y & 0xfff);
++        if (pressure == pre_press){
++                pressure--;
++        }
++        pre_press = pressure;
++        input_report_abs(ts->idev, ABS_PRESSURE, pressure & 0xfff);
++      input_sync(ts->idev);
++#ifdef CONFIG_IPM
++      ipm_event_notify(IPM_EVENT_UI, IPM_EVENT_DEVICE_TSI, NULL, 0);
++#endif
++        return 0;
++}
++
++/*
++ * add a pen up event
++ */
++static void codec_zy_ts_evt_release(codec_zy_ts_t* ts)
++{
++      input_report_abs(ts->idev, ABS_PRESSURE, 0);
++      input_sync(ts->idev);
++
++#ifdef CONFIG_IPM
++      ipm_event_notify(IPM_EVENT_UI, IPM_EVENT_DEVICE_TSI, NULL, 0);
++#endif
++      p_zy_codec_ctxt->g_pfn_event_ack(p_zy_codec_ctxt,ZY_EVENT_TYPE_PDN);
++}
++
++/*
++ * Kill the touchscreen thread and stop
++ * the touch digitiser.
++ */
++static void codec_zy_ts_input_close(struct input_dev *idev)
++{
++      codec_zy_ts_t *ts = (codec_zy_ts_t *) &codec_zy_ts;
++
++#ifdef CONFIG_PM
++      if(touch_suspend){
++              pr_info("touch is suspended!\n");
++              return -1;
++      }
++#endif
++      dbg("close ts input!\n");
++      if (--ts->use_count == 0) {
++              del_timer(ts->timer);
++              if (ts->timer != NULL)
++                      kfree(ts->timer);
++              p_zy_codec_ctxt->g_pfn_disable_touch(p_zy_codec_ctxt);
++      }
++}
++
++/*
++ * Sample the touchscreen
++ */
++int ac97_poll_touch(codec_zy_ts_t *ts)
++{
++      unsigned short x=0, y=0;
++      int if_down= 0;
++      zy_acodec_error_t status = ZY_ACODEC_SUCCESS;
++
++#ifdef DEBUG
++        start_time = OSCR;
++#endif
++
++      /* get x value */
++      status = zy_acodec_get_adc_sample(p_zy_codec_ctxt, &x, ZY_TOUCH_SAMPLE_X, &if_down);
++      if (ZY_ACODEC_SUCCESS != status ){
++              return -EIO;
++      }
++      dbg("x:0x%x\n", x);
++
++      /* the pen is up */
++      if (1 != if_down){
++              return PEN_UP;
++      }
++
++      /* get y vaule */
++      status = zy_acodec_get_adc_sample(p_zy_codec_ctxt, &y, ZY_TOUCH_SAMPLE_Y, &if_down);
++      if (ZY_ACODEC_SUCCESS != status ){
++              return -EIO;
++      }
++      dbg("y:0x%x\n",y);
++
++      /* the pen is up */
++      if (1 != if_down){
++              return PEN_UP;
++      }
++
++      /* the pen is down, can not get the pressure value,
++       * so if pen is down, give the max pressure value
++       */
++      codec_zy_ts_evt_add(ts,0xfff, x, y);
++
++#ifdef DEBUG
++        end_time = OSCR;
++        PRINT_TIME();
++#endif
++
++      return PEN_DOWN;
++}
++
++static void touch_timer_handler(unsigned long unused)
++{
++      int event;
++      codec_zy_ts_t *ts = &codec_zy_ts;
++
++      event = ac97_poll_touch(ts);
++
++      if (event == PEN_DOWN) {
++              dbg("pen down!\n");
++              ts->timer->expires = jiffies + TS_SAMPLE_INTERVAL;
++              add_timer(ts->timer);
++      } else if(event == PEN_UP) {
++              dbg("pen up!\n");
++              codec_zy_ts_evt_release(ts);
++      } else if(event == -EIO) {
++              printk(KERN_ERR "Access touch interface error!\n");
++      }
++      return;
++}
++
++static zy_acodec_error_t  zy_ac97_acodec_cold_reset(zy_acocec_context_t * p_ac97_ctxt)
++{
++      zy_acodec_error_t       status = ZY_ACODEC_SUCCESS;
++      p_zy_ac97acodec_t p_ac97 = (p_zy_ac97acodec_t)(p_ac97_ctxt->p_ctrl_reg);
++      int              pri_codec_ready;
++      unsigned long           time_remaining;
++
++      p_ac97->gcr = 0;
++      p_ac97->gcr |= ZY_AC97_GCR_CLKBPB_MSK;
++      /*  Hold reset active for a minimum time */
++      udelay(ZY_AC97_COLD_HOLDTIME);
++      p_ac97->gcr &= ~ZY_AC97_GCR_CLKBPB_MSK;
++
++      /*  Deactivate cold reset condition */
++      p_ac97->gcr |= (ZY_AC97_GCR_COLD_RESET_MSK | ZY_AC97_GCR_WARM_RESET_MSK);
++
++
++      pri_codec_ready = 0;
++      time_remaining = (p_ac97_ctxt->u_max_setup_time_out_ms) * 10;
++      do
++      {
++              udelay(1);
++              if (p_ac97->gsr & ZY_AC97_GSR_PCRDY_MSK)
++                      pri_codec_ready = 1;
++      }
++      while (time_remaining-- && (pri_codec_ready == 0));
++
++      /*  Timeout status if some of the devices weren't ready. */
++      if (pri_codec_ready == 0)
++      {
++              status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
++      }
++
++      return (status);
++}
++
++
++zy_acodec_error_t  zy_ac97_acodec_init(zy_acocec_context_t *p_ac97_ctxt)
++{
++      zy_acodec_error_t       status ;
++
++      status = zy_ac97_acodec_cold_reset(p_ac97_ctxt);
++
++      return (status);
++}
++
++
++/*
++ * Start the touchscreen thread and
++ * the touch digitiser.
++ */
++static int codec_zy_ts_input_open(struct input_dev *idev)
++{
++      codec_zy_ts_t *ts = (codec_zy_ts_t *) &codec_zy_ts;
++
++#ifdef CONFIG_PM
++      if(touch_suspend){
++              pr_info("touch is suspended!\n");
++              return -1;
++      }
++#endif
++
++      if (ts->use_count++ > 0)
++              return 0;
++
++      dbg("Touch is opened. Use count: %d\n", ts->use_count);
++      ts->idev = idev;
++      ts->timer = kmalloc(sizeof(struct timer_list), GFP_KERNEL);
++      if (!ts->timer) {
++              printk(KERN_ERR "Alloc memory error for timer!\n");
++              return -ENOMEM;
++      }
++
++      init_timer(ts->timer);
++      ts->timer->function = touch_timer_handler;
++      ts->timer->data = 0;
++      p_zy_codec_ctxt->g_pfn_enable_touch(p_zy_codec_ctxt);
++
++      return 0;
++}
++
++/*
++ * initilze the pxa touch screen
++ */
++static int alsa_ts_init( void )
++{
++      codec_zy_ts_t* ts = &codec_zy_ts;
++
++      memset(ts, 0, sizeof(codec_zy_ts_t));
++
++      codec_zy_ts_input = input_allocate_device();
++      if (!codec_zy_ts_input)
++              return -ENOMEM;
++
++
++      /* tell input system what we events we accept and register */
++      codec_zy_ts_input->name = "codec zy touchscreen";
++      codec_zy_ts_input->open = codec_zy_ts_input_open;
++      codec_zy_ts_input->close = codec_zy_ts_input_close;
++      __set_bit(EV_ABS, codec_zy_ts_input->evbit);
++      __set_bit(ABS_X, codec_zy_ts_input->absbit);
++      __set_bit(ABS_Y, codec_zy_ts_input->absbit);
++      __set_bit(ABS_PRESSURE, codec_zy_ts_input->absbit);
++      input_register_device(codec_zy_ts_input);
++
++      return 0;
++}
++
++static irqreturn_t pxa_touch_irq(int irq, void *dev)
++{
++      unsigned char event_type;
++
++      //printk(KERN_ERR "%s: enter codec event handler\n", __FUNCTION__);
++
++      dbg("%s: enter codec event handler\n", __FUNCTION__);
++      p_zy_codec_ctxt->g_pfn_get_event(p_zy_codec_ctxt, &event_type);
++      switch (event_type) {
++              case ZY_EVENT_TYPE_PDN:
++              {
++                      codec_zy_ts_t *ts = &codec_zy_ts;
++                      /*if the touch is not open need not acknowledge the event*/
++                      if (ts->use_count <= 0)
++                              break;
++                      ts->timer->expires = jiffies + TS_SAMPLE_INTERVAL;
++                      add_timer(ts->timer);
++                      break;
++              }
++              default:
++                      printk("unsupported codec event:0x%x\n", event_type);
++      }
++
++      return IRQ_HANDLED;
++}
++
++
++
++
++
++
++
++
++
++static mfp_cfg_t extra_cfg[] = {
++      MFP_CFG_X(GPIO17, AF3, DS03X, PULL_LOW),
++      MFP_CFG_X(GPIO25, AF0, DS01X, PULL_LOW),
++};
++
++#define ARRAY_AND_SIZE(x)     (x), ARRAY_SIZE(x)
++
++extern void dump_mfp(void);
++
++zy_acodec_error_t     zy_ac97_acodec_mfp_init(zy_acocec_context_t *p_device_context)
++{
++      unsigned short codec_id;
++
++      //mhn_mfp_set_afds(MFP_RSVD_AC97_SDATA_IN_0, MFP_AF0, MFP_DS03X);
++      //enable_ac97_pins();
++      zy_ac97_acodec_init(p_device_context);
++      if (zy_ac97_acodec_read(p_device_context, 0x0, &codec_id)){
++
++              /*
++               * there is a bug on MonahansL/MonhansPL PC card: AC97_SDATA_IN is not connected to CODEC
++               * ECO 72: Connect PWM_0(MFP_RSVD_AC97_SDATA_IN_0) to CODEC as AC97_SDATA_IN
++               */
++
++              //mhn_mfp_set_afds(MFP_RSVD_AC97_SDATA_IN_0, MFP_RSVD_AC97_SDATA_IN_0_AF, MFP_DS03X);
++              //mhn_mfp_set_afds(MFP_AC97_SDATA_IN_0, MFP_AF0, MFP_DS01X);
++
++              gpio_direction_output(mfp_to_gpio(MFP_PIN_GPIO17), 0);
++              pxa3xx_mfp_config(ARRAY_AND_SIZE(extra_cfg));
++              gpio_direction_input(mfp_to_gpio(MFP_PIN_GPIO25));
++      }
++
++
++      return ZY_ACODEC_SUCCESS;
++}
++
++#define ZY_AC97_WM9713_GPIO_PIN_PDN ( 0x1 << 13 )  /* Pen down */
++
++/*power enable bit in 3ch and 3eh */
++/*3ch */
++#define ZY_AC97_9713_PWR_PADCPD   ( 0x1 << 15 )
++#define ZY_AC97_9713_PWR_VMID     ( 0x1 << 14 )
++#define ZY_AC97_9713_PWR_TSHUT    ( 0x1 << 13 )
++#define ZY_AC97_9713_PWR_VXDAC    ( 0x1 << 12 )
++#define ZY_AC97_9713_PWR_AUXDAC   ( 0x1 << 11 )
++#define ZY_AC97_9713_PWR_MBIAS    ( 0x1 << 10 )
++#define ZY_AC97_9713_PWR_PLL      ( 0x1 << 9 )
++#define ZY_AC97_9713_PWR_DACL     ( 0x1 << 7 )
++#define ZY_AC97_9713_PWR_DACR     ( 0x1 << 6 )
++#define ZY_AC97_9713_PWR_ADCL     ( 0x1 << 5 )
++#define ZY_AC97_9713_PWR_ADCR     ( 0x1 << 4 )
++#define ZY_AC97_9713_PWR_HPLX     ( 0x1 << 3 )
++#define ZY_AC97_9713_PWR_HPRX     ( 0x1 << 2 )
++#define ZY_AC97_9713_PWR_SPKX     ( 0x1 << 1 )
++#define ZY_AC97_9713_PWR_MX       ( 0x1 << 0 )
++
++/*3EH */
++#define ZY_AC97_9713_PWR_MCD      ( 0x1 << 15 )
++#define ZY_AC97_9713_PWR_MICBIAS  ( 0x1 << 14 )
++#define ZY_AC97_9713_PWR_MONO     ( 0x1 << 13 )
++#define ZY_AC97_9713_PWR_OUT4     ( 0x1 << 12 )
++#define ZY_AC97_9713_PWR_OUT3     ( 0x1 << 11 )
++#define ZY_AC97_9713_PWR_HPL      ( 0x1 << 10 )
++#define ZY_AC97_9713_PWR_HPR      ( 0x1 << 9 )
++#define ZY_AC97_9713_PWR_SPKL     ( 0x1 << 8 )
++#define ZY_AC97_9713_PWR_SPKR     ( 0x1 << 7 )
++#define ZY_AC97_9713_PWR_LL       ( 0x1 << 6 )
++#define ZY_AC97_9713_PWR_LR       ( 0x1 << 5 )
++#define ZY_AC97_9713_PWR_MOIN     ( 0x1 << 4 )
++#define ZY_AC97_9713_PWR_MA       ( 0x1 << 3 )
++#define ZY_AC97_9713_PWR_MB       ( 0x1 << 2 )
++#define ZY_AC97_9713_PWR_MPA      ( 0x1 << 1 )
++#define ZY_AC97_9713_PWR_MPB      ( 0x1 << 0 )
++
++
++void zy_wm9713_get_event(zy_acocec_context_t *p_device_context, unsigned char * event_type)
++{
++      unsigned short event_state = 0;
++      zy_ac97_acodec_read(p_device_context, GPIO_PIN_STATUS, &event_state);
++      if(event_state & ZY_AC97_WM9713_GPIO_PIN_PDN){
++              *event_type = ZY_EVENT_TYPE_PDN;
++              return;
++      }
++      return;
++}
++
++void zy_wm9713_event_ack(zy_acocec_context_t *p_device_context, unsigned char event_type)
++{
++      unsigned short event_state = 0;
++      zy_ac97_acodec_read(p_device_context, GPIO_PIN_STATUS, &event_state);
++      if( event_type == ZY_EVENT_TYPE_PDN){
++              zy_ac97_acodec_write(p_device_context,
++                                      GPIO_PIN_STATUS,
++                                      (event_state & (~ZY_AC97_WM9713_GPIO_PIN_PDN)));
++      }
++
++      zy_ac97_acodec_read(p_device_context, GPIO_PIN_STATUS, &event_state);
++      return;
++}
++
++static void * p_saved_memory = NULL;
++static void * p_zy_scenario = NULL;
++static p_zy_acocec_context_t p_zy_ctxt = NULL;
++
++#define WM9713_SAVE_REGISTER_NO (64-11)
++typedef struct {
++    unsigned short wm9713RegisterContext [WM9713_SAVE_REGISTER_NO + 1]; /* Fixed (data misalignment error) */
++}ZY_9713_CONTEXT_SAVE_T;
++
++
++/**
++ * alsa_prepare_for_zy - create and initialize the p_zy_acocec_context_t
++ *                               open the clock of data link
++ * @p_p_zy_ctxt: return the data structure p_zy_acocec_context_t
++ * return: 0 success ; -ENOMEM
++ **/
++int alsa_prepare_for_zy(p_zy_acocec_context_t * p_p_zy_ctxt)
++{
++      if (p_zy_ctxt) {
++              p_zy_ctxt->use_count++;
++              *p_p_zy_ctxt = p_zy_ctxt;
++              return 0;
++      }
++
++      p_zy_ctxt = kzalloc(sizeof(zy_acocec_context_t), GFP_KERNEL);
++      if (!p_zy_ctxt)
++              return -ENOMEM;
++
++      /* enable CLK_POUT as CODEC clock input */
++      OSCC |= 0x800;
++
++      p_saved_memory = kzalloc(sizeof(ZY_9713_CONTEXT_SAVE_T) +
++                              sizeof(zy_ac97_save_context_t), GFP_KERNEL);
++      if (NULL == p_saved_memory) {
++              if (p_zy_ctxt)
++                      kfree(p_zy_ctxt);
++              return -ENOMEM;
++      }
++
++      p_zy_ctxt->acodec_id = (zy_acodec_device_id_t) (WM_9713_ID);
++      p_zy_ctxt->use_count++;
++      /*
++      p_zy_ctxt->pMfpRegBase = (unsigned long) (MFP_BASE);
++      p_zy_ctxt->pMfpRmDb = ZY_MFP_RM_DATABASE;
++      p_zy_ctxt->p_ost_regs = OST_BASE;
++      */
++      p_zy_ctxt->p_voice_reg = NULL;
++      p_zy_ctxt->p_hifi_reg = (void *) (&POCR);
++      p_zy_ctxt->p_ctrl_reg = (void *) (&POCR);
++      p_zy_ctxt->u_max_read_write_time_out_ms = ZY_AC97_RW_TIMEOUT_DEF;
++      p_zy_ctxt->u_max_setup_time_out_ms = ZY_AC97_SETUP_TIMEOUT_DEF;
++      p_zy_ctxt->p_save_memory = p_saved_memory;
++      p_zy_ctxt->p_zy_scenario = p_zy_scenario;
++//    pxa_set_cken(24, 1);
++      CKENA |= (1 << 24);
++      AC97_DIV = 1625<<12 | 128;
++#ifdef DEBUG_ALSA_ZY
++      debug_pac97ctxt = p_zy_ctxt;
++      misc_register(&audio_dev);
++#endif
++
++      (*p_p_zy_ctxt) = p_zy_ctxt;
++
++      return 0;
++}
++
++
++/* this is platform specific */
++/* do later: not to enable recording route and playback route in this function,
++ * leave it to driver to call other function
++ */
++zy_acodec_error_t zy_wm9713_specific_init (zy_acocec_context_t *p_device_context)
++{
++
++      unsigned short value;
++
++      /* this assumes that the aclink is initialized wait some time and then
++       * do a warm reset to enabled the ACLINK, required for wm9713
++       * (not wm9712 or ucb1400)
++       */
++
++      /* pay attention: whether the workaround is still needed? */
++      p_zy_ac97acodec_t p_ac97_reg = (p_zy_ac97acodec_t)(p_device_context->p_ctrl_reg);
++
++      p_ac97_reg->gcr |= ZY_AC97_GCR_WARM_RESET_MSK;
++
++      mdelay(5);
++
++      /* power on all the necessary unit */
++      zy_ac97_acodec_write(p_device_context,POWERDOWN_CTRL_STAT, 0x000);      /*26*/
++      /* open left headphone mixer */
++      /* open right headphone mixer */
++      /* open right/left dac */
++      /* open right/left adc */
++      /* open temperature sensor */
++      /* enable reference generator */
++      zy_ac97_acodec_write(p_device_context,POWER_DOWN_1, 0xda00);            /*3c */
++      /* open microphone bias */
++      /* open HPL output PGA */
++      /* open HPR output PGA */
++      /* open mic PGA MA */
++      /* open mic pre-amp MPA */
++      /* if here we enable SPKL and SPKR PGA, then Touch screen will doesn't work */
++      zy_ac97_acodec_write(p_device_context,POWER_DOWN_2,0xb9f5);   /*3e */
++
++      /* recording route and microphone input */
++      /* microphone selection, now fixed to MIC1 input and mic bias output */
++      /* MIC1 only, MICBIAS enable */
++      zy_ac97_acodec_write (p_device_context, MIC_BIAS, 0xC440);      /*0x22h*/
++
++      /* mic pga setting to mixer (side tone) */
++      /* comment the below code to make MICA/B play back volume gain + 0db */
++      /* zy_ac97_acodec_write (p_device_context, MIC_PGA_VOLUME, 0x0000); */  /*0x0eh*/
++
++      /* recording side tone and ADC boost, now fixed to default (14h) */
++      /* recording volume  0dB */
++      zy_ac97_acodec_write(p_device_context, REC_PGA_VOL, 0x0); /*12*/
++
++      /* hifi playback route and output mixer  */
++      /* by default, fixed to enable headphone only */
++
++      /* comment the below code to make SPEAKER default MUTE */
++      zy_ac97_acodec_write (p_device_context, SPEAKER_VOLUME, 0x0);           /*02*/
++
++      /* comment the below code to make OUT3_OUT4 default MUTE */
++      /* zy_ac97_acodec_write (p_device_context, OUT3_OUT4_VOLUME, 0x8000); */        /*06*/
++
++      /* remove all  the mute bit  volume gain + 0db  */
++      zy_ac97_acodec_write(p_device_context, HEADPHONE_VOLUME, 0x0);  /*04*/
++
++      /* DAC route */
++      /* open DAC to headphone mixer path */
++      /* left DAC gain +0db */
++      /* right DAC gain +0db */
++      zy_ac97_acodec_write(p_device_context, DAC_PGA_VOL_ROUTE,0x0808);       /*0c*/
++
++      /* out3 configure, invert to HPMIXR */
++      /* zy_ac97_acodec_write(p_device_context,DAC_3D_CTRL_INV_MUX_SEL, 0x8000); */   /*1e*/
++
++      /* output control */
++       /* select HPMIXR HPMIXL out */
++       /* other out are all VIM */
++      zy_ac97_acodec_write(p_device_context,OUTPUT_PGA_MUX, 0x9BA8);          /*1c*/
++
++      /* set sample rates */
++      /* enable variable rate conversion */
++      zy_ac97_acodec_write(p_device_context, EXTENDED_AUD_STAT_CTRL , 0x1); /*2a*/
++      /*  DAC 44kHZ */
++      zy_ac97_acodec_write(p_device_context,AUDIO_DAC_RATE,0xac44); /*2c*/
++      /*  ADC 16KHZ */
++      zy_ac97_acodec_write(p_device_context,AUDIO_ADC_RATE,0x3E80); /*32*/
++
++      /* clock scheme, use external clock, it is 24MHZ from MCLK_A */
++
++
++      zy_ac97_acodec_read(p_device_context, MCLK_PLL_CTRL_1, &value);
++      zy_ac97_acodec_write(p_device_context, MCLK_PLL_CTRL_1, value | 0x2);
++
++      return ZY_ACODEC_SUCCESS;
++}
++
++zy_acodec_error_t zy_wm9713_specific_deinit (zy_acocec_context_t *p_device_context)
++{/* do later: shut down all power */
++      unsigned short value = 0;
++
++      /* close the power of all units */
++      zy_ac97_acodec_write(p_device_context, POWER_DOWN_1, 0xffff);
++      zy_ac97_acodec_write(p_device_context, POWER_DOWN_2, 0xffff);
++      zy_ac97_acodec_read(p_device_context, POWER_DOWN_1, &value);
++      value &= ~(ZY_AC97_9713_PWR_MBIAS);
++      zy_ac97_acodec_write(p_device_context, POWER_DOWN_1, value);
++
++      return ZY_ACODEC_SUCCESS;
++}
++
++zy_acodec_error_t zy_acodec_set_pen_down_interrupt(zy_acocec_context_t *p_device_context, int enable)
++{/* disable/enable pen down interrupt in the codec. This function is not implemented for Wm9713 */
++      /* because the pen down detection could not be disabled in codec */
++      return ZY_ACODEC_SUCCESS;
++}
++
++zy_acodec_error_t zy_wm9713_enable_touch(zy_acocec_context_t *p_device_context)
++{/* enable touch functionality in the codec */
++      zy_acodec_error_t       status = ZY_ACODEC_SUCCESS;
++      unsigned short value;
++
++      /* power setting */
++      status = zy_ac97_acodec_read(p_device_context, POWER_DOWN_1, &value);
++      value &= ~(ZY_AC97_9713_PWR_PADCPD);
++      status = zy_ac97_acodec_write(p_device_context, POWER_DOWN_1, value);
++
++      /* basic touch setting   */
++      status = zy_ac97_acodec_write(p_device_context, DIGITIZER_3_WM13, 0xc008);
++      status = zy_ac97_acodec_write(p_device_context, DIGITIZER_2_WM13, 0x6);
++
++
++      /* 9713 powerdown virtual gpio setting (polarity, sticky, wakeup) */
++      /* 9713 gpio 2(pin45) route to IRQ */
++      /*  Notes: Can use defaults for IRQ polarity, PENDOWN polarity in IRQ, */
++      /*   sticky for PENDOWN in IRQ and wakeup for PENDOWN.   */
++      status = zy_ac97_acodec_read(p_device_context, GPIO_PIN_CFG, &value);
++      value &= ~(0x4);
++      status = zy_ac97_acodec_write(p_device_context, GPIO_PIN_CFG, value);
++
++      status = zy_ac97_acodec_read(p_device_context, GPIO_PIN_SHARING, &value);
++      value &= ~(0x4);
++      status = zy_ac97_acodec_write(p_device_context, GPIO_PIN_SHARING, value);
++
++      status = zy_ac97_acodec_read(p_device_context, GPIO_PIN_WAKEUP, &value);
++      value |= (0x2000);
++      status = zy_ac97_acodec_write(p_device_context, GPIO_PIN_WAKEUP, value);
++
++      status = zy_ac97_acodec_read(p_device_context, GPIO_PIN_STICKY, &value);
++      value |= (0x2000);
++      status = zy_ac97_acodec_write(p_device_context, GPIO_PIN_STICKY, value);
++
++      return status;
++}
++
++zy_acodec_error_t zy_wm9713_disable_touch(zy_acocec_context_t *p_device_context)
++{/* disable touch functionality in the codec */
++      zy_acodec_error_t       status = ZY_ACODEC_SUCCESS;
++      unsigned short value;
++
++      /* power setting */
++      status = zy_ac97_acodec_read(p_device_context, POWER_DOWN_1, &value);
++      value |= (ZY_AC97_9713_PWR_PADCPD);
++      status = zy_ac97_acodec_write(p_device_context, POWER_DOWN_1, value);
++
++      return status;
++}
++zy_acodec_error_t     zy_ac97_acodec_mfp_deinit(zy_acocec_context_t *p_device_context)
++{/* do later: free all MFP resources. */
++    return ZY_ACODEC_SUCCESS;
++}
++
++static zy_acodec_error_t  zy_ac97_acodec_shut_down_aclink(p_zy_ac97acodec_t p_ac97_reg, int * p_ost_regs)
++{
++      zy_acodec_error_t       status = ZY_ACODEC_SUCCESS;
++      unsigned long time_remaining = ZY_AC97_LINKOFF_TIMEOUT_DEF;
++
++      p_ac97_reg->gcr |= ZY_AC97_GCR_LINK_OFF_MSK;
++      p_ac97_reg->gcr |= ZY_AC97_GCR_CLKBPB_MSK;
++
++      while (!(p_ac97_reg->gsr & ZY_AC97_GSR_ACOFFD_MSK))
++      {
++              time_remaining --;
++              if (0 == time_remaining)
++              {
++                      status = ZY_ACODEC_CONTROLLER_INTERFACE_TIMEOUT;
++                      break;
++              }
++              udelay(1);
++      }
++      p_ac97_reg->gcr |= ZY_AC97_GCR_FRCRST_MSK;
++      /* check later: any delay needed */
++      p_ac97_reg->gcr &= ~ZY_AC97_GCR_FRCRST_MSK;
++      p_ac97_reg->gcr &= ~ZY_AC97_GCR_CLKBPB_MSK;
++
++      return(status);
++}
++
++
++zy_acodec_error_t  zy_ac97_acodec_deinit(zy_acocec_context_t * p_ac97_ctxt)
++{
++      zy_acodec_error_t       status ;
++
++      status = zy_ac97_acodec_shut_down_aclink((p_zy_ac97acodec_t)(p_ac97_ctxt->p_ctrl_reg), p_ac97_ctxt->p_ost_regs);
++
++      return (status);
++}
++
++zy_acodec_error_t zy_acodec_deinit(zy_acocec_context_t *p_device_context)
++{
++      /* power down codec by codec specific power down function */
++      if (p_device_context->g_pfn_codec_specific_dinit)
++      {
++              p_device_context->g_pfn_codec_specific_dinit(p_device_context);
++      }
++      /* call bus deinit function */
++      zy_ac97_acodec_deinit(p_device_context);
++      /* restore MFP, set GPIO to suitable value */
++      zy_ac97_acodec_mfp_deinit(p_device_context);
++
++      return ZY_ACODEC_SUCCESS;
++}
++
++void alsa_zy_codec_put(p_zy_acocec_context_t p_acodectxt)
++{
++
++      zy_acodec_deinit(p_acodectxt);
++      //pxa_set_cken(24, 0);
++      CKENA &= ~(1 << 24);
++
++      if(p_acodectxt->p_save_memory){
++              kfree(p_saved_memory);
++      }
++      if(p_acodectxt->p_zy_scenario){
++              kfree(p_zy_scenario);
++      }
++}
++
++
++zy_acodec_error_t zy_acodec_init(zy_acocec_context_t *p_device_context, int hw_init)
++{
++      /* set codec specific functions
++       * set mfp for Zylonite platform
++       * call bus init function (AC97, I2S, I2C, SSP)
++       * call specific init of codec
++       */
++      zy_acodec_error_t retval = ZY_ACODEC_SUCCESS;
++
++      if (p_device_context->acodec_id != WM_9713_ID)
++      {/* on Zylonite, it is Wolfson 9713 codec only */
++              return ZY_ACODEC_GENERAL_SW_ERR;
++      }
++
++      if (1 == hw_init)
++      {
++              zy_ac97_acodec_mfp_init(p_device_context);
++              zy_ac97_acodec_init(p_device_context);  /* codec init common to ac97 */
++      }
++
++      /* wm9713-specific functions */
++      (p_device_context->g_pfn_codec_specific_init)   = zy_wm9713_specific_init;
++      (p_device_context->g_pfn_codec_specific_dinit)  = zy_wm9713_specific_deinit;
++      (p_device_context->g_pfn_acodec_read)           = zy_ac97_acodec_read;
++      (p_device_context->g_pfn_acodec_write)          = zy_ac97_acodec_write;
++
++      (p_device_context->g_pfn_event_ack)    = zy_wm9713_event_ack;
++      (p_device_context->g_pfn_get_event)    = zy_wm9713_get_event;
++      (p_device_context->g_pfn_disable_touch)        = zy_wm9713_disable_touch;
++      (p_device_context->g_pfn_enable_touch) = zy_wm9713_enable_touch;
++
++      if (1 == hw_init)
++      {
++              retval = p_device_context->g_pfn_codec_specific_init(p_device_context);
++      }
++
++      return retval;
++}
++
++static int __devinit touch_codec_zy_probe(struct platform_device *dev)
++{
++      int ret = 0;
++      struct snd_card *card = NULL;
++      zy_acodec_error_t status;
++
++      /* will increase codec context use count */
++      ret = alsa_prepare_for_zy(&p_zy_codec_ctxt);
++      if (ret)
++              goto err;
++
++      /* codec specific initialization, audio will do it either */
++      if (1 == p_zy_codec_ctxt->use_count) {
++              status = zy_acodec_init(p_zy_codec_ctxt, 1);
++              if (ZY_ACODEC_SUCCESS != status) {
++                      printk(KERN_ERR "initialize codec error\n");
++                      ret = -EIO;
++                      goto err;
++              }
++
++      /* power down the units of the acodec, sleep the acodec, zy_acodec_init()
++       * will open all the units' power of the codec while ALSA need all the codec
++       * units power down and the codec should sleep if it can.
++       * So on the zylonite platform we call below function to power down and sleep
++       * wm9713 codec.
++       */
++      p_zy_codec_ctxt->g_pfn_codec_specific_dinit(p_zy_codec_ctxt);
++
++      }
++
++      alsa_ts_init();
++
++      //mhn_mfp_set_afds(MFP_AC97_INT_N_GPIO,0,0);
++      //mhn_gpio_set_direction(MFP_AC97_INT_N_GPIO, GPIO_DIR_IN);
++      //mhn_gpio_clear_edge_detect_status(MFP_AC97_INT_N_GPIO);
++      gpio_direction_input(mfp_to_gpio(MFP_PIN_GPIO26));
++      ret = request_irq(IRQ_GPIO(mfp_to_gpio(MFP_PIN_GPIO26)),
++                      pxa_touch_irq, IRQF_TRIGGER_RISING,
++                      "wm9713 touch event interrupt", NULL);
++      if (ret) {
++              printk(KERN_ERR "Request IRQ for touch failed (%d).\n", ret);
++              goto err;
++      }
++
++      return 0;
++err:
++      if (p_zy_codec_ctxt && (!--p_zy_codec_ctxt->use_count)) {
++              zy_acodec_deinit(p_zy_codec_ctxt);
++              //pxa_set_cken(24, 0);
++              CKENA &= ~(1 << 24);
++              kfree(p_zy_codec_ctxt);
++              p_zy_codec_ctxt = NULL;
++      }
++
++      if (card)
++              snd_card_free(card);
++
++      return ret;
++}
++
++static int __devexit touch_codec_zy_remove(struct platform_device *dev)
++{
++      struct snd_card *card = platform_get_drvdata(dev);
++
++      input_unregister_device(codec_zy_ts_input);
++
++      if (p_zy_codec_ctxt && (!--p_zy_codec_ctxt->use_count)) {
++              alsa_zy_codec_put(p_zy_codec_ctxt);
++              kfree(p_zy_codec_ctxt);
++              p_zy_codec_ctxt = NULL;
++      }
++
++      if (card) {
++              snd_card_free(card);
++              platform_set_drvdata(dev, NULL);
++      }
++
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int touch_codec_zy_suspend(struct platform_device *_dev, pm_message_t state, u32 level)
++{
++      int ret=0;
++      
++      if (level == SUSPEND_DISABLE) {
++              ret = audio_codec_zy_do_suspend(NULL, SNDRV_CTL_POWER_D3cold, p_zy_codec_ctxt);
++              touch_suspend = 1;
++      }
++      return ret;
++}
++
++static int touch_codec_zy_resume(struct platform_device *_dev, u32 level)
++{
++      int ret = 0;
++      
++      if (level == RESUME_ENABLE) {
++              ret = audio_codec_zy_do_resume(NULL, SNDRV_CTL_POWER_D0, p_zy_codec_ctxt);
++              touch_suspend = 0;
++      }
++      return ret;
++}
++#else
++#define touch_codec_zy_suspend        NULL
++#define touch_codec_zy_resume NULL
++#endif
++
++static struct platform_driver touch_codec_zy_driver = {
++      .probe  =       touch_codec_zy_probe,
++      .remove =       __devexit_p(touch_codec_zy_remove),
++      .suspend=       touch_codec_zy_suspend,
++      .resume =       touch_codec_zy_resume,
++      .driver = {
++              .name   =       "pxa2xx-touch",
++      },
++};
++
++static int __init touch_codec_zy_init(void)
++{
++      return platform_driver_register(&touch_codec_zy_driver);
++}
++
++static void __exit touch_code_zy_exit(void)
++{
++      platform_driver_unregister(&touch_codec_zy_driver);
++}
++module_init(touch_codec_zy_init);
++module_exit(touch_code_zy_exit);
++
++EXPORT_SYMBOL(p_zy_codec_ctxt);
++
++MODULE_AUTHOR("bridge.wu@marvell.com");
++MODULE_DESCRIPTION("zylonite audio touch codec driver on ALSA");
++MODULE_LICENSE("GPL");
++
index 9488105..2309235 100644 (file)
@@ -15,13 +15,14 @@ CHSRC = "http://oz.drigon.com/patches"
 TKSRC = "http://www.informatik.hu-berlin.de/~tkunze/zaurus/patches"
 
 COMPATIBLE_HOST = "(arm|i.86).*-linux"
-COMPATIBLE_MACHINE = '(collie|poodle|c7x0|akita|spitz|tosa|hx2000|qemuarm|qemux86|bootcdx86|htcuniversal)'
+COMPATIBLE_MACHINE = '(collie|poodle|c7x0|akita|spitz|tosa|hx2000|qemuarm|qemux86|bootcdx86|htcuniversal|zylonite)'
 
 KERNEL_DEFCONFIG ?= "defconfig-${MACHINE}"
 
 CMDLINE_CON = "console=ttyS0,115200n8 console=tty1 noinitrd"
 CMDLINE_CON_collie = "console=ttySA0,115200n8 console=tty1 noinitrd"
 CMDLINE_CON_qemuarm = "console=ttyAMA0,115200n8 console=tty1 noinitrd"
+CMDLINE_CON_zylonite = "console=ttyS0,38400"
 CMDLINE_ROOT ?= "root=/dev/mtdblock2 rootfstype=jffs2"
 CMDLINE_ROOT_spitz ?= "root=/dev/hda1 rootfstype=ext3 rootdelay=1 rw"
 #CMDLINE_ROOT_spitz = "root=/dev/mmcblk0p2 rootfstype=ext2 rootdelay=3 rw"
@@ -35,6 +36,7 @@ export mem = '${@bb.data.getVar("COLLIE_MEMORY_SIZE",d,1) or "64"}'
 export rd  = '${@bb.data.getVar("COLLIE_RAMDISK_SIZE",d,1) or "0"}'
 
 CMDLINE_MEM_collie = "mem=${mem}M"
+CMDLINE_MEM_zylonite = "mem=64M"
 CMDLINE_ROTATE_spitz = "fbcon=rotate:1"
 CMDLINE_ROTATE_akita = "fbcon=rotate:1"
 CMDLINE_ROTATE_collie = "fbcon=rotate:1"
@@ -53,7 +55,6 @@ module_autoload_snd-soc-corgi_c7x0 = "snd-soc-corgi"
 module_autoload_snd-soc-spitz_akita = "snd-soc-spitz"
 module_autoload_snd-soc-spitz_spitz = "snd-soc-spitz"
 module_autoload_snd-soc-poodle_poodle = "snd-soc-poodle"
-
 module_autoload_locomo-spi_collie = "locomo-spi"
 module_autoload_mmc_block_collie = "mmc_block"
 module_autoload_mmc_spi = "mmc-spi"
index f4967e1..4bb06b6 100644 (file)
@@ -1,6 +1,6 @@
 require linux-rp.inc
 
-PR = "r27"
+PR = "r34"
 
 # Handy URLs
 # git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git;protocol=git;tag=ef7d1b244fa6c94fb76d5f787b8629df64ea4046
@@ -43,6 +43,8 @@ SRC_URI = "${KERNELORG_MIRROR}pub/linux/kernel/v2.6/linux-2.6.23.tar.bz2 \
            ${RPSRC}/poodle_pm-r4.patch;patch=1 \
            ${RPSRC}/poodle_lcd_hack-r0.patch;patch=1 \
            ${RPSRC}/poodle_asoc_fix-r1.patch;patch=1 \
+           file://wm8750-treble.patch;patch=1 \
+           file://mtd-module.patch;patch=1 \
            file://squashfs3.0-2.6.15.patch;patch=1;status=external \
            ${RPSRC}/logo_oh-r1.patch.bz2;patch=1;status=unmergable \
            ${RPSRC}/pxa-linking-bug.patch;patch=1;status=unmergable \
@@ -132,14 +134,10 @@ SRC_URI_append_tosa = "\
 
 SRC_URI_append_akita = "\
            file://sharpsl-rc-r1.patch;patch=1;status=external \
-           file://wm8750-treble.patch;patch=1;status=external \
-           file://mtd-module.patch;patch=1 \
            "
 
 SRC_URI_append_spitz = "\
            file://sharpsl-rc-r1.patch;patch=1;status=external \
-           file://wm8750-treble.patch;patch=1;status=external \
-           file://mtd-module.patch;patch=1 \
            "
 
 SRC_URI_append_htcuniversal ="\
@@ -150,6 +148,9 @@ SRC_URI_append_zylonite ="\
        file://arm_pxa_20070923.patch;patch=1 \
        file://pxa_fb_overlay.patch;patch=1 \
        file://zylonite-boot.patch;patch=1 \
+       file://zylonite_mtd-r0.patch;patch=1 \
+       file://zylonite_touch-r0.patch;patch=1 \
+       file://zylonite_keypad-r0.patch;patch=1 \
        "
 
 S = "${WORKDIR}/linux-2.6.23"