summaryrefslogtreecommitdiff
path: root/packages/linux
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux')
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-akita9
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-bootcdx86489
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-c7x02
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-collie2
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-htcuniversal2
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-hx20002
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-poodle2
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-qemuarm2
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-qemux862
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-spitz2
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-tosa2
-rw-r--r--packages/linux/linux-rp-2.6.23/defconfig-zylonite27
-rw-r--r--packages/linux/linux-rp-2.6.23/zylonite_keypad-r0.patch1187
-rw-r--r--packages/linux/linux-rp-2.6.23/zylonite_mtd-r0.patch4093
-rw-r--r--packages/linux/linux-rp-2.6.23/zylonite_touch-r0.patch1548
-rw-r--r--packages/linux/linux-rp.inc5
-rw-r--r--packages/linux/linux-rp_2.6.23.bb11
17 files changed, 7065 insertions, 322 deletions
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-akita b/packages/linux/linux-rp-2.6.23/defconfig-akita
index 9587fb2a23..ddc7ba01b1 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-akita
+++ b/packages/linux/linux-rp-2.6.23/defconfig-akita
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-bootcdx86 b/packages/linux/linux-rp-2.6.23/defconfig-bootcdx86
index e8852205e5..244df733ac 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-bootcdx86
+++ b/packages/linux/linux-rp-2.6.23/defconfig-bootcdx86
@@ -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
@@ -1290,41 +1255,10 @@ CONFIG_USB_UHCI_HCD=y
# 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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-c7x0 b/packages/linux/linux-rp-2.6.23/defconfig-c7x0
index 4f6b8d202d..f1d0295fb0 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-c7x0
+++ b/packages/linux/linux-rp-2.6.23/defconfig-c7x0
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-collie b/packages/linux/linux-rp-2.6.23/defconfig-collie
index fd10d3df85..64e5090ae6 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-collie
+++ b/packages/linux/linux-rp-2.6.23/defconfig-collie
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-htcuniversal b/packages/linux/linux-rp-2.6.23/defconfig-htcuniversal
index ead49c2c8a..3f33b1446f 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-htcuniversal
+++ b/packages/linux/linux-rp-2.6.23/defconfig-htcuniversal
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-hx2000 b/packages/linux/linux-rp-2.6.23/defconfig-hx2000
index 09ce9e5740..447d26da80 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-hx2000
+++ b/packages/linux/linux-rp-2.6.23/defconfig-hx2000
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-poodle b/packages/linux/linux-rp-2.6.23/defconfig-poodle
index 210997df4a..5afa7c556b 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-poodle
+++ b/packages/linux/linux-rp-2.6.23/defconfig-poodle
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-qemuarm b/packages/linux/linux-rp-2.6.23/defconfig-qemuarm
index c369657596..78f08bea40 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-qemuarm
+++ b/packages/linux/linux-rp-2.6.23/defconfig-qemuarm
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-qemux86 b/packages/linux/linux-rp-2.6.23/defconfig-qemux86
index c5e91d989f..62bbaceaf9 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-qemux86
+++ b/packages/linux/linux-rp-2.6.23/defconfig-qemux86
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-spitz b/packages/linux/linux-rp-2.6.23/defconfig-spitz
index a4e849cba2..d3512f2a4b 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-spitz
+++ b/packages/linux/linux-rp-2.6.23/defconfig-spitz
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-tosa b/packages/linux/linux-rp-2.6.23/defconfig-tosa
index 5173e242a8..d005193a34 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-tosa
+++ b/packages/linux/linux-rp-2.6.23/defconfig-tosa
@@ -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
diff --git a/packages/linux/linux-rp-2.6.23/defconfig-zylonite b/packages/linux/linux-rp-2.6.23/defconfig-zylonite
index 8be4a3bd47..d98974989f 100644
--- a/packages/linux/linux-rp-2.6.23/defconfig-zylonite
+++ b/packages/linux/linux-rp-2.6.23/defconfig-zylonite
@@ -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
index 0000000000..1889b3884e
--- /dev/null
+++ b/packages/linux/linux-rp-2.6.23/zylonite_keypad-r0.patch
@@ -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
index 0000000000..cb5a9c5f72
--- /dev/null
+++ b/packages/linux/linux-rp-2.6.23/zylonite_mtd-r0.patch
@@ -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
index 0000000000..1c00696051
--- /dev/null
+++ b/packages/linux/linux-rp-2.6.23/zylonite_touch-r0.patch
@@ -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");
++
diff --git a/packages/linux/linux-rp.inc b/packages/linux/linux-rp.inc
index 9488105f0b..2309235139 100644
--- a/packages/linux/linux-rp.inc
+++ b/packages/linux/linux-rp.inc
@@ -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"
diff --git a/packages/linux/linux-rp_2.6.23.bb b/packages/linux/linux-rp_2.6.23.bb
index f4967e16ae..4bb06b60b1 100644
--- a/packages/linux/linux-rp_2.6.23.bb
+++ b/packages/linux/linux-rp_2.6.23.bb
@@ -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"