diff -uprN linux-2.6.20/arch/arm/Kconfig linux-2.6.20-at92_e1.5/arch/arm/Kconfig
--- linux-2.6.20/arch/arm/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -113,6 +113,9 @@ config VECTORS_BASE
 	help
 	  The base address of exception vectors.
 
+config RUNTIME_PHYS_OFFSET
+	bool
+
 source "init/Kconfig"
 
 menu "System Type"
@@ -187,6 +190,7 @@ config ARCH_EP93XX
 	bool "EP93xx-based"
 	select ARM_AMBA
 	select ARM_VIC
+	select RUNTIME_PHYS_OFFSET
 	help
 	  This enables support for the Cirrus EP93xx series of CPUs.
 
@@ -930,6 +934,8 @@ source "drivers/isdn/Kconfig"
 
 source "drivers/input/Kconfig"
 
+source "drivers/ioex/Kconfig"
+
 source "drivers/char/Kconfig"
 
 source "drivers/i2c/Kconfig"
diff -uprN linux-2.6.20/arch/arm/boot/compressed/Makefile linux-2.6.20-at92_e1.5/arch/arm/boot/compressed/Makefile
--- linux-2.6.20/arch/arm/boot/compressed/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/boot/compressed/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -78,13 +78,10 @@ targets       := vmlinux vmlinux.lds pig
 EXTRA_CFLAGS  := -fpic
 EXTRA_AFLAGS  :=
 
-# Supply ZRELADDR, INITRD_PHYS and PARAMS_PHYS to the decompressor via
-# linker symbols.  We only define initrd_phys and params_phys if the
-# machine class defined the corresponding makefile variable.
+# Supply ZRELADDR and PARAMS_PHYS to the decompressor via linker
+# symbols.  We only define params_phys if the machine class defined
+# the corresponding makefile variable.
 LDFLAGS_vmlinux := --defsym zreladdr=$(ZRELADDR)
-ifneq ($(INITRD_PHYS),)
-LDFLAGS_vmlinux += --defsym initrd_phys=$(INITRD_PHYS)
-endif
 ifneq ($(PARAMS_PHYS),)
 LDFLAGS_vmlinux += --defsym params_phys=$(PARAMS_PHYS)
 endif
diff -uprN linux-2.6.20/arch/arm/boot/compressed/head.S linux-2.6.20-at92_e1.5/arch/arm/boot/compressed/head.S
--- linux-2.6.20/arch/arm/boot/compressed/head.S	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/boot/compressed/head.S	2008-02-07 10:24:58.000000000 -0500
@@ -156,6 +156,11 @@ not_angel:
 		.text
 		adr	r0, LC0
 		ldmia	r0, {r1, r2, r3, r4, r5, r6, ip, sp}
+#ifdef CONFIG_RUNTIME_PHYS_OFFSET
+		and	r10, pc, #0xf0000000	@ fix up zreladdr
+		add	r4, r4, r10
+#endif
+
 		subs	r0, r0, r1		@ calculate the delta offset
 
 						@ if delta is zero, we are
diff -uprN linux-2.6.20/arch/arm/configs/at91sam9263ek_defconfig linux-2.6.20-at92_e1.5/arch/arm/configs/at91sam9263ek_defconfig
--- linux-2.6.20/arch/arm/configs/at91sam9263ek_defconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/configs/at91sam9263ek_defconfig	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,1184 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.20-rc1
+# Mon Jan  8 16:06:54 2007
+#
+CONFIG_ARM=y
+# CONFIG_GENERIC_TIME is not set
+CONFIG_MMU=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+
+#
+# General setup
+#
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+# CONFIG_SWAP is not set
+CONFIG_SYSVIPC=y
+# CONFIG_IPC_NS is not set
+# CONFIG_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_UTS_NS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_SYSFS_DEPRECATED=y
+# CONFIG_RELAY is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_SHMEM=y
+CONFIG_SLAB=y
+CONFIG_VM_EVENT_COUNTERS=y
+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=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# Block layer
+#
+CONFIG_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+CONFIG_ARCH_AT91=y
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_CO285 is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+
+#
+# Atmel AT91 System-on-Chip
+#
+# CONFIG_ARCH_AT91RM9200 is not set
+# CONFIG_ARCH_AT91SAM9260 is not set
+# CONFIG_ARCH_AT91SAM9261 is not set
+CONFIG_ARCH_AT91SAM9263=y
+
+#
+# AT91SAM9263 Board Type
+#
+CONFIG_MACH_AT91SAM9263EK=y
+
+#
+# AT91 Board Options
+#
+CONFIG_MTD_AT91_DATAFLASH_CARD=y
+# CONFIG_MTD_NAND_AT91_BUSWIDTH_16 is not set
+
+#
+# AT91 Feature Selections
+#
+# CONFIG_AT91_PROGRAMMABLE_CLOCKS is not set
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM926T=y
+CONFIG_CPU_32v5=y
+CONFIG_CPU_ABRT_EV5TJ=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_ARM_THUMB is not set
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_WRITETHROUGH is not set
+# CONFIG_CPU_CACHE_ROUND_ROBIN is not set
+
+#
+# Bus support
+#
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+# CONFIG_NO_IDLE_HZ is not set
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+# CONFIG_ARCH_DISCONTIGMEM_ENABLE is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+# CONFIG_SPARSEMEM_STATIC is not set
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
+# CONFIG_XIP_KERNEL is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+# CONFIG_VFP is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+# CONFIG_PM is not set
+# CONFIG_APM is not set
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NETDEBUG is not set
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+# CONFIG_IP_PNP_DHCP is not set
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+# CONFIG_SYN_COOKIES is not set
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+
+#
+# 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
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+
+#
+# QoS and/or fair queueing
+#
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+# CONFIG_FW_LOADER is not set
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_SYS_HYPERVISOR is not set
+
+#
+# Connector - unified userspace <-> kernelspace linker
+#
+# CONFIG_CONNECTOR is not set
+
+#
+# Memory Technology Devices (MTD)
+#
+CONFIG_MTD=y
+# CONFIG_MTD_DEBUG is not set
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+CONFIG_MTD_CMDLINE_PARTS=y
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+# CONFIG_MTD_OBSOLETE_CHIPS is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+CONFIG_MTD_DATAFLASH=y
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+
+#
+# NAND Flash Device Drivers
+#
+CONFIG_MTD_NAND=y
+# CONFIG_MTD_NAND_VERIFY_WRITE is not set
+# CONFIG_MTD_NAND_ECC_SMC is not set
+CONFIG_MTD_NAND_IDS=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+CONFIG_MTD_NAND_AT91=y
+# CONFIG_MTD_NAND_NANDSIM is not set
+
+#
+# OneNAND Flash Device Drivers
+#
+# CONFIG_MTD_ONENAND is not set
+
+#
+# Parallel port support
+#
+# CONFIG_PARPORT is not set
+
+#
+# Plug and Play support
+#
+
+#
+# Block devices
+#
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+# CONFIG_BLK_DEV_CRYPTOLOOP is not set
+# CONFIG_BLK_DEV_NBD is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=8192
+CONFIG_BLK_DEV_RAM_BLOCKSIZE=1024
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI_NETLINK is not set
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+# CONFIG_CHR_DEV_ST is not set
+# CONFIG_CHR_DEV_OSST is not set
+# CONFIG_BLK_DEV_SR is not set
+# CONFIG_CHR_DEV_SG is not set
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+CONFIG_SCSI_MULTI_LUN=y
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+
+#
+# SCSI Transports
+#
+# CONFIG_SCSI_SPI_ATTRS is not set
+# CONFIG_SCSI_FC_ATTRS is not set
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+
+#
+# SCSI low-level drivers
+#
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_DEBUG is not set
+
+#
+# Serial ATA (prod) and Parallel ATA (experimental) drivers
+#
+# CONFIG_ATA is not set
+
+#
+# Multi-device support (RAID and LVM)
+#
+# CONFIG_MD is not set
+
+#
+# Fusion MPT device support
+#
+# CONFIG_FUSION is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# I2O device support
+#
+
+#
+# Network device support
+#
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+# CONFIG_PHYLIB is not set
+
+#
+# Ethernet (10 or 100Mbit)
+#
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=y
+# CONFIG_SMC91X is not set
+# CONFIG_DM9000 is not set
+
+#
+# Ethernet (1000 Mbit)
+#
+
+#
+# Ethernet (10000 Mbit)
+#
+
+#
+# Token Ring devices
+#
+
+#
+# Wireless LAN (non-hamradio)
+#
+# CONFIG_NET_RADIO is not set
+
+#
+# Wan interfaces
+#
+# CONFIG_WAN is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_SHAPER is not set
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+
+#
+# ISDN subsystem
+#
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_TSDEV=y
+CONFIG_INPUT_TSDEV_SCREEN_X=240
+CONFIG_INPUT_TSDEV_SCREEN_Y=320
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+# CONFIG_INPUT_KEYBOARD is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_ADS7846=y
+# CONFIG_TOUCHSCREEN_GUNZE is not set
+# CONFIG_TOUCHSCREEN_ELO is not set
+# CONFIG_TOUCHSCREEN_MTOUCH is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1400 is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_ATMEL=y
+CONFIG_SERIAL_ATMEL_CONSOLE=y
+# CONFIG_SERIAL_ATMEL_TTYAT is not set
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_NOWAYOUT=y
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+
+#
+# USB-based Watchdog Cards
+#
+# CONFIG_USBPCWATCHDOG is not set
+CONFIG_HW_RANDOM=y
+# CONFIG_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+# CONFIG_TCG_TPM is not set
+
+#
+# I2C support
+#
+CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
+
+#
+# I2C Algorithms
+#
+# CONFIG_I2C_ALGOBIT is not set
+# CONFIG_I2C_ALGOPCF is not set
+# CONFIG_I2C_ALGOPCA is not set
+
+#
+# I2C Hardware Bus support
+#
+CONFIG_I2C_AT91=y
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_STUB is not set
+# CONFIG_I2C_PCA is not set
+# CONFIG_I2C_PCA_ISA is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_SENSORS_DS1337 is not set
+# CONFIG_SENSORS_DS1374 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+
+#
+# SPI support
+#
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+CONFIG_SPI_ATMEL=y
+# CONFIG_SPI_BITBANG is not set
+
+#
+# SPI Protocol Masters
+#
+
+#
+# Dallas's 1-wire bus
+#
+# CONFIG_W1 is not set
+
+#
+# Hardware Monitoring support
+#
+# CONFIG_HWMON is not set
+# CONFIG_HWMON_VID is not set
+
+#
+# Misc devices
+#
+# CONFIG_TIFM_CORE is not set
+
+#
+# LED devices
+#
+# CONFIG_NEW_LEDS is not set
+
+#
+# LED drivers
+#
+
+#
+# LED Triggers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+# CONFIG_FIRMWARE_EDID is not set
+CONFIG_FB=y
+# CONFIG_FB_CFB_FILLRECT is not set
+# CONFIG_FB_CFB_COPYAREA is not set
+# CONFIG_FB_CFB_IMAGEBLIT is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE is not set
+
+#
+# Logo configuration
+#
+# CONFIG_LOGO is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Sound
+#
+# CONFIG_SOUND is not set
+
+#
+# HID Devices
+#
+CONFIG_HID=y
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+# CONFIG_USB_BANDWIDTH is not set
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_MULTITHREAD_PROBE is not set
+# CONFIG_USB_OTG is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_ISP116X_HCD is not set
+CONFIG_USB_OHCI_HCD=y
+# CONFIG_USB_OHCI_BIG_ENDIAN is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+# CONFIG_USB_SL811_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+
+#
+# NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
+#
+
+#
+# may also be needed; see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=y
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_DPCM is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Input Devices
+#
+# CONFIG_USB_HID is not set
+
+#
+# USB HID Boot Protocol drivers
+#
+# CONFIG_USB_KBD is not set
+# CONFIG_USB_MOUSE is not set
+# CONFIG_USB_AIPTEK is not set
+# CONFIG_USB_WACOM is not set
+# 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
+
+#
+# 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=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_AUERSWALD is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_TEST is not set
+
+#
+# USB DSL modem support
+#
+
+#
+# USB Gadget Support
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_PXA2XX is not set
+# CONFIG_USB_GADGET_GOKU is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+CONFIG_USB_GADGET_AT91=y
+CONFIG_USB_AT91=y
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+CONFIG_USB_ZERO=m
+# CONFIG_USB_ETH is not set
+CONFIG_USB_GADGETFS=m
+CONFIG_USB_FILE_STORAGE=m
+# CONFIG_USB_FILE_STORAGE_TEST is not set
+CONFIG_USB_G_SERIAL=m
+# CONFIG_USB_MIDI_GADGET is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+CONFIG_MMC_AT91=m
+# CONFIG_MMC_TIFM_SD is not set
+
+#
+# Real Time Clock
+#
+CONFIG_RTC_LIB=y
+# CONFIG_RTC_CLASS is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+# CONFIG_EXT3_FS is not set
+# CONFIG_EXT4DEV_FS is not set
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_DNOTIFY=y
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+# CONFIG_ISO9660_FS is not set
+# CONFIG_UDF_FS is not set
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_NTFS_FS is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+CONFIG_CRAMFS=y
+# CONFIG_VXFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+
+#
+# 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=y
+CONFIG_LOCKD=y
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+# 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
+#
+# CONFIG_PARTITION_ADVANCED is not set
+CONFIG_MSDOS_PARTITION=y
+
+#
+# Native Language Support
+#
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+# CONFIG_NLS_CODEPAGE_737 is not set
+# CONFIG_NLS_CODEPAGE_775 is not set
+CONFIG_NLS_CODEPAGE_850=y
+# CONFIG_NLS_CODEPAGE_852 is not set
+# CONFIG_NLS_CODEPAGE_855 is not set
+# CONFIG_NLS_CODEPAGE_857 is not set
+# CONFIG_NLS_CODEPAGE_860 is not set
+# CONFIG_NLS_CODEPAGE_861 is not set
+# CONFIG_NLS_CODEPAGE_862 is not set
+# CONFIG_NLS_CODEPAGE_863 is not set
+# CONFIG_NLS_CODEPAGE_864 is not set
+# CONFIG_NLS_CODEPAGE_865 is not set
+# CONFIG_NLS_CODEPAGE_866 is not set
+# CONFIG_NLS_CODEPAGE_869 is not set
+# CONFIG_NLS_CODEPAGE_936 is not set
+# CONFIG_NLS_CODEPAGE_950 is not set
+# CONFIG_NLS_CODEPAGE_932 is not set
+# CONFIG_NLS_CODEPAGE_949 is not set
+# CONFIG_NLS_CODEPAGE_874 is not set
+# CONFIG_NLS_ISO8859_8 is not set
+# CONFIG_NLS_CODEPAGE_1250 is not set
+# CONFIG_NLS_CODEPAGE_1251 is not set
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+# CONFIG_NLS_ISO8859_2 is not set
+# CONFIG_NLS_ISO8859_3 is not set
+# CONFIG_NLS_ISO8859_4 is not set
+# CONFIG_NLS_ISO8859_5 is not set
+# CONFIG_NLS_ISO8859_6 is not set
+# CONFIG_NLS_ISO8859_7 is not set
+# CONFIG_NLS_ISO8859_9 is not set
+# CONFIG_NLS_ISO8859_13 is not set
+# CONFIG_NLS_ISO8859_14 is not set
+# CONFIG_NLS_ISO8859_15 is not set
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Distributed Lock Manager
+#
+# CONFIG_DLM is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_MUST_CHECK=y
+# CONFIG_MAGIC_SYSRQ is not set
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_RWSEMS is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_LIST is not set
+CONFIG_FRAME_POINTER=y
+CONFIG_FORCED_INLINING=y
+# CONFIG_RCU_TORTURE_TEST is not set
+CONFIG_DEBUG_USER=y
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_PLIST=y
+CONFIG_IOMAP_COPY=y
diff -uprN linux-2.6.20/arch/arm/configs/csb337_defconfig linux-2.6.20-at92_e1.5/arch/arm/configs/csb337_defconfig
--- linux-2.6.20/arch/arm/configs/csb337_defconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/configs/csb337_defconfig	2008-02-07 10:24:58.000000000 -0500
@@ -355,10 +355,12 @@ CONFIG_MTD_CFI_UTIL=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0
+CONFIG_MTD_PHYSMAP_LEN=0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_PLATRAM is not set
-CONFIG_MTD_CSB337=y
 
 #
 # Self-contained MTD device drivers
diff -uprN linux-2.6.20/arch/arm/configs/csb637_defconfig linux-2.6.20-at92_e1.5/arch/arm/configs/csb637_defconfig
--- linux-2.6.20/arch/arm/configs/csb637_defconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/configs/csb637_defconfig	2008-02-07 10:24:58.000000000 -0500
@@ -355,10 +355,12 @@ CONFIG_MTD_CFI_UTIL=y
 # Mapping drivers for chip access
 #
 # CONFIG_MTD_COMPLEX_MAPPINGS is not set
-# CONFIG_MTD_PHYSMAP is not set
+CONFIG_MTD_PHYSMAP=y
+CONFIG_MTD_PHYSMAP_START=0
+CONFIG_MTD_PHYSMAP_LEN=0
+CONFIG_MTD_PHYSMAP_BANKWIDTH=0
 # CONFIG_MTD_ARM_INTEGRATOR is not set
 # CONFIG_MTD_PLATRAM is not set
-CONFIG_MTD_CSB637=y
 
 #
 # Self-contained MTD device drivers
diff -uprN linux-2.6.20/arch/arm/kernel/head.S linux-2.6.20-at92_e1.5/arch/arm/kernel/head.S
--- linux-2.6.20/arch/arm/kernel/head.S	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/kernel/head.S	2008-02-07 10:24:58.000000000 -0500
@@ -43,8 +43,8 @@
 	.globl	swapper_pg_dir
 	.equ	swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000
 
-	.macro	pgtbl, rd
-	ldr	\rd, =(KERNEL_RAM_PADDR - 0x4000)
+	.macro	pgtbl, rd, phys_offset
+	add	\rd, \phys_offset, #(TEXT_OFFSET - 0x4000)
 	.endm
 
 #ifdef CONFIG_XIP_KERNEL
@@ -206,10 +206,22 @@ __turn_mmu_on:
  * Returns:
  *  r0, r3, r6, r7 corrupted
  *  r4 = physical page table address
+ *  r5 = PHYS_OFFSET
  */
 	.type	__create_page_tables, %function
 __create_page_tables:
-	pgtbl	r4				@ page table address
+#ifdef CONFIG_RUNTIME_PHYS_OFFSET
+	adr	r5, stext
+	sub	r5, r5, #TEXT_OFFSET		@ r5 = phys_offset
+
+	ldr	r4, =(phys_offset - PAGE_OFFSET)
+	add	r4, r4, r5
+	str	r5, [r4]			@ save phys_offset
+#else
+	mov	r5, #PHYS_OFFSET		@ r5 = phys_offset
+#endif
+
+	pgtbl	r4, r5				@ r4 = page table address
 
 	/*
 	 * Clear the 16K level 1 swapper page table
@@ -255,8 +267,7 @@ __create_page_tables:
 	 * Then map first 1MB of ram in case it contains our boot params.
 	 */
 	add	r0, r4, #PAGE_OFFSET >> 18
-	orr	r6, r7, #(PHYS_OFFSET & 0xff000000)
-	orr	r6, r6, #(PHYS_OFFSET & 0x00e00000)
+	orr	r6, r7, r5
 	str	r6, [r0]
 
 #ifdef CONFIG_XIP_KERNEL
diff -uprN linux-2.6.20/arch/arm/kernel/setup.c linux-2.6.20-at92_e1.5/arch/arm/kernel/setup.c
--- linux-2.6.20/arch/arm/kernel/setup.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/kernel/setup.c	2008-02-07 10:24:58.000000000 -0500
@@ -59,6 +59,16 @@ extern void reboot_setup(char *str);
 extern int root_mountflags;
 extern void _stext, _text, _etext, __data_start, _edata, _end;
 
+#ifdef CONFIG_RUNTIME_PHYS_OFFSET
+/*
+ * The assignment is here solely to prevent this variable from ending
+ * up in bss.  As the early startup code writes to it, we don't want it
+ * to be zeroed again later.
+ */
+unsigned long phys_offset = 0xdeadbeef;
+EXPORT_SYMBOL(phys_offset);
+#endif
+
 unsigned int processor_id;
 unsigned int __machine_arch_type;
 EXPORT_SYMBOL(__machine_arch_type);
@@ -749,7 +759,7 @@ static struct init_tags {
 	{ tag_size(tag_core), ATAG_CORE },
 	{ 1, PAGE_SIZE, 0xff },
 	{ tag_size(tag_mem32), ATAG_MEM },
-	{ MEM_SIZE, PHYS_OFFSET },
+	{ MEM_SIZE, 0 },
 	{ 0, ATAG_NONE }
 };
 
@@ -770,6 +780,8 @@ void __init setup_arch(char **cmdline_p)
 	struct machine_desc *mdesc;
 	char *from = default_command_line;
 
+	init_tags.mem.start = PHYS_OFFSET;
+
 	setup_processor();
 	mdesc = setup_machine(machine_arch_type);
 	machine_name = mdesc->name;
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/Kconfig linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/Kconfig
--- linux-2.6.20/arch/arm/mach-at91rm9200/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/Kconfig	2008-02-07 10:24:59.000000000 -0500
@@ -9,11 +9,14 @@ config ARCH_AT91RM9200
 	bool "AT91RM9200"
 
 config ARCH_AT91SAM9260
-	bool "AT91SAM9260"
+	bool "AT91SAM9260 or AT91SAM9XE"
 
 config ARCH_AT91SAM9261
 	bool "AT91SAM9261"
 
+config ARCH_AT91SAM9263
+	bool "AT91SAM9263"
+
 endchoice
 
 # ----------------------------------------------------------
@@ -90,17 +93,39 @@ endif
 
 if ARCH_AT91SAM9260
 
-comment "AT91SAM9260 Board Type"
+comment "AT91SAM9260 Variants"
+
+config ARCH_AT91SAM9260_SAM9XE
+	bool "AT91SAM9XE"
+	depends on ARCH_AT91SAM9260
+	help
+	  Select this if you are using Atmel's AT91SAM9XE System-on-Chip.
+	  They are basicaly AT91SAM9260s with various sizes of embedded Flash.
+
+comment "AT91SAM9260 / AT91SAM9XE Board Type"
 
 config MACH_AT91SAM9260EK
-	bool "Atmel AT91SAM9260-EK Evaluation Kit"
+	bool "Atmel AT91SAM9260-EK / AT91SAM9XE Evaluation Kit"
 	depends on ARCH_AT91SAM9260
 	help
-	  Select this if you are using Atmel's AT91SAM9260-EK Evaluation Kit.
+	  Select this if you are using Atmel's AT91SAM9260-EK or AT91SAM9XE Evaluation Kit
 	  <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933>
 
-endif
+config MACH_SOM9260M
+	bool "EMAC SoM-9260M"
+	depends on ARCH_AT91SAM9260
+	help
+	  Select this if you are using EMAC's SoM-9260M module.
+
+config ARMSTRONG_HWMS
+	bool "EMAC Armstrong HWMS Project"
+	depends on MACH_SOM9260M
+	help
+	  Support for the EMAC.Inc Armstrong HWMS project carrier
+	  board and peripherals. Enables compilation of drivers
+	  for ADC and counter.
 
+endif
 # ----------------------------------------------------------
 
 if ARCH_AT91SAM9261
@@ -118,21 +143,56 @@ endif
 
 # ----------------------------------------------------------
 
+if ARCH_AT91SAM9263
+
+comment "AT91SAM9263 Board Type"
+
+config MACH_AT91SAM9263EK
+	bool "Atmel AT91SAM9263-EK Evaluation Kit"
+	depends on ARCH_AT91SAM9263
+	help
+	  Select this if you are using Atmel's AT91SAM9263-EK Evaluation Kit.
+	  <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4057>
+
+endif
+
+# ----------------------------------------------------------
+
 comment "AT91 Board Options"
 
 config MTD_AT91_DATAFLASH_CARD
 	bool "Enable DataFlash Card support"
-	depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK)
+	depends on (ARCH_AT91RM9200DK || MACH_AT91RM9200EK || MACH_AT91SAM9260EK || MACH_AT91SAM9261EK || MACH_AT91SAM9263EK)
 	help
 	  Enable support for the DataFlash card.
 
 config MTD_NAND_AT91_BUSWIDTH_16
 	bool "Enable 16-bit data bus interface to NAND flash"
-	depends on (MACH_AT91SAM9261EK || MACH_AT91SAM9260EK)
+	depends on (MACH_AT91SAM9261EK || MACH_AT91SAM9260EK || MACH_AT91SAM9263EK)
 	help
 	  On AT91SAM926x boards both types of NAND flash can be present
 	  (8 and 16 bit data bus width).
 
+config CSB300_WAKE_SW0
+	bool "CSB300 SW0 irq0 wakeup"
+	depends on MACH_CSB337 && PM
+	help
+	  If you have a CSB300 connected to your CSB337, this lets
+	  SW0 serve as a wakeup button.  It uses IRQ0.
+
+config CSB300_WAKE_SW1
+	bool "CSB300 SW1 gpio wakeup"
+	depends on MACH_CSB337 && PM
+	help
+	  If you have a CSB300 connected to your CSB337, this lets
+	  SW1 serve as a wakeup button.  It uses GPIO.
+
+config RTSCLS
+	bool "Enable gpio class for the RTS flow control line"
+	depends on (MACH_SOM9260M)
+	help
+	  Enable class based control of the RTS flow control line.
+
 # ----------------------------------------------------------
 
 comment "AT91 Feature Selections"
@@ -143,6 +203,13 @@ config AT91_PROGRAMMABLE_CLOCKS
 	  Select this if you need to program one or more of the PCK0..PCK3
 	  programmable clock outputs.
 
+config AT91_SLOW_CLOCK
+	bool "Suspend-to-RAM uses slow clock mode (EXPERIMENTAL)"
+	depends on PM && EXPERIMENTAL
+	help
+	  Select this if you wish to put the CPU into slow clock mode
+	  while in the "Suspend to RAM" state, to save more power.
+
 endmenu
 
 endif
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/Makefile linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/Makefile
--- linux-2.6.20/arch/arm/mach-at91rm9200/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -8,11 +8,13 @@ obj-n		:=
 obj-		:=
 
 obj-$(CONFIG_PM)		+= pm.o
+obj-$(CONFIG_AT91_SLOW_CLOCK)	+= pm_slowclock.o
 
 # CPU-specific support
 obj-$(CONFIG_ARCH_AT91RM9200)	+= at91rm9200.o at91rm9200_time.o at91rm9200_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9260)	+= at91sam9260.o at91sam926x_time.o at91sam9260_devices.o
 obj-$(CONFIG_ARCH_AT91SAM9261)	+= at91sam9261.o at91sam926x_time.o at91sam9261_devices.o
+obj-$(CONFIG_ARCH_AT91SAM9263)	+= at91sam9263.o at91sam926x_time.o at91sam9263_devices.o
 
 # AT91RM9200 board-specific support
 obj-$(CONFIG_MACH_ONEARM)	+= board-1arm.o
@@ -27,10 +29,14 @@ obj-$(CONFIG_MACH_KAFA)		+= board-kafa.o
 
 # AT91SAM9260 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
+obj-$(CONFIG_MACH_SOM9260M) += board-som9260m.o atod-som9260m.o led-som9260m.o
 
 # AT91SAM9261 board-specific support
 obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o
 
+# AT91SAM9263 board-specific support
+obj-$(CONFIG_MACH_AT91SAM9263EK) += board-sam9263ek.o
+
 # LEDs support
 led-$(CONFIG_ARCH_AT91RM9200DK)	+= leds.o
 led-$(CONFIG_MACH_AT91RM9200EK)	+= leds.o
@@ -41,7 +47,7 @@ led-$(CONFIG_MACH_KAFA)		+= leds.o
 obj-$(CONFIG_LEDS) += $(led-y)
 
 # VGA support
-#obj-$(CONFIG_FB_S1D13XXX)	+= ics1523.o
+obj-$(CONFIG_FB_S1D13XXX)	+= ics1523.o
 
 
 ifeq ($(CONFIG_PM_DEBUG),y)
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91rm9200.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91rm9200.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91rm9200.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91rm9200.c	2008-02-07 10:24:58.000000000 -0500
@@ -117,6 +117,36 @@ static struct clk pioD_clk = {
 	.pmc_mask	= 1 << AT91RM9200_ID_PIOD,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk tc0_clk = {
+	.name		= "tc0_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_TC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc1_clk = {
+	.name		= "tc1_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_TC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc2_clk = {
+	.name		= "tc2_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_TC2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc3_clk = {
+	.name		= "tc3_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_TC3,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc4_clk = {
+	.name		= "tc4_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_TC4,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc5_clk = {
+	.name		= "tc5_clk",
+	.pmc_mask	= 1 << AT91RM9200_ID_TC5,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 
 static struct clk *periph_clocks[] __initdata = {
 	&pioA_clk,
@@ -132,7 +162,12 @@ static struct clk *periph_clocks[] __ini
 	&twi_clk,
 	&spi_clk,
 	// ssc 0 .. ssc2
-	// tc0 .. tc5
+	&tc0_clk,
+	&tc1_clk,
+	&tc2_clk,
+	&tc3_clk,
+	&tc4_clk,
+	&tc5_clk,
 	&ohci_clk,
 	&ether_clk,
 	// irq0 .. irq6
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91rm9200_devices.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91rm9200_devices.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91rm9200_devices.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91rm9200_devices.c	2008-02-07 10:24:58.000000000 -0500
@@ -315,7 +315,7 @@ static struct platform_device at91rm9200
 	.num_resources	= ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(struct at91_mmc_data *data)
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
 {
 	if (!data)
 		return;
@@ -361,7 +361,7 @@ void __init at91_add_device_mmc(struct a
 	platform_device_register(&at91rm9200_mmc_device);
 }
 #else
-void __init at91_add_device_mmc(struct at91_mmc_data *data) {}
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
 #endif
 
 
@@ -480,7 +480,18 @@ void __init at91_add_device_i2c(void) {}
  *  SPI
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_SPI_AT91) || defined(CONFIG_SPI_AT91_MODULE) || defined(CONFIG_AT91_SPI) || defined(CONFIG_AT91_SPI_MODULE)
+#if defined(CONFIG_AT91_SPI) || defined(CONFIG_AT91_SPI_MODULE)		/* legacy SPI driver */
+#define SPI_DEVNAME	"at91_spi"
+
+#elif defined(CONFIG_SPI_AT91) || defined(CONFIG_SPI_AT91_MODULE)	/* SPI bitbanging driver */
+#define SPI_DEVNAME	"at91_spi"
+
+#elif defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)	/* new SPI driver */
+#define SPI_DEVNAME	"atmel_spi"
+
+#endif
+
+#ifdef SPI_DEVNAME
 static u64 spi_dmamask = 0xffffffffUL;
 
 static struct resource spi_resources[] = {
@@ -497,7 +508,7 @@ static struct resource spi_resources[] =
 };
 
 static struct platform_device at91rm9200_spi_device = {
-	.name		= "at91_spi",
+	.name		= SPI_DEVNAME,
 	.id		= 0,
 	.dev		= {
 				.dma_mask		= &spi_dmamask,
@@ -594,6 +605,10 @@ u8 at91_leds_timer;
 
 void __init at91_init_leds(u8 cpu_led, u8 timer_led)
 {
+	/* Enable GPIO to access the LEDs */
+	at91_set_gpio_output(cpu_led, 1);
+	at91_set_gpio_output(timer_led, 1);
+
 	at91_leds_cpu	= cpu_led;
 	at91_leds_timer	= timer_led;
 }
@@ -602,6 +617,32 @@ void __init at91_init_leds(u8 cpu_led, u
 #endif
 
 
+#if defined(CONFIG_NEW_LEDS)
+
+static struct platform_device at91_leds = {
+	.name		= "at91_leds",
+	.id		= -1,
+};
+
+void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr)
+{
+	if (!nr)
+		return;
+
+	at91_leds.dev.platform_data = leds;
+
+	for ( ; nr; nr--, leds++) {
+		leds->index = nr;	/* first record stores number of leds */
+		at91_set_gpio_output(leds->gpio, (leds->flags & 1) == 0);
+	}
+
+	platform_device_register(&at91_leds);
+}
+#else
+void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr) {}
+#endif
+
+
 /* --------------------------------------------------------------------
  *  UART
  * -------------------------------------------------------------------- */
@@ -872,4 +913,21 @@ static int __init at91_add_standard_devi
 	return 0;
 }
 
+/**
+ * cpu specific method for setting SDRAM self refresh mode 
+ */
+int at91_self_refresh(unsigned state){
+	at91_sys_write(AT91_SDRAMC_SRR, 1);	/* self-refresh mode */
+}
+
+/**
+ * cpu specific method for turning off SDRAM low power mode. 
+ */
+int at91_lp_disable(unsigned state){
+	at91_sys_write(AT91_SDRAMC_LPR, 0);
+}
+
+int at91_stopclock(unsigned state){}
+
+
 arch_initcall(at91_add_standard_devices);
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91rm9200_time.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91rm9200_time.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91rm9200_time.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91rm9200_time.c	2008-02-07 10:24:58.000000000 -0500
@@ -38,7 +38,8 @@ static unsigned long last_crtr;
  * The ST_CRTR is updated asynchronously to the master clock.  It is therefore
  *  necessary to read it twice (with the same value) to ensure accuracy.
  */
-static inline unsigned long read_CRTR(void) {
+static inline unsigned long read_CRTR(void)
+{
 	unsigned long x1, x2;
 
 	do {
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9260.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9260.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9260.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9260.c	2008-02-07 10:24:58.000000000 -0500
@@ -14,6 +14,7 @@
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
+#include <asm/arch/cpu.h>
 #include <asm/arch/at91sam9260.h>
 #include <asm/arch/at91_pmc.h>
 #include <asm/arch/at91_rstc.h>
@@ -27,7 +28,11 @@ static struct map_desc at91sam9260_io_de
 		.pfn		= __phys_to_pfn(AT91_BASE_SYS),
 		.length		= SZ_16K,
 		.type		= MT_DEVICE,
-	}, {
+	}
+};
+
+static struct map_desc at91sam9260_sram_desc[] __initdata = {
+	{
 		.virtual	= AT91_IO_VIRT_BASE - AT91SAM9260_SRAM0_SIZE,
 		.pfn		= __phys_to_pfn(AT91SAM9260_SRAM0_BASE),
 		.length		= AT91SAM9260_SRAM0_SIZE,
@@ -37,7 +42,14 @@ static struct map_desc at91sam9260_io_de
 		.pfn		= __phys_to_pfn(AT91SAM9260_SRAM1_BASE),
 		.length		= AT91SAM9260_SRAM1_SIZE,
 		.type		= MT_DEVICE,
-	},
+	}
+};
+
+static struct map_desc at91sam9xe_sram_desc[] __initdata = {
+	{
+		.pfn		= __phys_to_pfn(AT91SAM9XE_SRAM_BASE),
+		.type		= MT_DEVICE,
+	}
 };
 
 /* --------------------------------------------------------------------
@@ -82,6 +94,11 @@ static struct clk usart2_clk = {
 	.pmc_mask	= 1 << AT91SAM9260_ID_US2,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk ssc_clk = {
+	.name		= "ssc_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_SSC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk mmc_clk = {
 	.name		= "mci_clk",
 	.pmc_mask	= 1 << AT91SAM9260_ID_MCI,
@@ -107,13 +124,28 @@ static struct clk spi1_clk = {
 	.pmc_mask	= 1 << AT91SAM9260_ID_SPI1,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk tc0_clk = {
+	.name		= "tc0_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc1_clk = {
+	.name		= "tc1_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc2_clk = {
+	.name		= "tc2_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk ohci_clk = {
 	.name		= "ohci_clk",
 	.pmc_mask	= 1 << AT91SAM9260_ID_UHP,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
-static struct clk ether_clk = {
-	.name		= "ether_clk",
+static struct clk macb_clk = {
+	.name		= "macb_clk",
 	.pmc_mask	= 1 << AT91SAM9260_ID_EMAC,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
@@ -137,6 +169,21 @@ static struct clk usart5_clk = {
 	.pmc_mask	= 1 << AT91SAM9260_ID_US5,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk tc3_clk = {
+	.name		= "tc3_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC3,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc4_clk = {
+	.name		= "tc4_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC4,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc5_clk = {
+	.name		= "tc5_clk",
+	.pmc_mask	= 1 << AT91SAM9260_ID_TC5,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 
 static struct clk *periph_clocks[] __initdata = {
 	&pioA_clk,
@@ -151,15 +198,19 @@ static struct clk *periph_clocks[] __ini
 	&twi_clk,
 	&spi0_clk,
 	&spi1_clk,
-	// ssc
-	// tc0 .. tc2
+	&ssc_clk,
+	&tc0_clk,
+	&tc1_clk,
+	&tc2_clk,
 	&ohci_clk,
-	&ether_clk,
+	&macb_clk,
 	&isi_clk,
 	&usart3_clk,
 	&usart4_clk,
 	&usart5_clk,
-	// tc3 .. tc5
+	&tc3_clk,
+	&tc4_clk,
+	&tc5_clk,
 	// irq0 .. irq2
 };
 
@@ -213,7 +264,7 @@ static struct at91_gpio_bank at91sam9260
 
 static void at91sam9260_reset(void)
 {
-	at91_sys_write(AT91_RSTC_CR, (0xA5 << 24) | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
+	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
 }
 
 
@@ -221,10 +272,36 @@ static void at91sam9260_reset(void)
  *  AT91SAM9260 processor initialization
  * -------------------------------------------------------------------- */
 
+static void __init at91sam9xe_initialize(void)
+{
+	unsigned long cidr, sram_size;
+
+	cidr = at91_sys_read(AT91_DBGU_CIDR);
+
+	switch (cidr & AT91_CIDR_SRAMSIZ) {
+		case AT91_CIDR_SRAMSIZ_32K:
+			sram_size = 2 * SZ_16K;
+			break;
+		case AT91_CIDR_SRAMSIZ_16K:
+		default:
+			sram_size = SZ_16K;
+	}
+
+	at91sam9xe_sram_desc->virtual = AT91_IO_VIRT_BASE - sram_size;
+	at91sam9xe_sram_desc->length = sram_size;
+
+	iotable_init(at91sam9xe_sram_desc, ARRAY_SIZE(at91sam9xe_sram_desc));
+}
+
 void __init at91sam9260_initialize(unsigned long main_clock)
 {
 	/* Map peripherals */
 	iotable_init(at91sam9260_io_desc, ARRAY_SIZE(at91sam9260_io_desc));
+	
+	if (cpu_is_at91sam9xe())
+		at91sam9xe_initialize();
+	else
+		iotable_init(at91sam9260_sram_desc, ARRAY_SIZE(at91sam9260_sram_desc));	
 
 	at91_arch_reset = at91sam9260_reset;
 	at91_extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9260_devices.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9260_devices.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9260_devices.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9260_devices.c	2008-02-07 10:24:58.000000000 -0500
@@ -12,6 +12,7 @@
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
 
+
 #include <linux/platform_device.h>
 
 #include <asm/arch/board.h>
@@ -19,6 +20,9 @@
 #include <asm/arch/at91sam9260.h>
 #include <asm/arch/at91sam926x_mc.h>
 #include <asm/arch/at91sam9260_matrix.h>
+#include <asm/arch/at91_pmc.h>
+
+#include <asm/mach/serial_at91.h>
 
 #include "generic.h"
 
@@ -128,7 +132,7 @@ void __init at91_add_device_udc(struct a
 
 #if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
 static u64 eth_dmamask = 0xffffffffUL;
-static struct eth_platform_data eth_data;
+static struct at91_eth_data eth_data;
 
 static struct resource eth_resources[] = {
 	[0] = {
@@ -155,7 +159,7 @@ static struct platform_device at91sam926
 	.num_resources	= ARRAY_SIZE(eth_resources),
 };
 
-void __init at91_add_device_eth(struct eth_platform_data *data)
+void __init at91_add_device_eth(struct at91_eth_data *data)
 {
 	if (!data)
 		return;
@@ -192,7 +196,7 @@ void __init at91_add_device_eth(struct e
 	platform_device_register(&at91sam9260_eth_device);
 }
 #else
-void __init at91_add_device_eth(struct eth_platform_data *data) {}
+void __init at91_add_device_eth(struct at91_eth_data *data) {}
 #endif
 
 
@@ -229,7 +233,7 @@ static struct platform_device at91sam926
 	.num_resources	= ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(struct at91_mmc_data *data)
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
 {
 	if (!data)
 		return;
@@ -275,7 +279,7 @@ void __init at91_add_device_mmc(struct a
 	platform_device_register(&at91sam9260_mmc_device);
 }
 #else
-void __init at91_add_device_mmc(struct at91_mmc_data *data) {}
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
 #endif
 
 
@@ -320,16 +324,16 @@ void __init at91_add_device_nand(struct 
 	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
 			| AT91_SMC_NRDSETUP_(0) | AT91_SMC_NCS_RDSETUP_(0));
 
-	at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(2) | AT91_SMC_NCS_WRPULSE_(5)
-			| AT91_SMC_NRDPULSE_(2) | AT91_SMC_NCS_RDPULSE_(5));
+	at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(3) | AT91_SMC_NCS_WRPULSE_(3)
+			| AT91_SMC_NRDPULSE_(3) | AT91_SMC_NCS_RDPULSE_(3));
 
-	at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(7) | AT91_SMC_NRDCYCLE_(7));
+	at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(5) | AT91_SMC_NRDCYCLE_(5));
 
 	if (data->bus_width_16)
 		mode = AT91_SMC_DBW_16;
 	else
 		mode = AT91_SMC_DBW_8;
-	at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(1));
+	at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(2));
 
 	/* enable pin */
 	if (data->enable_pin)
@@ -515,6 +519,10 @@ u8 at91_leds_timer;
 
 void __init at91_init_leds(u8 cpu_led, u8 timer_led)
 {
+	/* Enable GPIO to access the LEDs */
+	at91_set_gpio_output(cpu_led, 1);
+	at91_set_gpio_output(timer_led, 1);
+
 	at91_leds_cpu	= cpu_led;
 	at91_leds_timer	= timer_led;
 }
@@ -523,6 +531,51 @@ void __init at91_init_leds(u8 cpu_led, u
 #endif
 
 
+#if defined(CONFIG_NEW_LEDS)
+
+static struct platform_device at91_leds = {
+	.name		= "at91_leds",
+	.id		= -1,
+};
+
+void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr)
+{
+	if (!nr)
+		return;
+
+	at91_leds.dev.platform_data = leds;
+
+	for ( ; nr; nr--, leds++) {
+		leds->index = nr;	/* first record stores number of leds */
+		at91_set_gpio_output(leds->gpio, (leds->flags & 1) == 0);
+	}
+
+	platform_device_register(&at91_leds);
+}
+#else
+void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr) {}
+#endif
+
+/* --------------------------------------------------------------------
+ *  RTC
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_RTC_DRV_AT91SAM926X) 
+static struct platform_device at91rm9200_rtc_device = {
+	.name		= "at91_rtt",
+	.id		= -1,
+	.num_resources	= 0,
+};
+
+static void __init at91_add_device_rtc(void)
+{
+	platform_device_register(&at91rm9200_rtc_device);
+}
+#else
+static void __init at91_add_device_rtc(void) {}
+#endif
+
+
 /* --------------------------------------------------------------------
  *  UART
  * -------------------------------------------------------------------- */
@@ -848,9 +901,20 @@ void __init at91_add_device_serial(void)
 			platform_device_register(at91_uarts[i]);
 	}
 }
+
+//if available, calls the serial driver for a given channel to set auto485 mode
+int at91_auto485_serial(int channel,int fos){
+	struct uart_port *port = NULL;
+	if(channel>ATMEL_MAX_UART)return -1;
+	if(at91_uarts[channel]==NULL)return -2;
+	if((port=platform_get_drvdata(at91_uarts[channel]))==NULL)return -3;
+	return atmel_auto485(port,fos);
+}
+
 #else
 void __init at91_init_serial(struct at91_uart_config *config) {}
 void __init at91_add_device_serial(void) {}
+int at91_auto485_serial(int channel,int onoff) {return 0;}
 #endif
 
 
@@ -861,7 +925,30 @@ void __init at91_add_device_serial(void)
  */
 static int __init at91_add_standard_devices(void)
 {
+  at91_add_device_rtc();	
+  return 0;
+}
+
+/**
+ * cpu specific method for setting SDRAM self refresh mode 
+ */
+int at91_self_refresh(unsigned state){
+	at91_sys_write(AT91_SDRAMC_LPR, AT91_SDRAMC_LPCB_SELF_REFRESH);
+	return 0;
+}
+
+/**
+ * cpu specific method for turning off SDRAM low power mode. 
+ */
+int at91_lp_disable(unsigned state){
+	at91_sys_write(AT91_SDRAMC_LPR, AT91_SDRAMC_LPCB_DISABLE);
+	return 0;
+}
+
+int at91_stopclock(unsigned state){
+	at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK);
 	return 0;
 }
 
+	
 arch_initcall(at91_add_standard_devices);
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9261.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9261.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9261.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9261.c	2008-02-07 10:24:58.000000000 -0500
@@ -72,6 +72,11 @@ static struct clk usart2_clk = {
 	.pmc_mask	= 1 << AT91SAM9261_ID_US2,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk ssc1_clk = {
+	.name		= "ssc1_clk",
+	.pmc_mask	= 1 << AT91SAM9261_ID_SSC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk mmc_clk = {
 	.name		= "mci_clk",
 	.pmc_mask	= 1 << AT91SAM9261_ID_MCI,
@@ -97,6 +102,21 @@ static struct clk spi1_clk = {
 	.pmc_mask	= 1 << AT91SAM9261_ID_SPI1,
 	.type		= CLK_TYPE_PERIPHERAL,
 };
+static struct clk tc0_clk = {
+	.name		= "tc0_clk",
+	.pmc_mask	= 1 << AT91SAM9261_ID_TC0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc1_clk = {
+	.name		= "tc1_clk",
+	.pmc_mask	= 1 << AT91SAM9261_ID_TC1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tc2_clk = {
+	.name		= "tc2_clk",
+	.pmc_mask	= 1 << AT91SAM9261_ID_TC2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
 static struct clk ohci_clk = {
 	.name		= "ohci_clk",
 	.pmc_mask	= 1 << AT91SAM9261_ID_UHP,
@@ -121,7 +141,10 @@ static struct clk *periph_clocks[] __ini
 	&spi0_clk,
 	&spi1_clk,
 	// ssc 0 .. ssc2
-	// tc0 .. tc2
+	&ssc1_clk,
+	&tc0_clk,
+	&tc1_clk,
+	&tc2_clk,
 	&ohci_clk,
 	&lcdc_clk,
 	// irq0 .. irq2
@@ -208,7 +231,7 @@ static struct at91_gpio_bank at91sam9261
 
 static void at91sam9261_reset(void)
 {
-	at91_sys_write(AT91_RSTC_CR, (0xA5 << 24) | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
+	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
 }
 
 
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9261_devices.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9261_devices.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9261_devices.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9261_devices.c	2008-02-07 10:24:58.000000000 -0500
@@ -14,6 +14,9 @@
 #include <asm/mach/map.h>
 
 #include <linux/platform_device.h>
+#include <linux/fb.h>
+
+#include <video/atmel_lcdc.h>
 
 #include <asm/arch/board.h>
 #include <asm/arch/gpio.h>
@@ -159,7 +162,7 @@ static struct platform_device at91sam926
 	.num_resources	= ARRAY_SIZE(mmc_resources),
 };
 
-void __init at91_add_device_mmc(struct at91_mmc_data *data)
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
 {
 	if (!data)
 		return;
@@ -192,7 +195,7 @@ void __init at91_add_device_mmc(struct a
 	platform_device_register(&at91sam9261_mmc_device);
 }
 #else
-void __init at91_add_device_mmc(struct at91_mmc_data *data) {}
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
 #endif
 
 
@@ -345,7 +348,13 @@ static struct platform_device at91sam926
 	.num_resources	= ARRAY_SIZE(spi0_resources),
 };
 
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PA5, AT91_PIN_PA6 };
+static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PA28, 
+#if defined(CONFIG_MACH_AT91SAM9261EK) && defined(CONFIG_SND_AT73C213) 
+	AT91_PIN_PA29 };
+#else
+	AT91_PIN_PA6 };
+#endif
+
 
 static struct resource spi1_resources[] = {
 	[0] = {
@@ -430,9 +439,9 @@ void __init at91_add_device_spi(struct s
  *  LCD Controller
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_FB_AT91) || defined(CONFIG_FB_AT91_MODULE)
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
 static u64 lcdc_dmamask = 0xffffffffUL;
-static struct at91fb_info lcdc_data;
+static struct atmel_lcdfb_info lcdc_data;
 
 static struct resource lcdc_resources[] = {
 	[0] = {
@@ -455,18 +464,18 @@ static struct resource lcdc_resources[] 
 };
 
 static struct platform_device at91_lcdc_device = {
-	.name		= "at91-fb",
-	.id		= 0,
-	.dev		= {
-				.dma_mask		= &lcdc_dmamask,
-				.coherent_dma_mask	= 0xffffffff,
-				.platform_data		= &lcdc_data,
+	.name           = "atmel_lcdfb",
+	.id             = 0,
+	.dev            = {
+				.dma_mask          = &lcdc_dmamask,
+				.coherent_dma_mask = 0xffffffff,
+				.platform_data     = &lcdc_data,
 	},
 	.resource	= lcdc_resources,
 	.num_resources	= ARRAY_SIZE(lcdc_resources),
 };
 
-void __init at91_add_device_lcdc(struct at91fb_info *data)
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
 {
 	if (!data) {
 		return;
@@ -499,7 +508,7 @@ void __init at91_add_device_lcdc(struct 
 	platform_device_register(&at91_lcdc_device);
 }
 #else
-void __init at91_add_device_lcdc(struct at91fb_info *data) {}
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
 #endif
 
 
@@ -513,6 +522,10 @@ u8 at91_leds_timer;
 
 void __init at91_init_leds(u8 cpu_led, u8 timer_led)
 {
+	/* Enable GPIO to access the LEDs */
+	at91_set_gpio_output(cpu_led, 1);
+	at91_set_gpio_output(timer_led, 1);
+
 	at91_leds_cpu	= cpu_led;
 	at91_leds_timer	= timer_led;
 }
@@ -521,6 +534,32 @@ void __init at91_init_leds(u8 cpu_led, u
 #endif
 
 
+#if defined(CONFIG_NEW_LEDS)
+
+static struct platform_device at91_leds = {
+	.name		= "at91_leds",
+	.id		= -1,
+};
+
+void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr)
+{
+	if (!nr)
+		return;
+
+	at91_leds.dev.platform_data = leds;
+
+	for ( ; nr; nr--, leds++) {
+		leds->index = nr;	/* first record stores number of leds */
+		at91_set_gpio_output(leds->gpio, (leds->flags & 1) == 0);
+	}
+
+	platform_device_register(&at91_leds);
+}
+#else
+void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr) {}
+#endif
+
+
 /* --------------------------------------------------------------------
  *  UART
  * -------------------------------------------------------------------- */
@@ -595,8 +634,10 @@ static inline void configure_usart0_pins
 {
 	at91_set_A_periph(AT91_PIN_PC8, 1);		/* TXD0 */
 	at91_set_A_periph(AT91_PIN_PC9, 0);		/* RXD0 */
+#if !defined(CONFIG_DM9000)
 	at91_set_A_periph(AT91_PIN_PC10, 0);		/* RTS0 */
 	at91_set_A_periph(AT91_PIN_PC11, 0);		/* CTS0 */
+#endif
 }
 
 static struct resource uart1_resources[] = {
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9263.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9263.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9263.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9263.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,318 @@
+/*
+ * arch/arm/mach-at91rm9200/at91sam9263.c
+ *
+ *  Copyright (C) 2007 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/arch/at91sam9263.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91_rstc.h>
+
+#include "generic.h"
+#include "clock.h"
+
+static struct map_desc at91sam9263_io_desc[] __initdata = {
+	{
+		.virtual	= AT91_VA_BASE_SYS,
+		.pfn		= __phys_to_pfn(AT91_BASE_SYS),
+		.length		= SZ_16K,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE,
+		.pfn		= __phys_to_pfn(AT91SAM9263_SRAM0_BASE),
+		.length		= AT91SAM9263_SRAM0_SIZE,
+		.type		= MT_DEVICE,
+	}, {
+		.virtual	= AT91_IO_VIRT_BASE - AT91SAM9263_SRAM0_SIZE - AT91SAM9263_SRAM1_SIZE,
+		.pfn		= __phys_to_pfn(AT91SAM9263_SRAM1_BASE),
+		.length		= AT91SAM9263_SRAM1_SIZE,
+		.type		= MT_DEVICE,
+	},
+};
+
+/* --------------------------------------------------------------------
+ *  Clocks
+ * -------------------------------------------------------------------- */
+
+/*
+ * The peripheral clocks.
+ */
+static struct clk pioA_clk = {
+	.name		= "pioA_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_PIOA,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioB_clk = {
+	.name		= "pioB_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_PIOB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk pioCDE_clk = {
+	.name		= "pioCDE_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_PIOCDE,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart0_clk = {
+	.name		= "usart0_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_US0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart1_clk = {
+	.name		= "usart1_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_US1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk usart2_clk = {
+	.name		= "usart2_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_US2,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc0_clk = {
+	.name		= "mci0_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_MCI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk mmc1_clk = {
+	.name		= "mci1_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_MCI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk twi_clk = {
+	.name		= "twi_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_TWI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi0_clk = {
+	.name		= "spi0_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_SPI0,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk spi1_clk = {
+	.name		= "spi1_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_SPI1,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk tcb_clk = {
+	.name		= "tcb_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_TCB,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ac97_clk = {
+	.name		= "ac97_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_AC97C,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk macb_clk = {
+	.name		= "macb_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_EMAC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk udc_clk = {
+	.name		= "udc_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_UDP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk isi_clk = {
+	.name		= "isi_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_ISI,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk lcdc_clk = {
+	.name		= "lcdc_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_LCDC,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+static struct clk ohci_clk = {
+	.name		= "ohci_clk",
+	.pmc_mask	= 1 << AT91SAM9263_ID_UHP,
+	.type		= CLK_TYPE_PERIPHERAL,
+};
+
+static struct clk *periph_clocks[] __initdata = {
+	&pioA_clk,
+	&pioB_clk,
+	&pioCDE_clk,
+	&usart0_clk,
+	&usart1_clk,
+	&usart2_clk,
+	&mmc0_clk,
+	&mmc1_clk,
+	// can
+	&twi_clk,
+	&spi0_clk,
+	&spi1_clk,
+	// ssc0 .. ssc1
+	&ac97_clk,
+	&tcb_clk,
+	// pwmc
+	&macb_clk,
+	// 2dge
+	&udc_clk,
+	&isi_clk,
+	&lcdc_clk,
+	// dma
+	&ohci_clk,
+	// irq0 .. irq1
+};
+
+/*
+ * The four programmable clocks.
+ * You must configure pin multiplexing to bring these signals out.
+ */
+static struct clk pck0 = {
+	.name		= "pck0",
+	.pmc_mask	= AT91_PMC_PCK0,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 0,
+};
+static struct clk pck1 = {
+	.name		= "pck1",
+	.pmc_mask	= AT91_PMC_PCK1,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 1,
+};
+static struct clk pck2 = {
+	.name		= "pck2",
+	.pmc_mask	= AT91_PMC_PCK2,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 2,
+};
+static struct clk pck3 = {
+	.name		= "pck3",
+	.pmc_mask	= AT91_PMC_PCK3,
+	.type		= CLK_TYPE_PROGRAMMABLE,
+	.id		= 3,
+};
+
+static void __init at91sam9263_register_clocks(void)
+{
+	int i;
+
+	for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
+		clk_register(periph_clocks[i]);
+
+	clk_register(&pck0);
+	clk_register(&pck1);
+	clk_register(&pck2);
+	clk_register(&pck3);
+}
+
+/* --------------------------------------------------------------------
+ *  GPIO
+ * -------------------------------------------------------------------- */
+
+static struct at91_gpio_bank at91sam9263_gpio[] = {
+	{
+		.id		= AT91SAM9263_ID_PIOA,
+		.offset		= AT91_PIOA,
+		.clock		= &pioA_clk,
+	}, {
+		.id		= AT91SAM9263_ID_PIOB,
+		.offset		= AT91_PIOB,
+		.clock		= &pioB_clk,
+	}, {
+		.id		= AT91SAM9263_ID_PIOCDE,
+		.offset		= AT91_PIOC,
+		.clock		= &pioCDE_clk,
+	}, {
+		.id		= AT91SAM9263_ID_PIOCDE,
+		.offset		= AT91_PIOD,
+		.clock		= &pioCDE_clk,
+	}, {
+		.id		= AT91SAM9263_ID_PIOCDE,
+		.offset		= AT91_PIOE,
+		.clock		= &pioCDE_clk,
+	}
+};
+
+static void at91sam9263_reset(void)
+{
+	at91_sys_write(AT91_RSTC_CR, AT91_RSTC_KEY | AT91_RSTC_PROCRST | AT91_RSTC_PERRST);
+}
+
+
+/* --------------------------------------------------------------------
+ *  AT91SAM9263 processor initialization
+ * -------------------------------------------------------------------- */
+
+void __init at91sam9263_initialize(unsigned long main_clock)
+{
+	/* Map peripherals */
+	iotable_init(at91sam9263_io_desc, ARRAY_SIZE(at91sam9263_io_desc));
+
+	at91_arch_reset = at91sam9263_reset;
+	at91_extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1);
+
+	/* Init clock subsystem */
+	at91_clock_init(main_clock);
+
+	/* Register the processor-specific clocks */
+	at91sam9263_register_clocks();
+
+	/* Register GPIO subsystem */
+	at91_gpio_init(at91sam9263_gpio, 5);
+}
+
+/* --------------------------------------------------------------------
+ *  Interrupt initialization
+ * -------------------------------------------------------------------- */
+
+/*
+ * The default interrupt priority levels (0 = lowest, 7 = highest).
+ */
+static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
+	7,	/* Advanced Interrupt Controller (FIQ) */
+	7,	/* System Peripherals */
+	0,	/* Parallel IO Controller A */
+	0,	/* Parallel IO Controller B */
+	0,	/* Parallel IO Controller C, D and E */
+	0,
+	0,
+	6,	/* USART 0 */
+	6,	/* USART 1 */
+	6,	/* USART 2 */
+	0,	/* Multimedia Card Interface 0 */
+	0,	/* Multimedia Card Interface 1 */
+	4,	/* CAN */
+	0,	/* Two-Wire Interface */
+	6,	/* Serial Peripheral Interface 0 */
+	6,	/* Serial Peripheral Interface 1 */
+	5,	/* Serial Synchronous Controller 0 */
+	5,	/* Serial Synchronous Controller 1 */
+	6,	/* AC97 Controller */
+	0,	/* Timer Counter 0, 1 and 2 */
+	0,	/* Pulse Width Modulation Controller */
+	3,	/* Ethernet */
+	0,
+	0,	/* 2D Graphic Engine */
+	3,	/* USB Device Port */
+	0,	/* Image Sensor Interface */
+	3,	/* LDC Controller */
+	0,	/* DMA Controller */
+	0,
+	3,	/* USB Host port */
+	0,	/* Advanced Interrupt Controller (IRQ0) */
+	0,	/* Advanced Interrupt Controller (IRQ1) */
+};
+
+void __init at91sam9263_init_interrupts(unsigned int priority[NR_AIC_IRQS])
+{
+	if (!priority)
+		priority = at91sam9263_default_irq_priority;
+
+	/* Initialize the AIC interrupt controller */
+	at91_aic_init(priority);
+
+	/* Enable GPIO interrupts */
+	at91_gpio_irq_setup();
+}
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9263_devices.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9263_devices.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91sam9263_devices.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam9263_devices.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,978 @@
+/*
+ * arch/arm/mach-at91rm9200/at91sam9263_devices.c
+ *
+ *  Copyright (C) 2007 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+
+#include <linux/platform_device.h>
+#include <linux/fb.h>
+
+#include <video/atmel_lcdc.h>
+
+#include <asm/delay.h>
+
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91sam9263.h>
+#include <asm/arch/at91sam926x_mc.h>
+#include <asm/arch/at91sam9263_matrix.h>
+
+#include "generic.h"
+
+#define SZ_512	0x00000200
+#define SZ_256	0x00000100
+#define SZ_16	0x00000010
+
+/* --------------------------------------------------------------------
+ *  USB Host
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
+static u64 ohci_dmamask = 0xffffffffUL;
+static struct at91_usbh_data usbh_data;
+
+static struct resource usbh_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_UHP_BASE,
+		.end	= AT91SAM9263_UHP_BASE + SZ_1M - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_UHP,
+		.end	= AT91SAM9263_ID_UHP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_usbh_device = {
+	.name		= "at91_ohci",
+	.id		= -1,
+	.dev		= {
+				.dma_mask		= &ohci_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &usbh_data,
+	},
+	.resource	= usbh_resources,
+	.num_resources	= ARRAY_SIZE(usbh_resources),
+};
+
+void __init at91_add_device_usbh(struct at91_usbh_data *data)
+{
+	int i;
+
+	if (!data)
+		return;
+
+	/* Enable VBus control for UHP ports */
+	for (i = 0; i < data->ports; i++) {
+		if (data->vbus_pin[i])
+			at91_set_gpio_output(data->vbus_pin[i], 0);
+	}
+
+	usbh_data = *data;
+	platform_device_register(&at91_usbh_device);
+}
+#else
+void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  USB Device (Gadget)
+ * -------------------------------------------------------------------- */
+
+#ifdef CONFIG_USB_GADGET_AT91
+static struct at91_udc_data udc_data;
+
+static struct resource udc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_UDP,
+		.end	= AT91SAM9263_BASE_UDP + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_UDP,
+		.end	= AT91SAM9263_ID_UDP,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_udc_device = {
+	.name		= "at91_udc",
+	.id		= -1,
+	.dev		= {
+				.platform_data		= &udc_data,
+	},
+	.resource	= udc_resources,
+	.num_resources	= ARRAY_SIZE(udc_resources),
+};
+
+void __init at91_add_device_udc(struct at91_udc_data *data)
+{
+	if (!data)
+		return;
+
+	if (data->vbus_pin) {
+		at91_set_gpio_input(data->vbus_pin, 0);
+		at91_set_deglitch(data->vbus_pin, 1);
+	}
+
+	/* Pullup pin is handled internally by USB device peripheral */
+
+	udc_data = *data;
+	platform_device_register(&at91_udc_device);
+}
+#else
+void __init at91_add_device_udc(struct at91_udc_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  Ethernet
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
+static u64 eth_dmamask = 0xffffffffUL;
+static struct at91_eth_data eth_data;
+
+static struct resource eth_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_EMAC,
+		.end	= AT91SAM9263_BASE_EMAC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_EMAC,
+		.end	= AT91SAM9263_ID_EMAC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_eth_device = {
+	.name		= "macb",
+	.id		= -1,
+	.dev		= {
+				.dma_mask		= &eth_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &eth_data,
+	},
+	.resource	= eth_resources,
+	.num_resources	= ARRAY_SIZE(eth_resources),
+};
+
+void __init at91_add_device_eth(struct at91_eth_data *data)
+{
+	if (!data)
+		return;
+
+	if (data->phy_irq_pin) {
+		at91_set_gpio_input(data->phy_irq_pin, 0);
+		at91_set_deglitch(data->phy_irq_pin, 1);
+	}
+
+	/* Pins used for MII and RMII */
+	at91_set_A_periph(AT91_PIN_PE21, 0);	/* ETXCK_EREFCK */
+	at91_set_B_periph(AT91_PIN_PC25, 0);	/* ERXDV */
+	at91_set_A_periph(AT91_PIN_PE25, 0);	/* ERX0 */
+	at91_set_A_periph(AT91_PIN_PE26, 0);	/* ERX1 */
+	at91_set_A_periph(AT91_PIN_PE27, 0);	/* ERXER */
+	at91_set_A_periph(AT91_PIN_PE28, 0);	/* ETXEN */
+	at91_set_A_periph(AT91_PIN_PE23, 0);	/* ETX0 */
+	at91_set_A_periph(AT91_PIN_PE24, 0);	/* ETX1 */
+	at91_set_A_periph(AT91_PIN_PE30, 0);	/* EMDIO */
+	at91_set_A_periph(AT91_PIN_PE29, 0);	/* EMDC */
+
+	if (!data->is_rmii) {
+		at91_set_A_periph(AT91_PIN_PE22, 0);	/* ECRS */
+		at91_set_B_periph(AT91_PIN_PC26, 0);	/* ECOL */
+		at91_set_B_periph(AT91_PIN_PC22, 0);	/* ERX2 */
+		at91_set_B_periph(AT91_PIN_PC23, 0);	/* ERX3 */
+		at91_set_B_periph(AT91_PIN_PC27, 0);	/* ERXCK */
+		at91_set_B_periph(AT91_PIN_PC20, 0);	/* ETX2 */
+		at91_set_B_periph(AT91_PIN_PC21, 0);	/* ETX3 */
+		at91_set_B_periph(AT91_PIN_PC24, 0);	/* ETXER */
+	}
+
+	eth_data = *data;
+	platform_device_register(&at91sam9263_eth_device);
+}
+#else
+void __init at91_add_device_eth(struct at91_eth_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  MMC / SD
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MMC_AT91) || defined(CONFIG_MMC_AT91_MODULE)
+static u64 mmc_dmamask = 0xffffffffUL;
+static struct at91_mmc_data mmc0_data, mmc1_data;
+
+static struct resource mmc0_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_MCI0,
+		.end	= AT91SAM9263_BASE_MCI0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_MCI0,
+		.end	= AT91SAM9263_ID_MCI0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_mmc0_device = {
+	.name		= "at91_mci",
+	.id		= 0,
+	.dev		= {
+				.dma_mask		= &mmc_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &mmc0_data,
+	},
+	.resource	= mmc0_resources,
+	.num_resources	= ARRAY_SIZE(mmc0_resources),
+};
+
+static struct resource mmc1_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_MCI1,
+		.end	= AT91SAM9263_BASE_MCI1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_MCI1,
+		.end	= AT91SAM9263_ID_MCI1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_mmc1_device = {
+	.name		= "at91_mci",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &mmc_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &mmc1_data,
+	},
+	.resource	= mmc1_resources,
+	.num_resources	= ARRAY_SIZE(mmc1_resources),
+};
+
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data)
+{
+	if (!data)
+		return;
+
+	/* input/irq */
+	if (data->det_pin) {
+		at91_set_gpio_input(data->det_pin, 1);
+		at91_set_deglitch(data->det_pin, 1);
+	}
+	if (data->wp_pin)
+		at91_set_gpio_input(data->wp_pin, 1);
+	if (data->vcc_pin)
+		at91_set_gpio_output(data->vcc_pin, 0);
+
+	if (mmc_id == 0) {		/* MCI0 */
+		/* CLK */
+		at91_set_A_periph(AT91_PIN_PA12, 0);
+
+		if (data->slot_b) {
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA16, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA17, 1);
+			if (data->wire4) {
+				at91_set_A_periph(AT91_PIN_PA18, 1);
+				at91_set_A_periph(AT91_PIN_PA19, 1);
+				at91_set_A_periph(AT91_PIN_PA20, 1);
+			}
+		} else {
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA1, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA0, 1);
+			if (data->wire4) {
+				at91_set_A_periph(AT91_PIN_PA3, 1);
+				at91_set_A_periph(AT91_PIN_PA4, 1);
+				at91_set_A_periph(AT91_PIN_PA5, 1);
+			}
+		}
+
+		mmc0_data = *data;
+		at91_clock_associate("mci0_clk", &at91sam9263_mmc1_device.dev, "mci_clk");
+		platform_device_register(&at91sam9263_mmc0_device);
+	} else {			/* MCI1 */
+		/* CLK */
+		at91_set_A_periph(AT91_PIN_PA6, 0);
+
+		if (data->slot_b) {
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA21, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA22, 1);
+			if (data->wire4) {
+				at91_set_A_periph(AT91_PIN_PA23, 1);
+				at91_set_A_periph(AT91_PIN_PA24, 1);
+				at91_set_A_periph(AT91_PIN_PA25, 1);
+			}
+		} else {
+			/* CMD */
+			at91_set_A_periph(AT91_PIN_PA7, 1);
+
+			/* DAT0, maybe DAT1..DAT3 */
+			at91_set_A_periph(AT91_PIN_PA8, 1);
+			if (data->wire4) {
+				at91_set_A_periph(AT91_PIN_PA9, 1);
+				at91_set_A_periph(AT91_PIN_PA10, 1);
+				at91_set_A_periph(AT91_PIN_PA11, 1);
+			}
+		}
+
+		mmc1_data = *data;
+		at91_clock_associate("mci1_clk", &at91sam9263_mmc1_device.dev, "mci_clk");
+		platform_device_register(&at91sam9263_mmc1_device);
+	}
+}
+#else
+void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  NAND / SmartMedia
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_MTD_NAND_AT91) || defined(CONFIG_MTD_NAND_AT91_MODULE)
+static struct at91_nand_data nand_data;
+
+#define NAND_BASE	AT91_CHIPSELECT_3
+
+static struct resource nand_resources[] = {
+	{
+		.start	= NAND_BASE,
+		.end	= NAND_BASE + SZ_256M - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device at91sam9263_nand_device = {
+	.name		= "at91_nand",
+	.id		= -1,
+	.dev		= {
+				.platform_data	= &nand_data,
+	},
+	.resource	= nand_resources,
+	.num_resources	= ARRAY_SIZE(nand_resources),
+};
+
+void __init at91_add_device_nand(struct at91_nand_data *data)
+{
+	unsigned long csa, mode;
+
+	if (!data)
+		return;
+
+	csa = at91_sys_read(AT91_MATRIX_EBI0CSA);
+	at91_sys_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC);
+
+	/* set the bus interface characteristics */
+	at91_sys_write(AT91_SMC_SETUP(3), AT91_SMC_NWESETUP_(0) | AT91_SMC_NCS_WRSETUP_(0)
+			| AT91_SMC_NRDSETUP_(0) | AT91_SMC_NCS_RDSETUP_(0));
+
+	at91_sys_write(AT91_SMC_PULSE(3), AT91_SMC_NWEPULSE_(3) | AT91_SMC_NCS_WRPULSE_(3)
+			| AT91_SMC_NRDPULSE_(3) | AT91_SMC_NCS_RDPULSE_(3));
+
+	at91_sys_write(AT91_SMC_CYCLE(3), AT91_SMC_NWECYCLE_(5) | AT91_SMC_NRDCYCLE_(5));
+
+	if (data->bus_width_16)
+		mode = AT91_SMC_DBW_16;
+	else
+		mode = AT91_SMC_DBW_8;
+	at91_sys_write(AT91_SMC_MODE(3), mode | AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_TDF_(2));
+
+	/* enable pin */
+	if (data->enable_pin)
+		at91_set_gpio_output(data->enable_pin, 1);
+
+	/* ready/busy pin */
+	if (data->rdy_pin)
+		at91_set_gpio_input(data->rdy_pin, 1);
+
+	/* card detect pin */
+	if (data->det_pin)
+		at91_set_gpio_input(data->det_pin, 1);
+
+	nand_data = *data;
+	platform_device_register(&at91sam9263_nand_device);
+}
+#else
+void __init at91_add_device_nand(struct at91_nand_data *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  TWI (i2c)
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
+
+static struct resource twi_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_TWI,
+		.end	= AT91SAM9263_BASE_TWI + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_TWI,
+		.end	= AT91SAM9263_ID_TWI,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_twi_device = {
+	.name		= "at91_i2c",
+	.id		= -1,
+	.resource	= twi_resources,
+	.num_resources	= ARRAY_SIZE(twi_resources),
+};
+
+void __init at91_add_device_i2c(void)
+{
+	/* pins used for TWI interface */
+	at91_set_A_periph(AT91_PIN_PB4, 0);		/* TWD */
+	at91_set_multi_drive(AT91_PIN_PB4, 1);
+
+	at91_set_A_periph(AT91_PIN_PB5, 0);		/* TWCK */
+	at91_set_multi_drive(AT91_PIN_PB5, 1);
+
+	platform_device_register(&at91sam9263_twi_device);
+}
+#else
+void __init at91_add_device_i2c(void) {}
+#endif
+
+/* --------------------------------------------------------------------
+ *  AC97
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SND_AT91_AC97) || defined(CONFIG_SND_AT91_AC97_MODULE)
+static u64 ac97_dmamask = 0xffffffffUL;
+static struct atmel_ac97_data ac97_data;
+
+static struct resource ac97_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_AC97C,
+		.end	= AT91SAM9263_BASE_AC97C + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_AC97C,
+		.end	= AT91SAM9263_ID_AC97C,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_ac97_device = {
+	.name		= "ac97c",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &ac97_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &ac97_data,
+	},
+	.resource	= ac97_resources,
+	.num_resources	= ARRAY_SIZE(ac97_resources),
+};
+
+void __init at91_add_device_ac97(struct atmel_ac97_data *ek_data)
+{
+	/* Set platform data */
+	ac97_data = *ek_data;
+
+	/* pins used for AC97 interface */
+	at91_set_A_periph(AT91_PIN_PB0, 0);  /* AC97FS */
+	at91_set_A_periph(AT91_PIN_PB1, 0);  /* AC97CK */
+	at91_set_A_periph(AT91_PIN_PB2, 0);  /* AC97TX */
+	at91_set_A_periph(AT91_PIN_PB3, 0);  /* AC97RX */
+
+	/* reset */
+	at91_set_gpio_output(ac97_data.reset_pin, 0);
+	at91_set_gpio_value(ac97_data.reset_pin, 0);
+	udelay(10);
+	at91_set_gpio_value(ac97_data.reset_pin, 1);
+
+	platform_device_register(&at91sam9263_ac97_device);
+}
+#else
+void __init at91_add_device_ac97(struct atmel_ac97_data *ek_data) {}
+#endif
+
+
+
+/* --------------------------------------------------------------------
+ *  SPI
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
+static u64 spi_dmamask = 0xffffffffUL;
+
+static struct resource spi0_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_SPI0,
+		.end	= AT91SAM9263_BASE_SPI0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_SPI0,
+		.end	= AT91SAM9263_ID_SPI0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_spi0_device = {
+	.name		= "atmel_spi",
+	.id		= 0,
+	.dev		= {
+				.dma_mask		= &spi_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+	},
+	.resource	= spi0_resources,
+	.num_resources	= ARRAY_SIZE(spi0_resources),
+};
+
+static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA5, AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PB11 };
+
+static struct resource spi1_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_SPI1,
+		.end	= AT91SAM9263_BASE_SPI1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_SPI1,
+		.end	= AT91SAM9263_ID_SPI1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9263_spi1_device = {
+	.name		= "atmel_spi",
+	.id		= 1,
+	.dev		= {
+				.dma_mask		= &spi_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+	},
+	.resource	= spi1_resources,
+	.num_resources	= ARRAY_SIZE(spi1_resources),
+};
+
+static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB15, AT91_PIN_PB16, AT91_PIN_PB17, AT91_PIN_PB18 };
+
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
+{
+	int i;
+	unsigned long cs_pin;
+	short enable_spi0 = 0;
+	short enable_spi1 = 0;
+
+	/* Choose SPI chip-selects */
+	for (i = 0; i < nr_devices; i++) {
+		if (devices[i].controller_data)
+			cs_pin = (unsigned long) devices[i].controller_data;
+		else if (devices[i].bus_num == 0)
+			cs_pin = spi0_standard_cs[devices[i].chip_select];
+		else
+			cs_pin = spi1_standard_cs[devices[i].chip_select];
+
+		if (devices[i].bus_num == 0)
+			enable_spi0 = 1;
+		else
+			enable_spi1 = 1;
+
+		/* enable chip-select pin */
+		at91_set_gpio_output(cs_pin, 1);
+
+		/* pass chip-select pin to driver */
+		devices[i].controller_data = (void *) cs_pin;
+	}
+
+	spi_register_board_info(devices, nr_devices);
+
+	/* Configure SPI bus(es) */
+	if (enable_spi0) {
+		at91_set_B_periph(AT91_PIN_PA0, 0);	/* SPI0_MISO */
+		at91_set_B_periph(AT91_PIN_PA1, 0);	/* SPI0_MOSI */
+		at91_set_B_periph(AT91_PIN_PA2, 0);	/* SPI0_SPCK */
+
+		at91_clock_associate("spi0_clk", &at91sam9263_spi0_device.dev, "spi_clk");
+		platform_device_register(&at91sam9263_spi0_device);
+	}
+	if (enable_spi1) {
+		at91_set_A_periph(AT91_PIN_PB12, 0);	/* SPI1_MISO */
+		at91_set_A_periph(AT91_PIN_PB13, 0);	/* SPI1_MOSI */
+		at91_set_A_periph(AT91_PIN_PB14, 0);	/* SPI1_SPCK */
+
+		at91_clock_associate("spi1_clk", &at91sam9263_spi1_device.dev, "spi_clk");
+		platform_device_register(&at91sam9263_spi1_device);
+	}
+}
+#else
+void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  LCD Controller
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static u64 lcdc_dmamask = 0xffffffffUL;
+static struct atmel_lcdfb_info lcdc_data;
+
+static struct resource lcdc_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_LCDC_BASE,
+		.end	= AT91SAM9263_LCDC_BASE + SZ_4K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_LCDC,
+		.end	= AT91SAM9263_ID_LCDC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91_lcdc_device = {
+	.name           = "atmel_lcdfb",
+	.id             = 0,
+	.dev            = {
+				.dma_mask          = &lcdc_dmamask,
+				.coherent_dma_mask = 0xffffffff,
+				.platform_data     = &lcdc_data,
+	},
+	.resource       = lcdc_resources,
+	.num_resources  = ARRAY_SIZE(lcdc_resources),
+};
+
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data)
+{
+	if (!data) {
+		return;
+	}
+
+	/* configure PIO for LCDC */
+        at91_set_A_periph(AT91_PIN_PC1, 0);	/* LCDHSYNC */
+        at91_set_A_periph(AT91_PIN_PC2, 0);	/* LCDDOTCK */
+        at91_set_A_periph(AT91_PIN_PC3, 0);	/* LCDDEN */
+        at91_set_B_periph(AT91_PIN_PB9, 0);	/* LCDCC */
+        at91_set_A_periph(AT91_PIN_PC6, 0);	/* LCDD2 */
+        at91_set_A_periph(AT91_PIN_PC7, 0);	/* LCDD3 */
+        at91_set_A_periph(AT91_PIN_PC8, 0);	/* LCDD4 */
+        at91_set_A_periph(AT91_PIN_PC9, 0);	/* LCDD5 */
+        at91_set_A_periph(AT91_PIN_PC10, 0);	/* LCDD6 */
+        at91_set_A_periph(AT91_PIN_PC11, 0);	/* LCDD7 */
+        at91_set_A_periph(AT91_PIN_PC14, 0);	/* LCDD10 */
+        at91_set_A_periph(AT91_PIN_PC15, 0);	/* LCDD11 */
+        at91_set_A_periph(AT91_PIN_PC16, 0);	/* LCDD12 */
+        at91_set_B_periph(AT91_PIN_PC12, 0);	/* LCDD13 */
+        at91_set_A_periph(AT91_PIN_PC18, 0);	/* LCDD14 */
+        at91_set_A_periph(AT91_PIN_PC19, 0);	/* LCDD15 */
+        at91_set_A_periph(AT91_PIN_PC22, 0);	/* LCDD18 */
+        at91_set_A_periph(AT91_PIN_PC23, 0);	/* LCDD19 */
+        at91_set_A_periph(AT91_PIN_PC24, 0);	/* LCDD20 */
+        at91_set_B_periph(AT91_PIN_PC17, 0);	/* LCDD21 */
+        at91_set_A_periph(AT91_PIN_PC26, 0);	/* LCDD22 */
+        at91_set_A_periph(AT91_PIN_PC27, 0);	/* LCDD23 */
+
+	lcdc_data = *data;
+	platform_device_register(&at91_lcdc_device);
+}
+#else
+void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  LEDs
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_LEDS)
+u8 at91_leds_cpu;
+u8 at91_leds_timer;
+
+void __init at91_init_leds(u8 cpu_led, u8 timer_led)
+{
+	/* Enable GPIO to access the LEDs */
+	at91_set_gpio_output(cpu_led, 1);
+	at91_set_gpio_output(timer_led, 1);
+
+	at91_leds_cpu	= cpu_led;
+	at91_leds_timer	= timer_led;
+}
+#else
+void __init at91_init_leds(u8 cpu_led, u8 timer_led) {}
+#endif
+
+
+#if defined(CONFIG_NEW_LEDS)
+
+static struct platform_device at91_leds = {
+	.name		= "at91_leds",
+	.id		= -1,
+};
+
+void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr)
+{
+	if (!nr)
+		return;
+
+	at91_leds.dev.platform_data = leds;
+
+	for ( ; nr; nr--, leds++) {
+		leds->index = nr;	/* first record stores number of leds */
+		at91_set_gpio_output(leds->gpio, (leds->flags & 1) == 0);
+	}
+
+	platform_device_register(&at91_leds);
+}
+#else
+void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr) {}
+#endif
+
+
+/* --------------------------------------------------------------------
+ *  UART
+ * -------------------------------------------------------------------- */
+
+#if defined(CONFIG_SERIAL_ATMEL)
+
+static struct resource dbgu_resources[] = {
+	[0] = {
+		.start	= AT91_VA_BASE_SYS + AT91_DBGU,
+		.end	= AT91_VA_BASE_SYS + AT91_DBGU + SZ_512 - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91_ID_SYS,
+		.end	= AT91_ID_SYS,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct atmel_uart_data dbgu_data = {
+	.use_dma_tx	= 0,
+	.use_dma_rx	= 0,		/* DBGU not capable of receive DMA */
+	.regs		= (void __iomem *)(AT91_VA_BASE_SYS + AT91_DBGU),
+};
+
+static struct platform_device at91sam9263_dbgu_device = {
+	.name		= "atmel_usart",
+	.id		= 0,
+	.dev		= {
+				.platform_data	= &dbgu_data,
+				.coherent_dma_mask = 0xffffffff,
+	},
+	.resource	= dbgu_resources,
+	.num_resources	= ARRAY_SIZE(dbgu_resources),
+};
+
+static inline void configure_dbgu_pins(void)
+{
+	at91_set_A_periph(AT91_PIN_PC30, 0);		/* DRXD */
+	at91_set_A_periph(AT91_PIN_PC31, 1);		/* DTXD */
+}
+
+static struct resource uart0_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_US0,
+		.end	= AT91SAM9263_BASE_US0 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_US0,
+		.end	= AT91SAM9263_ID_US0,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct atmel_uart_data uart0_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+
+static struct platform_device at91sam9263_uart0_device = {
+	.name		= "atmel_usart",
+	.id		= 1,
+	.dev		= {
+				.platform_data	= &uart0_data,
+				.coherent_dma_mask = 0xffffffff,
+	},
+	.resource	= uart0_resources,
+	.num_resources	= ARRAY_SIZE(uart0_resources),
+};
+
+static inline void configure_usart0_pins(void)
+{
+	at91_set_A_periph(AT91_PIN_PA26, 1);		/* TXD0 */
+	at91_set_A_periph(AT91_PIN_PA27, 0);		/* RXD0 */
+	at91_set_A_periph(AT91_PIN_PA28, 0);		/* RTS0 */
+	at91_set_A_periph(AT91_PIN_PA29, 0);		/* CTS0 */
+}
+
+static struct resource uart1_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_US1,
+		.end	= AT91SAM9263_BASE_US1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_US1,
+		.end	= AT91SAM9263_ID_US1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct atmel_uart_data uart1_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+
+static struct platform_device at91sam9263_uart1_device = {
+	.name		= "atmel_usart",
+	.id		= 2,
+	.dev		= {
+				.platform_data	= &uart1_data,
+				.coherent_dma_mask = 0xffffffff,
+	},
+	.resource	= uart1_resources,
+	.num_resources	= ARRAY_SIZE(uart1_resources),
+};
+
+static inline void configure_usart1_pins(void)
+{
+	at91_set_A_periph(AT91_PIN_PD0, 1);		/* TXD1 */
+	at91_set_A_periph(AT91_PIN_PD1, 0);		/* RXD1 */
+	at91_set_B_periph(AT91_PIN_PD7, 0);		/* RTS1 */
+	at91_set_B_periph(AT91_PIN_PD8, 0);		/* CTS1 */
+}
+
+static struct resource uart2_resources[] = {
+	[0] = {
+		.start	= AT91SAM9263_BASE_US2,
+		.end	= AT91SAM9263_BASE_US2 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9263_ID_US2,
+		.end	= AT91SAM9263_ID_US2,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct atmel_uart_data uart2_data = {
+	.use_dma_tx	= 1,
+	.use_dma_rx	= 1,
+};
+
+static struct platform_device at91sam9263_uart2_device = {
+	.name		= "atmel_usart",
+	.id		= 3,
+	.dev		= {
+				.platform_data	= &uart2_data,
+				.coherent_dma_mask = 0xffffffff,
+	},
+	.resource	= uart2_resources,
+	.num_resources	= ARRAY_SIZE(uart2_resources),
+};
+
+static inline void configure_usart2_pins(void)
+{
+	at91_set_A_periph(AT91_PIN_PD2, 1);		/* TXD2 */
+	at91_set_A_periph(AT91_PIN_PD3, 0);		/* RXD2 */
+	at91_set_B_periph(AT91_PIN_PD5, 0);		/* RTS2 */
+	at91_set_B_periph(AT91_PIN_PD6, 0);		/* CTS2 */
+}
+
+struct platform_device *at91_uarts[ATMEL_MAX_UART];	/* the UARTs to use */
+struct platform_device *atmel_default_console_device;	/* the serial console device */
+
+void __init at91_init_serial(struct at91_uart_config *config)
+{
+	int i;
+
+	/* Fill in list of supported UARTs */
+	for (i = 0; i < config->nr_tty; i++) {
+		switch (config->tty_map[i]) {
+			case 0:
+				configure_usart0_pins();
+				at91_uarts[i] = &at91sam9263_uart0_device;
+				at91_clock_associate("usart0_clk", &at91sam9263_uart0_device.dev, "usart");
+				break;
+			case 1:
+				configure_usart1_pins();
+				at91_uarts[i] = &at91sam9263_uart1_device;
+				at91_clock_associate("usart1_clk", &at91sam9263_uart1_device.dev, "usart");
+				break;
+			case 2:
+				configure_usart2_pins();
+				at91_uarts[i] = &at91sam9263_uart2_device;
+				at91_clock_associate("usart2_clk", &at91sam9263_uart2_device.dev, "usart");
+				break;
+			case 3:
+				configure_dbgu_pins();
+				at91_uarts[i] = &at91sam9263_dbgu_device;
+				at91_clock_associate("mck", &at91sam9263_dbgu_device.dev, "usart");
+				break;
+			default:
+				continue;
+		}
+		at91_uarts[i]->id = i;		/* update ID number to mapped ID */
+	}
+
+	/* Set serial console device */
+	if (config->console_tty < ATMEL_MAX_UART)
+		atmel_default_console_device = at91_uarts[config->console_tty];
+	if (!atmel_default_console_device)
+		printk(KERN_INFO "AT91: No default serial console defined.\n");
+}
+
+void __init at91_add_device_serial(void)
+{
+	int i;
+
+	for (i = 0; i < ATMEL_MAX_UART; i++) {
+		if (at91_uarts[i])
+			platform_device_register(at91_uarts[i]);
+	}
+}
+#else
+void __init at91_init_serial(struct at91_uart_config *config) {}
+void __init at91_add_device_serial(void) {}
+#endif
+
+
+/* -------------------------------------------------------------------- */
+/*
+ * These devices are always present and don't need any board-specific
+ * setup.
+ */
+static int __init at91_add_standard_devices(void)
+{
+	return 0;
+}
+
+arch_initcall(at91_add_standard_devices);
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/at91sam926x_time.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam926x_time.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/at91sam926x_time.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/at91sam926x_time.c	2008-02-07 10:24:58.000000000 -0500
@@ -30,7 +30,6 @@
  * Returns number of microseconds since last timer interrupt.  Note that interrupts
  * will have been disabled by do_gettimeofday()
  *  'LATCH' is hwclock ticks (see CLOCK_TICK_RATE in timex.h) per jiffy.
- *  'tick' is usecs per jiffy (linux/timex.h).
  */
 static unsigned long at91sam926x_gettimeoffset(void)
 {
@@ -39,7 +38,7 @@ static unsigned long at91sam926x_gettime
 
 	elapsed = (PIT_PICNT(t) * LATCH) + PIT_CPIV(t);		/* hardware clock cycles */
 
-	return (unsigned long)(elapsed * 1000000) / LATCH;
+	return (unsigned long)(elapsed * jiffies_to_usecs(1)) / LATCH;
 }
 
 /*
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/atod-som9260m.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/atod-som9260m.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/atod-som9260m.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/atod-som9260m.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,97 @@
+/*
+ * arch/arm/mach-at91rm9200/atod-som9260m.c
+ * EMAC.Inc SOM9260m low level AtoD interactions
+ *
+ * Copyright (C) 2007 EMAC.Inc <support@emacinc.com>
+ */
+
+
+#include "atod-som9260m.h"
+
+/* Global Variables Used in the Driver. */
+int drdy;
+void __iomem *adc_base;
+struct clk *adc_clk;
+
+
+int som9260m_atod_init(void){
+	
+	adc_clk = clk_get(NULL, "adc_clk");
+	clk_enable(adc_clk);
+
+	at91_set_A_periph(AT91_PIN_PC0,0);
+	at91_set_A_periph(AT91_PIN_PC1,0);
+	at91_set_A_periph(AT91_PIN_PC2,0);
+	at91_set_A_periph(AT91_PIN_PC3,0);
+	
+
+	//Set up the ADC
+	adc_base = ioremap(AT91SAM9260_BASE_ADC,SZ_16K);
+	__raw_writel((SHTIM << 24 | STARTUP << 16 | PRESCAL << 8 | SLEEP_MODE << 5 | 
+	LOWRES << 4 | TRGSEL << 1 | TRGEN), adc_base + ADC_MR); //Mode setup
+	__raw_writel((0x1 << 0)^(0xF), adc_base + ADC_CHDR);    //Disable Channels 1-3
+	__raw_writel((0x1 << 0), adc_base + ADC_CHER);     		//Enable Channel 0	
+	return 0;
+}
+
+int som9260m_atod_switch(int channel){
+	
+	__raw_writel((0x1 << channel)^(0xF), adc_base + ADC_CHDR);	//Disable Channels 		
+	__raw_writel((0x1 << channel), adc_base + ADC_CHER);	//Enable Channel
+	
+	return 0;
+}
+
+int som9260m_atod_read_current(void){
+	int data;
+	  
+	drdy = __raw_readl(adc_base + ADC_SR);
+	if (drdy & 0x10000){
+		data = __raw_readl(adc_base + ADC_LCDR);
+		return data;
+	}
+	else 
+		return -1;
+	
+	
+	
+	return (data);
+}
+
+static gpio_data atod_data_read(struct gpio_s *gpio){
+	int data;	
+	
+	
+	__raw_writel(0x02, adc_base + ADC_CR); //starts the conversion
+	
+	do {data = som9260m_atod_read_current();}
+	while(data==-1);//get first available data
+
+	return data;	
+}
+
+static gpio_data atod_index_read(struct gpio_s *gpio){
+	return gpio->index;
+}
+	
+static int atod_index_write(struct gpio_s *gpio,gpio_data index){
+	if(index>4)return -1;
+	if(index<0)return -1;
+	gpio->index = index;
+	som9260m_atod_switch(index);	
+	return 0;
+}
+
+struct class_device *som9260m_atod_class_create(const char *name){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	gpio->name = name;
+	gpio->subclass = GPIO_SUBCLASS;
+	gpio->data_write = gpio_empty_write;
+	gpio->data_read = atod_data_read;
+	gpio->index_write = atod_index_write;
+	gpio->index_read = atod_index_read;
+	atod_index_write(gpio,0);
+	printk("registering indexed atod device: %s\n",name);
+	return gpio_register_class_device(gpio);
+}
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/atod-som9260m.h linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/atod-som9260m.h
--- linux-2.6.20/arch/arm/mach-at91rm9200/atod-som9260m.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/atod-som9260m.h	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,45 @@
+#ifndef ATODSOM9260M_H_
+#define ATODSOM9260M_H_
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <linux/class/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/at91sam9260.h>
+#include <asm/arch/gpio.h>
+
+
+#define ADC_CR          0x00    //Control Register Offset
+#define ADC_MR          0x04    //Mode Register Offset
+#define ADC_CHER        0x10    //Channel Enable Register Offset
+#define ADC_CHDR        0x14    //Channel Disable Register Offset
+#define ADC_CHSR        0x18    //Channel Status Register Offset
+#define ADC_SR          0x1C    //Status Register Offset
+#define ADC_LCDR        0x20    //Last Converted Data Register Offset
+#define ADC_IER         0x24    //Interrupt Enable Register Offset
+#define ADC_IDR         0x28    //Interrupt Disable Register Offset
+#define ADC_IMR         0x2C    //Interrupt Mask Register Offset
+#define ADC_CDR0        0x30    //Channel Data Register 0 Offset
+#define ADC_CDR1        0x34    //Channel Data Register 1 Offset
+#define ADC_CDR2        0x38    //Channel Data Register 2 Offset
+#define ADC_CDR3        0x3C    //Channel Data Register 3 Offset
+
+/* Define some of the values we will want in the registers
+ * This can be changed to reflect the needs of the driver
+ */
+
+#define TRGEN           0x00    //Trigger Enable
+#define TRGSEL          0x00    //Trigger Select
+#define LOWRES          0x00    //Resolution
+#define SLEEP_MODE      0x00    //Sleep Mode
+#define PRESCAL         0x22   //Prescaler Rate Selection (22 --> ~100 samples/sec)
+#define STARTUP         0x02    //Start Up Time
+#define SHTIM           0x00    //Sample and Hold Time
+
+
+int som9260m_atod_init(void);
+int som9260m_atod_switch(int channel);
+int som9260m_atod_read_current(void);
+struct class_device *som9260m_atod_class_create(const char *name);
+
+#endif /*ATODSOM9260M_H_*/
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-carmeva.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-carmeva.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-carmeva.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-carmeva.c	2008-02-07 10:24:58.000000000 -0500
@@ -134,7 +134,7 @@ static void __init carmeva_board_init(vo
 	/* Compact Flash */
 //	at91_add_device_cf(&carmeva_cf_data);
 	/* MMC */
-	at91_add_device_mmc(&carmeva_mmc_data);
+	at91_add_device_mmc(0, &carmeva_mmc_data);
 }
 
 MACHINE_START(CARMEVA, "Carmeva")
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-csb337.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-csb337.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-csb337.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-csb337.c	2008-02-07 10:24:58.000000000 -0500
@@ -24,6 +24,8 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/physmap.h>
 
 #include <asm/hardware.h>
 #include <asm/setup.h>
@@ -58,6 +60,7 @@ static void __init csb337_map_io(void)
 
 	/* Setup the LEDs */
 	at91_init_leds(AT91_PIN_PB0, AT91_PIN_PB1);
+	at91_set_gpio_output(AT91_PIN_PB2, 1);		/* third (unused) LED */
 
 	/* Setup the serial ports and console */
 	at91_init_serial(&csb337_uart_config);
@@ -112,6 +115,91 @@ static struct spi_board_info csb337_spi_
 	},
 };
 
+#define CSB_FLASH_BASE	AT91_CHIPSELECT_0
+#define CSB_FLASH_SIZE	0x800000
+
+static struct mtd_partition csb_flash_partitions[] = {
+	{
+		.name		= "uMON flash",
+		.offset		= 0,
+		.size		= MTDPART_SIZ_FULL,
+		.mask_flags	= MTD_WRITEABLE,	/* read only */
+	}
+};
+
+static struct physmap_flash_data csb_flash_data = {
+	.width		= 2,
+	.parts		= csb_flash_partitions,
+	.nr_parts	= ARRAY_SIZE(csb_flash_partitions),
+};
+
+static struct resource csb_flash_resources[] = {
+	{
+		.start	= CSB_FLASH_BASE,
+		.end	= CSB_FLASH_BASE + CSB_FLASH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device csb_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+				.platform_data = &csb_flash_data,
+			},
+	.resource	= csb_flash_resources,
+	.num_resources	= ARRAY_SIZE(csb_flash_resources),
+};
+
+static struct at91_gpio_led csb337_leds[] = {
+	{
+		.name		= "led0",
+		.gpio		= AT91_PIN_PB0,
+		.trigger	= "heartbeat",
+	},
+	{
+		.name		= "led1",
+		.gpio		= AT91_PIN_PB1,
+		.trigger	= "timer",
+	},
+	{
+		.name		= "led2",
+		.gpio		= AT91_PIN_PB2,
+	}
+};
+
+#if defined(CONFIG_CSB300_WAKE_SW0) || defined(CONFIG_CSB300_WAKE_SW1)
+static irqreturn_t switch_irq_handler(int irq, void *context)
+{
+	return IRQ_HANDLED;
+}
+
+static inline void __init switch_irq_setup(int irq, char *name, unsigned long mode)
+{
+	int res;
+
+	res = request_irq(irq, switch_irq_handler, IRQF_SAMPLE_RANDOM | mode, name, NULL);
+	if (res == 0)
+		enable_irq_wake(irq);
+}
+
+static void __init csb300_switches(void)
+{
+#ifdef CONFIG_CSB300_WAKE_SW0
+	at91_set_A_periph(AT91_PIN_PB29, 1);		/* IRQ0 */
+	switch_irq_setup(AT91RM9200_ID_IRQ0, "csb300_sw0", IRQF_TRIGGER_FALLING);
+#endif
+#ifdef CONFIG_CSB300_WAKE_SW1
+	at91_set_gpio_input(AT91_PIN_PB28, 1);
+	at91_set_deglitch(AT91_PIN_PB28, 1);
+	switch_irq_setup(AT91_PIN_PB28, "csb300_sw1", IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING);
+#endif
+	/* there's also SW2 at PA21, GPIO or TIOA2 */
+}
+#else
+static void __init csb300_switches(void) {}
+#endif
+
 static void __init csb337_board_init(void)
 {
 	/* Serial */
@@ -130,7 +218,13 @@ static void __init csb337_board_init(voi
 	/* SPI */
 	at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices));
 	/* MMC */
-	at91_add_device_mmc(&csb337_mmc_data);
+	at91_add_device_mmc(0, &csb337_mmc_data);
+	/* LEDS */
+	at91_gpio_leds(csb337_leds, ARRAY_SIZE(csb337_leds));
+	/* NOR flash */
+	platform_device_register(&csb_flash);
+	/* Switches on CSB300 */
+	csb300_switches();
 }
 
 MACHINE_START(CSB337, "Cogent CSB337")
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-csb637.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-csb637.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-csb637.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-csb637.c	2008-02-07 10:24:58.000000000 -0500
@@ -23,6 +23,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
+#include <linux/mtd/physmap.h>
 
 #include <asm/hardware.h>
 #include <asm/setup.h>
@@ -81,6 +82,42 @@ static struct at91_udc_data __initdata c
 	.pullup_pin   = AT91_PIN_PB1,
 };
 
+#define CSB_FLASH_BASE	AT91_CHIPSELECT_0
+#define CSB_FLASH_SIZE	0x1000000
+
+static struct mtd_partition csb_flash_partitions[] = {
+	{
+		.name		= "uMON flash",
+		.offset		= 0,
+		.size		= MTDPART_SIZ_FULL,
+		.mask_flags	= MTD_WRITEABLE,	/* read only */
+	}
+};
+
+static struct physmap_flash_data csb_flash_data = {
+	.width		= 2,
+	.parts		= csb_flash_partitions,
+	.nr_parts	= ARRAY_SIZE(csb_flash_partitions),
+};
+
+static struct resource csb_flash_resources[] = {
+	{
+		.start	= CSB_FLASH_BASE,
+		.end	= CSB_FLASH_BASE + CSB_FLASH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device csb_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+				.platform_data = &csb_flash_data,
+			},
+	.resource	= csb_flash_resources,
+	.num_resources	= ARRAY_SIZE(csb_flash_resources),
+};
+
 static void __init csb637_board_init(void)
 {
 	/* Serial */
@@ -95,6 +132,8 @@ static void __init csb637_board_init(voi
 	at91_add_device_i2c();
 	/* SPI */
 	at91_add_device_spi(NULL, 0);
+	/* NOR flash */
+	platform_device_register(&csb_flash);
 }
 
 MACHINE_START(CSB637, "Cogent CSB637")
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-dk.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-dk.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-dk.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-dk.c	2008-02-07 10:24:58.000000000 -0500
@@ -73,6 +73,185 @@ static void __init dk_init_irq(void)
 	at91rm9200_init_interrupts(NULL);
 }
 
+#if defined(CONFIG_FB_S1D13XXX) || defined(CONFIG_FB_S1D13XXX_MODULE)
+#include <video/s1d13xxxfb.h>
+#include <asm/arch/ics1523.h>
+
+/* EPSON S1D13806 FB */
+#define AT91_FB_REG_BASE	0x30000000L
+#define AT91_FB_REG_SIZE	0x200
+#define AT91_FB_VMEM_BASE	0x30200000L
+#define AT91_FB_VMEM_SIZE	0x140000L
+
+static void __init dk_init_video(void)
+{
+	/* NWAIT Signal */
+	at91_set_A_periph(AT91_PIN_PC6, 0);
+
+	/* Initialization of the Static Memory Controller for Chip Select 2 */
+	at91_sys_write(AT91_SMC_CSR(2), AT91_SMC_DBW_16			/* 16 bit */
+				| AT91_SMC_WSEN | AT91_SMC_NWS_(4)	/* wait states */
+				| AT91_SMC_TDF_(1)			/* float time */
+	);
+
+	at91_ics1523_init();
+}
+
+/* CRT:    (active)   640x480 60Hz (PCLK=CLKI=25.175MHz)
+   Memory: Embedded SDRAM (MCLK=CLKI3=50.000MHz) (BUSCLK=60.000MHz) */
+static const struct s1d13xxxfb_regval dk_s1dfb_initregs[] = {
+	{S1DREG_MISC,			0x00},	/* Enable Memory/Register select bit */
+	{S1DREG_COM_DISP_MODE,		0x00},	/* disable display output */
+	{S1DREG_GPIO_CNF0,		0x00},
+	{S1DREG_GPIO_CNF1,		0x00},
+	{S1DREG_GPIO_CTL0,		0x08},
+	{S1DREG_GPIO_CTL1,		0x00},
+	{S1DREG_CLK_CNF,		0x01},	/* no divide, MCLK source is CLKI3 0x02*/
+	{S1DREG_LCD_CLK_CNF,		0x00},
+	{S1DREG_CRT_CLK_CNF,		0x00},
+	{S1DREG_MPLUG_CLK_CNF,		0x00},
+	{S1DREG_CPU2MEM_WST_SEL,	0x01},	/* 2*period(MCLK) - 4ns > period(BCLK) */
+	{S1DREG_SDRAM_REF_RATE,		0x03},	/* 32768 <= MCLK <= 50000 (MHz) */
+	{S1DREG_SDRAM_TC0,		0x00},	/* MCLK source freq (MHz): */
+	{S1DREG_SDRAM_TC1,		0x01},	/* 42 <= MCLK <= 50 */
+	{S1DREG_MEM_CNF,		0x80},	/* SDRAM Initialization - needed before mem access */
+	{S1DREG_PANEL_TYPE,		0x25},	/* std TFT 16bit, 8bit SCP format 2, single passive LCD */
+	{S1DREG_MOD_RATE,		0x00},	/* toggle every FPFRAME */
+	{S1DREG_LCD_DISP_HWIDTH,	0x4F},	/* 680 pix */
+	{S1DREG_LCD_NDISP_HPER,		0x12},	/* 152 pix */
+	{S1DREG_TFT_FPLINE_START,	0x01},	/* 13 pix */
+	{S1DREG_TFT_FPLINE_PWIDTH,	0x0B},	/* 96 pix */
+	{S1DREG_LCD_DISP_VHEIGHT0,	0xDF},
+	{S1DREG_LCD_DISP_VHEIGHT1,	0x01},	/* 480 lines */
+	{S1DREG_LCD_NDISP_VPER,		0x2C},	/* 44 lines */
+	{S1DREG_TFT_FPFRAME_START,	0x0A},	/* 10 lines */
+	{S1DREG_TFT_FPFRAME_PWIDTH,	0x01},	/* 2 lines */
+	{S1DREG_LCD_DISP_MODE,		0x05},  /* 16 bpp */
+	{S1DREG_LCD_MISC,		0x00},	/* dithering enabled, dual panel buffer enabled */
+	{S1DREG_LCD_DISP_START0,	0x00},
+	{S1DREG_LCD_DISP_START1,	0xC8},
+	{S1DREG_LCD_DISP_START2,	0x00},
+	{S1DREG_LCD_MEM_OFF0,		0x80},
+	{S1DREG_LCD_MEM_OFF1,		0x02},
+	{S1DREG_LCD_PIX_PAN,		0x00},
+	{S1DREG_LCD_DISP_FIFO_HTC,	0x3B},
+	{S1DREG_LCD_DISP_FIFO_LTC,	0x3C},
+	{S1DREG_CRT_DISP_HWIDTH,	0x4F},	/* 680 pix */
+	{S1DREG_CRT_NDISP_HPER,		0x13},	/* 160 pix */
+	{S1DREG_CRT_HRTC_START,		0x01},	/* 13 pix */
+	{S1DREG_CRT_HRTC_PWIDTH,	0x0B},	/* 96 pix */
+	{S1DREG_CRT_DISP_VHEIGHT0,	0xDF},
+	{S1DREG_CRT_DISP_VHEIGHT1,	0x01},	/* 480 lines */
+	{S1DREG_CRT_NDISP_VPER,		0x2B},	/* 44 lines */
+	{S1DREG_CRT_VRTC_START,		0x09},	/* 10 lines */
+	{S1DREG_CRT_VRTC_PWIDTH,	0x01},	/* 2 lines */
+	{S1DREG_TV_OUT_CTL,		0x10},
+	{S1DREG_CRT_DISP_MODE,		0x05},	/* 16 bpp */
+	{S1DREG_CRT_DISP_START0,	0x00},
+	{S1DREG_CRT_DISP_START1,	0x00},
+	{S1DREG_CRT_DISP_START2,	0x00},
+	{S1DREG_CRT_MEM_OFF0,		0x80},
+	{S1DREG_CRT_MEM_OFF1,		0x02},
+	{S1DREG_CRT_PIX_PAN,		0x00},
+	{S1DREG_CRT_DISP_FIFO_HTC,	0x3B},
+	{S1DREG_CRT_DISP_FIFO_LTC,	0x3C},
+	{S1DREG_LCD_CUR_CTL,		0x00},	/* inactive */
+	{S1DREG_LCD_CUR_START,		0x01},
+	{S1DREG_LCD_CUR_XPOS0,		0x00},
+	{S1DREG_LCD_CUR_XPOS1,		0x00},
+	{S1DREG_LCD_CUR_YPOS0,		0x00},
+	{S1DREG_LCD_CUR_YPOS1,		0x00},
+	{S1DREG_LCD_CUR_BCTL0,		0x00},
+	{S1DREG_LCD_CUR_GCTL0,		0x00},
+	{S1DREG_LCD_CUR_RCTL0,		0x00},
+	{S1DREG_LCD_CUR_BCTL1,		0x1F},
+	{S1DREG_LCD_CUR_GCTL1,		0x3F},
+	{S1DREG_LCD_CUR_RCTL1,		0x1F},
+	{S1DREG_LCD_CUR_FIFO_HTC,	0x00},
+	{S1DREG_CRT_CUR_CTL,		0x00},	/* inactive */
+	{S1DREG_CRT_CUR_START,		0x01},
+	{S1DREG_CRT_CUR_XPOS0,		0x00},
+	{S1DREG_CRT_CUR_XPOS1,		0x00},
+	{S1DREG_CRT_CUR_YPOS0,		0x00},
+	{S1DREG_CRT_CUR_YPOS1,		0x00},
+	{S1DREG_CRT_CUR_BCTL0,		0x00},
+	{S1DREG_CRT_CUR_GCTL0,		0x00},
+	{S1DREG_CRT_CUR_RCTL0,		0x00},
+	{S1DREG_CRT_CUR_BCTL1,		0x1F},
+	{S1DREG_CRT_CUR_GCTL1,		0x3F},
+	{S1DREG_CRT_CUR_RCTL1,		0x1F},
+	{S1DREG_CRT_CUR_FIFO_HTC,	0x00},
+	{S1DREG_BBLT_CTL0,		0x00},
+	{S1DREG_BBLT_CTL0,		0x00},
+	{S1DREG_BBLT_CC_EXP,		0x00},
+	{S1DREG_BBLT_OP,		0x00},
+	{S1DREG_BBLT_SRC_START0,	0x00},
+	{S1DREG_BBLT_SRC_START1,	0x00},
+	{S1DREG_BBLT_SRC_START2,	0x00},
+	{S1DREG_BBLT_DST_START0,	0x00},
+	{S1DREG_BBLT_DST_START1,	0x00},
+	{S1DREG_BBLT_DST_START2,	0x00},
+	{S1DREG_BBLT_MEM_OFF0,		0x00},
+	{S1DREG_BBLT_MEM_OFF1,		0x00},
+	{S1DREG_BBLT_WIDTH0,		0x00},
+	{S1DREG_BBLT_WIDTH1,		0x00},
+	{S1DREG_BBLT_HEIGHT0,		0x00},
+	{S1DREG_BBLT_HEIGHT1,		0x00},
+	{S1DREG_BBLT_BGC0,		0x00},
+	{S1DREG_BBLT_BGC1,		0x00},
+	{S1DREG_BBLT_FGC0,		0x00},
+	{S1DREG_BBLT_FGC1,		0x00},
+	{S1DREG_LKUP_MODE,		0x00},	/* LCD LUT r | LCD and CRT/TV LUT w */
+	{S1DREG_LKUP_ADDR,		0x00},
+	{S1DREG_PS_CNF,			0x00},	/* Power Save disable */
+	{S1DREG_PS_STATUS,		0x02},	/* LCD Panel down, mem up */
+	{S1DREG_CPU2MEM_WDOGT,		0x00},
+	{S1DREG_COM_DISP_MODE,		0x02},	/* enable CRT display output */
+};
+
+static struct s1d13xxxfb_pdata dk_s1dfb_pdata = {
+	.initregs		= dk_s1dfb_initregs,
+	.initregssize		= ARRAY_SIZE(dk_s1dfb_initregs),
+	.platform_init_video	= dk_init_video,
+};
+
+static u64 s1dfb_dmamask = 0xffffffffUL;
+
+static struct resource dk_s1dfb_resource[] = {
+	[0] = {	/* video mem */
+		.name   = "s1d13806 memory",
+		.start  = AT91_FB_VMEM_BASE,
+		.end    = AT91_FB_VMEM_BASE + AT91_FB_VMEM_SIZE -1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {	/* video registers */
+		.name   = "s1d13806 registers",
+		.start  = AT91_FB_REG_BASE,
+		.end    = AT91_FB_REG_BASE + AT91_FB_REG_SIZE -1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device dk_s1dfb_device = {
+	.name		= "s1d13806fb",
+	.id		= -1,
+	.dev		= {
+			.dma_mask		= &s1dfb_dmamask,
+			.coherent_dma_mask	= 0xffffffff,
+			.platform_data		= &dk_s1dfb_pdata,
+	},
+	.resource	= dk_s1dfb_resource,
+	.num_resources	= ARRAY_SIZE(dk_s1dfb_resource),
+};
+
+static void __init dk_add_device_video(void)
+{
+	platform_device_register(&dk_s1dfb_device);
+}
+#else
+static void __init dk_add_device_video(void) {}
+#endif
+
 static struct at91_eth_data __initdata dk_eth_data = {
 	.phy_irq_pin	= AT91_PIN_PC4,
 	.is_rmii	= 1,
@@ -151,7 +330,7 @@ static struct at91_nand_data __initdata 
 #define DK_FLASH_SIZE	0x200000
 
 static struct physmap_flash_data dk_flash_data = {
-	.width	= 2,
+	.width		= 2,
 };
 
 static struct resource dk_flash_resource = {
@@ -170,6 +349,13 @@ static struct platform_device dk_flash =
 	.num_resources	= 1,
 };
 
+static struct at91_gpio_led dk_leds[] = {
+	{
+		.name		= "led0",
+		.gpio		= AT91_PIN_PB2,
+		.trigger	= "timer",
+	}
+};
 
 static void __init dk_board_init(void)
 {
@@ -194,14 +380,16 @@ static void __init dk_board_init(void)
 #else
 	/* MMC */
 	at91_set_gpio_output(AT91_PIN_PB7, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
-	at91_add_device_mmc(&dk_mmc_data);
+	at91_add_device_mmc(0, &dk_mmc_data);
 #endif
 	/* NAND */
 	at91_add_device_nand(&dk_nand_data);
 	/* NOR Flash */
 	platform_device_register(&dk_flash);
+	/* LEDs */
+	at91_gpio_leds(dk_leds, ARRAY_SIZE(dk_leds));
 	/* VGA */
-//	dk_add_device_video();
+	dk_add_device_video();
 }
 
 MACHINE_START(AT91RM9200DK, "Atmel AT91RM9200-DK")
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-eb9200.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-eb9200.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-eb9200.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-eb9200.c	2008-02-07 10:24:58.000000000 -0500
@@ -109,7 +109,7 @@ static void __init eb9200_board_init(voi
 	at91_add_device_spi(NULL, 0);
 	/* MMC */
 	/* only supports 1 or 4 bit interface, not wired through to SPI */
-	at91_add_device_mmc(&eb9200_mmc_data);
+	at91_add_device_mmc(0, &eb9200_mmc_data);
 }
 
 MACHINE_START(ATEB9200, "Embest ATEB9200")
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-ek.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-ek.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-ek.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-ek.c	2008-02-07 10:24:58.000000000 -0500
@@ -73,6 +73,187 @@ static void __init ek_init_irq(void)
 	at91rm9200_init_interrupts(NULL);
 }
 
+#if defined(CONFIG_FB_S1D13XXX) || defined(CONFIG_FB_S1D13XXX_MODULE)
+#include <video/s1d13xxxfb.h>
+#include <asm/arch/ics1523.h>
+
+/* EPSON S1D13806 FB */
+#define AT91_FB_REG_BASE	0x40000000L
+#define	AT91_FB_REG_SIZE	0x200
+#define AT91_FB_VMEM_BASE	0x40200000L
+#define AT91_FB_VMEM_SIZE	0x140000L
+
+static void __init ek_init_video(void)
+{
+	/* NWAIT Signal */
+	at91_set_A_periph(AT91_PIN_PC6, 0);
+
+	/* Initialization of the Static Memory Controller for Chip Select 3 */
+	at91_sys_write(AT91_SMC_CSR(3), AT91_SMC_DBW_16			/* 16 bit */
+				| AT91_SMC_WSEN | AT91_SMC_NWS_(5)	/* wait states */
+				| AT91_SMC_TDF_(1)			/* float time */
+	);
+
+	at91_ics1523_init();
+}
+
+/* CRT:    (active)   640x480 60Hz (PCLK=CLKI=25.175MHz)
+   Memory: Embedded SDRAM (MCLK=CLKI3=50.000MHz) (BUSCLK=60.000MHz) */
+static const struct s1d13xxxfb_regval ek_s1dfb_initregs[] = {
+	{S1DREG_MISC,			0x00},	/* Enable Memory/Register select bit */
+	{S1DREG_COM_DISP_MODE,		0x00},	/* disable display output */
+	{S1DREG_GPIO_CNF0,		0xFF},	// 0x00
+	{S1DREG_GPIO_CNF1,		0x1F},	// 0x08
+	{S1DREG_GPIO_CTL0,		0x00},
+	{S1DREG_GPIO_CTL1,		0x00},
+	{S1DREG_CLK_CNF,		0x01},	/* no divide, MCLK source is CLKI3 0x02*/
+	{S1DREG_LCD_CLK_CNF,		0x00},
+	{S1DREG_CRT_CLK_CNF,		0x00},
+	{S1DREG_MPLUG_CLK_CNF,		0x00},
+	{S1DREG_CPU2MEM_WST_SEL,	0x01},	/* 2*period(MCLK) - 4ns > period(BCLK) */
+	{S1DREG_SDRAM_REF_RATE,		0x03},	/* 32768 <= MCLK <= 50000 (MHz) */
+	{S1DREG_SDRAM_TC0,		0x00},	/* MCLK source freq (MHz): */
+	{S1DREG_SDRAM_TC1,		0x01},	/* 42 <= MCLK <= 50 */
+	{S1DREG_MEM_CNF,		0x80},	/* SDRAM Initialization - needed before mem access */
+	{S1DREG_PANEL_TYPE,		0x25},	/* std TFT 16bit, 8bit SCP format 2, single passive LCD */
+	{S1DREG_MOD_RATE,		0x00},	/* toggle every FPFRAME */
+	{S1DREG_LCD_DISP_HWIDTH,	0x4F},	/* 680 pix */
+	{S1DREG_LCD_NDISP_HPER,		0x12},	/* 152 pix */
+	{S1DREG_TFT_FPLINE_START,	0x01},	/* 13 pix */
+	{S1DREG_TFT_FPLINE_PWIDTH,	0x0B},	/* 96 pix */
+	{S1DREG_LCD_DISP_VHEIGHT0,	0xDF},
+	{S1DREG_LCD_DISP_VHEIGHT1,	0x01},	/* 480 lines */
+	{S1DREG_LCD_NDISP_VPER,		0x2C},	/* 44 lines */
+	{S1DREG_TFT_FPFRAME_START,	0x0A},	/* 10 lines */
+	{S1DREG_TFT_FPFRAME_PWIDTH,	0x01},	/* 2 lines */
+	{S1DREG_LCD_DISP_MODE,		0x05},  /* 16 bpp */
+	{S1DREG_LCD_MISC,		0x00},	/* dithering enabled, dual panel buffer enabled */
+	{S1DREG_LCD_DISP_START0,	0x00},
+	{S1DREG_LCD_DISP_START1,	0xC8},
+	{S1DREG_LCD_DISP_START2,	0x00},
+	{S1DREG_LCD_MEM_OFF0,		0x80},
+	{S1DREG_LCD_MEM_OFF1,		0x02},
+	{S1DREG_LCD_PIX_PAN,		0x00},
+	{S1DREG_LCD_DISP_FIFO_HTC,	0x3B},
+	{S1DREG_LCD_DISP_FIFO_LTC,	0x3C},
+	{S1DREG_CRT_DISP_HWIDTH,	0x4F},	/* 680 pix */
+	{S1DREG_CRT_NDISP_HPER,		0x13},	/* 160 pix */
+	{S1DREG_CRT_HRTC_START,		0x01},	/* 13 pix */
+	{S1DREG_CRT_HRTC_PWIDTH,	0x0B},	/* 96 pix */
+	{S1DREG_CRT_DISP_VHEIGHT0,	0xDF},
+	{S1DREG_CRT_DISP_VHEIGHT1,	0x01},	/* 480 lines */
+	{S1DREG_CRT_NDISP_VPER,		0x2B},	/* 44 lines */
+	{S1DREG_CRT_VRTC_START,		0x09},	/* 10 lines */
+	{S1DREG_CRT_VRTC_PWIDTH,	0x01},	/* 2 lines */
+	{S1DREG_TV_OUT_CTL,		0x10},
+	{0x005E,			0x9F},
+	{0x005F,			0x00},
+	{S1DREG_CRT_DISP_MODE,		0x05},	/* 16 bpp */
+	{S1DREG_CRT_DISP_START0,	0x00},
+	{S1DREG_CRT_DISP_START1,	0x00},
+	{S1DREG_CRT_DISP_START2,	0x00},
+	{S1DREG_CRT_MEM_OFF0,		0x80},
+	{S1DREG_CRT_MEM_OFF1,		0x02},
+	{S1DREG_CRT_PIX_PAN,		0x00},
+	{S1DREG_CRT_DISP_FIFO_HTC,	0x3B},
+	{S1DREG_CRT_DISP_FIFO_LTC,	0x3C},
+	{S1DREG_LCD_CUR_CTL,		0x00},	/* inactive */
+	{S1DREG_LCD_CUR_START,		0x01},
+	{S1DREG_LCD_CUR_XPOS0,		0x00},
+	{S1DREG_LCD_CUR_XPOS1,		0x00},
+	{S1DREG_LCD_CUR_YPOS0,		0x00},
+	{S1DREG_LCD_CUR_YPOS1,		0x00},
+	{S1DREG_LCD_CUR_BCTL0,		0x00},
+	{S1DREG_LCD_CUR_GCTL0,		0x00},
+	{S1DREG_LCD_CUR_RCTL0,		0x00},
+	{S1DREG_LCD_CUR_BCTL1,		0x1F},
+	{S1DREG_LCD_CUR_GCTL1,		0x3F},
+	{S1DREG_LCD_CUR_RCTL1,		0x1F},
+	{S1DREG_LCD_CUR_FIFO_HTC,	0x00},
+	{S1DREG_CRT_CUR_CTL,		0x00},	/* inactive */
+	{S1DREG_CRT_CUR_START,		0x01},
+	{S1DREG_CRT_CUR_XPOS0,		0x00},
+	{S1DREG_CRT_CUR_XPOS1,		0x00},
+	{S1DREG_CRT_CUR_YPOS0,		0x00},
+	{S1DREG_CRT_CUR_YPOS1,		0x00},
+	{S1DREG_CRT_CUR_BCTL0,		0x00},
+	{S1DREG_CRT_CUR_GCTL0,		0x00},
+	{S1DREG_CRT_CUR_RCTL0,		0x00},
+	{S1DREG_CRT_CUR_BCTL1,		0x1F},
+	{S1DREG_CRT_CUR_GCTL1,		0x3F},
+	{S1DREG_CRT_CUR_RCTL1,		0x1F},
+	{S1DREG_CRT_CUR_FIFO_HTC,	0x00},
+	{S1DREG_BBLT_CTL0,		0x00},
+	{S1DREG_BBLT_CTL0,		0x00},
+	{S1DREG_BBLT_CC_EXP,		0x00},
+	{S1DREG_BBLT_OP,		0x00},
+	{S1DREG_BBLT_SRC_START0,	0x00},
+	{S1DREG_BBLT_SRC_START1,	0x00},
+	{S1DREG_BBLT_SRC_START2,	0x00},
+	{S1DREG_BBLT_DST_START0,	0x00},
+	{S1DREG_BBLT_DST_START1,	0x00},
+	{S1DREG_BBLT_DST_START2,	0x00},
+	{S1DREG_BBLT_MEM_OFF0,		0x00},
+	{S1DREG_BBLT_MEM_OFF1,		0x00},
+	{S1DREG_BBLT_WIDTH0,		0x00},
+	{S1DREG_BBLT_WIDTH1,		0x00},
+	{S1DREG_BBLT_HEIGHT0,		0x00},
+	{S1DREG_BBLT_HEIGHT1,		0x00},
+	{S1DREG_BBLT_BGC0,		0x00},
+	{S1DREG_BBLT_BGC1,		0x00},
+	{S1DREG_BBLT_FGC0,		0x00},
+	{S1DREG_BBLT_FGC1,		0x00},
+	{S1DREG_LKUP_MODE,		0x00},	/* LCD LUT r | LCD and CRT/TV LUT w */
+	{S1DREG_LKUP_ADDR,		0x00},
+	{S1DREG_PS_CNF,			0x10},	/* Power Save disable */
+	{S1DREG_PS_STATUS,		0x02},	/* LCD Panel down, mem up */
+	{S1DREG_CPU2MEM_WDOGT,		0x00},
+	{S1DREG_COM_DISP_MODE,		0x02},	/* enable CRT display output */
+};
+
+static struct s1d13xxxfb_pdata ek_s1dfb_pdata = {
+	.initregs		= ek_s1dfb_initregs,
+	.initregssize		= ARRAY_SIZE(ek_s1dfb_initregs),
+	.platform_init_video	= ek_init_video,
+};
+
+static u64 s1dfb_dmamask = 0xffffffffUL;
+
+static struct resource ek_s1dfb_resource[] = {
+	[0] = {	/* video mem */
+		.name   = "s1d13806 memory",
+		.start  = AT91_FB_VMEM_BASE,
+		.end    = AT91_FB_VMEM_BASE + AT91_FB_VMEM_SIZE -1,
+		.flags  = IORESOURCE_MEM,
+	},
+	[1] = {	/* video registers */
+		.name   = "s1d13806 registers",
+		.start  = AT91_FB_REG_BASE,
+		.end    = AT91_FB_REG_BASE + AT91_FB_REG_SIZE -1,
+		.flags  = IORESOURCE_MEM,
+	},
+};
+
+static struct platform_device ek_s1dfb_device = {
+	.name		= "s1d13806fb",
+	.id		= -1,
+	.dev		= {
+			.dma_mask		= &s1dfb_dmamask,
+			.coherent_dma_mask	= 0xffffffff,
+			.platform_data		= &ek_s1dfb_pdata,
+	},
+	.resource	= ek_s1dfb_resource,
+	.num_resources	= ARRAY_SIZE(ek_s1dfb_resource),
+};
+
+static void __init ek_add_device_video(void)
+{
+	platform_device_register(&ek_s1dfb_device);
+}
+#else
+static void __init ek_add_device_video(void) {}
+#endif
+
 static struct at91_eth_data __initdata ek_eth_data = {
 	.phy_irq_pin	= AT91_PIN_PC4,
 	.is_rmii	= 1,
@@ -113,7 +294,7 @@ static struct spi_board_info ek_spi_devi
 #define EK_FLASH_SIZE	0x200000
 
 static struct physmap_flash_data ek_flash_data = {
-	.width	= 2,
+	.width		= 2,
 };
 
 static struct resource ek_flash_resource = {
@@ -132,6 +313,18 @@ static struct platform_device ek_flash =
 	.num_resources	= 1,
 };
 
+static struct at91_gpio_led ek_leds[] = {
+	{
+		.name		= "led0",
+		.gpio		= AT91_PIN_PB1,
+		.trigger	= "heartbeat",
+	},
+	{
+		.name		= "led1",
+		.gpio		= AT91_PIN_PB2,
+		.trigger	= "timer",
+	}
+};
 
 static void __init ek_board_init(void)
 {
@@ -154,12 +347,14 @@ static void __init ek_board_init(void)
 #else
 	/* MMC */
 	at91_set_gpio_output(AT91_PIN_PB22, 1);	/* this MMC card slot can optionally use SPI signaling (CS3). */
-	at91_add_device_mmc(&ek_mmc_data);
+	at91_add_device_mmc(0, &ek_mmc_data);
 #endif
 	/* NOR Flash */
 	platform_device_register(&ek_flash);
+	/* LEDs */
+	at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
 	/* VGA */
-//	ek_add_device_video();
+	ek_add_device_video();
 }
 
 MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-kb9202.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-kb9202.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-kb9202.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-kb9202.c	2008-02-07 10:24:58.000000000 -0500
@@ -122,7 +122,7 @@ static void __init kb9202_board_init(voi
 	/* USB Device */
 	at91_add_device_udc(&kb9202_udc_data);
 	/* MMC */
-	at91_add_device_mmc(&kb9202_mmc_data);
+	at91_add_device_mmc(0, &kb9202_mmc_data);
 	/* I2C */
 	at91_add_device_i2c();
 	/* SPI */
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-sam9260ek.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-sam9260ek.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-sam9260ek.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-sam9260ek.c	2008-02-07 10:24:58.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-at91rm9200/board-ek.c
+ * linux/arch/arm/mach-at91rm9200/board-sam9260ek.c
  *
  *  Copyright (C) 2005 SAN People
  *  Copyright (C) 2006 Atmel
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
+#include <linux/clk.h>
 
 #include <asm/hardware.h>
 #include <asm/setup.h>
@@ -85,6 +86,69 @@ static struct at91_udc_data __initdata e
 
 
 /*
+ * AT73C213
+ */
+#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
+static struct atmel_at73c213_data at73c213_data;
+
+static u64 ssc_dmamask = 0xffffffffUL;
+static struct resource ssc_resource[] = {
+	[0] = {
+		.start	= AT91SAM9260_BASE_SSC,
+		.end	= AT91SAM9260_BASE_SSC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9260_ID_SSC,
+		.end	= AT91SAM9260_ID_SSC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9260_ssc_device = {
+	.name		= "atmel_ssc_at73c213",
+	.id		= -1,
+	.dev		= {
+				.dma_mask		= &ssc_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &at73c213_data,
+	},
+	.resource		= ssc_resource,
+	.num_resources	= ARRAY_SIZE(ssc_resource),
+};
+void __init at91_add_device_ssc_at73c213(void)
+{
+	struct clk *at73_clk;
+	struct clk *ssc_clk;
+	struct clk *parent_clk;
+
+	/* Set SSC1 IO */
+	at91_set_A_periph(AT91_PIN_PB16, 0);		/* TK0 */
+	at91_set_A_periph(AT91_PIN_PB17, 0);		/* TF0 */
+	at91_set_A_periph(AT91_PIN_PB18, 0);		/* TD0 */
+
+	/* AT73C213 MCK Clock */
+	at91_set_B_periph(AT91_PIN_PC1, 0);		/* PCK0 */
+
+	at73_clk = clk_get(NULL, "pck0");
+	parent_clk = clk_get(NULL, "plla");
+	clk_set_parent(at73_clk, parent_clk);
+	clk_set_rate(at73_clk, 12416000);
+	clk_enable(at73_clk);
+
+	ssc_clk = clk_get(NULL, "ssc_clk");
+	clk_enable(ssc_clk);
+
+	at73c213_data.ssc_div  = 32;
+	at73c213_data.at73_mck = at73_clk;
+
+	platform_device_register(&at91sam9260_ssc_device);
+}
+#else
+	void __init at91_add_device_ssc_at73c213(void) {}
+#endif
+
+/*
  * SPI devices.
  */
 static struct spi_board_info ek_spi_devices[] = {
@@ -104,9 +168,9 @@ static struct spi_board_info ek_spi_devi
 	},
 #endif
 #endif
-#if defined(CONFIG_SND_AT73C213)
+#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
 	{	/* AT73C213 DAC */
-		.modalias	= "snd_at73c213",
+		.modalias	= "at73c213",
 		.chip_select	= 0,
 		.max_speed_hz	= 10 * 1000 * 1000,
 		.bus_num	= 1,
@@ -118,7 +182,7 @@ static struct spi_board_info ek_spi_devi
 /*
  * MACB Ethernet device
  */
-static struct __initdata eth_platform_data ek_macb_data = {
+static struct __initdata at91_eth_data ek_macb_data = {
 	.phy_irq_pin	= AT91_PIN_PA7,
 	.is_rmii	= 1,
 };
@@ -187,7 +251,9 @@ static void __init ek_board_init(void)
 	/* Ethernet */
 	at91_add_device_eth(&ek_macb_data);
 	/* MMC */
-	at91_add_device_mmc(&ek_mmc_data);
+	at91_add_device_mmc(0, &ek_mmc_data);
+	/* AT73C213 & SSC port */
+	at91_add_device_ssc_at73c213();
 }
 
 MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-sam9261ek.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-sam9261ek.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-sam9261ek.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-sam9261ek.c	2008-02-07 10:24:58.000000000 -0500
@@ -1,5 +1,5 @@
 /*
- * linux/arch/arm/mach-at91rm9200/board-ek.c
+ * linux/arch/arm/mach-at91rm9200/board-sam9261ek.c
  *
  *  Copyright (C) 2005 SAN People
  *  Copyright (C) 2006 Atmel
@@ -26,6 +26,11 @@
 #include <linux/platform_device.h>
 #include <linux/spi/spi.h>
 #include <linux/dm9000.h>
+#include <linux/spi/ads7846.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+
+#include <video/atmel_lcdc.h>
 
 #include <asm/hardware.h>
 #include <asm/setup.h>
@@ -148,6 +153,105 @@ static struct at91_udc_data __initdata e
 
 
 /*
+ * Touchscreen ads7843
+ */
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+
+int ads7843_pendown_state(void)
+{
+	return !at91_get_gpio_value(AT91_PIN_PC2);
+}
+
+static struct ads7846_platform_data ads_info = {
+	.model			= 7843,
+	.x_min	= 150,	.x_max	= 3830,
+	.y_min	= 190,	.y_max	= 3830,
+	.vref_delay_usecs	= 100,
+	.x_plate_ohms		= 450,
+	.y_plate_ohms		= 250,
+	.pressure_max		= 15000,
+	.debounce_max		= 1,
+	.debounce_rep		= 0,
+	.debounce_tol		= (~0),
+	.get_pendown_state	= ads7843_pendown_state,
+};
+
+void __init at91_add_device_ts(void)
+{
+	/* Configure Interrupt 1 as external IRQ, with pullup */
+	at91_set_B_periph(AT91_PIN_PC2, 1);		/* IRQ0 */
+	/* ts busy */
+	at91_set_gpio_input(AT91_PIN_PA11, 1);
+}
+#else
+void __init at91_add_device_ts(void) {}
+#endif
+
+/*
+ * AT73C213
+ */
+#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
+static struct atmel_at73c213_data at73c213_data;
+
+static u64 ssc1_dmamask = 0xffffffffUL;
+static struct resource ssc1_resource[] = {
+	[0] = {
+		.start	= AT91SAM9261_BASE_SSC1,
+		.end	= AT91SAM9261_BASE_SSC1 + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9261_ID_SSC1,
+		.end	= AT91SAM9261_ID_SSC1,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9261_ssc1_device = {
+	.name		= "atmel_ssc_at73c213",
+	.id			= -1,
+	.dev		= {
+				.dma_mask		= &ssc1_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &at73c213_data,
+	},
+	.resource		= ssc1_resource,
+	.num_resources	= ARRAY_SIZE(ssc1_resource),
+};
+void __init at91_add_device_ssc1_at73c213(void)
+{
+	struct clk *at73_clk;
+	struct clk *ssc_clk;
+	struct clk *parent_clk;
+
+	/* Set SSC1 IO */
+	at91_set_B_periph(AT91_PIN_PA17, 0);		/* TD1 */
+	at91_set_B_periph(AT91_PIN_PA18, 0);		/* TF1 */
+	at91_set_B_periph(AT91_PIN_PA19, 0);		/* TK1 */
+
+	/* AT73C213 MCK Clock */
+	at91_set_B_periph(AT91_PIN_PB31, 0);		/* PCK2 */
+
+	at73_clk = clk_get(NULL, "pck2");
+	parent_clk = clk_get(NULL, "plla");
+	clk_set_parent(at73_clk, parent_clk);
+	clk_set_rate(at73_clk, 12416000);
+	clk_enable(at73_clk);
+
+	ssc_clk = clk_get(NULL, "ssc1_clk");
+	clk_enable(ssc_clk);
+	
+	at73c213_data.ssc_div  = 32;  
+	at73c213_data.at73_mck = at73_clk;  
+
+	platform_device_register(&at91sam9261_ssc1_device);
+}
+#else
+	void __init at91_add_device_ssc1_at73c213(void) {}
+#endif
+
+
+/*
  * MCI (SD/MMC)
  */
 static struct at91_mmc_data __initdata ek_mmc_data = {
@@ -204,6 +308,17 @@ static struct spi_board_info ek_spi_devi
 		.max_speed_hz	= 15 * 1000 * 1000,
 		.bus_num	= 0,
 	},
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+	{
+		.modalias	= "ads7846",
+		.chip_select	= 2,
+		.max_speed_hz	= 125000	/* max sample rate at 3V */
+					* 26,	/* command + data + overhead */
+		.bus_num	= 0,
+		.platform_data	= &ads_info,
+		.irq		= AT91SAM9261_ID_IRQ0,
+	},
+#endif
 #if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
 	{	/* DataFlash card - jumper (J12) configurable to CS3 or CS0 */
 		.modalias	= "mtd_dataflash",
@@ -211,9 +326,9 @@ static struct spi_board_info ek_spi_devi
 		.max_speed_hz	= 15 * 1000 * 1000,
 		.bus_num	= 0,
 	},
-#elif defined(CONFIG_SND_AT73C213)
+#elif defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
 	{	/* AT73C213 DAC */
-		.modalias	= "snd_at73c213",
+		.modalias	= "at73c213",
 		.chip_select	= 3,
 		.max_speed_hz	= 10 * 1000 * 1000,
 		.bus_num	= 0,
@@ -222,6 +337,64 @@ static struct spi_board_info ek_spi_devi
 };
 
 
+/*
+ * LCD Controller
+ */
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static struct fb_videomode at91_tft_vga_modes[] = {
+	{
+	        .name           = "TX09D50VM1CCA @ 60",
+		.refresh	= 60,
+		.xres		= 240,		.yres		= 320,
+		.pixclock	= KHZ2PICOS(4965),
+
+		.left_margin	= 1,		.right_margin	= 33,
+		.upper_margin	= 1,		.lower_margin	= 0,
+		.hsync_len	= 5,		.vsync_len	= 1,
+
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+};
+
+static struct fb_monspecs at91fb_default_monspecs = {
+	.manufacturer	= "HIT",
+	.monitor        = "TX09D50VM1CCA",
+
+        .modedb		= at91_tft_vga_modes,
+	.modedb_len	= ARRAY_SIZE(at91_tft_vga_modes),
+	.hfmin		= 15000,
+	.hfmax		= 64000,
+	.vfmin		= 50,
+	.vfmax		= 150,
+};
+
+/* Driver defaults */
+#define AT91SAM9261_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
+					| ATMEL_LCDC_DISTYPE_TFT    \
+					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+
+#define AT91SAM9261_DEFAULT_FB_FLAGS	(FBINFO_DEFAULT \
+					| FBINFO_PARTIAL_PAN_OK \
+					| FBINFO_HWACCEL_XPAN \
+					| FBINFO_HWACCEL_YPAN)
+
+/* Driver datas */
+static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+	.default_bpp = 16,
+	.default_dmacon = ATMEL_LCDC_DMAEN,
+	.default_lcdcon2 = AT91SAM9261_DEFAULT_LCDCON2,
+	.default_monspecs = &at91fb_default_monspecs,
+	.default_flags = AT91SAM9261_DEFAULT_FB_FLAGS,
+	.power_control_pin = AT91_PIN_PA12,
+	.guard_time = 1,
+};
+
+#else
+static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+#endif
+
+
 static void __init ek_board_init(void)
 {
 	/* Serial */
@@ -243,8 +416,14 @@ static void __init ek_board_init(void)
 	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
 #else
 	/* MMC */
-	at91_add_device_mmc(&ek_mmc_data);
+	at91_add_device_mmc(0, &ek_mmc_data);
 #endif
+	/* LCD Controller */
+	at91_add_device_lcdc(&ek_lcdc_data);
+	/* Touchscreen */
+	at91_add_device_ts();
+	/* AT73C213 & SSC1 port */
+	at91_add_device_ssc1_at73c213(); 
 }
 
 MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-sam9263ek.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-sam9263ek.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-sam9263ek.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-sam9263ek.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,302 @@
+/*
+ * linux/arch/arm/mach-at91rm9200/board-sam9263ek.c
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2007 Atmel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/ads7846.h>
+#include <linux/fb.h>
+#include <linux/clk.h>
+
+#include <video/atmel_lcdc.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91sam926x_mc.h>
+
+#include "generic.h"
+
+
+/*
+ * Serial port configuration.
+ *    0 .. 2 = USART0 .. USART2
+ *    3      = DBGU
+ */
+static struct at91_uart_config __initdata ek_uart_config = {
+	.console_tty	= 0,				/* ttyS0 */
+	.nr_tty		= 2,
+	.tty_map	= { 3, 0, -1, -1, }		/* ttyS0, ..., ttyS3 */
+};
+
+static void __init ek_map_io(void)
+{
+	/* Initialize processor: 16.367 MHz crystal */
+	at91sam9263_initialize(16367660);
+
+	/* Setup the serial ports and console */
+	at91_init_serial(&ek_uart_config);
+}
+
+static void __init ek_init_irq(void)
+{
+	at91sam9263_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata ek_usbh_data = {
+	.ports		= 2,
+	.vbus_pin	= { AT91_PIN_PA24, AT91_PIN_PA21 },
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata ek_udc_data = {
+	.vbus_pin	= AT91_PIN_PA25,
+	.pullup_pin	= 0,		/* pull-up driven by UDC */
+};
+
+/*
+ * Touchscreen ads7843
+ */
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+
+int ads7843_pendown_state(void)
+{
+	return !at91_get_gpio_value(AT91_PIN_PA15);
+}
+
+static struct ads7846_platform_data ads_info = {
+	.model			= 7843,
+	.x_min	= 150,	.x_max	= 3830,
+	.y_min	= 190,	.y_max	= 3830,
+	.vref_delay_usecs	= 100,
+	.x_plate_ohms		= 450,
+	.y_plate_ohms		= 250,
+	.pressure_max		= 15000,
+	.debounce_max		= 1,
+	.debounce_rep		= 0,
+	.debounce_tol		= (~0),
+	.get_pendown_state	= ads7843_pendown_state,
+};
+
+void __init at91_add_device_ts(void)
+{
+	/* Configure Interrupt 1 as external IRQ, with pullup */
+	at91_set_B_periph(AT91_PIN_PA15, 1);		/* IRQ1 */
+	/* ts busy */
+	at91_set_gpio_input(AT91_PIN_PA31, 1);
+}
+#else
+void __init at91_add_device_ts(void) {}
+#endif
+
+/*
+ * SPI devices.
+ */
+static struct spi_board_info ek_spi_devices[] = {
+#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
+	{	/* DataFlash card */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 0,
+		.max_speed_hz	= 15 * 1000 * 1000,
+		.bus_num	= 0,
+	},
+#endif
+#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
+	{
+		.modalias	= "ads7846",
+		.chip_select	= 3,
+		.max_speed_hz	= 125000	/* max sample rate at 3V */
+					* 26,	/* command + data + overhead */
+		.bus_num	= 0,
+		.platform_data	= &ads_info,
+		.irq		= AT91SAM9263_ID_IRQ1,
+	},
+#endif
+};
+
+/*
+ * MACB device
+ */
+static struct  __initdata  at91_eth_data ek_macb_data = {
+	.is_rmii = 1,
+};
+
+/*
+ * MCI (SD/MMC)
+ */
+static struct at91_mmc_data __initdata ek_mmc_data = {
+	.wire4		= 1,
+	.det_pin	= AT91_PIN_PE18,
+	.wp_pin		= AT91_PIN_PE19,
+//	.vcc_pin	= ... not connected
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata ek_nand_partition[] = {
+	{
+		.name	= "Partition 1",
+		.offset	= 0,
+		.size	= 64 * 1024 * 1024,
+	},
+	{
+		.name	= "Partition 2",
+		.offset	= 64 * 1024 * 1024,
+		.size	= MTDPART_SIZ_FULL,
+	},
+};
+
+static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+{
+	*num_partitions = ARRAY_SIZE(ek_nand_partition);
+	return ek_nand_partition;
+}
+
+static struct at91_nand_data __initdata ek_nand_data = {
+	.ale		= 21,
+	.cle		= 22,
+//	.det_pin	= ... not connected
+	.rdy_pin	= AT91_PIN_PA22,
+	.enable_pin	= AT91_PIN_PD15,
+	.partition_info	= nand_partitions,
+#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+	.bus_width_16	= 1,
+#else
+	.bus_width_16	= 0,
+#endif
+};
+
+/*
+ * LCD Controller
+ */
+#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
+static struct fb_videomode at91_tft_vga_modes[] = {
+	{
+	        .name           = "TX09D50VM1CCA @ 60",
+		.refresh	= 60,
+		.xres		= 240,		.yres		= 320,
+		.pixclock	= KHZ2PICOS(4965),
+
+		.left_margin	= 1,		.right_margin	= 33,
+		.upper_margin	= 1,		.lower_margin	= 0,
+		.hsync_len	= 5,		.vsync_len	= 1,
+
+		.sync		= FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
+		.vmode		= FB_VMODE_NONINTERLACED,
+	},
+};
+
+static struct fb_monspecs at91fb_default_monspecs = {
+	.manufacturer	= "HIT",
+	.monitor        = "TX09D70VM1CCA",
+
+        .modedb		= at91_tft_vga_modes,
+	.modedb_len	= ARRAY_SIZE(at91_tft_vga_modes),
+	.hfmin		= 15000,
+	.hfmax		= 64000,
+	.vfmin		= 50,
+	.vfmax		= 150,
+};
+
+/* Driver defaults */
+#define AT91SAM9261_DEFAULT_LCDCON2 	(ATMEL_LCDC_MEMOR_LITTLE \
+					| ATMEL_LCDC_DISTYPE_TFT    \
+					| ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
+
+#define AT91SAM9261_DEFAULT_FB_FLAGS	(FBINFO_DEFAULT \
+					| FBINFO_PARTIAL_PAN_OK \
+					| FBINFO_HWACCEL_XPAN \
+					| FBINFO_HWACCEL_YPAN)
+
+/* Driver datas */
+static struct atmel_lcdfb_info __initdata ek_lcdc_data = {
+	.default_bpp = 16,
+	.default_dmacon = ATMEL_LCDC_DMAEN,
+	.default_lcdcon2 = AT91SAM9261_DEFAULT_LCDCON2,
+	.default_monspecs = &at91fb_default_monspecs,
+	.default_flags = AT91SAM9261_DEFAULT_FB_FLAGS,
+	.power_control_pin = AT91_PIN_PD12,
+	.guard_time = 1,
+};
+
+#else
+static struct atmel_lcdfb_info __initdata ek_lcdc_data;
+#endif
+
+struct atmel_ac97_data ek_ac97_data = {
+	.reset_pin = AT91_PIN_PA13,
+};
+
+static void __init ek_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* USB Host */
+	at91_add_device_usbh(&ek_usbh_data);
+	/* USB Device */
+	at91_add_device_udc(&ek_udc_data);
+	/* select SPI clk for Dataflash card slot */
+	at91_set_gpio_output(AT91_PIN_PE20, 1);
+	/* SPI */
+	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+	/* MMC */
+	at91_add_device_mmc(1, &ek_mmc_data);
+	/* MACB */
+	at91_add_device_eth(&ek_macb_data);
+	/* NAND */
+	at91_add_device_nand(&ek_nand_data);
+	/* LCD Controller */
+	at91_add_device_lcdc(&ek_lcdc_data);
+	/* Touchscreen */
+	at91_add_device_ts();
+	/* AC97 */
+	at91_add_device_ac97(&ek_ac97_data);
+}
+
+MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
+	/* Maintainer: Atmel */
+	.phys_io	= AT91_BASE_SYS,
+	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91sam926x_timer,
+	.map_io		= ek_map_io,
+	.init_irq	= ek_init_irq,
+	.init_machine	= ek_board_init,
+MACHINE_END
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/board-som9260m.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-som9260m.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/board-som9260m.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/board-som9260m.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,632 @@
+/*
+ * linux/arch/arm/mach-at91rm9200/board-som9260m.c
+ *
+ *  Copyright (C) 2005 SAN People
+ *  Copyright (C) 2006 Atmel
+ *  Copyright (C) 2007 EMAC.Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/clk.h>
+#include <linux/ioex/ecoreex.h>
+#include <linux/mtd/physmap.h>
+#include <linux/class/spi.h>
+#include <linux/class/spi_interface.h>
+
+#include <asm/hardware.h>
+#include <asm/setup.h>
+#include <asm/mach-types.h>
+#include <asm/irq.h>
+
+#include <asm/mach/arch.h>
+#include <asm/mach/map.h>
+#include <asm/mach/irq.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+#include <asm/arch/at91sam9260.h>
+#include <asm/arch/at91sam926x_mc.h>
+
+#include "generic.h"
+#include "atod-som9260m.h"
+
+/*
+ * Serial port configuration.
+ *    0 .. 5 = USART0 .. USART5
+ *    6      = DBGU
+ */
+static struct at91_uart_config __initdata ek_uart_config = {
+	.console_tty	= 3,				/* ttyS3 */
+	.nr_tty		= 5,
+	.tty_map	= { 0, 1, 2, 3, 6, -1, -1 }	/* ttyS0, ..., ttyS6 */
+};
+
+static void __init ek_map_io(void)
+{
+	/* Initialize processor: 18.432 MHz crystal */
+	at91sam9260_initialize(18432000);
+
+	/* Setup the serial ports and console */
+	at91_init_serial(&ek_uart_config);
+}
+
+static void __init ek_init_irq(void)
+{
+	at91sam9260_init_interrupts(NULL);
+}
+
+
+/*
+ * USB Host port
+ */
+static struct at91_usbh_data __initdata ek_usbh_data = {
+	.ports		= 2,
+};
+
+/*
+ * USB Device port
+ */
+static struct at91_udc_data __initdata ek_udc_data = {
+	.vbus_pin	= AT91_PIN_PB31,
+	.pullup_pin	= 0,		/* pull-up driven by UDC */
+};
+
+
+/*
+ * AT73C213
+ */
+#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
+static struct atmel_at73c213_data at73c213_data;
+
+static u64 ssc_dmamask = 0xffffffffUL;
+static struct resource ssc_resource[] = {
+	[0] = {
+		.start	= AT91SAM9260_BASE_SSC,
+		.end	= AT91SAM9260_BASE_SSC + SZ_16K - 1,
+		.flags	= IORESOURCE_MEM,
+	},
+	[1] = {
+		.start	= AT91SAM9260_ID_SSC,
+		.end	= AT91SAM9260_ID_SSC,
+		.flags	= IORESOURCE_IRQ,
+	},
+};
+
+static struct platform_device at91sam9260_ssc_device = {
+	.name		= "atmel_ssc_at73c213",
+	.id		= -1,
+	.dev		= {
+				.dma_mask		= &ssc_dmamask,
+				.coherent_dma_mask	= 0xffffffff,
+				.platform_data		= &at73c213_data,
+	},
+	.resource		= ssc_resource,
+	.num_resources	= ARRAY_SIZE(ssc_resource),
+};
+void __init at91_add_device_ssc_at73c213(void)
+{
+	struct clk *at73_clk;
+	struct clk *ssc_clk;
+	struct clk *parent_clk;
+
+	/* Set SSC1 IO */
+	at91_set_A_periph(AT91_PIN_PB16, 0);		/* TK0 */
+	at91_set_A_periph(AT91_PIN_PB17, 0);		/* TF0 */
+	at91_set_A_periph(AT91_PIN_PB18, 0);		/* TD0 */
+
+	/* AT73C213 MCK Clock */
+	at91_set_B_periph(AT91_PIN_PC1, 0);		/* PCK0 */
+
+	at73_clk = clk_get(NULL, "pck0");
+	parent_clk = clk_get(NULL, "plla");
+	clk_set_parent(at73_clk, parent_clk);
+	clk_set_rate(at73_clk, 12416000);
+	clk_enable(at73_clk);
+
+	ssc_clk = clk_get(NULL, "ssc_clk");
+	clk_enable(ssc_clk);
+
+	at73c213_data.ssc_div  = 32;
+	at73c213_data.at73_mck = at73_clk;
+
+	platform_device_register(&at91sam9260_ssc_device);
+}
+#else
+	void __init at91_add_device_ssc_at73c213(void) {}
+#endif
+
+/*
+ * SPI devices.
+ */
+	
+/************************************************************
+ * mcp3208 atod interface over EMAC SPI class
+ */
+
+static struct spi_s mcp3208_spi = 
+{
+ .name = "mcp3208",
+ .subclass = 0,
+ .bsize = 16,
+ .tip = lsi2esc_spi_tip,
+ .xmit = lsi2esc_spi_xmit,
+ .confwrite = lsi2esc_spi_confwrite,
+ .confread = lsi2esc_spi_confread,
+ .speedread = lsi2esc_spi_speedread,
+ .speedwrite = lsi2esc_spi_speedwrite,
+};
+
+static struct spi_s fake_spi = 
+{
+ .name = "fake",
+ .subclass = 0,
+ .bsize = 16,
+ .tip = lsi2esc_spi_tip,
+ .xmit = lsi2esc_spi_xmit,
+ .confwrite = lsi2esc_spi_confwrite,
+ .confread = lsi2esc_spi_confread,
+ .speedread = lsi2esc_spi_speedread,
+ .speedwrite = lsi2esc_spi_speedwrite,
+};
+
+	
+static struct spi_board_info ek_spi_devices[] = {
+#if !defined(CONFIG_MMC_AT91)
+	{	/* DataFlash chip */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 1,
+		.max_speed_hz	= 15 * 1000 * 1000,
+		.bus_num	= 0,
+	},
+#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
+	{	/* DataFlash card */
+		.modalias	= "mtd_dataflash",
+		.chip_select	= 0,
+		.max_speed_hz	= 15 * 1000 * 1000,
+		.bus_num	= 0,
+	},
+#endif
+#endif
+#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
+	{	/* AT73C213 DAC */
+		.modalias	= "at73c213",
+		.chip_select	= 0,
+		.max_speed_hz	= 10 * 1000 * 1000,
+		.bus_num	= 1,
+	},
+#endif
+#if defined(CONFIG_ARMSTRONG_HWMS)
+	{ /* mcp3208 ADC */
+	  .modalias = "lsi2esc", /* use the SPI class interface */
+	  .chip_select = 0,
+	  .max_speed_hz = 1e6,
+	  .bus_num = 1,
+	  .platform_data = &mcp3208_spi,
+	},
+	{ /*fake*/
+	  .modalias = "lsi2esc",
+	  .chip_select = 1,
+	  .max_speed_hz = 10 * 1000 * 1000,
+	  .bus_num = 0,
+	  .platform_data = &fake_spi,
+	},
+#endif
+};
+
+/*
+ * MACB Ethernet device
+ */
+static struct __initdata at91_eth_data ek_macb_data = {
+	.phy_irq_pin	= AT91_PIN_PA7,
+	.is_rmii	= 0,
+};
+
+
+/*
+ * NAND flash
+ */
+static struct mtd_partition __initdata ek_nand_partition[] = {
+	{
+		.name	= "Boot Partition",
+		.offset	= 0,
+		.size	= 64 * 2 * 1024,
+	},
+	{
+		.name	= "UBoot Partition",
+		.offset	= 64 * 2 * 1024,
+		.size	= 64 * 14 * 1024,
+	},
+ 	{
+ 		.name	= "Kernel Partition",
+ 		.offset	= 64 * 16 * 1024,
+ 		.size	= 64 * 48 * 1024,
+ 	},
+ 	{
+ 		.name	= "Disk Partition",
+ 		.offset	= 64 * 64 * 1024,
+ 		.size	= 64 * 256 * 1024,
+ 	},
+};
+
+static struct mtd_partition *nand_partitions(int size, int *num_partitions)
+{
+	*num_partitions = ARRAY_SIZE(ek_nand_partition);
+	return ek_nand_partition;
+}
+
+static struct at91_nand_data __initdata ek_nand_data = {
+	.ale		= 21,
+	.cle		= 22,
+//	.det_pin	= ... not connected
+	.rdy_pin	= AT91_PIN_PC13,
+	.enable_pin	= AT91_PIN_PC14,
+	.partition_info	= nand_partitions,
+#if defined(CONFIG_MTD_NAND_AT91_BUSWIDTH_16)
+	.bus_width_16	= 1,
+#else
+	.bus_width_16	= 0,
+#endif
+};
+
+/*
+ *  NOR Flash
+ */
+
+#define SOM_FLASH_BASE	0x10000000
+#define SOM_FLASH_SIZE	0x2000000
+
+static struct mtd_partition som_flash_partitions[] = {
+	{
+		.name	= "Boot Partition",
+		.offset	= 0,
+		.size	= 64 * 2 * 1024,
+		.mask_flags	= MTD_WRITEABLE,
+	},
+	{
+		.name	= "UBoot Partition",
+		.offset	= 64 * 2 * 1024,
+		.size	= 64 * 14 * 1024,
+		.mask_flags	= MTD_WRITEABLE,
+	},
+ 	{
+ 		.name	= "Kernel Partition",
+ 		.offset	= 64 * 16 * 1024,
+ 		.size	= 64 * 48 * 1024,
+ 	},
+ 	{
+ 		.name	= "Disk Partition",
+ 		.offset	= 64 * 64 * 1024,
+ 		.size	= 64 * 256 * 1024,
+ 	},
+ };
+
+static struct physmap_flash_data som_flash_data = {
+	.width		= 2,
+	.parts		= som_flash_partitions,
+	.nr_parts	= ARRAY_SIZE(som_flash_partitions),
+};
+
+static struct resource som_flash_resources[] = {
+	{
+		.start	= SOM_FLASH_BASE,
+		.end	= SOM_FLASH_BASE + SOM_FLASH_SIZE - 1,
+		.flags	= IORESOURCE_MEM,
+	}
+};
+
+static struct platform_device som_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+				.platform_data = &som_flash_data,
+			},
+	.resource	= som_flash_resources,
+	.num_resources	= ARRAY_SIZE(som_flash_resources),
+};
+
+/*
+ * MCI (SD/MMC)
+ */
+static struct at91_mmc_data __initdata ek_mmc_data = {
+	.slot_b		= 1,
+	.wire4		= 1,
+//	.det_pin	= ... not connected
+//	.wp_pin		= ... not connected
+//	.vcc_pin	= ... not connected
+};
+
+/************************************************************
+ * IOEX Device
+ * Onboard EMAC I/O core platform device used by the ecoreex driver
+ */
+#define CS4_START ((unsigned long)0x50000000)
+#define CS4_END  ((unsigned long)0x5FFFFFFF)
+#define CS4_LEN  ((unsigned long)(CS0_END-CS0_START+1))
+/* key is defined, but may be overridden by the ecoreex driver
+ * based on the static key definition in the config file
+ */
+#define CPLDKEY 0xF
+
+static struct ecoreex_data som9260m_ecoreex_data = {
+	.key_offset	= CPLDKEY,
+	.irq = AT91SAM9260_ID_IRQ1,
+};
+
+static struct resource som9260m_ecoreex_resource = {
+		.start	= CS4_START,
+		.end	= CS4_END,
+		.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device som9260m_ecoreex_device = {
+	.name		= "ecoreex",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &som9260m_ecoreex_data,
+	},
+	.num_resources	= 1,
+	.resource	= &som9260m_ecoreex_resource,
+};
+
+
+
+/**
+ * enable a generic memory map on cs4 and required module I/O
+ */
+static inline void cs4_setup(void){
+	at91_sys_write(AT91_SMC_SETUP(4),
+			0
+	);
+
+	at91_sys_write(AT91_SMC_PULSE(4),
+			AT91_SMC_NWEPULSE_(4)|
+			AT91_SMC_NCS_WRPULSE_(6)|
+			AT91_SMC_NRDPULSE_(3)|
+			AT91_SMC_NCS_RDPULSE_(5)
+	);
+	
+	at91_sys_write(AT91_SMC_CYCLE(4),
+			AT91_SMC_NWECYCLE_(5)|
+			AT91_SMC_NRDCYCLE_(6) 
+	);
+	
+	at91_sys_write(AT91_SMC_MODE(4),
+			AT91_SMC_READMODE|
+			AT91_SMC_WRITEMODE|
+			AT91_SMC_EXNWMODE_DISABLE|
+			AT91_SMC_DBW_8|
+			AT91_SMC_TDF_(0X0f)
+	);
+		
+	//at91_sys_write(AT91C_PIOC_PDR,0x100);
+	//at91_sys_write(AT91C_PIOC_OER,0x100);
+	
+	at91_set_A_periph(AT91_PIN_PC8, 1);	
+}
+
+/**
+ * creates the 200k clock in using timer1 outputB
+ * TODO: move regdefs to a more appropriate general header
+ * NOTES: hard coded clock values could be more flexibly done through the clock registery, 
+ * but it would require some 
+ * fixed point math, which will be put off for a full PWM implementation
+ * at which point it's methods will replace this code block.
+ */
+#include <asm/arch/at91_tc.h>
+#define AT91SAM9260_TC1_CCR	(AT91SAM9260_BASE_TC1 + AT91_TC_CCR)
+#define AT91SAM9260_TC1_CMR	(AT91SAM9260_BASE_TC1 + AT91_TC_CMR)
+#define AT91SAM9260_TC1_RB	(AT91SAM9260_BASE_TC1 + AT91_TC_RB)
+#define AT91SAM9260_TC1_RC	(AT91SAM9260_BASE_TC1 + AT91_TC_RC)
+
+#define MCLK (25000000)
+
+#define at91_tc_read(reg)		__raw_readl(reg)
+#define at91_tc_write(reg, val)	__raw_writel((val), reg)
+
+static inline void set200kclock(void){
+	struct clk *tc1_clk = clk_get(NULL, "tc1_clk");
+	unsigned long tc1 = (unsigned long)ioremap(AT91SAM9260_BASE_TC1,SZ_16K);
+	
+	clk_enable(tc1_clk);//enable tc1 clock in the pmc
+	
+	//if(tc1)
+	//tc1 setup for waveform on TCIOB1
+	at91_tc_write((tc1 + AT91_TC_CMR),
+			AT91_TC_TIMER_CLOCK1|
+			AT91_TC_WAVE|
+			AT91_TC_EEVT_XC0|
+			AT91_TC_WAVESEL_UP_AUTO|
+			AT91_TC_BCPB_TOGGLE
+			);
+	//else printk("tc1 is NULL");
+
+	//set the frequency
+	at91_tc_write((tc1 + AT91_TC_RC),(MCLK/200000));
+	
+	//set RB to < RC for toggle (50% duty)
+	at91_tc_write((tc1 + AT91_TC_RB),((MCLK/200000)/2));
+	
+	//reset and start the timer
+	at91_tc_write((tc1 + AT91_TC_CCR),AT91_TC_CLKEN|AT91_TC_SWTRG);
+	
+	//enable timer functionality on PC7, TIOB1 
+	at91_set_A_periph(AT91_PIN_PC7, 1);		
+
+}
+
+
+
+
+static inline void at91_add_device_ecoreex4(void){
+	cs4_setup();
+	set200kclock();
+	at91_set_A_periph(AT91_PIN_PC15, 1);//enable IRQ1 on PC15	
+	platform_device_register(&som9260m_ecoreex_device);
+}
+
+/************************************************************/
+#ifdef CONFIG_RTSCLS
+#define GPIOBIT			0
+#define AUTORTSBIT		1
+#define GPIOMASK		(1<<GPIOBIT)
+#define AUTORTSMASK		(1<<AUTORTSBIT)
+#define RS485CHANNEL 	1
+
+/**
+ * set the rts line manually or put it in auto mode.
+ * bit 1 (0x02) is the auto rts control 0-off 1-on
+ * bit 0 (0x01) is the state of the pin, this cannot be set manually while in auto mode.
+ */
+static int rts_data_write(struct gpio_s *gpio,gpio_data data){
+	if(data&AUTORTSMASK){
+		at91_set_A_periph(AT91_PIN_PB28, 1);//return RTS to primary functionality
+		at91_auto485_serial(RS485CHANNEL,1);//call down into the driver to enable RTS auto toggle
+		}
+	else {
+		at91_auto485_serial(RS485CHANNEL,0);//Auto control off
+		at91_set_gpio_output(AT91_PIN_PB28,(char)(data&GPIOMASK));//set data manually
+	}
+	return 0;
+}
+
+/**
+ * returns the current auto flow control state and 
+ * state of the pins by reading the hardware registers.
+ */
+static gpio_data rts_data_read(struct gpio_s *gpio){
+	return (at91_get_gpio_value(AT91_PIN_PB28)|(at91_auto485_serial(RS485CHANNEL,2)<<AUTORTSBIT));
+}
+
+/**
+ * Create gpio rts interface through boardspec
+ */
+static inline struct class_device *som9260m_rtscls(void){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	at91_set_gpio_output(AT91_PIN_PB28,1);//rts line
+	gpio->name = "rtsctl";
+	gpio->subclass = GPIO_SUBCLASS;
+	gpio->data_write = rts_data_write;
+	gpio->data_read = rts_data_read;
+	printk("registering gpio device: %s\n",gpio->name);
+	return gpio_register_class_device(gpio);	
+}
+
+#else//CONFIG_RTSCLS
+#define som9260m_rtscls()
+#endif
+
+static int physw_write(struct gpio_s *gpio,gpio_data data){
+	at91_set_gpio_output(AT91_PIN_PA31,(char)data);
+	return 0;
+}
+
+static gpio_data physw_read(struct gpio_s *gpio){
+	return at91_get_gpio_value(AT91_PIN_PA31);
+}
+
+static inline struct class_device *som9260m_physw(void){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	at91_set_gpio_output(AT91_PIN_PB28,1);//rts line
+	gpio->name = "physw";
+	gpio->subclass = GPIO_SUBCLASS;
+	gpio->data_write = physw_write;
+	gpio->data_read = physw_read;
+	printk("registering gpio device: %s\n",gpio->name);
+	return gpio_register_class_device(gpio);
+}
+
+/************************************************************
+ * device registrations from the arch go here, 
+ * which are called by the boardspec ioex driver
+ */
+static int som9260m_classes(void)
+{
+	som9260m_atod_init();
+	som9260m_atod_class_create("indexed_atod");
+	
+	som9260m_led_init();
+	som9260m_led_class_create("indexed_led");
+	
+	som9260m_rtscls();
+	
+	som9260m_physw();
+	
+	//set wakeup mask to all uarts
+	set_irq_wake(AT91SAM9260_ID_US0,1);
+	set_irq_wake(AT91SAM9260_ID_US1,1);
+	set_irq_wake(AT91SAM9260_ID_US2,1);
+	set_irq_wake(AT91SAM9260_ID_US3,1);
+	set_irq_wake(AT91SAM9260_ID_US4,1);
+	set_irq_wake(AT91SAM9260_ID_US5,1);
+	
+	return 0;
+}
+
+static struct platform_device boardspec_device = {
+	.name = "boardspec",
+	.id = 1,
+	.dev		= {
+		.platform_data	= &som9260m_classes,
+	},
+};
+
+static inline void at91_add_device_boardspec(void){
+	platform_device_register(&boardspec_device);
+}
+/************************************************************/
+
+static void __init ek_board_init(void)
+{
+	/* Serial */
+	at91_add_device_serial();
+	/* USB Host */
+	at91_add_device_usbh(&ek_usbh_data);
+	/* USB Device */
+	at91_add_device_udc(&ek_udc_data);
+	/* SPI */
+	at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
+	/* Ethernet */
+	at91_add_device_eth(&ek_macb_data);
+	/* MMC */
+	at91_add_device_mmc(0, &ek_mmc_data);
+	/* AT73C213 & SSC port */
+	at91_add_device_ssc_at73c213();
+	/* EMAC Core Extensions */
+	at91_add_device_ecoreex4();
+	/* Board Specific */
+	at91_add_device_boardspec();
+	/* NOR Flash */
+	platform_device_register(&som_flash);
+}
+
+MACHINE_START(AT91SAM9260EK, "EMAC SoM-9260M")
+	/* Maintainer: EMAC.Inc */
+	.phys_io	= AT91_BASE_SYS,
+	.io_pg_offst	= (AT91_VA_BASE_SYS >> 18) & 0xfffc,
+	.boot_params	= AT91_SDRAM_BASE + 0x100,
+	.timer		= &at91sam926x_timer,
+	.map_io		= ek_map_io,
+	.init_irq	= ek_init_irq,
+	.init_machine	= ek_board_init,
+MACHINE_END
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/clock.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/clock.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/clock.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/clock.c	2008-02-07 10:24:58.000000000 -0500
@@ -375,6 +375,7 @@ static int at91_clk_show(struct seq_file
 	seq_printf(s, "PLLB = %8x\n", at91_sys_read(AT91_CKGR_PLLBR));
 
 	seq_printf(s, "MCKR = %8x\n", at91_sys_read(AT91_PMC_MCKR));
+#warning "Hard-coded PCK"
 	for (i = 0; i < 4; i++)
 		seq_printf(s, "PCK%d = %8x\n", i, at91_sys_read(AT91_PMC_PCKR(i)));
 	seq_printf(s, "SR   = %8x\n", sr = at91_sys_read(AT91_PMC_SR));
@@ -525,27 +526,6 @@ fail:
 	return 0;
 }
 
-/*
- * Several unused clocks may be active.  Turn them off.
- */
-static void __init at91_periphclk_reset(void)
-{
-	unsigned long reg;
-	struct clk *clk;
-
-	reg = at91_sys_read(AT91_PMC_PCSR);
-
-	list_for_each_entry(clk, &clocks, node) {
-		if (clk->mode != pmc_periph_mode)
-			continue;
-
-		if (clk->users > 0)
-			reg &= ~clk->pmc_mask;
-	}
-
-	at91_sys_write(AT91_PMC_PCDR, reg);
-}
-
 static struct clk *const standard_pmc_clocks[] __initdata = {
 	/* four primary clocks */
 	&clk32k,
@@ -586,7 +566,7 @@ int __init at91_clock_init(unsigned long
 		pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
 
 	/*
-	 * USB clock init:  choose 48 MHz PLLB value, turn all clocks off,
+	 * USB clock init:  choose 48 MHz PLLB value,
 	 * disable 48MHz clock during usb peripheral suspend.
 	 *
 	 * REVISIT:  assumes MCK doesn't derive from PLLB!
@@ -596,16 +576,10 @@ int __init at91_clock_init(unsigned long
 	if (cpu_is_at91rm9200()) {
 		uhpck.pmc_mask = AT91RM9200_PMC_UHP;
 		udpck.pmc_mask = AT91RM9200_PMC_UDP;
-		at91_sys_write(AT91_PMC_SCDR, AT91RM9200_PMC_UHP | AT91RM9200_PMC_UDP);
 		at91_sys_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
-	} else if (cpu_is_at91sam9260()) {
+	} else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() || cpu_is_at91sam9263()) {
 		uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
 		udpck.pmc_mask = AT91SAM926x_PMC_UDP;
-		at91_sys_write(AT91_PMC_SCDR, AT91SAM926x_PMC_UHP | AT91SAM926x_PMC_UDP);
-	} else if (cpu_is_at91sam9261()) {
-		uhpck.pmc_mask = (AT91SAM926x_PMC_UHP | AT91_PMC_HCK0);
-		udpck.pmc_mask = AT91SAM926x_PMC_UDP;
-		at91_sys_write(AT91_PMC_SCDR, AT91SAM926x_PMC_UHP | AT91_PMC_HCK0 | AT91SAM926x_PMC_UDP);
 	}
 	at91_sys_write(AT91_CKGR_PLLBR, 0);
 
@@ -634,11 +608,34 @@ int __init at91_clock_init(unsigned long
 		(unsigned) main_clock / 1000000,
 		((unsigned) main_clock % 1000000) / 1000);
 
-	/* disable all programmable clocks */
-	at91_sys_write(AT91_PMC_SCDR, AT91_PMC_PCK0 | AT91_PMC_PCK1 | AT91_PMC_PCK2 | AT91_PMC_PCK3);
+	return 0;
+}
+
+/*
+ * Several unused clocks may be active.  Turn them off.
+ */
+static int __init at91_clock_reset(void)
+{
+	unsigned long pcdr = 0;
+	unsigned long scdr = 0;
+	struct clk *clk;
+
+	list_for_each_entry(clk, &clocks, node) {
+		if (clk->users > 0)
+			continue;
+
+		if (clk->mode == pmc_periph_mode)
+			pcdr |= clk->pmc_mask;
+
+		if (clk->mode == pmc_sys_mode)
+			scdr |= clk->pmc_mask;
+
+		pr_debug("Clocks: disable unused %s\n", clk->name);
+	}
 
-	/* disable all other unused peripheral clocks */
-	at91_periphclk_reset();
+	at91_sys_write(AT91_PMC_PCDR, pcdr);
+	at91_sys_write(AT91_PMC_SCDR, scdr);
 
 	return 0;
 }
+late_initcall(at91_clock_reset);
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/generic.h linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/generic.h
--- linux-2.6.20/arch/arm/mach-at91rm9200/generic.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/generic.h	2008-02-07 10:24:58.000000000 -0500
@@ -12,11 +12,13 @@
 extern void __init at91rm9200_initialize(unsigned long main_clock, unsigned short banks);
 extern void __init at91sam9260_initialize(unsigned long main_clock);
 extern void __init at91sam9261_initialize(unsigned long main_clock);
+extern void __init at91sam9263_initialize(unsigned long main_clock);
 
  /* Interrupts */
 extern void __init at91rm9200_init_interrupts(unsigned int priority[]);
 extern void __init at91sam9260_init_interrupts(unsigned int priority[]);
 extern void __init at91sam9261_init_interrupts(unsigned int priority[]);
+extern void __init at91sam9263_init_interrupts(unsigned int priority[]);
 extern void __init at91_aic_init(unsigned int priority[]);
 
  /* Timer */
@@ -28,10 +30,20 @@ extern struct sys_timer at91sam926x_time
 extern int __init at91_clock_init(unsigned long main_clock);
 struct device;
 extern void __init at91_clock_associate(const char *id, struct device *dev, const char *func);
+extern int at91_stopclock(unsigned state);
 
  /* Power Management */
 extern void at91_irq_suspend(void);
 extern void at91_irq_resume(void);
+extern int at91_self_refresh(unsigned state);//NZG
+extern int at91_lp_disable(unsigned state);
+
+/*Uarts*/
+extern int at91_auto485_serial(int channel,int fos);
+
+/*LEDs*/
+int som9260m_led_init(void);
+struct class_device *som9260m_led_class_create(const char *name);
 
  /* GPIO */
 #define AT91RM9200_PQFP		3	/* AT91RM9200 PQFP package has 3 banks */
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/ics1523.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/ics1523.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/ics1523.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/ics1523.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,207 @@
+/*
+ * arch/arm/mach-at91rm9200/ics1523.c
+ *
+ *  Copyright (C) 2003 ATMEL Rousset
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <asm/hardware.h>
+#include <asm/io.h>
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+
+#include <asm/arch/ics1523.h>
+#include <asm/arch/at91_twi.h>
+#include <asm/arch/gpio.h>
+
+/* TWI Errors */
+#define	AT91_TWI_ERROR	(AT91_TWI_NACK | AT91_TWI_UNRE | AT91_TWI_OVRE)
+
+
+static void __iomem *twi_base;
+
+#define at91_twi_read(reg)		__raw_readl(twi_base + (reg))
+#define at91_twi_write(reg, val)	__raw_writel((val), twi_base + (reg))
+
+
+/* -----------------------------------------------------------------------------
+ * Initialization of TWI CLOCK
+ * ----------------------------------------------------------------------------- */
+
+static void at91_ics1523_SetTwiClock(unsigned int mck_khz)
+{
+	int sclock;
+
+	/* Here, CKDIV = 1 and CHDIV = CLDIV  ==> CLDIV = CHDIV = 1/4*((Fmclk/FTWI) -6) */
+	sclock = (10*mck_khz / ICS_TRANSFER_RATE);
+	if (sclock % 10 >= 5)
+		sclock = (sclock /10) - 5;
+	else
+		sclock = (sclock /10)- 6;
+	sclock = (sclock + (4 - sclock %4)) >> 2;	/* div 4 */
+
+	at91_twi_write(AT91_TWI_CWGR, 0x00010000 | sclock | (sclock << 8));
+}
+
+/* -----------------------------------------------------------------------------
+ * Read a byte with TWI Interface from the Clock Generator ICS1523
+ * ----------------------------------------------------------------------------- */
+
+static int at91_ics1523_ReadByte(unsigned char reg_address, unsigned char *data_in)
+{
+	int Status, nb_trial;
+
+	at91_twi_write(AT91_TWI_MMR, AT91_TWI_MREAD | AT91_TWI_IADRSZ_1 | ((ICS_ADDR << 16) & AT91_TWI_DADR));
+	at91_twi_write(AT91_TWI_IADR, reg_address);
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_START | AT91_TWI_STOP);
+
+	/* Program temporizing period (300us) */
+	udelay(300);
+
+	/* Wait TXcomplete ... */
+	nb_trial = 0;
+	Status = at91_twi_read(AT91_TWI_SR);
+	while (!(Status & AT91_TWI_TXCOMP) && (nb_trial < 10)) {
+		nb_trial++;
+		Status = at91_twi_read(AT91_TWI_SR);
+	}
+
+	if (Status & AT91_TWI_TXCOMP) {
+		*data_in = (unsigned char) at91_twi_read(AT91_TWI_RHR);
+		return ICS1523_ACCESS_OK;
+	}
+	else
+		return ICS1523_ACCESS_ERROR;
+}
+
+/* -----------------------------------------------------------------------------
+ * Write a byte with TWI Interface to the Clock Generator ICS1523
+ * ----------------------------------------------------------------------------- */
+
+static int at91_ics1523_WriteByte(unsigned char reg_address, unsigned char data_out)
+{
+	int Status, nb_trial;
+
+	at91_twi_write(AT91_TWI_MMR, AT91_TWI_IADRSZ_1 | ((ICS_ADDR << 16) & AT91_TWI_DADR));
+	at91_twi_write(AT91_TWI_IADR, reg_address);
+	at91_twi_write(AT91_TWI_THR, data_out);
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_START | AT91_TWI_STOP);
+
+	/* Program temporizing period (300us) */
+	udelay(300);
+
+	nb_trial = 0;
+	Status = at91_twi_read(AT91_TWI_SR);
+	while (!(Status & AT91_TWI_TXCOMP) && (nb_trial < 10)) {
+		nb_trial++;
+		if (Status & AT91_TWI_ERROR) {
+			/* If Underrun OR NACK - Start again */
+			at91_twi_write(AT91_TWI_CR, AT91_TWI_START | AT91_TWI_STOP);
+
+			/*  Program temporizing period (300us) */
+			udelay(300);
+		}
+		Status = at91_twi_read(AT91_TWI_SR);
+	};
+
+	if (Status & AT91_TWI_TXCOMP)
+		return ICS1523_ACCESS_OK;
+	else
+		return ICS1523_ACCESS_ERROR;
+}
+
+/* -----------------------------------------------------------------------------
+ * Initialization of the Clock Generator ICS1523
+ * ----------------------------------------------------------------------------- */
+
+int at91_ics1523_init(void)
+{
+	int		nb_trial;
+	int		ack = ICS1523_ACCESS_OK;
+	unsigned int	status = 0xffffffff;
+	struct clk	*twi_clk;
+
+	/* Map in TWI peripheral */
+	twi_base = ioremap(AT91RM9200_BASE_TWI, SZ_16K);
+	if (!twi_base)
+		return -ENOMEM;
+
+	/* pins used for TWI interface */
+	at91_set_A_periph(AT91_PIN_PA25, 0);            /* TWD */
+	at91_set_multi_drive(AT91_PIN_PA25, 1);
+	at91_set_A_periph(AT91_PIN_PA26, 0);            /* TWCK */
+	at91_set_multi_drive(AT91_PIN_PA26, 1);
+
+	/* Enable the TWI clock */
+	twi_clk = clk_get(NULL, "twi_clk");
+	if (IS_ERR(twi_clk))
+		return ICS1523_ACCESS_ERROR;
+	clk_enable(twi_clk);
+
+	/* Disable interrupts */
+	at91_twi_write(AT91_TWI_IDR, -1);
+
+	/* Reset peripheral */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_SWRST);
+
+	/* Set Master mode */
+	at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN);
+
+	/* Set TWI Clock Waveform Generator Register */
+	at91_ics1523_SetTwiClock(60000);     /* MCK in KHz = 60000 KHz */
+
+	/* ICS1523 Initialisation */
+	ack |= at91_ics1523_WriteByte ((unsigned char) ICS_ICR, (unsigned char) 0);
+	ack |= at91_ics1523_WriteByte ((unsigned char) ICS_OE, (unsigned char) (ICS_OEF | ICS_OET2 | ICS_OETCK));
+	ack |= at91_ics1523_WriteByte ((unsigned char) ICS_OD, (unsigned char) (ICS_INSEL | 0x7F));
+	ack |= at91_ics1523_WriteByte ((unsigned char) ICS_DPAO, (unsigned char) 0);
+
+	nb_trial = 0;
+	do {
+		nb_trial++;
+		ack |= at91_ics1523_WriteByte ((unsigned char) ICS_ICR, (unsigned char) (ICS_ENDLS | ICS_ENPLS | ICS_PDEN /*| ICS_FUNCSEL*/));
+		ack |= at91_ics1523_WriteByte ((unsigned char) ICS_LCR, (unsigned char) (ICS_PSD | ICS_PFD));
+		ack |= at91_ics1523_WriteByte ((unsigned char) ICS_FD0, (unsigned char) 0x39) ; /* 0x7A */
+		ack |= at91_ics1523_WriteByte ((unsigned char) ICS_FD1, (unsigned char) 0x00);
+		ack |= at91_ics1523_WriteByte ((unsigned char) ICS_SWRST, (unsigned char) (ICS_PLLR));
+
+		/* Program 1ms temporizing period */
+		mdelay(1);
+
+		at91_ics1523_ReadByte ((unsigned char) ICS_SR, (char *)&status);
+	} while (!((unsigned int) status & (unsigned int) ICS_PLLLOCK) && (nb_trial < 10));
+
+	ack |= at91_ics1523_WriteByte ((unsigned char) ICS_DPAC, (unsigned char) 0x03) ; /* 0x01 */
+	ack |= at91_ics1523_WriteByte ((unsigned char) ICS_SWRST, (unsigned char) (ICS_DPAR));
+
+	/* Program 1ms temporizing period */
+	mdelay(1);
+
+	ack |= at91_ics1523_WriteByte ((unsigned char) ICS_DPAO, (unsigned char) 0x00);
+
+	/* Program 1ms temporizing period */
+	mdelay(1);
+	
+	/* All done - cleanup */
+	iounmap(twi_base);
+	clk_disable(twi_clk);
+	clk_put(twi_clk);
+
+	return ack;
+}
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/led-som9260m.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/led-som9260m.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/led-som9260m.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/led-som9260m.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,63 @@
+/*
+ * arch/arm/mach-at91rm9200/led-som9260m.c
+ * EMAC.Inc SOM9260m low level led interactions
+ *
+ * Copyright (C) 2007 EMAC.Inc <support@emacinc.com>
+ */
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <linux/class/gpio.h>
+#include <asm/arch/board.h>
+#include <asm/arch/at91sam9260.h>
+#include <asm/arch/gpio.h>
+
+#define LED_CNT 2
+
+/* Global Variables Used in the Driver. */
+int led_array[LED_CNT] = { AT91_PIN_PA9, AT91_PIN_PA10 };
+char led_value[LED_CNT] = { 0, 0 };
+
+int som9260m_led_init(void){
+	int i;
+	
+	for(i=0;i<LED_CNT;i++)
+		at91_set_gpio_output(led_array[i],led_value[i]);
+	
+	return 0;
+}
+
+static gpio_data led_data_read(struct gpio_s *gpio){
+	return at91_get_gpio_value(led_array[gpio->index]);
+}
+
+static int led_data_write(struct gpio_s *gpio,gpio_data data){
+	led_value[gpio->index] = (char)data;
+	at91_set_gpio_output(led_array[gpio->index],led_value[gpio->index]);
+	return 0;
+}
+
+static gpio_data led_index_read(struct gpio_s *gpio){
+	return gpio->index;
+}
+	
+static int led_index_write(struct gpio_s *gpio,gpio_data index){
+	if(index>LED_CNT)return -1;
+	if(index<0)return -1;
+	gpio->index = index;
+	return 0;
+}
+
+struct class_device *som9260m_led_class_create(const char *name){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	gpio->name = name;
+	gpio->subclass = GPIO_SUBCLASS;
+	gpio->data_write = led_data_write;
+	gpio->data_read = led_data_read;
+	gpio->index_write = led_index_write;
+	gpio->index_read = led_index_read;
+	led_index_write(gpio,0);
+	printk("registering indexed led device: %s\n",name);
+	return gpio_register_class_device(gpio);
+}
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/leds.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/leds.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/leds.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/leds.c	2008-02-07 10:24:58.000000000 -0500
@@ -86,10 +86,6 @@ static int __init leds_init(void)
 	if (!at91_leds_timer || !at91_leds_cpu)
 		return -ENODEV;
 
-	/* Enable PIO to access the LEDs */
-	at91_set_gpio_output(at91_leds_timer, 1);
-	at91_set_gpio_output(at91_leds_cpu, 1);
-
 	leds_event = at91_leds_event;
 
 	leds_event(led_start);
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/pm.c linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/pm.c
--- linux-2.6.20/arch/arm/mach-at91rm9200/pm.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/pm.c	2008-02-07 10:24:58.000000000 -0500
@@ -63,6 +63,7 @@ static int at91_pm_prepare(suspend_state
  * Verify that all the clocks are correct before entering
  * slow-clock mode.
  */
+#warning "SAM9260 only has 3 programmable clocks."
 static int at91_pm_verify_clocks(void)
 {
 	unsigned long scsr;
@@ -80,6 +81,8 @@ static int at91_pm_verify_clocks(void)
 #warning "Check SAM9260 USB clocks"
 	} else if (cpu_is_at91sam9261()) {
 #warning "Check SAM9261 USB clocks"
+	} else if (cpu_is_at91sam9263()) {
+#warning "Check SAM9263 USB clocks"
 	}
 
 #ifdef CONFIG_AT91_PROGRAMMABLE_CLOCKS
@@ -126,7 +129,7 @@ static int at91_pm_enter(suspend_state_t
 	at91_gpio_suspend();
 	at91_irq_suspend();
 
-	pr_debug("AT91: PM - wake mask %08x, pm state %d\n",
+	pr_info("AT91: PM - wake mask %08x, pm state %d\n",
 			/* remember all the always-wake irqs */
 			(at91_sys_read(AT91_PMC_PCSR)
 					| (1 << AT91_ID_FIQ)
@@ -175,21 +178,25 @@ static int at91_pm_enter(suspend_state_t
 			 */
 			asm("b 1f; .align 5; 1:");
 			asm("mcr p15, 0, r0, c7, c10, 4");	/* drain write buffer */
-			at91_sys_write(AT91_SDRAMC_SRR, 1);	/* self-refresh mode */
+			at91_self_refresh(1);//make this more generic to encompass the 9260
 			/* fall though to next state */
 
+		at91_stopclock(1);//if supported,stop the cpu clock on wfi instruction.
+			
 		case PM_SUSPEND_ON:
-			asm("mcr p15, 0, r0, c7, c0, 4");	/* wait for interrupt */
+			asm("mcr p15, 0, r0, c7, c0, 4");	// wait for interrupt 
 			break;
 
+			
+			
 		default:
 			pr_debug("AT91: PM - bogus suspend state %d\n", state);
 			goto error;
 	}
 
 	pr_debug("AT91: PM - wakeup %08x\n",
-			at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR));
-
+	at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR));
+	
 error:
 	target_state = PM_SUSPEND_ON;
 	at91_irq_resume();
@@ -205,20 +212,27 @@ static struct pm_ops at91_pm_ops ={
 	.enter		= at91_pm_enter,
 };
 
+#ifdef CONFIG_AT91_SLOW_CLOCK
+extern void at91rm9200_slow_clock(void);
+extern u32 at91rm9200_slow_clock_sz;
+#endif
+
 static int __init at91_pm_init(void)
 {
-	printk("AT91: Power Management\n");
-
-#ifdef CONFIG_AT91_PM_SLOW_CLOCK
-	/* REVISIT allocations of SRAM should be dynamically managed.
+#ifdef CONFIG_AT91_SLOW_CLOCK
+	/*
+	 * REVISIT allocations of SRAM should be dynamically managed.
 	 * FIQ handlers and other components will want SRAM/TCM too...
 	 */
-	slow_clock = (void *) (AT91_VA_BASE_SRAM + (3 * SZ_4K));
+	slow_clock = (void *) (AT91_IO_VIRT_BASE - AT91RM9200_SRAM_SIZE + (3 * SZ_4K));
 	memcpy(slow_clock, at91rm9200_slow_clock, at91rm9200_slow_clock_sz);
+	printk("AT91: Power Management (with slow clock mode)\n");
+#else
+	printk("AT91: Power Management\n");
 #endif
 
 	/* Disable SDRAM low-power mode.  Cannot be used with self-refresh. */
-	at91_sys_write(AT91_SDRAMC_LPR, 0);
+	at91_lp_disable(1);
 
 	pm_set_ops(&at91_pm_ops);
 
diff -uprN linux-2.6.20/arch/arm/mach-at91rm9200/pm_slowclock.S linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/pm_slowclock.S
--- linux-2.6.20/arch/arm/mach-at91rm9200/pm_slowclock.S	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-at91rm9200/pm_slowclock.S	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,172 @@
+/*
+ * arch/arm/mach-at91rm9200/pm_slow_clock.S
+ *
+ *  Copyright (C) 2006 Savin Zlobec
+ *
+ * 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/linkage.h>
+#include <asm/hardware.h>
+#include <asm/arch/at91_pmc.h>
+#include <asm/arch/at91rm9200_mc.h>
+
+#define MCKRDY_TIMEOUT		1000
+#define MOSCRDY_TIMEOUT 	1000
+#define PLLALOCK_TIMEOUT	1000
+
+	.macro wait_mckrdy
+	mov	r2, #MCKRDY_TIMEOUT
+1:	sub	r2, r2, #1
+	cmp	r2, #0
+	beq	2f
+	ldr	r3, [r1, #AT91_PMC_SR]
+	tst	r3, #AT91_PMC_MCKRDY
+	beq	1b
+2:
+	.endm
+
+	.macro wait_moscrdy
+	mov	r2, #MOSCRDY_TIMEOUT
+1:	sub	r2, r2, #1
+	cmp	r2, #0
+	beq	2f
+	ldr	r3, [r1, #AT91_PMC_SR]
+	tst	r3, #AT91_PMC_MOSCS
+	beq	1b
+2:
+	.endm
+
+	.macro wait_pllalock
+	mov	r2, #PLLALOCK_TIMEOUT
+1:	sub	r2, r2, #1
+	cmp	r2, #0
+	beq	2f
+	ldr	r3, [r1, #AT91_PMC_SR]
+	tst	r3, #AT91_PMC_LOCKA
+	beq	1b
+2:
+	.endm
+
+	.macro wait_plladis
+	mov	r2, #PLLALOCK_TIMEOUT
+1:	sub	r2, r2, #1
+	cmp	r2, #0
+	beq	2f
+	ldr	r3, [r1, #AT91_PMC_SR]
+	tst	r3, #AT91_PMC_LOCKA
+	bne	1b
+2:
+	.endm
+
+	.text
+
+ENTRY(at91rm9200_slow_clock)
+
+	ldr	r1, .at91_va_base_sys
+
+	/* Put SDRAM in self refresh mode */
+
+	b	1f
+	.align	5
+1:	mcr	p15, 0, r0, c7, c10, 4
+	mov	r2, #1
+	str	r2, [r1, #AT91_SDRAMC_SRR]
+
+	/* Save Master clock setting */
+
+	ldr	r2, [r1, #AT91_PMC_MCKR]
+	str	r2, .saved_mckr
+
+	/*
+	 * Set the Master clock source to slow clock
+	 *
+	 * First set the CSS field, wait for MCKRDY
+	 * and than set the PRES and MDIV fields.
+	 *
+	 * See eratta #2[78] for details.
+	 */
+
+	bic	r2, r2, #3
+	str	r2, [r1, #AT91_PMC_MCKR]
+
+	wait_mckrdy
+
+	mov	r2, #0
+	str	r2, [r1, #AT91_PMC_MCKR]
+
+	/* Save PLLA setting and disable it */
+
+	ldr	r2, [r1, #AT91_CKGR_PLLAR]
+	str	r2, .saved_pllar
+
+	mov	r2, #0
+	str	r2, [r1, #AT91_CKGR_PLLAR]
+
+	wait_plladis
+
+	/* Turn off the main oscillator */
+
+	ldr	r2, [r1, #AT91_CKGR_MOR]
+	bic	r2, r2, #AT91_PMC_MOSCEN
+	str	r2, [r1, #AT91_CKGR_MOR]
+
+	/* Wait for interrupt */
+
+	mcr	p15, 0, r0, c7, c0, 4
+
+	/* Turn on the main oscillator */
+
+	ldr	r2, [r1, #AT91_CKGR_MOR]
+	orr	r2, r2, #AT91_PMC_MOSCEN
+	str	r2, [r1, #AT91_CKGR_MOR]
+
+	wait_moscrdy
+
+	/* Restore PLLA setting */
+
+	ldr	r2, .saved_pllar
+	str	r2, [r1, #AT91_CKGR_PLLAR]
+
+	wait_pllalock
+
+	/*
+	 * Restore master clock setting
+	 *
+	 * First set PRES if it was not 0,
+	 * than set CSS and MDIV fields.
+	 * After every change wait for
+	 * MCKRDY.
+	 *
+	 * See eratta #2[78] for details.
+	 */
+
+	ldr	r2, .saved_mckr
+	tst	r2, #0x1C
+	beq	2f
+	and	r2, r2, #0x1C
+	str	r2, [r1, #AT91_PMC_MCKR]
+
+	wait_mckrdy
+
+2:	ldr	r2, .saved_mckr
+	str	r2, [r1, #AT91_PMC_MCKR]
+
+	wait_mckrdy
+
+	mov	pc, lr
+
+.saved_mckr:
+	.word 0
+
+.saved_pllar:
+	.word 0
+
+.at91_va_base_sys:
+	.word AT91_VA_BASE_SYS
+
+ENTRY(at91rm9200_slow_clock_sz)
+	.word .-at91rm9200_slow_clock
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/Kconfig linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/Kconfig
--- linux-2.6.20/arch/arm/mach-ep93xx/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -7,6 +7,21 @@ config CRUNCH
 	help
 	  Enable kernel support for MaverickCrunch.
 
+config EP93XX_PWM
+	bool "Support EP93xx PWMs"
+	help
+	  Say 'Y' here if you want your kernel to support ep93xx pwms.
+
+config EP93XX_ATOD
+	bool "Support EP93xx AtoD"
+	help
+	  Say 'Y' here if you want your kernel to support ep93xx AtoD.
+	  
+config EP93XX_SPI
+	bool "Support EP93xx SPI"
+	help
+	  Say 'Y' here if you want your kernel to support ep93xx spi.
+
 comment "EP93xx Platforms"
 
 config MACH_ADSSPHERE
@@ -57,6 +72,11 @@ config MACH_TS72XX
 	  Say 'Y' here if you want your kernel to support the
 	  Technologic Systems TS-72xx board.
 
+config MACH_IPAC9302
+	bool "Support EMAC.Inc iPAC-9302 SBC"
+	help
+	  Say 'Y' here if you want your kernel to support the
+	  EMAC.Inc iPAC-9302 board.
 endmenu
-
+	
 endif
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/Makefile linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/Makefile
--- linux-2.6.20/arch/arm/mach-ep93xx/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -14,3 +14,7 @@ obj-$(CONFIG_MACH_EDB9315)	+= edb9315.o
 obj-$(CONFIG_MACH_EDB9315A)	+= edb9315a.o
 obj-$(CONFIG_MACH_GESBC9312)	+= gesbc9312.o
 obj-$(CONFIG_MACH_TS72XX)	+= ts72xx.o
+obj-$(CONFIG_MACH_IPAC9302)	+= ipac9302.o
+obj-$(CONFIG_EP93XX_PWM) += pwm-ep93xx.o
+obj-$(CONFIG_EP93XX_SPI) += spi-ep93xx.o
+obj-$(CONFIG_EP93XX_ATOD) += atod-ep93xx.o
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/Makefile.boot linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/Makefile.boot
--- linux-2.6.20/arch/arm/mach-ep93xx/Makefile.boot	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/Makefile.boot	2008-02-07 10:24:58.000000000 -0500
@@ -1,2 +1 @@
    zreladdr-y	:= 0x00008000
-params_phys-y	:= 0x00000100
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/atod-ep93xx.c linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/atod-ep93xx.c
--- linux-2.6.20/arch/arm/mach-ep93xx/atod-ep93xx.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/atod-ep93xx.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,88 @@
+/*
+ * arch/arm/mach-ep93xx/atod-ep93xx.c
+ * EMAC.Inc ep93xx low level AtoD interactions
+ *
+ * Copyright (C) 2007 EMAC.Inc <support@emacinc.com>
+ */
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/arch/ep93xx_util.h>
+#include "atod-ep93xx.h"
+
+int ep93xx_atod_init(void){		
+	__u32 devicecfg = ioread32((void *)EP93XX_SYSCON_DEVICE_CONFIG);
+	EP93XX_SYSUNLOCK();
+	//iowrite32(EP93XX_SYSCON_ADCCLKDIV_ADCEN|EP93XX_SYSCON_ADCCLKDIV_ADIV,(void *)EP93XX_SYSCON_ADCCLKDIV);//enable AtoD clocks
+	iowrite32(EP93XX_SYSCON_ADCCLKDIV_ADCEN,(void *)EP93XX_SYSCON_ADCCLKDIV);//enable AtoD clocks
+	printk("atod: EP93XX_SYSCON_ADCCLKDIV: %x\n",ioread32((void *)EP93XX_SYSCON_ADCCLKDIV));
+	devicecfg|=EP93XX_SYSCON_DEVICE_CONFIG_ADCEN;//disable touchscreen (TIN on the ep9315)
+	devicecfg&=~EP93XX_SYSCON_DEVICE_CONFIG_ADCPD;//turn on the AtoD clock
+	EP93XX_DEVCFG_WRITE(devicecfg);//enable the AtoD
+	iowrite32(0,(void *)EP93XX_ADCSETUP1);//clear out any TS settings.
+	printk("atod: device config set to %x\n",ioread32((void *)EP93XX_SYSCON_DEVICE_CONFIG));
+	return 0;
+}
+
+int ep93xx_atod_switch(int channel){
+	const int decoder[5] = {0x608,0x680,0x640,0x620,0x610}; 
+	int code = decoder[channel];
+	iowrite32(0xAA,(void *)EP93XX_ADCSWLOCK);//this may have to be inlined.
+	iowrite32(code,(void *)EP93XX_ADCSWITCH);
+	return 0;
+}
+
+/**
+ * read result, reads a 16 bit signed value,
+ * some number massaging is done in accordance with the discussion posted on
+ * http://arm.cirrus.com/forum/viewtopic.php?p=8563#8563
+ * 
+ * if a new conversion is not yet ready -1 is returned.
+ */
+
+int ep93xx_atod_read_current(void){
+	int reading = ioread32((void *)EP93XX_ADCRESULT);
+	u16 data = reading;//implicity cut off the top.
+	if(!(reading&EP93XX_ADCRESULT_SDR)){
+		//printk("no new data, read %x\n",reading);
+		return -1;//no new reading available yet.
+	}
+ 	//Check limits and adjust bias (see page 34 in EP9302 datasheet (DS653PP3)) 
+ 	if ((data>25000)&&(data<=32767)) data=25000; //Enforce +25000 count limit 
+ 	if ((data>=32678)&&(data<40536)) data=40536;//Enforce -25000 count limit 
+ 	data-=40536; //Adjust bias value 
+	return (data);
+}
+
+static gpio_data atod_data_read(struct gpio_s *gpio){
+	int data;
+	do {data = ep93xx_atod_read_current();}while(data==-1);//get first available data
+	return data;	
+}
+
+static gpio_data atod_index_read(struct gpio_s *gpio){
+	return gpio->index;
+}
+	
+static int atod_index_write(struct gpio_s *gpio,gpio_data index){
+	if(index>4)return -1;
+	if(index<0)return -1;
+	gpio->index = index;
+	ep93xx_atod_switch(index);
+	ioread32((void *)EP93XX_ADCRESULT);//begin conversion cycle on the new channel
+	return 0;
+}
+
+struct class_device *ep93xx_atod_class_create(const char *name){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	gpio->name = name;
+	gpio->subclass = GPIO_SUBCLASS;
+	gpio->data_write = gpio_empty_write;
+    gpio->data_read = atod_data_read;
+	gpio->index_write = atod_index_write;
+    gpio->index_read = atod_index_read;
+    atod_index_write(gpio,0);
+    printk("registering indexed atod device: %s\n",name);
+    return gpio_register_class_device(gpio);
+}
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/atod-ep93xx.h linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/atod-ep93xx.h
--- linux-2.6.20/arch/arm/mach-ep93xx/atod-ep93xx.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/atod-ep93xx.h	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,12 @@
+#ifndef ATODEP93XX_H_
+#define ATODEP93XX_H_
+
+#include <asm/io.h>
+#include <linux/class/gpio.h>
+
+int ep93xx_atod_init(void);
+int ep93xx_atod_switch(int channel);
+int ep93xx_atod_read_current(void);
+struct class_device *ep93xx_atod_class_create(const char *name);
+
+#endif /*ATODEP93XX_H_*/
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/ipac9302.c linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/ipac9302.c
--- linux-2.6.20/arch/arm/mach-ep93xx/ipac9302.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/ipac9302.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,318 @@
+/*
+ * arch/arm/mach-ep93xx/ipac9302.c
+ * EMAC.Inc iPAC-9302 Support.
+ *
+ * Copyright (C) 2007 EMAC.Inc <support@emacinc.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/ioex/ecoreex.h>
+#include <linux/class/pwm.h>
+#include <linux/class/mmcprot.h>
+#include <linux/class/spi.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <asm/arch/ep93xx_util.h>
+#include "spi-ep93xx.h"
+#include "atod-ep93xx.h"
+
+#define OSCCLOCK		14745600
+
+/************************************************************
+ * Flash Device
+ * Flash platform device used by the MTD platform driver
+ */
+
+static struct physmap_flash_data ipac9302_flash_data = {
+	.width		= 2,
+};
+
+static struct resource ipac9302_flash_resource = {
+	.start		= 0x60000000,
+	.end		= 0x60ffffff,
+	.flags		= IORESOURCE_MEM,
+};
+
+static struct platform_device ipac9302_flash = {
+	.name		= "physmap-flash",
+	.id		= 0,
+	.dev		= {
+		.platform_data	= &ipac9302_flash_data,
+	},
+	.num_resources	= 1,
+	.resource	= &ipac9302_flash_resource,
+};
+
+/************************************************************
+ * Ethernet Device
+ * Ethernet platform device used bye the ep93xx ethernet platform driver
+ */
+ 
+static struct ep93xx_eth_data ipac9302_eth_data = {
+	.phy_id			= 1,
+};
+
+static struct resource ipac9302_eth_resource[] = {
+	{
+		.start	= EP93XX_ETHERNET_PHYS_BASE,
+		.end	= EP93XX_ETHERNET_PHYS_BASE + 0xffff,
+		.flags	= IORESOURCE_MEM,
+	}, {
+		.start	= IRQ_EP93XX_ETHERNET,
+		.end	= IRQ_EP93XX_ETHERNET,
+		.flags	= IORESOURCE_IRQ,
+	}
+};
+
+static struct platform_device ipac9302_eth_device = {
+	.name		= "ep93xx-eth",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &ipac9302_eth_data,
+	},
+	.num_resources	= 2,
+	.resource	= ipac9302_eth_resource,
+};
+
+/**
+ * Attempt to set a tip flag atomically, 
+ * if it is already set return an error indicating that
+ * the device is already held, note that this does not enforce any locking itself, only 
+ * provides the variable to do it, individual locking mechanisms must be implemented by the underlying
+ * driver/class layer, as the result of failing to obtain a lock will vary depending on the context.
+ */
+static ep93xx_spiconfig_t spiconfig = {.id		= 4,};
+/**
+ * SPI tip locking, the function provides locking with the
+ * other onboard spi devices (in this case the MMC)
+ * currently no chip select is implemented so it simply controls/reads the software lock.
+ */
+static int spitip(spi_t *s,int ofs){
+	return ep93xx_spitip(ofs,&spiconfig);
+}
+
+/************************************************************
+ * MMC/SD Slot
+ * MMC slot through the spi layer with some functions provided by the ecroeex.
+ * card detect/write protect functions are provided by ecoreex.
+ * note that this requires ep93xx spi code to build
+ */
+#ifdef CONFIG_MMCCLASS 
+static ep93xx_spiconfig_t mmcspiconfig = {.id		= 5,};//mmc spi configuration settings
+
+#define MMCDR() 		(ioread32(EP93XX_GPIO_B_DR))
+#define MMCDDR()		(ioread32(EP93XX_GPIO_B_DDR))
+
+#define MMCCSON() 		{iowrite32((MMCDR()&(~1)),(void *)EP93XX_GPIO_B_DR);} 
+#define MMCCSOFF() 		{iowrite32((MMCDR()|1),(void *)EP93XX_GPIO_B_DR);} 
+#define MMCCSSETUP()	{iowrite32(((MMCDDR())|1),(void *)EP93XX_GPIO_B_DDR);MMCCSOFF();}
+
+/**
+ * set hardware up for an MMC transfer over the SPI
+ * declare transfer in progress true/false 
+ * (moves chip select, potentially turns off the clock)
+ * This implementation simply flips on/off the MMC CS
+ * Note that the spi lines could be sitting at an invalid state when this is flipped.
+ * mmc configuration is therefore done prior to chip select assertionn
+ */
+static int mmctip(mmcslot_t *s,int onoff){
+if(onoff==1){
+	if(ep93xx_spitip(1,&mmcspiconfig)<0)return -1;//could not obtain lock, fail and return.
+	MMCCSON();//lock obtained, turn on the chip select
+	return 1;
+}
+if(onoff==0){MMCCSOFF();ep93xx_spitip(0,&mmcspiconfig);}//OFF
+return 0;//currently does not return status other than failure
+} 
+
+/**
+ * mmc specific bidirectional transfer, miso and mosi may be the same
+ * passing NULL to mosi transfers 0xff.
+ * This call is non-preemptive, so should never interrupt another spi call.
+ * real time spi devices may need to get and restore spi state before stealing it away from
+ * the mmc.
+ */
+static int mmcexchange(mmcslot_t *s,u8 *mosi, u8 *miso, int size){
+	//ep93xx_spiconfigure(&mmcspiconfig);//set mmc specific spi configuration - done by tip
+	ep93xx_spi_transfer_blocking(mosi, miso, size);//blocking spi transfer the mmc information
+	return 0;
+}
+
+/**
+ * change mmc spi bitrate
+ */	
+static int mmcsetspeed(mmcslot_t *s,unsigned long speed){
+	spi_setup_config(mmcspiconfig.cp0,speed,&mmcspiconfig);
+	return 0;
+}
+
+static int mmcboardinit(void){
+	MMCCSSETUP();	
+	spi_setup_config(EP93XX_CP0_MOTO_MODE|BITSPERWORD(8),100000,&mmcspiconfig);
+	//spi_setup_config(EP93XX_CP0_TEXAS_MODE|BITSPERWORD(8),200000,&mmcspiconfig);
+	return 0;
+}
+ 
+static mmcslot_t mmcslot = {
+	.slotnumber = 0,
+	.name = "mmca",
+	.tip = mmctip,
+	.exchange = mmcexchange,
+	.setspeed = mmcsetspeed,
+};
+
+static struct platform_device mmcslot_device = {
+	.name = "mmc",
+	.dev		= {
+		.platform_data	= &mmcslot,
+	},
+};
+
+#endif //CONFIG_MMCCLASS 
+ 
+/************************************************************
+ * IOEX Device
+ * Onboard EMAC I/O core platform device used by the ecoreex driver
+ */
+#define CS0_START ((unsigned long)0x10000)
+#define CS0_END  ((unsigned long)0xFFFFFFF)
+#define CS0_LEN  ((unsigned long)(CS0_END-CS0_START+1))
+#define CPLDKEY 0xF
+
+static struct ecoreex_data ipac9302_ecoreex_data = {
+	.key_offset	= CPLDKEY,
+	.read_periodusa	= NULL, //virtual clock A defined as user settable
+	.mmcslot = &mmcslot,//allow the ecroeex to fill out mmc functions not currently implemented
+};
+
+static struct resource ipac9302_ecoreex_resource = {
+		.start	= CS0_START,
+		.end	= CS0_END,
+		.flags	= IORESOURCE_MEM,
+};
+
+static struct platform_device ipac9302_ecoreex_device = {
+	.name		= "ecoreex",
+	.id		= -1,
+	.dev		= {
+		.platform_data	= &ipac9302_ecoreex_data,
+	},
+	.num_resources	= 1,
+	.resource	= &ipac9302_ecoreex_resource,
+};
+
+/************************************************************
+ * ep93xx pwm1 initialization routine (generic)
+ * TODO:move routines to generic ep93xx code.
+ */
+#ifdef CONFIG_EP93XX_PWM 
+#include <asm/mach/ep93xx_pwm.h>
+
+static void ep93xx_pwm1_enable(void){
+	u32 devicecfg = ioread32((void *)EP93XX_SYSCON_DEVICE_CONFIG);
+	devicecfg|=EP93XX_SYSCON_DEVICE_CONFIG_PONG;
+	EP93XX_SYSUNLOCK();
+	iowrite32(devicecfg,(void *)EP93XX_SYSCON_DEVICE_CONFIG);
+}
+
+static inline void ep93xx_pwm_map(int num, const char *name){			
+	pwm_declare();	
+	ep93xx_pwm_device_create(EP93XX_PWM(num),name);		
+}
+#endif
+
+/************************************************************
+ * device registrations from the arch go here, 
+ * which are called by the boardspec ioex driver
+ */
+static int ipac9302_classes(void)
+{
+#ifdef CONFIG_EP93XX_PWM
+	ep93xx_pwm1_enable();
+	ep93xx_pwm_map(1,"ep93xx_pwm1");
+#endif	
+#ifdef CONFIG_EP93XX_ATOD 
+	ep93xx_atod_init();
+	ep93xx_atod_class_create("indexed_atod");
+#endif
+#ifdef CONFIG_SPICLASS 
+	spi_setup_config(EP93XX_CP0_MOTO_MODE|BITSPERWORD(8),200000,&spiconfig);
+	ep93xx_spi_class_create("ep93xx_spi",&spiconfig,spitip);
+#endif	
+	return 0;
+}
+
+static struct platform_device boardspec_device = {
+	.name = "boardspec",
+	.id = 1,
+	.dev		= {
+		.platform_data	= &ipac9302_classes,
+	},
+};
+
+
+/************************************************************
+ * Linux Board initialization routine 
+ */
+static int chiprevision;
+const char *chip_revisions[] ={"A","B","C","D0","D1","E0","E1","E2",">E2"};
+
+/**
+ * return sspclock, varies by chip revision number
+ */
+u32 getsspclock(void){
+	if(chiprevision>6)return OSCCLOCK;
+	return OSCCLOCK/2;
+}
+
+#define EP93XX_REVISION_OFFSET	28
+
+static inline int ep93xx_chip_revision(void){
+	return(ioread32(EP93XX_SYSCON_CHIPID)>>EP93XX_REVISION_OFFSET);	
+}
+ 
+static void __init ipac9302_init_machine(void){	
+	chiprevision = ep93xx_chip_revision();	
+	printk("ep9302 rev %s detected\n",chip_revisions[chiprevision]);
+	ep93xx_init_devices();
+	/**initialize mmc hardware local to the processor, 
+	 * uses mmc driver as it's io extension declaration rather than boardspec
+	 * change this? Note that using the platform driver means that it can effectively only register 1 slot,
+	 * which seems quite reasonable, although artificially limiting.
+	 * */
+	mmcboardinit();
+	platform_device_register(&ipac9302_flash);
+	memcpy(ipac9302_eth_data.dev_addr,(void *)(EP93XX_ETHERNET_BASE + 0x50), 6);//MAC address
+	platform_device_register(&ipac9302_eth_device);
+	platform_device_register(&ipac9302_ecoreex_device);	
+	platform_device_register(&boardspec_device);
+	platform_device_register(&mmcslot_device);
+
+}
+
+/************************************************************
+ * standard mach structure for the iPac board
+ */
+MACHINE_START(IPAC9302, "EMAC.Inc iPac 9302 SBC")
+	.phys_io		= EP93XX_APB_PHYS_BASE,
+	.io_pg_offst	= ((EP93XX_APB_VIRT_BASE) >> 18) & 0xfffc,
+	.boot_params	= 0xc0000100,
+	.map_io			= ep93xx_map_io,
+	.init_irq		= ep93xx_init_irq,
+	.timer			= &ep93xx_timer,
+	.init_machine	= ipac9302_init_machine,
+MACHINE_END
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/pwm-ep93xx.c linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/pwm-ep93xx.c
--- linux-2.6.20/arch/arm/mach-ep93xx/pwm-ep93xx.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/pwm-ep93xx.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,149 @@
+/**
+ * ep93xx PWM interface, 
+ * registers with misc classes if available. 
+ * 
+*/
+
+#include <linux/class/pwm.h>
+#include <asm/io.h>
+#include <asm/mach/ep93xx_pwm.h>
+
+
+//#define PWM_DEBUG 
+ 
+#undef PWMDEBUG
+#ifdef PWM_DEBUG
+	#define PWMDEBUG(x...)  {printk("%s(): %d ",__PRETTY_FUNCTION__, __LINE__);printk(x);}
+#else
+	#define PWMDEBUG(x...)	do { } while (0)
+#endif 
+
+#define EP93XX_PWM_SUBCLASS 93
+
+//#define get_sclk() (66000000)
+
+#define get_sclk() 	(14745600)
+
+//internal errors
+#define SYSCLOCK_UNSUPPORTED	-2
+
+static inline int us2reg(__u32 *value){
+		switch(get_sclk()){
+			case 66000000:{
+				const __u32 regmax = (0xffff/66);
+				PWMDEBUG("value in:%x\n",*value);
+				if(*value>regmax)*value=regmax;
+				*value*=66;
+				PWMDEBUG("value out:%x\n",*value);
+				// pwms seem to do funny things when zeros are written to period or width;
+				if(*value==0)*value=1;
+				return 0;
+			}
+			case 14745600:{
+				const __u32 regmax = ((0xffff*100)/1475);
+				PWMDEBUG("value in:%x\n",*value);
+				if(*value>regmax)*value=regmax;
+				*value*=1475;
+				*value/=100;
+				PWMDEBUG("value out:%x\n",*value);
+				// pwms seem to do funny things when zeros are written to period or width;
+				if(*value==0)*value=1;
+				return 0;
+			}
+			default:return SYSCLOCK_UNSUPPORTED;
+	}
+}
+
+static inline int reg2us(__u32 *value){
+		switch(get_sclk()){
+			case 66000000:
+				PWMDEBUG("value in:%x\n",*value);
+				*value/=66;
+				PWMDEBUG("value out:%x\n",*value);
+				return 0;
+			case 14745600:
+				PWMDEBUG("value in:%x\n",*value);
+				*value*=100;
+				*value/=1475;
+				PWMDEBUG("value out:%x\n",*value);
+				return 0;
+			default:return SYSCLOCK_UNSUPPORTED;
+	}
+}
+
+
+static int ep93xx_period_write(struct pwm_s *pwm, pwm_data period){
+	if(us2reg(&period)==SYSCLOCK_UNSUPPORTED)
+		{printk("sysclock unsupported\n");return SYSCLOCK_UNSUPPORTED;}
+	
+	PWMDEBUG("period:%x\n",period);
+	iowrite16((u16)period,pwm->periodus);
+	
+	return 0;
+}
+
+static int ep93xx_width_write(struct pwm_s *pwm, pwm_data width){
+	if(us2reg(&width)==SYSCLOCK_UNSUPPORTED)
+		{printk("sysclock unsupported\n");return SYSCLOCK_UNSUPPORTED;}
+	
+	PWMDEBUG("widthus:%x\n",width);
+	iowrite16((u16)width,pwm->widthus);
+	return 0;
+}
+
+static pwm_data ep93xx_period_read(struct pwm_s *pwm){
+	__u32 period = ioread16(pwm->periodus);
+	
+	if(reg2us(&period)==SYSCLOCK_UNSUPPORTED)
+		{printk("sysclock unsupported\n");return SYSCLOCK_UNSUPPORTED;}
+	
+	PWMDEBUG("period:%x\n",period);	
+	return (period); 
+}
+
+static pwm_data ep93xx_width_read(struct pwm_s *pwm){
+	__u32 width = ioread16(pwm->widthus);
+	
+	if(reg2us(&width)==SYSCLOCK_UNSUPPORTED)
+		{printk("sysclock unsupported\n");return SYSCLOCK_UNSUPPORTED;}
+	
+	PWMDEBUG("width:%x\n",width);	
+	return (width);
+}
+
+static pwm_data ep93xx_pwm_inv_read(pwm_t *pwm){
+	return (ioread16(pwm->control)&(1));
+}
+
+static int  ep93xx_pwm_inv_write(pwm_t *pwm, pwm_data data){
+	u16 pwmcontrol = (ioread16(pwm->control)&(~1))|((data)?(1):0);
+	iowrite16(pwmcontrol,pwm->control);
+	return 0;
+}
+
+
+struct class_device *ep93xx_pwm_device_create(unsigned long base, const char *name){
+	pwm_t *pwm = kmalloc(sizeof(pwm_t),GFP_KERNEL);
+	memset(pwm,0,sizeof(pwm_t));
+	pwm->name = name;
+	pwm->subclass = EP93XX_PWM_SUBCLASS;
+	
+	pwm->periodus = (u16 *)base;
+	pwm->widthus = (u16 *)(base+4);
+	pwm->control = (u16 *)(base+12);
+
+	iowrite16(1,pwm->control);//invert by default to power up off
+	iowrite16(1,(u16 *)(base+8));//enable PWM
+	
+	pwm->widthus_write = ep93xx_width_write;
+    pwm->widthus_read = ep93xx_width_read;
+    pwm->periodus_write = ep93xx_period_write;
+    pwm->periodus_read = ep93xx_period_read;
+    pwm->invert_write = ep93xx_pwm_inv_write;
+    pwm->invert_read = ep93xx_pwm_inv_read;
+	printk("registering ep93xx pwm device: %s\n",name);
+
+    return pwm_register_class_device(pwm);
+}
+
+
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/spi-ep93xx.c linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/spi-ep93xx.c
--- linux-2.6.20/arch/arm/mach-ep93xx/spi-ep93xx.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/spi-ep93xx.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,331 @@
+/*
+ * arch/arm/mach-ep93xx/spi-ep93xx.c
+ * EMAC.Inc ep93xx low level SPI interactions
+ *
+ * Copyright (C) 2007 EMAC.Inc <support@emacinc.com>
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/ioport.h>
+#include <linux/mtd/physmap.h>
+#include <linux/platform_device.h>
+#include <linux/ioex/ecoreex.h>
+#include <linux/class/pwm.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/mach-types.h>
+#include <asm/mach/arch.h>
+#include <linux/class/spi.h>
+#include "spi-ep93xx.h"
+ 
+/**
+ * create a configuration structure implementing the desired 
+ * transfer characteristics.
+ */
+int spi_setup_config(int mode, u32 speed_hz, ep93xx_spiconfig_t *c){
+	u8 prediv;
+	u8 div;
+	unsigned long E;
+	u32 sspclock = getsspclock();//provided by the mach
+			
+	if(!speed_hz)speed_hz = 1;//if zero is passed in both positions, set it to the minimum value
+	E = sspclock/speed_hz;//min divider required.
+	
+	if(E%2)E++;//can't handle odd numbers, round divider up (clock down)
+	prediv = MIN(E,254);
+	
+	if(prediv) div = MIN((E/prediv)-1,255);
+	else{//speed_hz > sspclock use the maximum clock rate.
+		div = 0;
+		prediv =2;	
+	}
+
+	c->cp0 = (div<<8)|(mode&EP93XX_CP0_MODEBITS);
+	c->cp1 = (EP93XX_CP1_MASTER|EP93XX_CP1_ENABLE);
+	c->prediv = prediv;
+	
+	EP93XXSPIDEBUG("%s\n",__FUNCTION__);
+	EP93XXSPIDEBUG("div=%d\n",div);
+	EP93XXSPIDEBUG("prediv=%d\n",prediv);
+	EP93XXSPIDEBUG("sspclock=%d\n",sspclock);
+	
+	//if a transfer is in progress for the device go ahead and reconfigure the hardware, otherwise it will be set on the next successful tip
+	if(ep93xx_spitip(TIPSTATUS,c))ep93xx_spiconfigure(c);
+	
+	return 0;	
+}
+
+/**
+ * convert register settings back to speed
+ */
+static u32 spi_getspeed(ep93xx_spiconfig_t *c){
+	u32 sspclock = getsspclock();//input clock determined by the mach
+	u8 prediv = c->prediv;
+	u8 div = (c->cp0>>8);
+	u32 denom = (1+div)*prediv;
+	EP93XXSPIDEBUG("%s\n",__FUNCTION__);
+	EP93XXSPIDEBUG("div=%d\n",div);
+	EP93XXSPIDEBUG("prediv=%d\n",prediv);
+	EP93XXSPIDEBUG("sspclock=%d\n",sspclock);
+	EP93XXSPIDEBUG("denom = %d\n",denom);
+	return(sspclock/denom);
+}
+
+/**
+ * executes the initialization sequence detailed on page 498 of the ep9301 manual.
+ */
+int ep93xx_spiconfigure(ep93xx_spiconfig_t *c){
+	iowrite16(EP93XX_CP1_ENABLE,(void *)EP93XX_SPI_CR1);//turn SPI on
+	iowrite16(c->cp0,(void *)EP93XX_SPI_CR0);//SET CR0
+	iowrite8(c->prediv,(void *)EP93XX_SPI_CPSR);//set CPSR
+	iowrite16(0,(void *)EP93XX_SPI_CR1);//turn SPI off
+	iowrite16(c->cp1,(void *)EP93XX_SPI_CR1);//turn SPI on and set cp1 bits.
+	
+	//EP93XXSPIDEBUG("cp0: %x\n",ioread16((void *)EP93XX_SPI_CR0));
+	///EP93XXSPIDEBUG("cpsr: %x\n",ioread16((void *)EP93XX_SPI_CPSR));
+	//EP93XXSPIDEBUG("cp1: %x\n",ioread16((void *)EP93XX_SPI_CR1));
+	
+	//write out a blank value to set up the default states correctly.
+	//ep93xx_spi_transfer_blocking(NULL, NULL, 1);
+	return 0;
+} 
+
+/**
+ * macros to determine if the SPI data fifos are full or empty
+ */
+#define RFF	8
+#define RNE	4	
+#define TNF	2
+#define TFE	1
+
+#define EP93XX_RXFULL (ioread8(EP93XX_SPI_SR)&RFF)
+#define EP93XX_RXEMPTY (!(ioread8(EP93XX_SPI_SR)&RNE))
+#define EP93XX_TXFULL (!(ioread8(EP93XX_SPI_SR)&TNF))
+#define EP93XX_TXEMPTY (ioread8(EP93XX_SPI_SR)&TFE)
+
+/**
+ * try to pull count words into rx.
+ * return the number of words pulled(not bytes).
+ */
+static inline int ep93xx_spi_rxpull(void *rx,u8 bpw,int count){
+	void *start = rx;	
+
+	if(rx==NULL){int bytes=0;
+		while(count--){
+		if(EP93XX_RXEMPTY)break;
+		ioread16(EP93XX_SPI_DR);
+		bytes++;
+		//EP93XXSPIDEBUG("A SR:%x\n",ioread8(EP93XX_SPI_SR));
+		}return bytes;}
+
+	if(BYTSPWORD(bpw)-1)while(count--){
+		if(EP93XX_RXEMPTY)break;
+		*((u16 *)rx++) = ioread16(EP93XX_SPI_DR);
+		//EP93XXSPIDEBUG("B SR:%x\n",ioread8(EP93XX_SPI_SR));
+		}
+	
+	else while(count--){
+		if(EP93XX_RXEMPTY)break;
+		*((u8 *)rx++) = ioread16(EP93XX_SPI_DR);
+		//EP93XXSPIDEBUG("C SR:%x\n",ioread8(EP93XX_SPI_SR));
+	}		
+	return (rx - start);
+}
+
+/**
+ * try to push count words from tx.
+ * return the number of words pushed(not bytes).
+ */
+static inline int ep93xx_spi_txpush(void *tx,u8 bpw,int count){
+	void *start = tx;
+	
+	if(tx==NULL){int bytes=0;
+		while(count--){
+		if(EP93XX_TXFULL)break;
+		iowrite16(0xFF,EP93XX_SPI_DR);
+		bytes++;
+		//EP93XXSPIDEBUG("D SR:%x\n",ioread8(EP93XX_SPI_SR));
+		}return bytes;}
+		
+	if(BYTSPWORD(bpw)-1)while(count--){
+		if(EP93XX_TXFULL)break;
+		iowrite16(*((u16 *)tx++),EP93XX_SPI_DR);
+		//EP93XXSPIDEBUG("E SR:%x\n",ioread8(EP93XX_SPI_SR));
+		}
+	
+	else while(count--){//count never filling up here? should probably be -- on all of the above.
+		if(EP93XX_TXFULL)break;
+		iowrite16(*((u8 *)tx++),EP93XX_SPI_DR);
+		//EP93XXSPIDEBUG("F SR:%x\n",ioread8(EP93XX_SPI_SR));
+	}
+	
+	return (tx - start);
+}
+
+/*DMA based transfer
+* not efficient for single bye transfers,but this is probably an acceptable tradeoff for now,
+* since efficiency will be far more important on large block transfers (i.e. MMC) 
+* NOTE: code may need to be added here to take advantage of the alternate dma buffers in the 
+* transmit structure.
+*/  
+#ifdef EP93XX_SPI_DMA
+static int ep93xx_spi_m2m_sleep(m2mchannel,t->tx_buf,t->rx_buf,size,void *address){
+	TODO:IMPLEMENT spi_m2m_sleep
+}
+#endif
+
+
+/**
+ * A blocking spi transfer. 
+ * Although the spi layer does provide IRQ's, the fifo is only 8 bits deep and will typically empty
+ * in only a few uS, which is in the same range as the typical latency from the interrupt itself.
+ * Therefore, short of a DMA trasfer, a blocking poll is probably the most efficent transfer method.
+ * Although system calls and user space tasks will be delayed, 
+ * this task does not disable interrupts, so preemptions are still allowed.
+ * To prevent overflows a count is maintained of the current number of elements in the Q, 
+ * which is never allowed to grow beyond the maximum Rx queue size.
+ * Note that large transfers could delay user space for some time if preemption is disabled.
+ * It may be desireable to set some limit on transfer size after which point the transaction must yield
+ * for a time to allow other tasks to run.A yield after every 8 bytes, however, will add far to large a latency to block drivers attached to the
+ * bus.
+ * 
+ * returns the number of bytes transferred
+ * 
+ * NOTES:currently hard coded to 8 bit transfers
+ */
+int ep93xx_spi_transfer_blocking(u8 *mosi, u8 *miso, int size){
+	unsigned togo = size;
+	unsigned count = 0;
+	unsigned words = 0;
+	if(!EP93XX_RXEMPTY){
+		printk("%s:unknown remainder in queue, transaction cannot begin\n",__FUNCTION__);	
+		return -1;
+	}
+	while(togo){//while transmission remaining
+		//EP93XXSPIDEBUG("togo %u count %u\n",togo,count);
+		words=ep93xx_spi_rxpull(miso,8,EP93XX_SPI_FIFO_SIZE);
+		count-=words;if(miso)miso+=words;
+		words=ep93xx_spi_txpush(mosi,8,MIN(togo,(EP93XX_SPI_FIFO_SIZE-count)));
+		count+=words;if(mosi)mosi+=words;
+		togo-=words;
+	}
+	
+	while(count){
+		words=ep93xx_spi_rxpull(miso,8,EP93XX_SPI_FIFO_SIZE);
+		count-=words;if(miso)miso+=words;
+		}//empty the fifo
+	
+	return(size - togo*BYTSPWORD(8));
+}
+
+/************************************************************
+ * generic spi locking function, 
+ * specific chip selects, keys, and error handling are left to the mach
+ */
+#define LOCKBIT	   0
+static long spiv = 0;//atomic int controlling access to the processor's spi port
+int ep93xx_spitip(int ofs,ep93xx_spiconfig_t *c){
+	//EP93XXSPIDEBUG("%s:ofs=%x,spiv=%x\n",__FUNCTION__,ofs,(int)spiv);
+	if(ofs==0){
+		if(test_and_clear_bit(c->id,&spiv)==0)return -1;//lock not owned by spiclass, can't remove it
+		if(test_and_clear_bit(LOCKBIT,&spiv)==0){
+			printk("%s:BUG:id %x is attempting to unlock an open lock\n",__FUNCTION__,c->id);
+			return -1;//lock was already cleared by a another source.
+		}
+		return 0;//unlocked
+	}
+	if(ofs==1){
+		if(test_bit(c->id,&spiv))return 1;//allow recursive calls
+		if(test_and_set_bit(LOCKBIT,&spiv)!=0)return -1;//lock already held cannot take ownership
+		if(test_and_set_bit(c->id,&spiv)==1){
+			printk("%s:BUG:id %x is attempting to mark a lock which is already owned\n",__FUNCTION__,c->id);
+			return -1;
+		}
+	if(c)ep93xx_spiconfigure(c);//set configuration to the new device settings	
+	return 1;//lock obtained
+	}
+	return (test_bit(c->id,&spiv));//otherwise return bitmask ?ownership of the lock
+}
+
+
+#ifdef CONFIG_SPICLASS
+/************************************************************
+ * SPI class access
+ * class driver interface to the spi port
+ * currently no chip selects are implemented, 
+ * these must be handled through gpio methods for direct class access.
+ * known mach chip selects may automate this by wrapping the tip with chip selects (this is how the mmc works)
+ */
+
+static int spixmit(struct spi_s *s,u8 *mosi, u8 *miso, int size){
+	//ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	//ep93xx_spiconfigure(c);//set mmc specific spi configuration
+	ep93xx_spi_transfer_blocking(mosi, miso, size);//blocking spi transfer the mmc information
+	return 0;
+}
+
+static int spiconfwrite(struct spi_s *s,spi_control flags){
+	ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	c->cp0 = 0;
+	if(flags&SPICL_CPHA)c->cp0|=EP93XX_CP0_CPHA;
+	if(flags&SPICL_CPOL)c->cp0|=EP93XX_CP0_CPOL;
+	if(flags&SPICL_EIGHTBIT)c->cp0|=EP93XX_CP0_EIGHTBIT;
+	return 0;
+}
+
+static spi_control spiconfread(struct spi_s *s){
+	ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	spi_control flags = 0;
+	if(c->cp0&EP93XX_CP0_CPHA)flags |= SPICL_CPHA;
+	if(c->cp0&EP93XX_CP0_CPOL)flags |= SPICL_CPOL;
+	if((c->cp0&EP93XX_CP0_EIGHTBIT)==EP93XX_CP0_EIGHTBIT)flags |= SPICL_EIGHTBIT;
+	return flags;
+}
+
+/**
+ * change spi bitrate
+ */	
+static int spisetspeed(struct spi_s *s,spi_control speed){
+	ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	EP93XXSPIDEBUG("setting speed to %d\n",speed);
+	spi_setup_config(c->cp0,speed,c);//set configuration structure to the new speed.
+	return 0;
+}
+
+/**
+ * retrieve the spi bitrate
+ */	
+static spi_control spigetspeed(struct spi_s *s){
+	ep93xx_spiconfig_t *c = container_of(s,ep93xx_spiconfig_t,s);
+	return spi_getspeed(c);
+}
+
+
+/************************************************************************************
+ * ep93xx spi device, 
+ * creates a single instance of a device for accessing the 
+ * ep93xx ssp port through the generic spi class.
+ */
+struct class_device *ep93xx_spi_class_create(
+		const char *name,
+		ep93xx_spiconfig_t *c,
+		int (*tip)(struct spi_s *s,int ofs))
+{
+	spi_t *s = &c->s;
+	memset(s,0,sizeof(spi_t));
+	s->name = name;
+	s->subclass = SPI_SUBCLASS;
+    s->xmit = spixmit;
+    s->confwrite = spiconfwrite;
+    s->confread = spiconfread;
+    s->speedwrite = spisetspeed;
+    s->speedread = spigetspeed;
+    s->tip = tip;
+    
+    printk("registering spi device: %s\n",name);
+    return spi_register_class_device(s);
+}
+#endif
diff -uprN linux-2.6.20/arch/arm/mach-ep93xx/spi-ep93xx.h linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/spi-ep93xx.h
--- linux-2.6.20/arch/arm/mach-ep93xx/spi-ep93xx.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mach-ep93xx/spi-ep93xx.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,53 @@
+#ifndef SPIEP93XX_H_
+#define SPIEP93XX_H_
+
+//#define EP93XXSPI_DEBUG
+
+#undef EP93XXSPIDEBUG
+#ifdef EP93XXSPI_DEBUG
+	#define EP93XXSPIDEBUG(x...)  {printk("%s(): %d ",__PRETTY_FUNCTION__, __LINE__);printk(x);}
+#else
+	#define EP93XXSPIDEBUG(x...)	do { } while (0)
+#endif 
+
+
+ //CR0 bit settings
+#define EP93XX_CP0_MOTO_MODE	(0)
+#define EP93XX_CP0_TEXAS_MODE	(0x10)
+#define EP93XX_CP0_CPHA			(0x80)
+#define EP93XX_CP0_CPOL			(0x40)
+#define EP93XX_CP0_EIGHTBIT		(0x07)
+#define EP93XX_CP0_MODEBITS		(0xff)
+
+//kernel.h defines typed min and max
+#define MIN(a,b) ((a<b)?a:b)
+#define MAX(a,b) ((a>b)?a:b)
+ 
+//CR1 bit settings
+#define EP93XX_CP1_MASTER	0
+#define EP93XX_CP1_ENABLE	0x10
+
+#define BITSPERWORD(b)	(b-1)
+#define BYTSPWORD(bpw) (bpw/9 + 1)
+
+typedef struct ep93xx_spiconfig_s{
+	u8  prediv;
+	u16 cp0,cp1;
+	int id;//id number 1-31, this determines ownership for locking purposes
+#ifdef CONFIG_SPICLASS
+	struct spi_s s;
+#endif	
+}ep93xx_spiconfig_t;
+
+int ep93xx_spi_init(void);
+u32 getsspclock(void);
+int spi_setup_config(int mode, u32 speed_hz, ep93xx_spiconfig_t *c);
+int ep93xx_spiconfigure(ep93xx_spiconfig_t *c);
+int ep93xx_spi_transfer_blocking(u8 *mosi, u8 *miso, int size);
+int ep93xx_spitip(int ofs,ep93xx_spiconfig_t *c);
+
+#ifdef CONFIG_SPICLASS
+struct class_device *ep93xx_spi_class_create(const char *name,ep93xx_spiconfig_t *c,int (*tip)(struct spi_s *s,int ofs));
+#endif
+
+#endif /*SPIEP93XX_H_*/
diff -uprN linux-2.6.20/arch/arm/mm/Kconfig linux-2.6.20-at92_e1.5/arch/arm/mm/Kconfig
--- linux-2.6.20/arch/arm/mm/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/mm/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -171,8 +171,8 @@ config CPU_ARM925T
 # ARM926T
 config CPU_ARM926T
 	bool "Support ARM926T processor"
-	depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261
-	default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261
+	depends on ARCH_INTEGRATOR || ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || MACH_REALVIEW_EB || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263
+	default y if ARCH_VERSATILE_PB || MACH_VERSATILE_AB || ARCH_OMAP730 || ARCH_OMAP16XX || ARCH_PNX4008 || ARCH_NETX || CPU_S3C2412 || ARCH_AT91SAM9260 || ARCH_AT91SAM9261 || ARCH_AT91SAM9263
 	select CPU_32v5
 	select CPU_ABRT_EV5TJ
 	select CPU_CACHE_VIVT
diff -uprN linux-2.6.20/arch/arm/tools/mach-types linux-2.6.20-at92_e1.5/arch/arm/tools/mach-types
--- linux-2.6.20/arch/arm/tools/mach-types	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/arch/arm/tools/mach-types	2008-02-07 10:24:58.000000000 -0500
@@ -12,7 +12,7 @@
 #
 #   http://www.arm.linux.org.uk/developer/machines/?action=new
 #
-# Last update: Tue Jan 16 16:52:56 2007
+# Last update: Tue Mar 6 16:46:14 2007
 #
 # machine_is_xxx	CONFIG_xxxx		MACH_TYPE_xxx		number
 #
@@ -1196,7 +1196,6 @@ medallion_sa2410	MACH_MEDALLION_SA2410	M
 ia_cpu_9200_2		MACH_IA_CPU_9200_2	IA_CPU_9200_2		1185
 dimmrm9200		MACH_DIMMRM9200		DIMMRM9200		1186
 pm9261			MACH_PM9261		PM9261			1187
-mx21			MACH_MX21		MX21			1188
 ml7304			MACH_ML7304		ML7304			1189
 ucp250			MACH_UCP250		UCP250			1190
 intboard		MACH_INTBOARD		INTBOARD		1191
@@ -1242,3 +1241,45 @@ xscale_treo680		MACH_XSCALE_TREO680	XSCA
 tecon_tmezon		MACH_TECON_TMEZON	TECON_TMEZON		1231
 zylonite		MACH_ZYLONITE		ZYLONITE		1233
 gene1270		MACH_GENE1270		GENE1270		1234
+zir2412			MACH_ZIR2412		ZIR2412			1235
+mx31lite		MACH_MX31LITE		MX31LITE		1236
+t700wx			MACH_T700WX		T700WX			1237
+vf100			MACH_VF100		VF100			1238
+nsb2			MACH_NSB2		NSB2			1239
+nxhmi_bb		MACH_NXHMI_BB		NXHMI_BB		1240
+nxhmi_re		MACH_NXHMI_RE		NXHMI_RE		1241
+n4100pro		MACH_N4100PRO		N4100PRO		1242
+sam9260			MACH_SAM9260		SAM9260			1243
+omap_treo600		MACH_OMAP_TREO600	OMAP_TREO600		1244
+indy2410		MACH_INDY2410		INDY2410		1245
+nelt_a			MACH_NELT_A		NELT_A			1246
+n311			MACH_N311		N311			1248
+at91sam9260vgk		MACH_AT91SAM9260VGK	AT91SAM9260VGK		1249
+at91leppe		MACH_AT91LEPPE		AT91LEPPE		1250
+at91lepccn		MACH_AT91LEPCCN		AT91LEPCCN		1251
+apc7100			MACH_APC7100		APC7100			1252
+stargazer		MACH_STARGAZER		STARGAZER		1253
+sonata			MACH_SONATA		SONATA			1254
+schmoogie		MACH_SCHMOOGIE		SCHMOOGIE		1255
+aztool			MACH_AZTOOL		AZTOOL			1256
+mioa701			MACH_MIOA701		MIOA701			1257
+sxni9260		MACH_SXNI9260		SXNI9260		1258
+mxc27520evb		MACH_MXC27520EVB	MXC27520EVB		1259
+armadillo5x0		MACH_ARMADILLO5X0	ARMADILLO5X0		1260
+mb9260			MACH_MB9260		MB9260			1261
+mb9263			MACH_MB9263		MB9263			1262
+ipac9302		MACH_IPAC9302		IPAC9302		1263
+cc9p9360js		MACH_CC9P9360JS		CC9P9360JS		1264
+gallium			MACH_GALLIUM		GALLIUM			1265
+msc2410			MACH_MSC2410		MSC2410			1266
+ghi270			MACH_GHI270		GHI270			1267
+davinci_leonardo	MACH_DAVINCI_LEONARDO	DAVINCI_LEONARDO	1268
+oiab			MACH_OIAB		OIAB			1269
+smdk6400		MACH_SMDK6400		SMDK6400		1270
+nokia_n800		MACH_NOKIA_N800		NOKIA_N800		1271
+greenphone		MACH_GREENPHONE		GREENPHONE		1272
+compex42x		MACH_COMPEXWP18		COMPEXWP18		1273
+xmate			MACH_XMATE		XMATE			1274
+energizer		MACH_ENERGIZER		ENERGIZER		1275
+ime1			MACH_IME1		IME1			1276
+sweda_tms		MACH_SWEDATMS		SWEDATMS		1277
diff -uprN linux-2.6.20/drivers/Kconfig linux-2.6.20-at92_e1.5/drivers/Kconfig
--- linux-2.6.20/drivers/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -46,6 +46,8 @@ source "drivers/telephony/Kconfig"
 
 source "drivers/input/Kconfig"
 
+source "drivers/ioex/Kconfig"
+
 source "drivers/char/Kconfig"
 
 source "drivers/i2c/Kconfig"
diff -uprN linux-2.6.20/drivers/Makefile linux-2.6.20-at92_e1.5/drivers/Makefile
--- linux-2.6.20/drivers/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -25,7 +25,7 @@ obj-$(CONFIG_CONNECTOR)		+= connector/
 obj-$(CONFIG_FB_I810)           += video/i810/
 obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 
-obj-y				+= serial/
+obj-y				+= serial/ ioex/
 obj-$(CONFIG_PARPORT)		+= parport/
 obj-y				+= base/ block/ misc/ mfd/ net/ media/
 obj-$(CONFIG_NUBUS)		+= nubus/
@@ -79,4 +79,4 @@ obj-$(CONFIG_SUPERH)		+= sh/
 obj-$(CONFIG_GENERIC_TIME)	+= clocksource/
 obj-$(CONFIG_DMA_ENGINE)	+= dma/
 obj-$(CONFIG_HID)		+= hid/
-obj-$(CONFIG_PPC_PS3)		+= ps3/
+obj-$(CONFIG_PPC_PS3)		+= ps3/
\ No newline at end of file
diff -uprN linux-2.6.20/drivers/char/Kconfig linux-2.6.20-at92_e1.5/drivers/char/Kconfig
--- linux-2.6.20/drivers/char/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/char/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -1030,5 +1030,21 @@ config TELCLOCK
 	  sysfs directory, /sys/devices/platform/telco_clock, with a number of
 	  files for controlling the behavior of this hardware.
 
+config AT91_SPI
+	bool "SPI driver (legacy) for AT91RM9200 processors"
+	depends on ARCH_AT91RM9200
+	default y
+	help
+	  The SPI driver gives access to this serial bus on the AT91RM9200
+	  processor.
+
+config AT91_SPIDEV
+	bool "SPI device interface (legacy) for AT91RM9200 processors"
+	depends on ARCH_AT91RM9200 && AT91_SPI
+	default n
+	help
+	  The SPI driver gives user mode access to this serial
+	  bus on the AT91RM9200 processor.
+
 endmenu
 
diff -uprN linux-2.6.20/drivers/char/Makefile linux-2.6.20-at92_e1.5/drivers/char/Makefile
--- linux-2.6.20/drivers/char/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/char/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -90,6 +90,8 @@ obj-$(CONFIG_CS5535_GPIO)	+= cs5535_gpio
 obj-$(CONFIG_GPIO_VR41XX)	+= vr41xx_giu.o
 obj-$(CONFIG_TANBAC_TB0219)	+= tb0219.o
 obj-$(CONFIG_TELCLOCK)		+= tlclk.o
+obj-$(CONFIG_AT91_SPI)		+= at91_spi.o
+obj-$(CONFIG_AT91_SPIDEV)	+= at91_spidev.o
 
 obj-$(CONFIG_WATCHDOG)		+= watchdog/
 obj-$(CONFIG_MWAVE)		+= mwave/
diff -uprN linux-2.6.20/drivers/char/at91_spi.c linux-2.6.20-at92_e1.5/drivers/char/at91_spi.c
--- linux-2.6.20/drivers/char/at91_spi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/char/at91_spi.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,336 @@
+/*
+ * Serial Peripheral Interface (SPI) driver for the Atmel AT91RM9200 (Thunder)
+ *
+ *  Copyright (C) SAN People (Pty) Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/dma-mapping.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/completion.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+#include <linux/atmel_pdc.h>
+#include <asm/io.h>
+#include <asm/semaphore.h>
+
+#include <asm/arch/at91_spi.h>
+#include <asm/arch/board.h>
+#include <asm/arch/spi.h>
+
+#undef DEBUG_SPI
+
+static struct spi_local spi_dev[NR_SPI_DEVICES];	/* state of the SPI devices */
+static int spi_enabled = 0;
+static struct semaphore spi_lock;			/* protect access to SPI bus */
+static int current_device = -1;				/* currently selected SPI device */
+static struct clk *spi_clk;				/* SPI clock */
+static void __iomem *spi_base;				/* SPI peripheral base-address */
+
+DECLARE_COMPLETION(transfer_complete);
+
+
+#define at91_spi_read(reg)		__raw_readl(spi_base + (reg))
+#define at91_spi_write(reg, val)	__raw_writel((val), spi_base + (reg))
+
+
+/* ......................................................................... */
+
+/*
+ * Access and enable the SPI bus.
+ * This MUST be called before any transfers are performed.
+ */
+void spi_access_bus(short device)
+{
+	/* Ensure that requested device is valid */
+	if ((device < 0) || (device >= NR_SPI_DEVICES))
+		panic("at91_spi: spi_access_bus called with invalid device");
+
+	if (spi_enabled == 0) {
+		clk_enable(spi_clk);				/* Enable Peripheral clock */
+		at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIEN);	/* Enable SPI */
+#ifdef DEBUG_SPI
+		printk("SPI on\n");
+#endif
+	}
+	spi_enabled++;
+
+	/* Lock the SPI bus */
+	down(&spi_lock);
+	current_device = device;
+
+	/* Configure SPI bus for device */
+	at91_spi_write(AT91_SPI_MR, AT91_SPI_MSTR | AT91_SPI_MODFDIS | (spi_dev[device].pcs << 16));
+}
+
+/*
+ * Relinquish control of the SPI bus.
+ */
+void spi_release_bus(short device)
+{
+	if (device != current_device)
+		panic("at91_spi: spi_release called with invalid device");
+
+	/* Release the SPI bus */
+	current_device = -1;
+	up(&spi_lock);
+
+	spi_enabled--;
+	if (spi_enabled == 0) {
+		at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIDIS);	/* Disable SPI */
+		clk_disable(spi_clk);				/* Disable Peripheral clock */
+#ifdef DEBUG_SPI
+		printk("SPI off\n");
+#endif
+	}
+}
+
+/*
+ * Perform a data transfer over the SPI bus
+ */
+int spi_transfer(struct spi_transfer_list* list)
+{
+	struct spi_local *device = (struct spi_local *) &spi_dev[current_device];
+	int tx_size;
+
+	if (!list)
+		panic("at91_spi: spi_transfer called with NULL transfer list");
+	if (current_device == -1)
+		panic("at91_spi: spi_transfer called without acquiring bus");
+
+#ifdef DEBUG_SPI
+	printk("SPI transfer start [%i]\n", list->nr_transfers);
+#endif
+
+	/* If we are in 16-bit mode, we need to modify what we pass to the PDC */
+	tx_size = (at91_spi_read(AT91_SPI_CSR(current_device)) & AT91_SPI_BITS_16) ? 2 : 1;
+
+	/* Store transfer list */
+	device->xfers = list;
+	list->curr = 0;
+
+	/* Assume there must be at least one transfer */
+	device->tx = dma_map_single(NULL, list->tx[0], list->txlen[0], DMA_TO_DEVICE);
+	device->rx = dma_map_single(NULL, list->rx[0], list->rxlen[0], DMA_FROM_DEVICE);
+
+	/* Program PDC registers */
+	at91_spi_write(ATMEL_PDC_TPR, device->tx);
+	at91_spi_write(ATMEL_PDC_RPR, device->rx);
+	at91_spi_write(ATMEL_PDC_TCR, list->txlen[0] / tx_size);
+	at91_spi_write(ATMEL_PDC_RCR, list->rxlen[0] / tx_size);
+
+	/* Is there a second transfer? */
+	if (list->nr_transfers > 1) {
+		device->txnext = dma_map_single(NULL, list->tx[1], list->txlen[1], DMA_TO_DEVICE);
+		device->rxnext = dma_map_single(NULL, list->rx[1], list->rxlen[1], DMA_FROM_DEVICE);
+
+		/* Program Next PDC registers */
+		at91_spi_write(ATMEL_PDC_TNPR, device->txnext);
+		at91_spi_write(ATMEL_PDC_RNPR, device->rxnext);
+		at91_spi_write(ATMEL_PDC_TNCR, list->txlen[1] / tx_size);
+		at91_spi_write(ATMEL_PDC_RNCR, list->rxlen[1] / tx_size);
+	}
+	else {
+		device->txnext = 0;
+		device->rxnext = 0;
+		at91_spi_write(ATMEL_PDC_TNCR, 0);
+		at91_spi_write(ATMEL_PDC_RNCR, 0);
+	}
+
+	// TODO: If we are doing consecutive transfers (at high speed, or
+	//   small buffers), then it might be worth modifying the 'Delay between
+	//   Consecutive Transfers' in the CSR registers.
+	//   This is an issue if we cannot chain the next buffer fast enough
+	//   in the interrupt handler.
+
+	/* Enable transmitter and receiver */
+	at91_spi_write(ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN | ATMEL_PDC_TXTEN);
+
+	at91_spi_write(AT91_SPI_IER, AT91_SPI_ENDRX);		/* enable buffer complete interrupt */
+	wait_for_completion(&transfer_complete);
+
+#ifdef DEBUG_SPI
+	printk("SPI transfer end\n");
+#endif
+
+	return 0;
+}
+
+/* ......................................................................... */
+
+/*
+ * Handle interrupts from the SPI controller.
+ */
+static irqreturn_t at91spi_interrupt(int irq, void *dev_id)
+{
+	unsigned int status;
+	struct spi_local *device = (struct spi_local *) &spi_dev[current_device];
+	struct spi_transfer_list *list = device->xfers;
+
+#ifdef DEBUG_SPI
+	printk("SPI interrupt %i\n", current_device);
+#endif
+
+	if (!list)
+		panic("at91_spi: spi_interrupt with a NULL transfer list");
+
+		status = at91_spi_read(AT91_SPI_SR) & at91_spi_read(AT91_SPI_IMR);	/* read status */
+
+	dma_unmap_single(NULL, device->tx, list->txlen[list->curr], DMA_TO_DEVICE);
+	dma_unmap_single(NULL, device->rx, list->rxlen[list->curr], DMA_FROM_DEVICE);
+
+	device->tx = device->txnext;	/* move next transfer to current transfer */
+	device->rx = device->rxnext;
+
+	list->curr = list->curr + 1;
+	if (list->curr == list->nr_transfers) {		/* all transfers complete */
+		at91_spi_write(AT91_SPI_IDR, AT91_SPI_ENDRX);		/* disable interrupt */
+
+		/* Disable transmitter and receiver */
+		at91_spi_write(ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+		device->xfers = NULL;
+		complete(&transfer_complete);
+	}
+	else if (list->curr+1 == list->nr_transfers) {	/* no more next transfers */
+		device->txnext = 0;
+		device->rxnext = 0;
+		at91_spi_write(ATMEL_PDC_TNCR, 0);
+		at91_spi_write(ATMEL_PDC_RNCR, 0);
+	}
+	else {
+		int i = (list->curr)+1;
+
+		/* If we are in 16-bit mode, we need to modify what we pass to the PDC */
+		int tx_size = (at91_spi_read(AT91_SPI_CSR(current_device)) & AT91_SPI_BITS_16) ? 2 : 1;
+
+		device->txnext = dma_map_single(NULL, list->tx[i], list->txlen[i], DMA_TO_DEVICE);
+		device->rxnext = dma_map_single(NULL, list->rx[i], list->rxlen[i], DMA_FROM_DEVICE);
+		at91_spi_write(ATMEL_PDC_TNPR, device->txnext);
+		at91_spi_write(ATMEL_PDC_RNPR, device->rxnext);
+		at91_spi_write(ATMEL_PDC_TNCR, list->txlen[i] / tx_size);
+		at91_spi_write(ATMEL_PDC_RNCR, list->rxlen[i] / tx_size);
+	}
+	return IRQ_HANDLED;
+}
+
+/* ......................................................................... */
+
+/*
+ * Initialize the SPI controller
+ */
+static int __init at91spi_probe(struct platform_device *pdev)
+{
+	int i;
+	unsigned long scbr;
+	struct resource *res;
+
+	init_MUTEX(&spi_lock);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	if (!request_mem_region(res->start, res->end - res->start + 1, "at91_spi"))
+		return -EBUSY;
+
+	spi_base = ioremap(res->start, res->end - res->start + 1);
+	if (!spi_base) {
+		release_mem_region(res->start, res->end - res->start + 1);
+		return -ENOMEM;
+	}
+
+	spi_clk = clk_get(NULL, "spi_clk");
+	if (IS_ERR(spi_clk)) {
+		printk(KERN_ERR "at91_spi: no clock defined\n");
+		iounmap(spi_base);
+		release_mem_region(res->start, res->end - res->start + 1);
+		return -ENODEV;
+	}
+
+	at91_spi_write(AT91_SPI_CR, AT91_SPI_SWRST);	/* software reset of SPI controller */
+
+	/*
+	 * Calculate the correct SPI baud-rate divisor.
+	 */
+	scbr = clk_get_rate(spi_clk) / (2 * DEFAULT_SPI_CLK);
+	scbr = scbr + 1;		/* round up */
+
+	printk(KERN_INFO "at91_spi: Baud rate set to %ld\n", clk_get_rate(spi_clk) / (2 * scbr));
+
+	/* Set Chip Select registers to good defaults */
+	for (i = 0; i < 4; i++) {
+		at91_spi_write(AT91_SPI_CSR(i), AT91_SPI_CPOL | AT91_SPI_BITS_8 | (16 << 16) | (scbr << 8));
+	}
+
+	at91_spi_write(ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+	memset(&spi_dev, 0, sizeof(spi_dev));
+	spi_dev[0].pcs = 0xE;
+	spi_dev[1].pcs = 0xD;
+	spi_dev[2].pcs = 0xB;
+	spi_dev[3].pcs = 0x7;
+
+	if (request_irq(AT91RM9200_ID_SPI, at91spi_interrupt, 0, "spi", NULL)) {
+		clk_put(spi_clk);
+		iounmap(spi_base);
+		release_mem_region(res->start, res->end - res->start + 1);
+		return -EBUSY;
+	}
+
+	at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIEN);		/* Enable SPI */
+
+	return 0;
+}
+
+static int __devexit at91spi_remove(struct platform_device *pdev)
+{
+	struct resource *res;
+
+	at91_spi_write(AT91_SPI_CR, AT91_SPI_SPIDIS);		/* Disable SPI */
+	clk_put(spi_clk);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	iounmap(spi_base);
+	release_mem_region(res->start, res->end - res->start + 1);
+
+	free_irq(AT91RM9200_ID_SPI, 0);
+	return 0;
+}
+
+static struct platform_driver at91spi_driver = {
+	.probe		= at91spi_probe,
+	.remove		= __devexit_p(at91spi_remove),
+	.driver		= {
+		.name	= "at91_spi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91spi_init(void)
+{
+	return platform_driver_register(&at91spi_driver);
+}
+
+static void __exit at91spi_exit(void)
+{
+	platform_driver_unregister(&at91spi_driver);
+}
+
+EXPORT_SYMBOL(spi_access_bus);
+EXPORT_SYMBOL(spi_release_bus);
+EXPORT_SYMBOL(spi_transfer);
+
+module_init(at91spi_init);
+module_exit(at91spi_exit);
+
+MODULE_LICENSE("GPL")
+MODULE_AUTHOR("Andrew Victor")
+MODULE_DESCRIPTION("SPI driver for Atmel AT91RM9200")
diff -uprN linux-2.6.20/drivers/char/at91_spidev.c linux-2.6.20-at92_e1.5/drivers/char/at91_spidev.c
--- linux-2.6.20/drivers/char/at91_spidev.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/char/at91_spidev.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,236 @@
+/*
+ * User-space interface to the SPI bus on Atmel AT91RM9200
+ *
+ *  Copyright (C) 2003 SAN People (Pty) Ltd
+ *
+ * Based on SPI driver by Rick Bronson
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/highmem.h>
+#include <linux/pagemap.h>
+#include <asm/arch/spi.h>
+
+#ifdef CONFIG_DEVFS_FS
+#include <linux/devfs_fs_kernel.h>
+#endif
+
+
+#undef DEBUG_SPIDEV
+
+/* ......................................................................... */
+
+/*
+ * Read or Write to SPI bus.
+ */
+static ssize_t spidev_rd_wr(struct file *file, char *buf, size_t count, loff_t *offset)
+{
+	unsigned int spi_device = (unsigned int) file->private_data;
+
+	struct mm_struct * mm;
+	struct page ** maplist;
+	struct spi_transfer_list* list;
+	int    pgcount;
+
+	unsigned int ofs, pagelen;
+	int res, i, err;
+
+	if (!count) {
+		return 0;
+	}
+
+	list = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL);
+	if (!list) {
+		return -ENOMEM;
+	}
+
+	mm = current->mm;
+
+	pgcount = ((unsigned long)buf+count+PAGE_SIZE-1)/PAGE_SIZE - (unsigned long)buf/PAGE_SIZE;
+
+	if (pgcount >= MAX_SPI_TRANSFERS) {
+		kfree(list);
+		return -EFBIG;
+	}
+
+	maplist = kmalloc (pgcount * sizeof (struct page *), GFP_KERNEL);
+
+	if (!maplist) {
+		kfree(list);
+		return -ENOMEM;
+	}
+	flush_cache_all();
+	down_read(&mm->mmap_sem);
+	err= get_user_pages(current, mm, (unsigned long)buf, pgcount, 1, 0, maplist, NULL);
+	up_read(&mm->mmap_sem);
+
+	if (err < 0) {
+		kfree(list);
+		kfree(maplist);
+		return err;
+	}
+	pgcount = err;
+
+#ifdef DEBUG_SPIDEV
+	printk("spidev_rd_rw: %i %i\n", count, pgcount);
+#endif
+
+	/* Set default return value = transfer length */
+	res = count;
+
+	/*
+	 * At this point, the virtual area buf[0] .. buf[count-1] will have
+	 * corresponding pages mapped in the physical memory and locked until
+	 * we unmap the kiobuf.  The pages cannot be swapped out or moved
+	 * around.
+	 */
+	ofs = (unsigned long) buf & (PAGE_SIZE -1);
+	pagelen = PAGE_SIZE - ofs;
+	if (count < pagelen)
+		pagelen = count;
+
+	for (i = 0; i < pgcount; i++) {
+		flush_dcache_page(maplist[i]);
+
+		list->tx[i] = list->rx[i] = page_address(maplist[i]) + ofs;
+		list->txlen[i] = list->rxlen[i] = pagelen;
+
+#ifdef DEBUG_SPIDEV
+		printk("  %i: %x  (%i)\n", i, list->tx[i], list->txlen[i]);
+#endif
+
+		ofs = 0;	/* all subsequent transfers start at beginning of a page */
+		count = count - pagelen;
+		pagelen = (count < PAGE_SIZE) ? count : PAGE_SIZE;
+	}
+	list->nr_transfers = pgcount;
+
+	/* Perform transfer on SPI bus */
+	spi_access_bus(spi_device);
+	spi_transfer(list);
+	spi_release_bus(spi_device);
+
+	while (pgcount--) {
+		page_cache_release (maplist[pgcount]);
+	}
+	flush_cache_all();
+
+	kfree(maplist);
+	kfree(list);
+
+	return res;
+}
+
+static int spidev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
+{
+	int spi_device = MINOR(inode->i_rdev);
+
+	if (spi_device >= NR_SPI_DEVICES)
+		return -ENODEV;
+
+	// TODO: This interface can be used to configure the SPI bus.
+	// Configurable options could include: Speed, Clock Polarity, Clock Phase
+
+	switch(cmd) {
+		default:
+			return -ENOIOCTLCMD;
+	}
+}
+
+/*
+ * Open the SPI device
+ */
+static int spidev_open(struct inode *inode, struct file *file)
+{
+	unsigned int spi_device = MINOR(inode->i_rdev);
+
+	if (spi_device >= NR_SPI_DEVICES)
+		return -ENODEV;
+
+	/*
+	 * 'private_data' is actually a pointer, but we overload it with the
+	 * value we want to store.
+	 */
+	file->private_data = (void *)spi_device;
+
+	return 0;
+}
+
+/*
+ * Close the SPI device
+ */
+static int spidev_close(struct inode *inode, struct file *file)
+{
+	return 0;
+}
+
+/* ......................................................................... */
+
+static struct file_operations spidev_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= spidev_rd_wr,
+	.write		= (int (*) (struct file *file, const char *buf, size_t count, loff_t *offset))spidev_rd_wr,
+	.ioctl		= spidev_ioctl,
+	.open		= spidev_open,
+	.release	= spidev_close,
+};
+
+/*
+ * Install the SPI /dev interface driver
+ */
+static int __init at91_spidev_init(void)
+{
+#ifdef CONFIG_DEVFS_FS
+	int i;
+#endif
+
+	if (register_chrdev(SPI_MAJOR, "spi", &spidev_fops)) {
+		printk(KERN_ERR "at91_spidev: Unable to get major %d for SPI bus\n", SPI_MAJOR);
+		return -EIO;
+	}
+
+#ifdef CONFIG_DEVFS_FS
+	devfs_mk_dir("spi");
+	for (i = 0; i < NR_SPI_DEVICES; i++) {
+		devfs_mk_cdev(MKDEV(SPI_MAJOR, i), S_IFCHR | S_IRUSR | S_IWUSR, "spi/%d",i);
+	}
+#endif
+	printk(KERN_INFO "AT91 SPI driver loaded\n");
+
+	return 0;
+}
+
+/*
+ * Remove the SPI /dev interface driver
+ */
+static void __exit at91_spidev_exit(void)
+{
+#ifdef CONFIG_DEVFS_FS
+	int i;
+	for (i = 0; i < NR_SPI_DEVICES; i++) {
+		devfs_remove("spi/%d", i);
+	}
+
+	devfs_remove("spi");
+#endif
+
+	if (unregister_chrdev(SPI_MAJOR, "spi")) {
+		printk(KERN_ERR "at91_spidev: Unable to release major %d for SPI bus\n", SPI_MAJOR);
+		return;
+	}
+}
+
+module_init(at91_spidev_init);
+module_exit(at91_spidev_exit);
+
+MODULE_LICENSE("GPL")
+MODULE_AUTHOR("Andrew Victor")
+MODULE_DESCRIPTION("SPI /dev interface for Atmel AT91RM9200")
diff -uprN linux-2.6.20/drivers/i2c/busses/Kconfig linux-2.6.20-at92_e1.5/drivers/i2c/busses/Kconfig
--- linux-2.6.20/drivers/i2c/busses/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/i2c/busses/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -81,6 +81,14 @@ config I2C_AT91
 	  This supports the use of the I2C interface on Atmel AT91
 	  processors.
 
+config I2C_AT91_CLOCKRATE
+	prompt "Atmel AT91 I2C/TWI clock-rate"
+	depends on I2C_AT91
+	int
+	default 100000
+	help
+	  Set the AT91 I2C/TWI clock-rate.
+
 config I2C_AU1550
 	tristate "Au1550/Au1200 SMBus interface"
 	depends on I2C && (SOC_AU1550 || SOC_AU1200)
diff -uprN linux-2.6.20/drivers/i2c/busses/i2c-at91.c linux-2.6.20-at92_e1.5/drivers/i2c/busses/i2c-at91.c
--- linux-2.6.20/drivers/i2c/busses/i2c-at91.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/i2c/busses/i2c-at91.c	2008-02-07 10:24:58.000000000 -0500
@@ -31,8 +31,11 @@
 #include <asm/arch/board.h>
 #include <asm/arch/cpu.h>
 
-#define TWI_CLOCK		100000		/* Hz. max 400 Kbits/sec */
 
+/* Clockrate is configurable - max 400 Kbits/sec */
+static unsigned int clockrate = CONFIG_I2C_AT91_CLOCKRATE;
+module_param(clockrate, uint, 0);
+MODULE_PARM_DESC(clockrate, "The TWI clockrate");
 
 static struct clk *twi_clk;
 static void __iomem *twi_base;
@@ -53,7 +56,7 @@ static void __devinit at91_twi_hwinit(vo
 	at91_twi_write(AT91_TWI_CR, AT91_TWI_MSEN);	/* Set Master mode */
 
 	/* Calcuate clock dividers */
-	cdiv = (clk_get_rate(twi_clk) / (2 * TWI_CLOCK)) - 3;
+	cdiv = (clk_get_rate(twi_clk) / (2 * clockrate)) - 3;
 	cdiv = cdiv + 1;	/* round up */
 	ckdiv = 0;
 	while (cdiv > 255) {
@@ -63,9 +66,14 @@ static void __devinit at91_twi_hwinit(vo
 
 	if (cpu_is_at91rm9200()) {			/* AT91RM9200 Errata #22 */
 		if (ckdiv > 5) {
-			printk(KERN_ERR "AT91 I2C: Invalid TWI_CLOCK value!\n");
+			printk(KERN_ERR "AT91 I2C: Invalid TWI clockrate!\n");
 			ckdiv = 5;
 		}
+	} else {
+		if (ckdiv > 7) {
+			printk(KERN_ERR "AT91 I2C: Invalid TWI clockrate!\n");
+			ckdiv = 7;
+		}
 	}
 
 	at91_twi_write(AT91_TWI_CWGR, (ckdiv << 16) | (cdiv << 8) | cdiv);
diff -uprN linux-2.6.20/drivers/input/touchscreen/ads7846.c linux-2.6.20-at92_e1.5/drivers/input/touchscreen/ads7846.c
--- linux-2.6.20/drivers/input/touchscreen/ads7846.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/input/touchscreen/ads7846.c	2008-02-07 10:24:58.000000000 -0500
@@ -17,8 +17,9 @@
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
  */
-#include <linux/device.h>
+#include <linux/hwmon.h>
 #include <linux/init.h>
+#include <linux/err.h>
 #include <linux/delay.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
@@ -38,7 +39,8 @@
 /*
  * This code has been heavily tested on a Nokia 770, and lightly
  * tested on other ads7846 devices (OSK/Mistral, Lubbock).
- * Support for ads7843 and ads7845 has only been stubbed in.
+ * Support for ads7843 tested on Atmel at91sam926x-EK.
+ * Support for ads7845 has only been stubbed in.
  *
  * IRQ handling needs a workaround because of a shortcoming in handling
  * edge triggered IRQs on some platforms like the OMAP1/2. These
@@ -54,7 +56,8 @@
  * files.
  */
 
-#define	TS_POLL_PERIOD	msecs_to_jiffies(10)
+#define TS_POLL_DELAY	(1 * 1000000)	/* ns delay before the first sample */
+#define TS_POLL_PERIOD	(5 * 1000000)	/* ns delay between samples */
 
 /* this driver doesn't aim at the peak continuous sample rate */
 #define	SAMPLE_BITS	(8 /*cmd*/ + 16 /*sample*/ + 2 /* before, after */)
@@ -63,12 +66,12 @@ struct ts_event {
 	/* For portability, we can't read 12 bit values using SPI (which
 	 * would make the controller deliver them as native byteorder u16
 	 * with msbs zeroed).  Instead, we read them as two 8-bit values,
-	 * which need byteswapping then range adjustment.
+	 * *** WHICH NEED BYTESWAPPING *** and range adjustment.
 	 */
-	__be16 x;
-	__be16 y;
-	__be16 z1, z2;
-	int    ignore;
+	u16	x;
+	u16	y;
+	u16	z1, z2;
+	int	ignore;
 };
 
 struct ads7846 {
@@ -76,7 +79,12 @@ struct ads7846 {
 	char			phys[32];
 
 	struct spi_device	*spi;
+
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
 	struct attribute_group	*attr_group;
+	struct class_device	*hwmon;
+#endif
+
 	u16			model;
 	u16			vref_delay_usecs;
 	u16			x_plate_ohms;
@@ -99,13 +107,16 @@ struct ads7846 {
 	u16			debounce_rep;
 
 	spinlock_t		lock;
-	struct timer_list	timer;		/* P: lock */
+	struct hrtimer		timer;
 	unsigned		pendown:1;	/* P: lock */
 	unsigned		pending:1;	/* P: lock */
 // FIXME remove "irq_disabled"
 	unsigned		irq_disabled:1;	/* P: lock */
 	unsigned		disabled:1;
 
+	int			(*filter)(void *data, int data_idx, int *val);
+	void			*filter_data;
+	void			(*filter_cleanup)(void *data);
 	int			(*get_pendown_state)(void);
 };
 
@@ -142,15 +153,16 @@ struct ads7846 {
 #define	MAX_12BIT	((1<<12)-1)
 
 /* leave ADC powered up (disables penirq) between differential samples */
-#define	READ_12BIT_DFR(x) (ADS_START | ADS_A2A1A0_d_ ## x \
-	| ADS_12_BIT | ADS_DFR)
-
-#define	READ_Y	(READ_12BIT_DFR(y)  | ADS_PD10_ADC_ON)
-#define	READ_Z1	(READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON)
-#define	READ_Z2	(READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON)
+#define	READ_12BIT_DFR(x, adc, vref) (ADS_START | ADS_A2A1A0_d_ ## x \
+	| ADS_12_BIT | ADS_DFR | \
+	(adc ? ADS_PD10_ADC_ON : 0) | (vref ? ADS_PD10_REF_ON : 0))
+
+#define	READ_Y(vref)	(READ_12BIT_DFR(y,  1, vref))
+#define	READ_Z1(vref)	(READ_12BIT_DFR(z1, 1, vref))
+#define	READ_Z2(vref)	(READ_12BIT_DFR(z2, 1, vref))
 
-#define	READ_X	(READ_12BIT_DFR(x)  | ADS_PD10_ADC_ON)
-#define	PWRDOWN	(READ_12BIT_DFR(y)  | ADS_PD10_PDOWN)	/* LAST */
+#define	READ_X(vref)	(READ_12BIT_DFR(x,  1, vref))
+#define	PWRDOWN		(READ_12BIT_DFR(y,  0, 0))	/* LAST */
 
 /* single-ended samples need to first power up reference voltage;
  * we leave both ADC and VREF powered
@@ -158,14 +170,19 @@ struct ads7846 {
 #define	READ_12BIT_SER(x) (ADS_START | ADS_A2A1A0_ ## x \
 	| ADS_12_BIT | ADS_SER)
 
-#define	REF_ON	(READ_12BIT_DFR(x) | ADS_PD10_ALL_ON)
-#define	REF_OFF	(READ_12BIT_DFR(y) | ADS_PD10_PDOWN)
+#define	REF_ON	(READ_12BIT_DFR(x, 1, 1))
+#define	REF_OFF	(READ_12BIT_DFR(y, 0, 0))
 
 /*--------------------------------------------------------------------------*/
 
 /*
  * Non-touchscreen sensors only use single-ended conversions.
+ * The range is GND..vREF. The ads7843 and ads7835 must use external vREF;
+ * ads7846 lets that pin be unconnected, to use internal vREF.
  */
+static unsigned vREF_mV;
+module_param(vREF_mV, uint, 0);
+MODULE_PARM_DESC(vREF_mV, "external vREF voltage, in milliVolts");
 
 struct ser_req {
 	u8			ref_on;
@@ -193,50 +210,53 @@ static int ads7846_read12_ser(struct dev
 	struct ser_req		*req = kzalloc(sizeof *req, GFP_KERNEL);
 	int			status;
 	int			sample;
-	int			i;
+	int			use_internal;
 
 	if (!req)
 		return -ENOMEM;
 
 	spi_message_init(&req->msg);
 
-	/* activate reference, so it has time to settle; */
-	req->ref_on = REF_ON;
-	req->xfer[0].tx_buf = &req->ref_on;
-	req->xfer[0].len = 1;
-	req->xfer[1].rx_buf = &req->scratch;
-	req->xfer[1].len = 2;
-
-	/*
-	 * for external VREF, 0 usec (and assume it's always on);
-	 * for 1uF, use 800 usec;
-	 * no cap, 100 usec.
-	 */
-	req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+	/* FIXME boards with ads7846 might use external vref instead ... */
+	use_internal = (ts->model == 7846);
+
+	/* maybe turn on internal vREF, and let it settle */
+	if (use_internal) {
+		req->ref_on = REF_ON;
+		req->xfer[0].tx_buf = &req->ref_on;
+		req->xfer[0].len = 1;
+		spi_message_add_tail(&req->xfer[0], &req->msg);
+
+		req->xfer[1].rx_buf = &req->scratch;
+		req->xfer[1].len = 2;
+
+		/* for 1uF, settle for 800 usec; no cap, 100 usec.  */
+		req->xfer[1].delay_usecs = ts->vref_delay_usecs;
+		spi_message_add_tail(&req->xfer[1], &req->msg);
+	}
 
 	/* take sample */
 	req->command = (u8) command;
 	req->xfer[2].tx_buf = &req->command;
 	req->xfer[2].len = 1;
+	spi_message_add_tail(&req->xfer[2], &req->msg);
+
 	req->xfer[3].rx_buf = &req->sample;
 	req->xfer[3].len = 2;
+	spi_message_add_tail(&req->xfer[3], &req->msg);
 
 	/* REVISIT:  take a few more samples, and compare ... */
 
-	/* turn off reference */
-	req->ref_off = REF_OFF;
+	/* converter in low power mode & enable PENIRQ */
+	req->ref_off = PWRDOWN;
 	req->xfer[4].tx_buf = &req->ref_off;
 	req->xfer[4].len = 1;
+	spi_message_add_tail(&req->xfer[4], &req->msg);
+
 	req->xfer[5].rx_buf = &req->scratch;
 	req->xfer[5].len = 2;
-
 	CS_CHANGE(req->xfer[5]);
-
-	/* group all the transfers together, so we can't interfere with
-	 * reading touchscreen state; disable penirq while sampling
-	 */
-	for (i = 0; i < 6; i++)
-		spi_message_add_tail(&req->xfer[i], &req->msg);
+	spi_message_add_tail(&req->xfer[5], &req->msg);
 
 	ts->irq_disabled = 1;
 	disable_irq(spi->irq);
@@ -256,25 +276,173 @@ static int ads7846_read12_ser(struct dev
 	return status ? status : sample;
 }
 
-#define SHOW(name) static ssize_t \
+#if defined(CONFIG_HWMON) || defined(CONFIG_HWMON_MODULE)
+
+#define SHOW(name, var, adjust) static ssize_t \
 name ## _show(struct device *dev, struct device_attribute *attr, char *buf) \
 { \
+	struct ads7846 *ts = dev_get_drvdata(dev); \
 	ssize_t v = ads7846_read12_ser(dev, \
-			READ_12BIT_SER(name) | ADS_PD10_ALL_ON); \
+			READ_12BIT_SER(var) | ADS_PD10_ALL_ON); \
 	if (v < 0) \
 		return v; \
-	return sprintf(buf, "%u\n", (unsigned) v); \
+	return sprintf(buf, "%u\n", adjust(ts, v)); \
 } \
 static DEVICE_ATTR(name, S_IRUGO, name ## _show, NULL);
 
-SHOW(temp0)
-SHOW(temp1)
-SHOW(vaux)
-SHOW(vbatt)
+
+/* Sysfs conventions report temperatures in millidegrees Celcius.
+ * ADS7846 could use the low-accuracy two-sample scheme, but can't do the high
+ * accuracy scheme without calibration data.  For now we won't try either;
+ * userspace sees raw sensor values, and must scale/calibrate appropriately.
+ */
+static inline unsigned null_adjust(struct ads7846 *ts, ssize_t v)
+{
+	return v;
+}
+
+SHOW(temp0, temp0, null_adjust)		/* temp1_input */
+SHOW(temp1, temp1, null_adjust)		/* temp2_input */
+
+
+/* sysfs conventions report voltages in millivolts.  We can convert voltages
+ * if we know vREF.  userspace may need to scale vAUX to match the board's
+ * external resistors; we assume that vBATT only uses the internal ones.
+ */
+static inline unsigned vaux_adjust(struct ads7846 *ts, ssize_t v)
+{
+	unsigned retval = v;
+
+	/* external resistors may scale vAUX into 0..vREF */
+	retval *= vREF_mV;
+	retval = retval >> 12;
+	return retval;
+}
+
+static inline unsigned vbatt_adjust(struct ads7846 *ts, ssize_t v)
+{
+	unsigned retval = vaux_adjust(ts, v);
+
+	/* ads7846 has a resistor ladder to scale this signal down */
+	if (ts->model == 7846)
+		retval *= 4;
+	return retval;
+}
+
+SHOW(in0_input, vaux, vaux_adjust)
+SHOW(in1_input, vbatt, vbatt_adjust)
+
+
+static struct attribute *ads7846_attributes[] = {
+	&dev_attr_temp0.attr,
+	&dev_attr_temp1.attr,
+	&dev_attr_in0_input.attr,
+	&dev_attr_in1_input.attr,
+	NULL,
+};
+
+static struct attribute_group ads7846_attr_group = {
+	.attrs = ads7846_attributes,
+};
+
+static struct attribute *ads7843_attributes[] = {
+	&dev_attr_in0_input.attr,
+	&dev_attr_in1_input.attr,
+	NULL,
+};
+
+static struct attribute_group ads7843_attr_group = {
+	.attrs = ads7843_attributes,
+};
+
+static struct attribute *ads7845_attributes[] = {
+	&dev_attr_in0_input.attr,
+	NULL,
+};
+
+static struct attribute_group ads7845_attr_group = {
+	.attrs = ads7845_attributes,
+};
+
+static int ads784x_hwmon_register(struct spi_device *spi, struct ads7846 *ts)
+{
+	struct class_device *hwmon;
+	int err;
+
+	/* hwmon sensors need a reference voltage */
+	switch (ts->model) {
+	case 7846:
+		if (!vREF_mV) {
+			dev_dbg(&spi->dev, "assuming 2.5V internal vREF\n");
+			vREF_mV = 2500;
+		}
+		break;
+	case 7845:
+	case 7843:
+		if (!vREF_mV) {
+			dev_warn(&spi->dev,
+				"external vREF for ADS%d not specified\n",
+				ts->model);
+			return 0;
+		}
+		break;
+	}
+
+	/* different chips have different sensor groups */
+	switch (ts->model) {
+	case 7846:
+		ts->attr_group = &ads7846_attr_group;
+		break;
+	case 7845:
+		ts->attr_group = &ads7845_attr_group;
+		break;
+	case 7843:
+		ts->attr_group = &ads7843_attr_group;
+		break;
+	default:
+		dev_dbg(&spi->dev, "ADS%d not recognized\n", ts->model);
+		return 0;
+	}
+
+	err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+	if (err)
+		return err;
+
+	hwmon = hwmon_device_register(&spi->dev);
+	if (IS_ERR(hwmon)) {
+		sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+		return PTR_ERR(hwmon);
+	}
+
+	ts->hwmon = hwmon;
+	return 0;
+}
+
+static void ads784x_hwmon_unregister(struct spi_device *spi,
+				     struct ads7846 *ts)
+{
+	if (ts->hwmon) {
+		sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+		hwmon_device_unregister(ts->hwmon);
+	}
+}
+
+#else
+static inline int ads784x_hwmon_register(struct spi_device *spi,
+					 struct ads7846 *ts)
+{
+	return 0;
+}
+
+static inline void ads784x_hwmon_unregister(struct spi_device *spi,
+					    struct ads7846 *ts)
+{
+}
+#endif
 
 static int is_pen_down(struct device *dev)
 {
-	struct ads7846		*ts = dev_get_drvdata(dev);
+	struct ads7846	*ts = dev_get_drvdata(dev);
 
 	return ts->pendown;
 }
@@ -318,46 +486,14 @@ static ssize_t ads7846_disable_store(str
 
 static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store);
 
-static struct attribute *ads7846_attributes[] = {
-	&dev_attr_temp0.attr,
-	&dev_attr_temp1.attr,
-	&dev_attr_vbatt.attr,
-	&dev_attr_vaux.attr,
-	&dev_attr_pen_down.attr,
-	&dev_attr_disable.attr,
-	NULL,
-};
-
-static struct attribute_group ads7846_attr_group = {
-	.attrs = ads7846_attributes,
-};
-
-/*
- * ads7843/7845 don't have temperature sensors, and
- * use the other sensors a bit differently too
- */
-
-static struct attribute *ads7843_attributes[] = {
-	&dev_attr_vbatt.attr,
-	&dev_attr_vaux.attr,
+static struct attribute *ads784x_attributes[] = {
 	&dev_attr_pen_down.attr,
 	&dev_attr_disable.attr,
 	NULL,
 };
 
-static struct attribute_group ads7843_attr_group = {
-	.attrs = ads7843_attributes,
-};
-
-static struct attribute *ads7845_attributes[] = {
-	&dev_attr_vaux.attr,
-	&dev_attr_pen_down.attr,
-	&dev_attr_disable.attr,
-	NULL,
-};
-
-static struct attribute_group ads7845_attr_group = {
-	.attrs = ads7845_attributes,
+static struct attribute_group ads784x_attr_group = {
+	.attrs = ads784x_attributes,
 };
 
 /*--------------------------------------------------------------------------*/
@@ -373,25 +509,22 @@ static struct attribute_group ads7845_at
 static void ads7846_rx(void *ads)
 {
 	struct ads7846		*ts = ads;
-	struct input_dev	*input_dev = ts->input;
 	unsigned		Rt;
-	unsigned		sync = 0;
 	u16			x, y, z1, z2;
-	unsigned long		flags;
 
-	/* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
-	 * built from two 8 bit values written msb-first.
+	/* ads7846_rx_val() did in-place conversion (including byteswap) from
+	 * on-the-wire format as part of debouncing to get stable readings.
 	 */
-	x = (be16_to_cpu(ts->tc.x) >> 3) & 0x0fff;
-	y = (be16_to_cpu(ts->tc.y) >> 3) & 0x0fff;
-	z1 = (be16_to_cpu(ts->tc.z1) >> 3) & 0x0fff;
-	z2 = (be16_to_cpu(ts->tc.z2) >> 3) & 0x0fff;
+	x = ts->tc.x;
+	y = ts->tc.y;
+	z1 = ts->tc.z1;
+	z2 = ts->tc.z2;
 
 	/* range filtering */
 	if (x == MAX_12BIT)
 		x = 0;
 
-	if (likely(x && z1 && !device_suspended(&ts->spi->dev))) {
+	if (likely(x && z1)) {
 		/* compute touch pressure resistance using equation #2 */
 		Rt = z2;
 		Rt -= z1;
@@ -402,101 +535,134 @@ static void ads7846_rx(void *ads)
 	} else
 		Rt = 0;
 
+	if (ts->model == 7843)
+		Rt = ts->pressure_max / 2;
+
+
 	/* Sample found inconsistent by debouncing or pressure is beyond
-	* the maximum. Don't report it to user space, repeat at least
-	* once more the measurement */
+	 * the maximum. Don't report it to user space, repeat at least
+	 * once more the measurement
+	 */
 	if (ts->tc.ignore || Rt > ts->pressure_max) {
-		mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
+#ifdef VERBOSE
+		pr_debug("%s: ignored %d pressure %d\n",
+			ts->spi->dev.bus_id, ts->tc.ignore, Rt);
+#endif
+		hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
+			      HRTIMER_REL);
 		return;
 	}
 
-	/* NOTE:  "pendown" is inferred from pressure; we don't rely on
-	 * being able to check nPENIRQ status, or "friendly" trigger modes
-	 * (both-edges is much better than just-falling or low-level).
-	 *
-	 * REVISIT:  some boards may require reading nPENIRQ; it's
-	 * needed on 7843.  and 7845 reads pressure differently...
+	/* NOTE: We can't rely on the pressure to determine the pen down
+	 * state, even this controller has a pressure sensor.  The pressure
+	 * value can fluctuate for quite a while after lifting the pen and
+	 * in some cases may not even settle at the expected value.
 	 *
-	 * REVISIT:  the touchscreen might not be connected; this code
-	 * won't notice that, even if nPENIRQ never fires ...
+	 * The only safe way to check for the pen up condition is in the
+	 * timer by reading the pen signal state (it's a GPIO _and_ IRQ).
 	 */
-	if (!ts->pendown && Rt != 0) {
-		input_report_key(input_dev, BTN_TOUCH, 1);
-		sync = 1;
-	} else if (ts->pendown && Rt == 0) {
-		input_report_key(input_dev, BTN_TOUCH, 0);
-		sync = 1;
-	}
-
 	if (Rt) {
-		input_report_abs(input_dev, ABS_X, x);
-		input_report_abs(input_dev, ABS_Y, y);
-		sync = 1;
-	}
+		struct input_dev *input = ts->input;
 
-	if (sync) {
-		input_report_abs(input_dev, ABS_PRESSURE, Rt);
-		input_sync(input_dev);
-	}
-
-#ifdef	VERBOSE
-	if (Rt || ts->pendown)
-		pr_debug("%s: %d/%d/%d%s\n", ts->spi->dev.bus_id,
-			x, y, Rt, Rt ? "" : " UP");
+		if (!ts->pendown) {
+			input_report_key(input, BTN_TOUCH, 1);
+			ts->pendown = 1;
+#ifdef VERBOSE
+			dev_dbg(&ts->spi->dev, "DOWN\n");
 #endif
+		}
+		input_report_abs(input, ABS_X, x);
+		input_report_abs(input, ABS_Y, y);
+		input_report_abs(input, ABS_PRESSURE, Rt);
+
+		input_sync(input);
+#ifdef VERBOSE
+		dev_dbg(&ts->spi->dev, "%4d/%4d/%4d\n", x, y, Rt);
+#endif
+	}
 
-	spin_lock_irqsave(&ts->lock, flags);
-
-	ts->pendown = (Rt != 0);
-	mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
-
-	spin_unlock_irqrestore(&ts->lock, flags);
+	hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), HRTIMER_REL);
 }
 
-static void ads7846_debounce(void *ads)
+static int ads7846_debounce(void *ads, int data_idx, int *val)
 {
 	struct ads7846		*ts = ads;
-	struct spi_message	*m;
-	struct spi_transfer	*t;
-	int			val;
-	int			status;
 
-	m = &ts->msg[ts->msg_idx];
-	t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
-	val = (be16_to_cpu(*(__be16 *)t->rx_buf) >> 3) & 0x0fff;
-	if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) {
+	if (!ts->read_cnt || (abs(ts->last_read - *val) > ts->debounce_tol)) {
+		/* Start over collecting consistent readings. */
+		ts->read_rep = 0;
 		/* Repeat it, if this was the first read or the read
 		 * wasn't consistent enough. */
 		if (ts->read_cnt < ts->debounce_max) {
-			ts->last_read = val;
+			ts->last_read = *val;
 			ts->read_cnt++;
+			return ADS7846_FILTER_REPEAT;
 		} else {
 			/* Maximum number of debouncing reached and still
 			 * not enough number of consistent readings. Abort
 			 * the whole sample, repeat it in the next sampling
 			 * period.
 			 */
-			ts->tc.ignore = 1;
 			ts->read_cnt = 0;
-			/* Last message will contain ads7846_rx() as the
-			 * completion function.
-			 */
-			m = ts->last_msg;
+			return ADS7846_FILTER_IGNORE;
 		}
-		/* Start over collecting consistent readings. */
-		ts->read_rep = 0;
 	} else {
 		if (++ts->read_rep > ts->debounce_rep) {
 			/* Got a good reading for this coordinate,
 			 * go for the next one. */
-			ts->tc.ignore = 0;
-			ts->msg_idx++;
 			ts->read_cnt = 0;
 			ts->read_rep = 0;
-			m++;
-		} else
+			return ADS7846_FILTER_OK;
+		} else {
 			/* Read more values that are consistent. */
 			ts->read_cnt++;
+			return ADS7846_FILTER_REPEAT;
+		}
+	}
+}
+
+static int ads7846_no_filter(void *ads, int data_idx, int *val)
+{
+	return ADS7846_FILTER_OK;
+}
+
+static void ads7846_rx_val(void *ads)
+{
+	struct ads7846 *ts = ads;
+	struct spi_message *m;
+	struct spi_transfer *t;
+	u16 *rx_val;
+	int val;
+	int action;
+	int status;
+
+	m = &ts->msg[ts->msg_idx];
+	t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list);
+	rx_val = t->rx_buf;
+
+	/* adjust:  on-wire is a must-ignore bit, a BE12 value, then padding;
+	 * built from two 8 bit values written msb-first.
+	 */
+	val = be16_to_cpu(*rx_val) >> 3;
+
+	action = ts->filter(ts->filter_data, ts->msg_idx, &val);
+	switch (action) {
+	case ADS7846_FILTER_REPEAT:
+		break;
+	case ADS7846_FILTER_IGNORE:
+		ts->tc.ignore = 1;
+		/* Last message will contain ads7846_rx() as the
+		 * completion function.
+		 */
+		m = ts->last_msg;
+		break;
+	case ADS7846_FILTER_OK:
+		*rx_val = val;
+		ts->tc.ignore = 0;
+		m = &ts->msg[++ts->msg_idx];
+		break;
+	default:
+		BUG();
 	}
 	status = spi_async(ts->spi, m);
 	if (status)
@@ -504,21 +670,34 @@ static void ads7846_debounce(void *ads)
 				status);
 }
 
-static void ads7846_timer(unsigned long handle)
+static int ads7846_timer(struct hrtimer *handle)
 {
-	struct ads7846	*ts = (void *)handle;
+	struct ads7846	*ts = container_of(handle, struct ads7846, timer);
 	int		status = 0;
 
 	spin_lock_irq(&ts->lock);
 
-	if (unlikely(ts->msg_idx && !ts->pendown)) {
+	if (unlikely(!ts->get_pendown_state() ||
+		     device_suspended(&ts->spi->dev))) {
+		if (ts->pendown) {
+			struct input_dev *input = ts->input;
+
+			input_report_key(input, BTN_TOUCH, 0);
+			input_report_abs(input, ABS_PRESSURE, 0);
+			input_sync(input);
+
+			ts->pendown = 0;
+#ifdef VERBOSE
+			dev_dbg(&ts->spi->dev, "UP\n");
+#endif
+		}
+
 		/* measurement cycle ended */
 		if (!device_suspended(&ts->spi->dev)) {
 			ts->irq_disabled = 0;
 			enable_irq(ts->spi->irq);
 		}
 		ts->pending = 0;
-		ts->msg_idx = 0;
 	} else {
 		/* pen is still down, continue with the measurement */
 		ts->msg_idx = 0;
@@ -528,6 +707,7 @@ static void ads7846_timer(unsigned long 
 	}
 
 	spin_unlock_irq(&ts->lock);
+	return HRTIMER_NORESTART;
 }
 
 static irqreturn_t ads7846_irq(int irq, void *handle)
@@ -546,7 +726,8 @@ static irqreturn_t ads7846_irq(int irq, 
 			ts->irq_disabled = 1;
 			disable_irq(ts->spi->irq);
 			ts->pending = 1;
-			mod_timer(&ts->timer, jiffies);
+			hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_DELAY),
+					HRTIMER_REL);
 		}
 	}
 	spin_unlock_irqrestore(&ts->lock, flags);
@@ -632,6 +813,7 @@ static int __devinit ads7846_probe(struc
 	struct ads7846_platform_data	*pdata = spi->dev.platform_data;
 	struct spi_message		*m;
 	struct spi_transfer		*x;
+	int				vref;
 	int				err;
 
 	if (!spi->irq) {
@@ -665,6 +847,10 @@ static int __devinit ads7846_probe(struc
 	 * may not.  So we stick to very-portable 8 bit words, both RX and TX.
 	 */
 	spi->bits_per_word = 8;
+	spi->mode = SPI_MODE_1;
+	err = spi_setup(spi);
+	if (err < 0)
+		return err;
 
 	ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
 	input_dev = input_allocate_device();
@@ -679,8 +865,7 @@ static int __devinit ads7846_probe(struc
 	ts->spi = spi;
 	ts->input = input_dev;
 
-	init_timer(&ts->timer);
-	ts->timer.data = (unsigned long) ts;
+	hrtimer_init(&ts->timer, CLOCK_MONOTONIC, HRTIMER_REL);
 	ts->timer.function = ads7846_timer;
 
 	spin_lock_init(&ts->lock);
@@ -689,14 +874,25 @@ static int __devinit ads7846_probe(struc
 	ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
 	ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
 	ts->pressure_max = pdata->pressure_max ? : ~0;
-	if (pdata->debounce_max) {
+
+	if (pdata->filter != NULL) {
+		if (pdata->filter_init != NULL) {
+			err = pdata->filter_init(pdata, &ts->filter_data);
+			if (err < 0)
+				goto err_free_mem;
+		}
+		ts->filter = pdata->filter;
+		ts->filter_cleanup = pdata->filter_cleanup;
+	} else if (pdata->debounce_max) {
 		ts->debounce_max = pdata->debounce_max;
+		if (ts->debounce_max < 2)
+			ts->debounce_max = 2;
 		ts->debounce_tol = pdata->debounce_tol;
 		ts->debounce_rep = pdata->debounce_rep;
-		if (ts->debounce_rep > ts->debounce_max + 1)
-			ts->debounce_rep = ts->debounce_max - 1;
+		ts->filter = ads7846_debounce;
+		ts->filter_data = ts;
 	} else
-		ts->debounce_tol = ~0;
+		ts->filter = ads7846_no_filter;
 	ts->get_pendown_state = pdata->get_pendown_state;
 
 	snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
@@ -718,6 +914,8 @@ static int __devinit ads7846_probe(struc
 	input_set_abs_params(input_dev, ABS_PRESSURE,
 			pdata->pressure_min, pdata->pressure_max, 0, 0);
 
+	vref = pdata->keep_vref_on;
+
 	/* set up the transfers to read touchscreen state; this assumes we
 	 * use formula #2 for pressure, not #3.
 	 */
@@ -727,7 +925,7 @@ static int __devinit ads7846_probe(struc
 	spi_message_init(m);
 
 	/* y- still on; turn on only y+ (and ADC) */
-	ts->read_y = READ_Y;
+	ts->read_y = READ_Y(vref);
 	x->tx_buf = &ts->read_y;
 	x->len = 1;
 	spi_message_add_tail(x, m);
@@ -737,7 +935,7 @@ static int __devinit ads7846_probe(struc
 	x->len = 2;
 	spi_message_add_tail(x, m);
 
-	m->complete = ads7846_debounce;
+	m->complete = ads7846_rx_val;
 	m->context = ts;
 
 	m++;
@@ -745,7 +943,7 @@ static int __devinit ads7846_probe(struc
 
 	/* turn y- off, x+ on, then leave in lowpower */
 	x++;
-	ts->read_x = READ_X;
+	ts->read_x = READ_X(vref);
 	x->tx_buf = &ts->read_x;
 	x->len = 1;
 	spi_message_add_tail(x, m);
@@ -755,7 +953,7 @@ static int __devinit ads7846_probe(struc
 	x->len = 2;
 	spi_message_add_tail(x, m);
 
-	m->complete = ads7846_debounce;
+	m->complete = ads7846_rx_val;
 	m->context = ts;
 
 	/* turn y+ off, x- on; we'll use formula #2 */
@@ -764,7 +962,7 @@ static int __devinit ads7846_probe(struc
 		spi_message_init(m);
 
 		x++;
-		ts->read_z1 = READ_Z1;
+		ts->read_z1 = READ_Z1(vref);
 		x->tx_buf = &ts->read_z1;
 		x->len = 1;
 		spi_message_add_tail(x, m);
@@ -774,14 +972,14 @@ static int __devinit ads7846_probe(struc
 		x->len = 2;
 		spi_message_add_tail(x, m);
 
-		m->complete = ads7846_debounce;
+		m->complete = ads7846_rx_val;
 		m->context = ts;
 
 		m++;
 		spi_message_init(m);
 
 		x++;
-		ts->read_z2 = READ_Z2;
+		ts->read_z2 = READ_Z2(vref);
 		x->tx_buf = &ts->read_z2;
 		x->len = 1;
 		spi_message_add_tail(x, m);
@@ -791,7 +989,7 @@ static int __devinit ads7846_probe(struc
 		x->len = 2;
 		spi_message_add_tail(x, m);
 
-		m->complete = ads7846_debounce;
+		m->complete = ads7846_rx_val;
 		m->context = ts;
 	}
 
@@ -820,31 +1018,24 @@ static int __devinit ads7846_probe(struc
 			spi->dev.driver->name, ts)) {
 		dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
 		err = -EBUSY;
-		goto err_free_mem;
+		goto err_cleanup_filter;
 	}
 
+	err = ads784x_hwmon_register(spi, ts);
+	if (err)
+		goto err_free_irq;
+
 	dev_info(&spi->dev, "touchscreen, irq %d\n", spi->irq);
 
-	/* take a first sample, leaving nPENIRQ active; avoid
+	/* take a first sample, leaving nPENIRQ active and vREF off; avoid
 	 * the touchscreen, in case it's not connected.
 	 */
 	(void) ads7846_read12_ser(&spi->dev,
 			  READ_12BIT_SER(vaux) | ADS_PD10_ALL_ON);
 
-	switch (ts->model) {
-	case 7846:
-		ts->attr_group = &ads7846_attr_group;
-		break;
-	case 7845:
-		ts->attr_group = &ads7845_attr_group;
-		break;
-	default:
-		ts->attr_group = &ads7843_attr_group;
-		break;
-	}
-	err = sysfs_create_group(&spi->dev.kobj, ts->attr_group);
+	err = sysfs_create_group(&spi->dev.kobj, &ads784x_attr_group);
 	if (err)
-		goto err_free_irq;
+		goto err_remove_hwmon;
 
 	err = input_register_device(input_dev);
 	if (err)
@@ -853,9 +1044,14 @@ static int __devinit ads7846_probe(struc
 	return 0;
 
  err_remove_attr_group:
-	sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+	sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
+ err_remove_hwmon:
+	ads784x_hwmon_unregister(spi, ts);
  err_free_irq:
 	free_irq(spi->irq, ts);
+ err_cleanup_filter:
+	if (ts->filter_cleanup)
+		ts->filter_cleanup(ts->filter_data);
  err_free_mem:
 	input_free_device(input_dev);
 	kfree(ts);
@@ -866,16 +1062,20 @@ static int __devexit ads7846_remove(stru
 {
 	struct ads7846		*ts = dev_get_drvdata(&spi->dev);
 
+	ads784x_hwmon_unregister(spi, ts);
 	input_unregister_device(ts->input);
 
 	ads7846_suspend(spi, PMSG_SUSPEND);
 
-	sysfs_remove_group(&spi->dev.kobj, ts->attr_group);
+	sysfs_remove_group(&spi->dev.kobj, &ads784x_attr_group);
 
 	free_irq(ts->spi->irq, ts);
 	/* suspend left the IRQ disabled */
 	enable_irq(ts->spi->irq);
 
+	if (ts->filter_cleanup)
+		ts->filter_cleanup(ts->filter_data);
+
 	kfree(ts);
 
 	dev_dbg(&spi->dev, "unregistered touchscreen\n");
diff -uprN linux-2.6.20/drivers/ioex/Kconfig linux-2.6.20-at92_e1.5/drivers/ioex/Kconfig
--- linux-2.6.20/drivers/ioex/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/ioex/Kconfig	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,66 @@
+#
+# IO expansion configuration
+#
+
+menu "IO expansion"
+
+config ECOREEX
+        tristate "EMAC cores"
+        ---help---
+        Provides autodetection and support for PLD cores following the EMAC 
+        format, which uses a device key to communicate the expansion devices available to 
+        the kernel.       
+
+config ECOREEX_TGPIO
+		depends on ECOREEX
+        bool "iPac True GPI/O expansion R1.0"
+        ---help---
+        Provides autodetection and support for the iPac GPI/O expansion
+
+config ECOREEX_SGPWM
+		depends on ECOREEX
+        bool "iPac Shadow GPI/O & PWM expansion R1.0"
+        ---help---
+        Provides autodetection and support for the iPac Shadow GPI/O & PWM expansion
+
+config ECOREEX_GCMB
+		depends on ECOREEX
+        bool "GCMB expansion I/O"
+        ---help---
+        Provides autodetection and support for the GCMB expansion
+
+config ECOREEX_DENM
+		depends on ECOREEX
+        bool "DENM expansion I/O"
+        ---help---
+        Provides autodetection and support for the DENM expansion       
+
+config ECOREEX_HWMS
+        depends on ECOREEX
+        bool "Armstrong HWMS expansion I/O"
+        ---help---
+        Provides support for the Armstrong HWMS PLD
+        
+config ECOREEX_KEY
+        depends on ECOREEX
+        bool "Define static version key"
+        ---help---
+        Disable auto-detection of the PLD core by defining the version key
+
+config ECOREEX_STATIC_KEY
+        depends on ECOREEX_KEY
+        hex "Version key"
+        default "0xC0"
+        ---help---
+        Set the static version key for the PLD core 
+
+config BOARDSPEC
+        tristate "board devices"
+        ---help---
+        Provides registration of devices provided by the mach. 
+
+endmenu
+
+
+
+
diff -uprN linux-2.6.20/drivers/ioex/Makefile linux-2.6.20-at92_e1.5/drivers/ioex/Makefile
--- linux-2.6.20/drivers/ioex/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/ioex/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,10 @@
+#
+# Makefile for the ioex devices
+#
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_ECOREEX)		+= ecoreex.o
+obj-$(CONFIG_BOARDSPEC)		+= boardspec.o
+obj-y						+= pwmd.o
+
diff -uprN linux-2.6.20/drivers/ioex/boardspec.c linux-2.6.20-at92_e1.5/drivers/ioex/boardspec.c
--- linux-2.6.20/drivers/ioex/boardspec.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/ioex/boardspec.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,52 @@
+ /***************************************************************************
+                          		boardspec.c    
+			Registration of board specific classes & devices. 
+			Registers and calls a function pointer from the arch's platform device
+			Important in that it allows for a proper module loading order, which may be
+			required as some methods call other modules (specifically Xenamai)             
+                             -------------------
+	author				 : NZG
+    begin                : Tue May 15 2007
+    copyright          	 : (C) 2007 by EMAC.Inc
+    email                : support@emacinc.com
+ ***************************************************************************/
+#include <linux/kernel.h>
+#include <linux/autoconf.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/ioex/ecoreex.h>
+#include <linux/platform_device.h>
+#include <asm/io.h> 
+ 
+#define DRV_MODULE_NAME 	"boardspec"
+#define DRV_MODULE_VERSION 	"1.0"
+
+static int boardspec_probe(struct platform_device *pdev){
+	int (*device_init)(void);
+	if (pdev == NULL)return -ENODEV;
+	device_init = pdev->dev.platform_data;
+	return device_init();
+}
+
+//driver currently has no removal method.
+static struct platform_driver boardspec_driver = {
+	.probe		= boardspec_probe,
+	.driver		= {
+		.name	= "boardspec",
+	},
+};
+
+static int __init boardspec_init_module(void)
+{
+	printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n");
+	return platform_driver_register(&boardspec_driver);
+}
+
+static void __exit boardspec_cleanup_module(void)
+{
+	platform_driver_unregister(&boardspec_driver);
+}
+
+
+module_init(boardspec_init_module);
+module_exit(boardspec_cleanup_module);
diff -uprN linux-2.6.20/drivers/ioex/ecoreex.c linux-2.6.20-at92_e1.5/drivers/ioex/ecoreex.c
--- linux-2.6.20/drivers/ioex/ecoreex.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/ioex/ecoreex.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,431 @@
+/***************************************************************************
+                          		ecoreex.c    
+					EMAC soft cores device registration             
+                             -------------------
+	author				 : NZG
+    rewrite              : Tue May 15 2007
+    copyright          	 : (C) 2007 by EMAC.Inc
+    email                : support@emacinc.com
+ ***************************************************************************/
+ 
+#include <linux/kernel.h>
+#include <linux/autoconf.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/class/gpio.h>
+#include <linux/class/pwm.h>
+#include <linux/class/mmcprot.h>
+#include <linux/ioex/ecoreex.h>
+#include <linux/ioex/pwmd.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/mach/irq.h>
+
+/*********************************************************************/
+#ifdef CONFIG_ECOREEX_HWMS
+#define CPLD_HWMS_NAME "HWMS GPI/O expansion R1.0"
+#define CPLD_HWMS 0xC0
+
+/**
+ * handler currently just indicates the that interrupt was handled and returns
+ */
+static irqreturn_t hwms_interrupt(int irq, void *na){
+    return IRQ_HANDLED;
+}
+
+static inline int CPLD_HWMS_map(unsigned long phys_addr, u8 *virt_addr, 
+        unsigned long size, const char *name, struct ecoreex_data *data)
+{   
+    gpio_t *gpio_counter;
+    gpio_t *gpio_control;
+    
+    if (request_mem_region(phys_addr, size, name) == NULL) {
+        printk("Could not obtain physical memory at %lx for EMAC core\n", phys_addr);
+        iounmap(virt_addr);
+    }
+    gpio_declare();
+    
+    gpio_control = gpio_device_create_unregistered(&virt_addr[0], NULL, "control");
+    ecoreex_setup_data_access(data->e_access, gpio_control);
+    /* no index read or write for the control -- only one register */
+    gpio_control->index_write = NULL;
+    gpio_control->index_read = NULL; 
+    
+    gpio_counter = gpio_device_create_unregistered(&virt_addr[1], NULL, "counter");
+    gpio_counter->index_write = gpio_index_write;
+    gpio_counter->index_read = gpio_index_read;
+    gpio_counter->range = 1;
+    ecoreex_setup_data_access(data->e_access, gpio_counter);
+    
+    gpio_register_class_device(gpio_control);
+    gpio_register_class_device(gpio_counter);
+    
+    /*
+     * Allocate the IRQ
+     */
+    if(data->irq){
+        int err = request_irq(data->irq, hwms_interrupt,IRQT_RISING,name, NULL);
+        if(err<0)
+            printk("ecoreex request for irq %d failed with %d\n",data->irq,err);
+        //printk("ecoreex request for irq %d failed\n",e->irq);
+
+        else set_irq_wake(data->irq,1);//if the board provides an irq, register it to wake up pm.
+    }
+
+    return 0;
+}
+
+#endif /* CONFIG_ECOREEX_HWMS */
+
+//---------------------------------------------------------------------------------
+#ifdef CONFIG_ECOREEX_TGPIO
+#define CPLD_BASE_NAME "iPac GPI/O expansion R1.0" 
+#define CPLD_BASE 0xA0
+
+#define CPLD_BASE_NAME_11 "iPac GPI/O expansion R1.1" 
+#define CPLD_BASE_11 0xA3
+
+static inline int CPLD_BASE_map(unsigned long phys_addr,u8 *virt_addr,unsigned long size,const char *name){
+	
+	if(request_mem_region(phys_addr,size,name)==NULL){
+		printk("could not obtain physical memory at %lx for EMAC core\n",phys_addr);
+		iounmap(virt_addr);
+		return -1;
+		}			
+	//add appropriate class devices for this version to the system
+	printk("%s detected at %lx\n",name,phys_addr);
+
+#ifdef CONFIG_GPIOCLASS
+	gpio_declare();
+	gpio_device_create(&virt_addr[0], &virt_addr[1],"portw");
+	gpio_device_create(&virt_addr[2], &virt_addr[3],"portx");
+	gpio_device_create(&virt_addr[4], &virt_addr[5],"porty");
+	gpio_device_create(&virt_addr[6], &virt_addr[7],"portz");
+#endif
+				
+return 0;
+}
+#endif //CONFIG_ECOREEX_TGPIO
+//---------------------------------------------------------------------------------
+#ifdef CONFIG_ECOREEX_SGPWM
+#define CPLD_GPWM_NAME "iPac Shadow GPI/O & PWM expansion R1.0"
+#define CPLD_GPWM 0xA1
+
+#define CPLD_GPWM_NAME_11 "iPac Shadow GPI/O & PWM expansion R1.1"
+#define CPLD_GPWM_11 0xA2
+
+#define CPLD_GPWM_NAME_12 "iPac Shadow GPI/O & PWM expansion R1.2"
+#define CPLD_GPWM_12 0xA4
+
+static int gpwm_carddetect(mmcslot_t *s){
+	u8 status = atomic_gpio_data_read(s->pd[MMCCD]);
+	return (status&1)?0:1;
+}
+
+static int gpwm_writeprotect(mmcslot_t *s){
+	u8 status = atomic_gpio_data_read(s->pd[MMCWP]);
+	return (status&2)?1:0;
+}
+
+static inline int CPLD_GPWM_map(unsigned long phys_addr,u8 *virt_addr,unsigned long size,const char *name,struct ecoreex_data *e){
+	if(request_mem_region(phys_addr,size,name)==NULL){
+		printk("could not obtain physical memory at %lx for EMAC core\n",phys_addr);
+		iounmap(virt_addr);
+		return -1;
+		}
+	
+	printk("%s detected at %lx\n",name,phys_addr);			
+	//add appropriate class devices for this version to the system
+
+#ifdef CONFIG_GPIOCLASS	
+{
+	struct class_device *status = gpi_device_create(&virt_addr[6],"status");
+	gpi_device_create(&virt_addr[0],"portw");
+	gpo_device_create(&virt_addr[1],"portx");
+	gpo_device_create(&virt_addr[2],"porty");
+	gpi_device_create(&virt_addr[3],"portz");
+	gpo_device_create(&virt_addr[7],"control");
+	 
+	if(e->mmcslot){//implement MMC CD and WP functions
+		e->mmcslot->carddetect = gpwm_carddetect;
+		e->mmcslot->writeprotect = gpwm_writeprotect;
+		e->mmcslot->pd[MMCWP]=e->mmcslot->pd[MMCCD]=status->class_data;//pass back gpio class structures
+	}
+}
+#endif	//CONFIG_GPIOCLASS
+
+#ifdef CONFIG_PWMCLASS
+	pwmd_device_create(&virt_addr[4],"gpwma",e->read_periodusa);
+	pwmd_device_create(&virt_addr[5],"gpwmb",e->read_periodusa);
+#endif	
+
+
+
+return 0;
+}
+
+#endif //CONFIG_ECOREEX_SGPWM
+
+//---------------------------------------------------------------------------------
+#ifdef CONFIG_ECOREEX_GCMB
+#define CPLD_GCMB_NAME_10 "GCMB CPLD expansion R1.0"
+#define CPLD_GCMB 0xB0
+
+static inline int CPLD_GCMB_map(unsigned long phys_addr,u8 *virt_addr,unsigned long size,const char *name){
+	
+	if(request_mem_region(phys_addr,size,name)==NULL){
+		printk("could not obtain physical memory at %lx for EMAC core\n",phys_addr);
+		iounmap(virt_addr);
+		return -1;
+		}
+	
+	printk("%s detected at %lx\n",name,phys_addr);			
+	//add appropriate class devices for this version to the system
+
+#ifdef CONFIG_GPIOCLASS	
+	gpio_declare();
+	gpo_device_create(&virt_addr[0],"dlais321");
+	gpi_device_create(&virt_addr[4],"rlwc3210");
+	gpio_device_create(&virt_addr[2], NULL,"spi_7730");
+#endif	//CONFIG_GPIOCLASS
+
+return 0;
+}
+
+#endif //CONFIG_ECOREEX_GCMB
+
+//---------------------------------------------------------------------------------
+#ifdef CONFIG_ECOREEX_DENM
+#define CPLD_DENM_NAME_12 "DENM CPLD expansion R1.2/R1.3"
+#define CPLD_DENM_NAME_14 "DENM CPLD expansion R1.4"
+#define CPLD_DENM_NAME_15 "DENM CPLD expansion R1.5"
+#define CPLD_DENM_NAME_16 "DENM CPLD expansion R1.6"
+#define CPLD_DENM_NAME_17 "DENM CPLD expansion R1.7"
+#define CPLD_DENM 0x92
+#define CPLD_DENM14 0x93
+#define CPLD_DENM15 0x94
+#define CPLD_DENM16 0x95
+#define CPLD_DENM17 0x98
+
+static inline int CPLD_DENM_map(unsigned long phys_addr,u8 *virt_addr,unsigned long size,const char *name){
+	
+	if(request_mem_region(phys_addr,size,name)==NULL){
+		printk("could not obtain physical memory at %lx for EMAC core\n",phys_addr);
+		iounmap(virt_addr);
+		return -1;
+		}
+	
+	printk("%s detected at %lx\n",name,phys_addr);			
+	//add appropriate class devices for this version to the system
+
+#ifdef CONFIG_GPIOCLASS	
+	gpio_declare();
+	gpi_device_create(&virt_addr[2],"counter0");
+	gpi_device_create(&virt_addr[4],"counter1");
+	gpi_device_create(&virt_addr[5],"counter2");
+	gpi_device_create(&virt_addr[8],"counter3");
+	gpi_device_create(&virt_addr[10],"counter4");
+	gpi_device_create(&virt_addr[12],"counter5");
+	gpi_device_create(&virt_addr[14],"ct543210");
+	
+	gpo_device_create(&virt_addr[16],"oxrs4321");
+	gpo_device_create(&virt_addr[17],"xxrt321b");
+	
+	gpio_device_create(&virt_addr[3], NULL,"rollover");
+#endif	//CONFIG_GPIOCLASS
+
+return 0;
+}
+
+static inline int CPLD_DENM14_map(unsigned long phys_addr,u8 *virt_addr,unsigned long size,const char *name){
+	
+	if(request_mem_region(phys_addr,size,name)==NULL){
+		printk("could not obtain physical memory at %lx for EMAC core\n",phys_addr);
+		iounmap(virt_addr);
+		return -1;
+		}
+	
+	printk("%s detected at %lx\n",name,phys_addr);			
+	//add appropriate class devices for this version to the system
+
+#ifdef CONFIG_GPIOCLASS	
+	gpio_declare();
+	gpi_device_create(&virt_addr[2],"counter0");
+	gpi_device_create(&virt_addr[4],"counter1");
+	gpi_device_create(&virt_addr[6],"counter2");
+	gpi_device_create(&virt_addr[8],"counter3");
+	gpi_device_create(&virt_addr[10],"counter4");
+	gpi_device_create(&virt_addr[12],"counter5");
+	gpi_device_create(&virt_addr[14],"ct543210");
+	
+	gpio_device_create(&virt_addr[16],NULL,"oxrs4321");
+	gpio_device_create(&virt_addr[17],NULL,"xxrt321b");
+	gpio_device_create(&virt_addr[3], NULL,"rollover");
+	gpo_device_create(&virt_addr[1],"debounce");
+	
+#endif	//CONFIG_GPIOCLASS
+
+return 0;
+}
+
+/**
+ * handler currently just indicates the that interrupt was handled and returns
+ */
+static irqreturn_t denm_interrupt(int irq, void *na){
+	//printk("denm interrupt\n");
+	return IRQ_HANDLED;
+}
+
+
+static inline int CPLD_DENM15_map(unsigned long phys_addr,u8 *virt_addr,unsigned long size,const char *name,struct ecoreex_data *e){
+	
+	if(request_mem_region(phys_addr,size,name)==NULL){
+		printk("could not obtain physical memory at %lx for EMAC core\n",phys_addr);
+		iounmap(virt_addr);
+		return -1;
+		}
+	
+	printk("%s detected at %lx\n",name,phys_addr);			
+	//add appropriate class devices for this version to the system
+
+#ifdef CONFIG_GPIOCLASS	
+	gpio_declare();
+	gpi_device_create(&virt_addr[2],"counter0");
+	gpi_device_create(&virt_addr[4],"counter1");
+	gpi_device_create(&virt_addr[6],"counter2");
+	gpi_device_create(&virt_addr[8],"counter3");
+	gpi_device_create(&virt_addr[10],"counter4");
+	gpi_device_create(&virt_addr[12],"counter5");
+	gpi_device_create(&virt_addr[14],"ct543210");
+	
+	gpio_device_create(&virt_addr[16],NULL,"oxrs4321");
+	gpio_device_create(&virt_addr[17],NULL,"xxrt321b");
+	gpio_device_create(&virt_addr[3], NULL,"rollover");
+	gpio_device_create(&virt_addr[1],NULL,"debounce");
+	
+	/*
+		 * Allocate the IRQ
+		 */
+	if(e->irq){
+		int err = request_irq(e->irq, denm_interrupt,IRQT_RISING,name, NULL);
+		if(err<0)
+			printk("ecoreex request for irq %d failed with %d\n",e->irq,err);
+			//printk("ecoreex request for irq %d failed\n",e->irq);
+		
+		else set_irq_wake(e->irq,1);//if the board provides an irq, register it to wake up pm.
+	}
+	
+#endif	//CONFIG_GPIOCLASS
+
+return 0;
+}
+
+#endif //CONFIG_ECOREEX_DENM
+
+/************************************************************
+ * core mappings based upon a key
+ */
+static inline void map_core(unsigned long phys_addr, unsigned long size, struct ecoreex_data *data)
+{
+    u8 *virt_addr = ioremap_nocache(phys_addr,size);
+    int version = VERSION_KEY;
+    
+    if(virt_addr==NULL)printk("could not remap physical memory at %lx for EMAC core\n",phys_addr);
+    else{
+        version =ioread8(&virt_addr[data->key_offset]);
+        //if (VERSION_KEY == -1)
+        //    version = data->e_access->ecoreex_key_read(data->key_offset, virt_addr);
+        /* else the version is predefined */
+		printk("EMAC core version %x detected at %lx\n",version,phys_addr+data->key_offset );
+		switch(version){
+#ifdef CONFIG_ECOREEX_HWMS
+        case CPLD_HWMS:
+            CPLD_HWMS_map(phys_addr, virt_addr, size, CPLD_HWMS_NAME, data);
+        break;
+#endif
+			//-----------------------------------------------------------
+			#ifdef CONFIG_ECOREEX_TGPIO
+			case CPLD_BASE:
+				CPLD_BASE_map(phys_addr,virt_addr,size,CPLD_BASE_NAME);
+			break;
+			case CPLD_BASE_11:
+				CPLD_BASE_map(phys_addr,virt_addr,size,CPLD_BASE_NAME_11);
+			break;
+			#endif //CONFIG_ECOREEX_TGPIO
+			//-----------------------------------------------------------
+			#ifdef CONFIG_ECOREEX_SGPWM
+			case CPLD_GPWM:
+				CPLD_GPWM_map(phys_addr,virt_addr,size,CPLD_GPWM_NAME,data);
+			break;
+			case CPLD_GPWM_11:
+				CPLD_GPWM_map(phys_addr,virt_addr,size,CPLD_GPWM_NAME_11,data);
+			break;
+			case CPLD_GPWM_12:
+				CPLD_GPWM_map(phys_addr,virt_addr,size,CPLD_GPWM_NAME_12,data);
+			break;
+			#endif //CONFIG_ECOREEX_SGPWM
+			//-----------------------------------------------------------
+			#ifdef CONFIG_ECOREEX_GCMB
+			case CPLD_GCMB:
+				CPLD_GCMB_map(phys_addr,virt_addr,size,CPLD_GCMB_NAME_10);
+			break;
+			#endif //CONFIG_ECOREEX_GCMB
+			//-----------------------------------------------------------			
+			#ifdef CONFIG_ECOREEX_DENM
+			case CPLD_DENM:
+				CPLD_DENM_map(phys_addr,virt_addr,size,CPLD_DENM_NAME_12);
+			break;
+			case CPLD_DENM14:
+				CPLD_DENM14_map(phys_addr,virt_addr,size,CPLD_DENM_NAME_14);
+			break;
+			case CPLD_DENM15:
+				CPLD_DENM15_map(phys_addr,virt_addr,size,CPLD_DENM_NAME_15,data);
+			break;
+			case CPLD_DENM16:
+				CPLD_DENM15_map(phys_addr,virt_addr,size,CPLD_DENM_NAME_16,data);	
+			break;
+			case CPLD_DENM17:
+				CPLD_DENM15_map(phys_addr,virt_addr,size,CPLD_DENM_NAME_17,data);	
+			break;
+			#endif //CONFIG_ECOREEX_DENM
+			//--------------------------------------------------------
+			
+			default://unrecognized CPLD or no CPLD available, silently fail and the physical memory region
+				iounmap(virt_addr);
+			}
+		}
+}
+
+static int ecoreex_probe(struct platform_device *pdev){
+	//printk("ecoreex_probe\n");	
+	if (pdev == NULL)return -ENODEV;
+	map_core(pdev->resource->start,(pdev->resource->end-pdev->resource->start+1),pdev->dev.platform_data);
+	return 0;
+}
+
+//driver currently has no removal method.
+static struct platform_driver ecoreex_driver = {
+	.probe		= ecoreex_probe,
+	.driver		= {
+		.name	= "ecoreex",
+	},
+};
+
+#define DRV_MODULE_NAME 	"ecoreex"
+#define DRV_MODULE_VERSION 	"1.2"
+static int __init ecoreex_init_module(void)
+{
+	printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n");
+	return platform_driver_register(&ecoreex_driver);
+}
+
+static void __exit ecoreex_cleanup_module(void)
+{
+	platform_driver_unregister(&ecoreex_driver);
+}
+
+module_init(ecoreex_init_module);
+module_exit(ecoreex_cleanup_module);
+
diff -uprN linux-2.6.20/drivers/ioex/pwmd.c linux-2.6.20-at92_e1.5/drivers/ioex/pwmd.c
--- linux-2.6.20/drivers/ioex/pwmd.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/ioex/pwmd.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,105 @@
+/**
+ * PWMD's 
+ * pwmd's modulate an external frequency, 
+ * this frequency is passed in as method, which is used to calcuate the widthus
+ * when written or read.
+*/
+
+#include <linux/class/pwm.h>
+#include <asm/io.h>
+
+#define PWMD_PWM_SUBCLASS 93
+
+#define REGMAX 255
+#define PERIODMAX ((0xffffffff)/(REGMAX))
+
+//internal errors
+#define SYSCLOCK_UNSUPPORTED	-2
+
+/**
+ * methods using a shadow register to set the periodus.
+ */
+static pwm_data pwmd_clock_read(struct pwm_s *pwm){
+	return pwm->periodus_shadow;
+}
+
+static int pwmd_clock_write(struct pwm_s *pwm,pwm_data clock){
+	if(!clock)clock=1;
+	if(clock>PERIODMAX)clock=PERIODMAX;//to prevent overflows
+	pwm->periodus_shadow = clock;
+	return 0;
+}
+
+static inline int us2reg(__u32 *value,__u32 periodus_in){
+	if(periodus_in)*value/=periodus_in;
+	//if the input period is zero written value has no effect and will be interpreted as zero in any case.
+	if(*value>REGMAX)*value=REGMAX;
+	return 0;
+}
+
+static inline int reg2us(__u32 *value,__u32 periodus_in){
+	*value*=periodus_in;
+	return 0;		
+}
+
+static int pwmd_widthus_write(struct pwm_s *pwm, pwm_data width){
+	pwm->widthus_shadow = width;
+	if(us2reg(&width,pwm->read_pwmclock(pwm))==SYSCLOCK_UNSUPPORTED)
+		{printk("sysclock unsupported\n");return SYSCLOCK_UNSUPPORTED;}
+	
+	iowrite16((u16)width,pwm->widthus);
+	return 0;
+}
+
+static pwm_data pwmd_widthus_read(struct pwm_s *pwm){
+	__u32 width = pwm->widthus_shadow;
+	
+	if(reg2us(&width,pwm->read_pwmclock(pwm))==SYSCLOCK_UNSUPPORTED)
+		{printk("sysclock unsupported\n");return SYSCLOCK_UNSUPPORTED;}
+		
+	return (width);
+}
+
+static pwm_data pwmd_periodus_read(struct pwm_s *pwm){
+	__u32 period = 0xff;
+	
+	if(reg2us(&period,pwm->read_pwmclock(pwm))==SYSCLOCK_UNSUPPORTED)
+		{printk("sysclock unsupported\n");return SYSCLOCK_UNSUPPORTED;}
+		
+	return (period); 
+}
+
+static int pwmd_periodus_write(struct pwm_s *pwm, pwm_data periodus){
+	pwmd_clock_write(pwm,periodus/REGMAX);
+	return 0;
+}
+
+struct class_device *pwmd_device_create(
+ void *widthus,
+ const char *name,
+ pwm_data (*read_pwmclock)(pwm_t *pwm)){
+	
+	pwm_t *pwm = kmalloc(sizeof(pwm_t),GFP_KERNEL);
+	memset(pwm,0,sizeof(pwm_t));
+	pwm->name = name;
+	pwm->subclass = PWMD_PWM_SUBCLASS;
+
+	pwm->widthus = widthus;
+	
+	pwm->widthus_write = pwmd_widthus_write;
+    pwm->widthus_read = pwmd_widthus_read;
+    pwm->periodus_read = pwmd_periodus_read;
+    
+	if(pwm->read_pwmclock)
+		pwm->periodus_write = pwm_empty_write;
+	else{
+		pwm->read_pwmclock = pwmd_clock_read;
+    	pwm->periodus_write = pwmd_periodus_write;
+    	pwmd_clock_write(pwm,1);
+	}
+	printk("registering pwmd device: %s\n",name);
+
+    return pwm_register_class_device(pwm);
+}
+
+
diff -uprN linux-2.6.20/drivers/leds/Kconfig linux-2.6.20-at92_e1.5/drivers/leds/Kconfig
--- linux-2.6.20/drivers/leds/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/leds/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -76,6 +76,13 @@ config LEDS_NET48XX
 	  This option enables support for the Soekris net4801 and net4826 error
 	  LED.
 
+config LEDS_AT91
+	tristate "LED support using AT91 GPIOs"
+	depends on LEDS_CLASS && ARCH_AT91 && !LEDS
+	help
+	  This option enables support for LEDs connected to GPIO lines
+	  on AT91-based boards.
+
 config LEDS_WRAP
 	tristate "LED Support for the WRAP series LEDs"
 	depends on LEDS_CLASS && SCx200_GPIO
diff -uprN linux-2.6.20/drivers/leds/Makefile linux-2.6.20-at92_e1.5/drivers/leds/Makefile
--- linux-2.6.20/drivers/leds/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/leds/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -14,6 +14,7 @@ obj-$(CONFIG_LEDS_S3C24XX)		+= leds-s3c2
 obj-$(CONFIG_LEDS_AMS_DELTA)		+= leds-ams-delta.o
 obj-$(CONFIG_LEDS_NET48XX)		+= leds-net48xx.o
 obj-$(CONFIG_LEDS_WRAP)			+= leds-wrap.o
+obj-$(CONFIG_LEDS_AT91)			+= leds-at91.o
 
 # LED Triggers
 obj-$(CONFIG_LEDS_TRIGGER_TIMER)	+= ledtrig-timer.o
diff -uprN linux-2.6.20/drivers/leds/leds-at91.c linux-2.6.20-at92_e1.5/drivers/leds/leds-at91.c
--- linux-2.6.20/drivers/leds/leds-at91.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/leds/leds-at91.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,140 @@
+/*
+ * AT91 GPIO based LED driver
+ *
+ * Copyright (C) 2006 David Brownell
+ *
+ * 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/init.h>
+#include <linux/platform_device.h>
+#include <linux/leds.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+static LIST_HEAD(at91_led_list);	/* list of AT91 LEDs */
+
+struct at91_led {
+	struct led_classdev	cdev;
+	struct list_head	list;
+	struct at91_gpio_led	*led_data;
+};
+
+/*
+ * Change the state of the LED.
+ */
+static void at91_led_set(struct led_classdev *cdev, enum led_brightness value)
+{
+	struct at91_led	*led = container_of(cdev, struct at91_led, cdev);
+	short		active = (value == LED_OFF);
+
+	if (led->led_data->flags & 1)	/* active high/low? */
+		active = !active;
+	at91_set_gpio_value(led->led_data->gpio, value == LED_OFF);
+}
+
+static int __devexit at91_led_remove(struct platform_device *pdev)
+{
+	struct at91_led		*led;
+
+	list_for_each_entry (led, &at91_led_list, list)
+		led_classdev_unregister(&led->cdev);
+
+#warning "Free allocated memory"
+	// TODO: Free memory.	kfree(led);
+
+	return 0;
+}
+
+static int __init at91_led_probe(struct platform_device *pdev)
+{
+	int			status = 0;
+	struct at91_gpio_led	*pdata = pdev->dev.platform_data;
+	unsigned		nr_leds;
+	struct at91_led		*led;
+
+	if (!pdata)
+		return -ENODEV;
+
+	nr_leds = pdata->index;		/* first index stores number of LEDs */
+
+	while (nr_leds--) {
+		led = kzalloc(sizeof(struct at91_led), GFP_KERNEL);
+		if (!led) {
+			dev_err(&pdev->dev, "No memory for device\n");
+			status = -ENOMEM;
+			goto cleanup;
+		}
+		led->led_data = pdata;
+		led->cdev.name = pdata->name;
+		led->cdev.brightness_set = at91_led_set,
+		led->cdev.default_trigger = pdata->trigger;
+
+		status = led_classdev_register(&pdev->dev, &led->cdev);
+		if (status < 0) {
+			dev_err(&pdev->dev, "led_classdev_register failed - %d\n", status);
+cleanup:
+			at91_led_remove(pdev);
+			break;
+		}
+		list_add(&led->list, &at91_led_list);
+		pdata++;
+	}
+	return status;
+}
+
+#ifdef CONFIG_PM
+static int at91_led_suspend(struct platform_device *dev, pm_message_t state)
+{
+	struct at91_led	*led;
+
+	list_for_each_entry (led, &at91_led_list, list)
+		led_classdev_suspend(&led->cdev);
+
+	return 0;
+}
+
+static int at91_led_resume(struct platform_device *dev)
+{
+	struct at91_led	*led;
+
+	list_for_each_entry (led, &at91_led_list, list)
+		led_classdev_resume(&led->cdev);
+
+	return 0;
+}
+#else
+#define	at91_led_suspend	NULL
+#define	at91_led_resume		NULL
+#endif
+
+static struct platform_driver at91_led_driver = {
+	.probe		= at91_led_probe,
+	.remove		= __devexit_p(at91_led_remove),
+	.suspend	= at91_led_suspend,
+	.resume		= at91_led_resume,
+	.driver		= {
+		.name	= "at91_leds",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91_led_init(void)
+{
+	return platform_driver_register(&at91_led_driver);
+}
+module_init(at91_led_init);
+
+static void __exit at91_led_exit(void)
+{
+	platform_driver_unregister(&at91_led_driver);
+}
+module_exit(at91_led_exit);
+
+MODULE_DESCRIPTION("AT91 GPIO LED driver");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
diff -uprN linux-2.6.20/drivers/misc/Kconfig linux-2.6.20-at92_e1.5/drivers/misc/Kconfig
--- linux-2.6.20/drivers/misc/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -88,4 +88,6 @@ config MSI_LAPTOP
 
 	  If you have an MSI S270 laptop, say Y or M here.
 
+source "drivers/misc/classes/Kconfig"
+
 endmenu
diff -uprN linux-2.6.20/drivers/misc/Makefile linux-2.6.20-at92_e1.5/drivers/misc/Makefile
--- linux-2.6.20/drivers/misc/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -10,3 +10,4 @@ obj-$(CONFIG_LKDTM)		+= lkdtm.o
 obj-$(CONFIG_TIFM_CORE)       	+= tifm_core.o
 obj-$(CONFIG_TIFM_7XX1)       	+= tifm_7xx1.o
 obj-$(CONFIG_SGI_IOC4)		+= ioc4.o
+obj-y						+= classes/ 
\ No newline at end of file
diff -uprN linux-2.6.20/drivers/misc/classes/Kconfig linux-2.6.20-at92_e1.5/drivers/misc/classes/Kconfig
--- linux-2.6.20/drivers/misc/classes/Kconfig	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/Kconfig	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,94 @@
+#
+# Input device configuration
+#
+
+menu "misc device classes"
+
+config GPIOCLASS
+        bool "GPIO class"
+        ---help---
+	  This is a set of classes for general purpose io ports.
+	  These devices typically contain a data register, 
+	  which holds the current state of the pins, and a ddr register, 
+	  which sets the pin to input or output, 0 or 1 respectively 
+
+config GPIOCLASS_SYSFS
+		depends on SYSFS && GPIOCLASS
+        bool "sysfs interface"
+        ---help---
+	  enables a sysfs interface to the gpio class
+
+config GPIOCLASS_RTDM 
+		depends on XENO_SKIN_RTDM && GPIOCLASS
+        bool "rtdm interface"
+        ---help---
+	  enables a Xenomai RTDM interface to the gpio class
+	  
+config GPIOCLASS_CHAR
+		depends on GPIOCLASS
+		bool "char interface"
+		---help---
+		Enables a character device interface to the GPIO class.
+
+config PWMCLASS
+        bool "PWM class"
+        ---help---
+	  This is a set of classes for pulse width modulation.
+	  It allows the creation of pwm classes which can be configured
+	  through sysfs. PWM devices typically contain a 
+	  duty and frequency configuration register.
+	  
+config PWMCLASS_SYSFS
+		depends on SYSFS && PWMCLASS
+        bool "sysfs interface"
+        ---help---
+	  enables a sysfs interface to the pwm class
+
+config PWMCLASS_RTDM 
+		depends on XENO_SKIN_RTDM && PWMCLASS
+        bool "rtdm interface"
+        ---help---
+	  enables a Xenomai RTDM interface to the pwm class	  
+	  
+config MMCCLASS
+        bool "SPI/MMC class based driver"
+        ---help---
+        A MMC/SD class for transferring MMC information to a block driver layer.
+        Designed for providing board specific syncronizations 
+        between periodic spi devices and mmc block devices.
+        This class allows the mach to orchistrate low level spi interactions.   
+        
+config SPICLASS
+        bool "SPI class"
+        ---help---
+	  This is a set of classes for SPI interfaces.
+	  It allows the creation of spi classes which can be configured
+	  through sysfs.SPI devices typically contain a 
+	  speed and flags register, a method for locking the bus, 
+	  and a bidirectional "xmit" method     
+
+config SPICLASS_SYSFS
+		depends on SYSFS && SPICLASS
+        bool "sysfs interface"
+        ---help---
+	  enables a sysfs interface to the spi class
+
+config SPICLASS_CHAR
+		depends on SPICLASS
+		bool "char interface"
+		---help---
+		Enables a character device interface to the spi class.
+
+config LSI2ESC
+        depends on SPICLASS
+        bool "Linux SPI Interface to EMAC SPI Class interface"
+        ---help---
+        Enables a generic interface between the Linux SPI
+        driver and the EMAC SPI Class. Boards with an SPI controller
+        driver can use this to define generic access to a device
+        through the EMAC SPI class.
+        
+endmenu
+
+
+
diff -uprN linux-2.6.20/drivers/misc/classes/Makefile linux-2.6.20-at92_e1.5/drivers/misc/classes/Makefile
--- linux-2.6.20/drivers/misc/classes/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/Makefile	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,13 @@
+#
+# Makefile for the misc classes
+#
+
+EXTRA_CFLAGS += -Iinclude/xenomai
+obj-$(CONFIG_GPIOCLASS)		+= gpio.o
+obj-$(CONFIG_PWMCLASS)		+= pwm.o
+obj-$(CONFIG_MMCCLASS)		+= mmc.o
+obj-$(CONFIG_SPICLASS)		+= spi.o
+obj-$(CONFIG_LSI2ESC)       += spi_interface.o
+mmc-y := mmcprot.o mmcblock.o
+obj-y += rtdm/
+obj-y += char/
diff -uprN linux-2.6.20/drivers/misc/classes/char/Makefile linux-2.6.20-at92_e1.5/drivers/misc/classes/char/Makefile
--- linux-2.6.20/drivers/misc/classes/char/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/char/Makefile	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,6 @@
+#
+# Makefile for the misc char classes
+#
+
+obj-$(CONFIG_GPIOCLASS_CHAR)	+= gpio_char.o
+obj-$(CONFIG_SPICLASS_CHAR)		+= spi_char.o
\ No newline at end of file
diff -uprN linux-2.6.20/drivers/misc/classes/char/gpio_char.c linux-2.6.20-at92_e1.5/drivers/misc/classes/char/gpio_char.c
--- linux-2.6.20/drivers/misc/classes/char/gpio_char.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/char/gpio_char.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,209 @@
+/**
+ * A character device interface to gpio devices. Part of the GPIO class.
+ * 
+ */
+
+/* TODO: analyze these includes to weed out any that are unnecessary */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/class/gpio.h>
+#include <linux/class/char/gpio_char.h>
+#include <asm/uaccess.h>
+
+static int gpio_major =    GPIO_MAJOR;
+static int gpio_minor =    0;
+static int gpio_num_devs = GPIO_MAX_DEVS;
+
+struct gpio_char_dev {
+    gpio_t *gpio;
+    struct cdev cdev;
+};
+
+//#define DEBUG_GC
+
+#ifdef DEBUG_GC
+#define DPRINTK(string, args...) printk("gpio_char: " string, ##args)
+#else
+#define DPRINTK(string, args...)
+#endif
+
+/* function prototypes */
+static int gpio_char_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg);
+static int gpio_char_open(struct inode *inode, struct file *file);
+static int gpio_char_release(struct inode *inode, struct file *file);
+static int gpio_char_setup_cdev(struct gpio_char_dev *dev);
+
+/* struct for fops declarations */
+static const struct file_operations gpio_char_fops =
+{ 
+    .ioctl   = gpio_char_ioctl, 
+    .open    = gpio_char_open,
+    .release = gpio_char_release,
+};
+
+static int gpio_char_open(struct inode *inode, struct file *file)
+{
+    struct gpio_char_dev *dev; /* device information */
+    DPRINTK("gpio_char_open\n");
+    /* TODO: This may or may not be necessary */
+    dev = container_of(inode->i_cdev, struct gpio_char_dev, cdev);
+    file->private_data = dev;
+    return 0;
+}
+
+static int gpio_char_release(struct inode *inode, struct file *file)
+{
+    DPRINTK("gpio_char_release\n");
+    /* nothing to do here */
+    return 0;
+}
+
+static int gpio_char_ioctl(struct inode *inode, struct file *file,
+        unsigned int cmd, unsigned long arg)
+{
+    struct gpio_char_dev *dev = container_of(inode->i_cdev, struct gpio_char_dev, cdev);
+    gpio_t *gpio = dev->gpio;
+    gpio_data kmem[1];
+    int ret;
+    
+    /* make sure that this command is indeed one of gpio_char's */
+    if (_IOC_TYPE(cmd) != CHAR_CLASS_GPIO)
+        return -ENOTTY;
+    
+    switch(cmd)
+    {
+    case DDRREAD:
+        DPRINTK("DDRREAD ioctl\n");
+        if (gpio->ddr_read)
+            kmem[0] = atomic_gpio_ddr_read(gpio);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(gpio_data)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case DDRWRITE:
+        DPRINTK("DDRWRITE ioctl\n");
+        if (copy_from_user(kmem, (void *)arg, sizeof(gpio_data)) != 0)
+            return -EFAULT;
+        if (gpio->ddr_write)
+            atomic_gpio_ddr_write(gpio, kmem[0]);
+        else 
+            return -EFAULT;
+        return 0;
+        break;
+    case DATAREAD:
+        DPRINTK("DATAREAD ioctl\n");
+        if (gpio->data_read)
+            kmem[0] = atomic_gpio_data_read(gpio);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(gpio_data)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case DATAWRITE:
+        DPRINTK("DATAWRITE ioctl\n");
+        if (copy_from_user(kmem, (void *)arg, sizeof(gpio_data)) != 0)
+            return -EFAULT;
+        if (gpio->data_write)
+            atomic_gpio_data_write(gpio, kmem[0]);
+        else {
+            DPRINTK("error: invalid data_write\n");
+            return -EFAULT;
+        }
+        return 0;
+        break;
+    case INDEXREAD:
+        DPRINTK("INDEXREAD ioctl\n");
+        if (gpio->index_read)
+            kmem[0] = atomic_gpio_index_read(gpio);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(gpio_data)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case INDEXWRITE:
+        DPRINTK("INDEXWRITE ioctl\n");
+        if ((ret = copy_from_user(kmem, (void __user *)arg, sizeof(gpio_data))) != 0) {
+            DPRINTK("copy_from_user returned error: %d bytes not copied\n", ret);
+            return -EFAULT;
+        }
+        if (gpio->index_write)
+            atomic_gpio_index_write(gpio, kmem[0]);
+        else {
+            DPRINTK("invalid index_write command\n");
+            return -EFAULT;
+        }
+        return 0;
+        break;
+    default :
+        DPRINTK("ioctl: no such command\n");
+        return -ENOTTY;
+    } /* END switch(cmd) */
+    DPRINTK("Invalid state, broke out of switch\n");
+    return -EFAULT; /* Error, we should never reach here */    
+}
+
+/* initialize the character interface -- called by gpio class on init */
+
+int gpio_char_init(void)
+{
+    int result;
+    dev_t dev = 0;
+    DPRINTK("gpio_char_init\n");
+    /* dynamic and static character device allocation */
+    if (gpio_major) {
+        dev = MKDEV(gpio_major, gpio_minor);
+        result = register_chrdev_region(dev, gpio_num_devs, "gpio_char");
+    }
+    else {
+        result = alloc_chrdev_region(&dev, gpio_minor, 
+                gpio_num_devs, "gpio_char");
+        gpio_major = MAJOR(dev);
+    }
+    if (result < 0)
+        printk(KERN_WARNING "gpio_char: can't get major %d, err %d\n", gpio_major,result);
+    
+    return result;
+}
+
+/* registers the actual char device, called by create when invoked by gpio class */
+
+static int gpio_char_setup_cdev(struct gpio_char_dev *dev)
+{
+    static int index = 0;
+    int err, devno = MKDEV(gpio_major, gpio_minor + index);
+    
+    DPRINTK("gpio_char_setup_cdev\n");
+    
+    cdev_init(&dev->cdev, &gpio_char_fops);
+    dev->cdev.owner = THIS_MODULE; /* not sure if this is still valid */
+    dev->cdev.ops = &gpio_char_fops;
+    err = cdev_add(&dev->cdev, devno, 1);
+    if (err)
+        printk(KERN_NOTICE "gpio_char: Error %d adding gpio_char%d\n", err, index);
+    
+    index++;
+    return devno;
+}
+
+/* create and register a new char device */
+
+int gpio_char_create(struct gpio_s *gpio)
+{
+    struct gpio_char_dev *chardev = kmalloc(sizeof(struct gpio_char_dev),GFP_KERNEL);
+    DPRINTK("gpio_char_create\n");
+    if (!chardev) {
+        printk(KERN_NOTICE "Error allocating memory\n");
+        return -ENOMEM;
+    }
+    chardev->gpio = gpio;
+    
+    return gpio_char_setup_cdev(chardev);
+}
diff -uprN linux-2.6.20/drivers/misc/classes/char/spi_char.c linux-2.6.20-at92_e1.5/drivers/misc/classes/char/spi_char.c
--- linux-2.6.20/drivers/misc/classes/char/spi_char.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/char/spi_char.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,223 @@
+/**
+ * A character device interface to spi devices. Part of the SPI class.
+ * 
+ */
+
+/* TODO: analyze these includes to weed out any that are unnecessary */
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/class/spi.h>
+#include <linux/class/char/spi_char.h>
+#include <asm/uaccess.h>
+
+static int spi_major =    SPI_MAJOR;
+static int spi_minor =    0;
+static int spi_num_devs = SPI_MAX_DEVS;
+
+struct spi_char_dev {
+    spi_t *spi;
+    struct cdev cdev;
+};
+
+//#define DEBUG_SC
+
+#ifdef DEBUG_SC
+#define DPRINTK(string, args...) printk("spi_char: " string, ##args)
+#else
+#define DPRINTK(string, args...)
+#endif
+
+/* function prototypes */
+static int spi_char_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg);
+static int spi_char_open(struct inode *inode, struct file *file);
+static int spi_char_release(struct inode *inode, struct file *file);
+static int spi_char_setup_cdev(struct spi_char_dev *dev);
+
+/* struct for fops declarations */
+static const struct file_operations spi_char_fops =
+{ 
+    .ioctl   = spi_char_ioctl, 
+    .open    = spi_char_open,
+    .release = spi_char_release,
+};
+
+static int spi_char_open(struct inode *inode, struct file *file)
+{
+    struct spi_char_dev *dev; /* device information */
+    DPRINTK("spi_char_open\n");
+    /* TODO: This may or may not be necessary */
+    dev = container_of(inode->i_cdev, struct spi_char_dev, cdev);
+    file->private_data = dev;
+    return 0;
+}
+
+static int spi_char_release(struct inode *inode, struct file *file)
+{
+    DPRINTK("spi_char_release\n");
+    /* nothing to do here */
+    return 0;
+}
+
+static int spi_char_ioctl(struct inode *inode, struct file *file,
+        unsigned int cmd, unsigned long arg)
+{
+    struct spi_char_dev *dev = container_of(inode->i_cdev, struct spi_char_dev, cdev);
+    spi_t *spi = dev->spi;
+    spi_control kmem[1];
+    
+    /* make sure that this command is indeed one of spi_char's */
+    if (_IOC_TYPE(cmd) != CHAR_CLASS_SPI)
+        return -ENOTTY;
+    
+    switch(cmd)
+    {
+    case XMIT:{
+    	spi_transfer_t *t=NULL;
+    	spi_data *buf=NULL;
+    	int errval=0;
+        DPRINTK("XMIT ioctl\n");
+        if (!spi->xmit)return -EFAULT;//method not available
+        if (copy_from_user(t, (void *)arg, sizeof(spi_transfer_t)) != 0){errval=-EFAULT;goto cleanup;}
+        if(t->size==0)return 0;//not an error, but nothing to do
+        if((t->miso)||(t->mosi))buf = kmalloc(t->size,GFP_KERNEL);
+        if(t->mosi)if (copy_from_user(buf, t->mosi, t->size) != 0){errval=-EFAULT;goto cleanup;}
+        if(atomic_spi_xmit(spi,t->mosi?buf:NULL,t->miso?buf:NULL,t->size)!=0){errval=-EFAULT;goto cleanup;}
+        if(t->miso)if(copy_to_user(t->miso, buf, t->size)!= 0 ){errval=-EFAULT;goto cleanup;}
+cleanup:
+        if(buf)kfree(buf);
+        return errval;
+        break;
+    }
+    case CONFREAD:
+        DPRINTK("CONFREAD ioctl\n");
+        if (spi->confread)
+            kmem[0] = atomic_spi_conf_read(spi);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(spi_control)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case CONFWRITE:
+        DPRINTK("CONFWRITE ioctl\n");
+        if (copy_from_user(kmem, (void *)arg, sizeof(spi_control)) != 0)
+            return -EFAULT;
+        if (spi->confwrite)
+            atomic_spi_conf_write(spi, kmem[0]);
+        else 
+            return -EFAULT;
+        return 0;
+        break;
+    case SPEEDREAD:
+        DPRINTK("SPEEDREAD ioctl\n");
+        if (spi->speedread)
+            kmem[0] = atomic_spi_speed_read(spi);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(spi_control)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case SPEEDWRITE:
+        DPRINTK("SPEEDWRITE ioctl\n");
+        if (copy_from_user(kmem, (void *)arg, sizeof(spi_control)) != 0)
+            return -EFAULT;
+        if (spi->speedwrite)
+            atomic_spi_speed_write(spi, kmem[0]);
+        else {
+            DPRINTK("error: invalid speed write\n");
+            return -EFAULT;
+        }
+        return 0;
+        break;
+    case TIPREAD:
+        DPRINTK("TIPREAD ioctl\n");
+        if (spi->tip)
+            kmem[0] = atomic_spi_tip_read(spi);
+        else
+            return -EFAULT;
+        return (copy_to_user((void *)arg, kmem, sizeof(spi_control)) == 0 ) ? 0 : -EFAULT;
+        break;
+    case TIPWRITE:
+        DPRINTK("TIPWRITE ioctl\n");
+        if (copy_from_user(kmem, (void *)arg, sizeof(spi_control)) != 0)
+            return -EFAULT;
+        if (spi->tip)
+            atomic_spi_tip_write(spi, kmem[0]);
+        else {
+            DPRINTK("error: invalid speed write\n");
+            return -EFAULT;
+        }
+        return 0;
+        break;
+    default :
+        DPRINTK("ioctl: no such command\n");
+        return -ENOTTY;
+    } /* END switch(cmd) */
+    DPRINTK("Invalid state, broke out of switch\n");
+    return -EFAULT; /* Error, we should never reach here */    
+}
+
+/* initialize the character interface -- called by spi class on init */
+
+int spi_char_init(void)
+{
+    int result;
+    dev_t dev = 0;
+    DPRINTK("spi_char_init\n");
+    /* dynamic and static character device allocation */
+    if (spi_major) {
+        dev = MKDEV(spi_major, spi_minor);
+        result = register_chrdev_region(dev, spi_num_devs, "spi_char");
+    }
+    else {
+        result = alloc_chrdev_region(&dev, spi_minor, 
+                spi_num_devs, "spi_char");
+        spi_major = MAJOR(dev);
+    }
+    if (result < 0)
+        printk(KERN_WARNING "spi_char: can't get major %d, err %d\n", spi_major,result);
+    
+    return result;
+}
+
+/* registers the actual char device, called by create when invoked by spi class */
+
+static int spi_char_setup_cdev(struct spi_char_dev *dev)
+{
+    static int index = 0;
+    int err, devno = MKDEV(spi_major, spi_minor + index);
+    
+    DPRINTK("spi_char_setup_cdev\n");
+    
+    cdev_init(&dev->cdev, &spi_char_fops);
+    dev->cdev.owner = THIS_MODULE; /* not sure if this is still valid */
+    dev->cdev.ops = &spi_char_fops;
+    err = cdev_add(&dev->cdev, devno, 1);
+    if (err)
+        printk(KERN_NOTICE "spi_char: Error %d adding spi_char%d\n", err, index);
+    
+    index++;
+    return devno;
+}
+
+/* create and register a new char device */
+
+int spi_char_create(struct spi_s *spi)
+{
+    struct spi_char_dev *chardev = kmalloc(sizeof(struct spi_char_dev),GFP_KERNEL);
+    DPRINTK("spi_char_create\n");
+    if (!chardev) {
+        printk(KERN_NOTICE "Error allocating memory\n");
+        return -ENOMEM;
+    }
+    chardev->spi = spi;
+    
+    return spi_char_setup_cdev(chardev);
+}
diff -uprN linux-2.6.20/drivers/misc/classes/gpio.c linux-2.6.20-at92_e1.5/drivers/misc/classes/gpio.c
--- linux-2.6.20/drivers/misc/classes/gpio.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/gpio.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,179 @@
+/**
+ * A class for simple gpio ports
+ * Several types of general purpose devices are available 
+ * which all export the same basic functionity 
+ * through different underlying methods
+ * This class can also be used to export simple interfaces
+ * to an 8 bit port into user space
+ */
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/kdev_t.h>
+#include <linux/chelper.h>
+#include <linux/class/gpio.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_GPIOCLASS_RTDM
+#include <rtdm/rtdm_driver.h>
+#include <linux/class/rtdm/gpio_rtdm.h>
+#define ATOMIC(a) RTDM_EXECUTE_ATOMICALLY(a)
+#else
+#define ATOMIC(a) a
+#endif //CONFIG_GPIOCLASS_RTDM
+
+#ifdef CONFIG_GPIOCLASS_CHAR
+#include <linux/class/char/gpio_char.h>
+#endif
+
+/************************************************************
+ * the global device class
+ */
+static struct class *gpioclass = NULL;
+
+struct class *gpio_declare(void){
+	if(!gpioclass){
+		printk("registering GPIO class\n");
+		gpioclass=class_create(THIS_MODULE,"gpio");
+#ifdef CONFIG_GPIOCLASS_CHAR
+		gpio_char_init();
+#endif
+	}
+	return gpioclass;
+}
+
+/***************************************************************************
+ * typical low level methods for accessing 8 bit ports
+ */
+ 
+int  gpio_ddr_write8(gpio_t *gpio, gpio_data data){iowrite8(data,gpio->ddr+gpio->index);return 0;}
+
+int  gpio_data_write8(gpio_t *gpio, gpio_data data){iowrite8(data,gpio->data+gpio->index);gpio->shadow=data;return 0;}
+
+int  gpio_index_write(gpio_t *gpio, gpio_data data){data = (data>gpio->range)?gpio->range:data;gpio->index = data;return 0;}
+
+int  gpio_empty_write(gpio_t *gpio, gpio_data data){return 0;}
+
+gpio_data gpio_ddr_read8(gpio_t *gpio){return ioread8(gpio->ddr+gpio->index);}
+
+gpio_data gpio_data_read8(gpio_t *gpio){return ioread8(gpio->data+gpio->index);}
+
+gpio_data gpio_index_read(gpio_t *gpio){return gpio->index;}
+
+gpio_data gpio_shadow_read8(gpio_t *gpio){return gpio->shadow;}
+	
+gpio_data gpio_ff_read(gpio_t *gpio){return 0xff;}
+	
+gpio_data gpio_zero_read(gpio_t *gpio){return 0;}
+
+/***************************************************************************
+ * Atomic method wrappers
+ */
+int atomic_gpio_ddr_write(gpio_t *gpio,gpio_data data){
+	ATOMIC(gpio->ddr_write(gpio,data);)
+	return 0;
+}
+	
+gpio_data atomic_gpio_ddr_read(gpio_t *gpio){
+	gpio_data retval;
+	ATOMIC(retval = gpio->ddr_read(gpio);)
+	return retval;
+}
+
+int atomic_gpio_data_write(gpio_t *gpio,gpio_data data){
+	ATOMIC(gpio->data_write(gpio,data);)
+	return 0;
+}
+	
+gpio_data atomic_gpio_data_read(gpio_t *gpio){
+	gpio_data retval;
+	ATOMIC(retval = gpio->data_read(gpio);)
+	return retval;
+}
+
+int atomic_gpio_index_write(gpio_t *gpio,gpio_data data){
+	ATOMIC(gpio->index_write(gpio,data);)
+	return 0;
+}
+	
+gpio_data atomic_gpio_index_read(gpio_t *gpio){
+	gpio_data retval;
+	ATOMIC(retval = gpio->index_read(gpio);)
+	return retval;
+}
+
+/***************************************************************************
+ * gpio sysfs operations
+ */
+#ifdef CONFIG_GPIOCLASS_SYSFS
+static ssize_t gpio_data_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	gpio_t *gpio = cls->class_data;
+	gpio_data data = sfs_getint(buf,count,&size);
+	atomic_gpio_data_write(gpio, data);
+	return size;
+}
+
+static ssize_t gpio_ddr_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	gpio_t *gpio = cls->class_data;
+	gpio_data data = sfs_getint(buf,count,&size);
+	atomic_gpio_ddr_write(gpio, data);
+	return size;
+}
+
+static ssize_t gpio_index_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	gpio_t *gpio = cls->class_data;
+	gpio_data data = sfs_getint(buf,count,&size);
+	atomic_gpio_index_write(gpio, data);
+	return size;
+}
+
+static ssize_t gpio_data_show(struct class_device *cls, char *buf){
+	gpio_t *gpio = cls->class_data;
+	return sprintf(buf,"%x\r\n",atomic_gpio_data_read(gpio));
+}
+
+static ssize_t gpio_ddr_show(struct class_device *cls, char *buf){
+	gpio_t *gpio = cls->class_data;
+	return sprintf(buf,"%x\r\n",atomic_gpio_ddr_read(gpio));
+}
+
+static ssize_t gpio_index_show(struct class_device *cls, char *buf){
+	gpio_t *gpio = cls->class_data;
+	return sprintf(buf,"%x\r\n",atomic_gpio_index_read(gpio));
+}
+
+static CLASS_DEVICE_ATTR(ddr,S_IRUGO|S_IWUGO,gpio_ddr_show,gpio_ddr_store);
+static CLASS_DEVICE_ATTR(data,S_IRUGO|S_IWUGO,gpio_data_show,gpio_data_store);
+static CLASS_DEVICE_ATTR(index,S_IRUGO|S_IWUGO,gpio_index_show,gpio_index_store);
+#endif //CONFIG_GPIOCLASS_SYSFS
+/***************************************************************************
+* class instantiation
+*/
+struct class_device *gpio_register_class_device(gpio_t *gpio){		
+struct class *gpio_master = gpio_declare();
+struct class_device *dev;	
+dev_t devnum = MKDEV(0, 0);
+
+#ifdef CONFIG_GPIOCLASS_CHAR
+devnum = gpio_char_create(gpio);
+#endif	
+	
+dev = class_device_create(gpio_master, NULL, devnum, NULL, gpio->name);
+dev->class_data = gpio;	
+
+#ifdef CONFIG_GPIOCLASS_SYSFS
+	if((gpio->ddr_write)&&(gpio->ddr_read))class_device_create_file(dev,&class_device_attr_ddr);
+	if((gpio->data_write)&&(gpio->data_read))class_device_create_file(dev,&class_device_attr_data);
+	if((gpio->index_write)&&(gpio->index_read))class_device_create_file(dev,&class_device_attr_index);
+#endif	 
+
+#ifdef CONFIG_GPIOCLASS_RTDM
+	rt_gpio_device_create(gpio);
+#endif
+
+return dev;			
+}
diff -uprN linux-2.6.20/drivers/misc/classes/mmcblock.c linux-2.6.20-at92_e1.5/drivers/misc/classes/mmcblock.c
--- linux-2.6.20/drivers/misc/classes/mmcblock.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/mmcblock.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,269 @@
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+
+#include <linux/kernel.h>	
+#include <linux/slab.h>		
+#include <linux/fs.h>		
+#include <linux/errno.h>	
+#include <linux/types.h>	
+#include <linux/fcntl.h>	
+#include <linux/hdreg.h>	
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/buffer_head.h>	
+#include <linux/bio.h>
+#include <linux/timer.h>
+
+#include <linux/class/mmcprot.h>
+#include <linux/class/mmcblock.h>
+
+/***************************************************************************
+ * External Functions from mcf_mmc_prot
+ ***************************************************************************/
+#define DEVICE_NAME "mmc"
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+#define MAJOR_NR 121
+
+/*
+ * We can tweak our hardware sector size, but the kernel talks to us
+ * in terms of small sectors, always.
+ */
+#define KERNEL_SECTOR_SIZE	512
+
+MODULE_AUTHOR("N.Z. Gustavson <ngustavson@emacinc.com");
+MODULE_DESCRIPTION("Driver for MMC/SD Cards");
+
+#define MMC_MINORS 16
+
+/**
+ * Block transfer implementation for the mmc/sd 
+ * This is the base hardware transfer function for all block driver calls.
+ */
+static inline int mmctransfer(mmcslot_t *s, unsigned long sector,
+		unsigned long nsect, char *buffer, int write){
+			
+	unsigned long offset = sector*KERNEL_SECTOR_SIZE;
+	unsigned long nbytes = nsect*KERNEL_SECTOR_SIZE;		
+	unsigned long blocks = nbytes/s->card.blocklength;
+	
+	MMCBDEBUG("mmc transfer\n");
+	MMCBDEBUG("mmc sector %lu\n",sector);
+	MMCBDEBUG("mmc nsect %lu\n",nsect);
+	MMCBDEBUG("mmc nbytes %lu\n",nbytes);
+    MMCBDEBUG("s->card.blocklength %u\n",s->card.blocklength);
+	
+	if ((offset + nbytes) > s->card.size) {
+		printk ("Beyond-end write (%ld %ld)\n", offset, nbytes);
+		return -1;
+	}
+	
+	if (blocks==0) {
+		printk ("Device blocklength>%u not supported\n",KERNEL_SECTOR_SIZE);
+		return -1;
+	}
+		
+	if (write)
+		return(WRITE_MULTIPLE_BLOCK(s,offset, buffer, s->card.blocklength, blocks));
+	else
+		return(READ_MULTIPLE_BLOCK(s,offset,buffer,s->card.blocklength,blocks));	
+}
+
+/**
+ * request implementation
+ */
+void mmc_request(request_queue_t *q){
+		
+	struct request *req;		
+	MMCBDEBUG("mmc_request\n"); 
+	
+		while ((req = elv_next_request(q)) != NULL) {
+			mmcslot_t *s = req->rq_disk->private_data;				
+				
+		if (!(s->state&READY)){
+			printk("Device is not currently valid\n");
+			end_request(req, 0);
+			continue;
+		}
+		
+		if (!blk_fs_request(req)) {
+			MMCBDEBUG (KERN_NOTICE "Skip non-fs request\n");
+			end_request(req, 0);
+			continue;
+		}
+					
+			if((mmctransfer(s, req->sector, req->current_nr_sectors,
+					req->buffer, rq_data_dir(req)))<0){
+				MMCBDEBUG ("transfer failed\n");							
+				end_request(req,0);//failure				
+				}
+			else{
+				MMCBDEBUG ("transfer success\n");
+				end_request(req,1);	//success	
+			}			
+		}	
+	MMCBDEBUG("mmc_request end\n");
+	}
+
+
+/******************************************************************************
+ * Removable media support
+ ******************************************************************************/
+static int mmc_check_media_change(struct gendisk *gd){
+mmcslot_t *s = gd->private_data;
+return(s->state&CHANGED ? 1:0);		
+}
+
+static int mmc_revalidate(struct gendisk *gd){
+mmcslot_t *s = gd->private_data;
+if (s->state==(CHANGED|VALID)){
+	int err;
+	printk("MMC media change detected, reinitializing\n");
+	if((err=mmcinit(s))<0){
+		printk("failed to initialize card\n");
+		s->state = INVALID;
+		return err;
+	}
+	set_capacity(gd, s->card.sectors*(s->card.blocklength/KERNEL_SECTOR_SIZE));
+	MMCBDEBUG("set capacity to %u\n",s->card.sectors*(s->card.blocklength/KERNEL_SECTOR_SIZE));
+	MMCBDEBUG("sectors=%u\n",s->card.sectors);
+	MMCBDEBUG("CSIZE=%u\n",s->card.CSD.C_SIZE);
+	MMCBDEBUG("CMULT=%u\n",s->card.CSD.C_SIZE_MULT);
+	s->state = VALID|READY;	
+}
+return -ENODEV;
+}
+
+/******************************************************************************
+ * Standard block driver file operations
+ ******************************************************************************/
+/**
+ * block device open 
+ */
+static int mmc_open(struct inode *inode, struct file *filp){
+	mmcslot_t *s = inode->i_bdev->bd_disk->private_data;
+	//struct gendisk *gd = s->private_data;	
+	
+	MMCBDEBUG("mmc_open\n"); 
+	
+	filp->private_data = s;
+	checkmedia_stop(s);
+	spin_lock(&s->lock); 
+	check_disk_change(inode->i_bdev);
+	if (!(s->state&READY)){
+			printk ("%s device not ready\n",s->name);
+			spin_unlock(&s->lock);
+			if(!s->users)checkmedia_start(s);//if no users remain, begin checking for media change again.
+			return -ENODEV;
+		}
+		
+	s->users++;
+	spin_unlock(&s->lock);		
+	return 0;
+}
+
+static int mmc_release(struct inode *inode, struct file *filp)
+{
+	mmcslot_t *s = inode->i_bdev->bd_disk->private_data;
+	MMCBDEBUG("mmc_release - getting lock\n"); 
+	spin_lock(&s->lock);
+	MMCBDEBUG("obtained lock\n"); 
+	s->users--;
+	if(!s->users)checkmedia_start(s);//if no users remain, begin checking for media change again.
+	spin_unlock(&s->lock);
+	MMCBDEBUG("released lock\n"); 
+	return 0;
+}
+
+static int mmc_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
+{
+	struct hd_geometry geometry;
+	//mmcslot_t *s = filp->private_data;
+	struct block_device *bdev = inode->i_bdev;
+	mmcslot_t *s = inode->i_bdev->bd_disk->private_data;
+	
+	if(!bdev){MMCBDEBUG("block device doesn't exist\n");return -EINVAL;}
+	if(!s){MMCBDEBUG("mmcslot doesn't exist\n");return -EINVAL;}
+	
+	MMCBDEBUG("mmc_ioctl\n"); 
+	
+	if (!(s->state&READY)){
+			printk ("Device is not currently valid\n");
+			return -ENODEV;
+		}
+	
+	if (cmd == BLKGETSIZE)
+	{
+		MMCBDEBUG("   BLKGETSIZE\n");
+		if (!arg) return -EINVAL;
+		if (copy_to_user((long *) arg, (long *) &s->card.blocklength, sizeof(s->card.blocklength))) return -EFAULT;
+		return 0;
+	}
+	else if (cmd == HDIO_GETGEO)
+	{
+		MMCBDEBUG("   HDIO_GETGEO\n");
+		if (!arg) return -EINVAL;
+		
+		geometry.cylinders	= get_capacity(bdev->bd_disk) / (4 * 16);
+		geometry.heads	= 4;
+		geometry.sectors	= 16;
+		geometry.start	= get_start_sect(bdev);
+		
+		if (copy_to_user((void *) arg, &geometry, sizeof(geometry))) return -EFAULT;
+		return 0;
+	}
+	else return -ENOTTY; /* unknown command */
+}
+
+static struct block_device_operations mmc_bdops = {
+	.owner           		= THIS_MODULE,
+	.open						=  mmc_open,
+	.release					=  mmc_release,
+	.ioctl 						=  mmc_ioctl,
+	.media_changed	= mmc_check_media_change,
+	.revalidate_disk	= mmc_revalidate,
+};
+/******************************************************************************
+ * driver initializations
+ ******************************************************************************/
+
+int mmc_diskize(mmcslot_t *s){
+	struct gendisk *gd = alloc_disk(MMC_MINORS);		
+	
+	MMCBDEBUG("setup device %s\n",s->name);	
+			 
+	gd->private_data =  s;
+	gd->major = MAJOR_NR;
+	gd->first_minor = s->slotnumber*MMC_MINORS;
+	gd->fops = &mmc_bdops;
+	gd->flags = GENHD_FL_REMOVABLE;
+	
+	if((gd->queue=blk_init_queue(mmc_request,&s->lock))==NULL){
+		printk("couldn't init block queue\n");
+		return -1;
+	}
+			
+	blk_queue_hardsect_size(gd->queue,s->card.blocklength);
+	gd->queue->queuedata = s;
+	snprintf (gd->disk_name, 32, s->name);
+
+	s->disk = gd;
+
+	add_disk(gd); 
+		
+	return 0;
+}
+
+int mmc_bdriver_init(void)
+{
+	register_blkdev(MAJOR_NR, DEVICE_NAME);
+	MMCBDEBUG("mmc block driver registered\n");
+	return 0;
+}
+
+void mmc_bdriver_exit(void)
+{
+	MMCBDEBUG("mmc block driver removed\n");	
+}
diff -uprN linux-2.6.20/drivers/misc/classes/mmcprot.c linux-2.6.20-at92_e1.5/drivers/misc/classes/mmcprot.c
--- linux-2.6.20/drivers/misc/classes/mmcprot.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/mmcprot.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,601 @@
+#define EXPORT_SYMTAB
+
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/wait.h>
+#include <linux/delay.h>
+#include <linux/platform_device.h>
+#include <linux/class/mmcprot.h>
+#include <linux/class/mmcblock.h>
+
+#define DRV_MODULE_NAME 	"mmc"
+#define DRV_MODULE_VERSION 	"1.0"
+
+//#define MMCHARDERROR
+#ifdef MMCHARDERROR
+//debugging error, hard lock to find signal error via scope
+#define MMCERROR(err)	{printk("%s:MMCERR %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); while (1);}
+#else
+//return an error value on invalid communication.
+#define MMCERROR(err)	{return -err;}
+#endif
+
+
+static void checkmedia(unsigned long ptr){
+	mmcslot_t *s  = (mmcslot_t *)ptr;
+	//MMCDEBUG("checking media\n");
+	
+	if(!s->carddetect){s->state = INVALID;return;}//if cardetect is not implemented just return.
+	{
+	mmcslot_t *s = (mmcslot_t *)ptr;
+	int state = (s->carddetect(s))?VALID:INVALID;
+	if(state!=(s->state&VALID)){//state change
+  		printk("Multimedia card %s\n",state==VALID ? "inserted":"removed");	
+  		s->state = state|CHANGED;				  			
+	}
+	mod_timer(&s->timer,jiffies + HZ);//reset to probe next scheduler period	
+	}
+}
+
+
+void checkmedia_start(mmcslot_t *s){
+	setup_timer(&s->timer,checkmedia,(unsigned long)s);//make sure timer is initialized
+	checkmedia((unsigned long)s);//check immediately and reschedule
+}
+
+void checkmedia_stop(mmcslot_t *s){
+	del_timer_sync(&s->timer);//turn off the media check
+}
+
+
+
+static int mmcprot_probe(struct platform_device *pdev){	
+	if (pdev == NULL){MMCDEBUG("no platform device found\n");return -ENODEV;}
+	
+	{
+		mmcslot_t *s = pdev->dev.platform_data;
+		mmc_bdriver_init();//initialize block driver layer.
+		spin_lock_init(&s->lock);
+		s->card.blocklength = 512;//this could theoretically change dynamically, although in practice all cards use 512	
+		
+		MMCDEBUG("setting up timer\n");
+		checkmedia_start(s);
+		mmc_diskize(s);//setup a disk based upon this platform device.
+	}
+	
+	return 0;
+}
+
+//driver currently has no removal method.
+static struct platform_driver mmcprot_driver = {
+	.probe		= mmcprot_probe,
+	.driver		= {
+		.name	= "mmc",
+	},
+};
+
+static int __init mmcprot_init_module(void)
+{
+	printk(KERN_INFO DRV_MODULE_NAME " version " DRV_MODULE_VERSION " loading\n");
+	return platform_driver_register(&mmcprot_driver);
+}
+
+static void __exit mmcprot_cleanup_module(void)
+{
+	platform_driver_unregister(&mmcprot_driver);
+}
+
+module_init(mmcprot_init_module);
+module_exit(mmcprot_cleanup_module);
+
+/**********************************************************************************
+ * MMC transfer protocols
+ */
+
+/**
+	 * Fake CRC7. Currently the CRC is unused so
+	 * hard coded to 0x95 for the first(and only used)
+	 * CRC value
+	 * @param array array to calculate the CRC7 on
+	 * @return
+	 */
+static int CRC7(u8 *array){
+			return 0x95;
+		}
+
+/**
+	 * MMC packet building function
+	 * This function builds the command, clears and clears the remaining
+	 * frame which will be filled by the xmit function.
+	 * @param frame an array object to packetize
+	 * @param framelen size of the frame
+	 * @param command command index number
+	 * @param arg1 first arguement, high bits 31:16
+	 * @param arg2 second arguement, low bits 15:0
+	 * @param response number of response bits expected
+	 * @return 0
+	 */
+static int packetize(u8 *frame, int framelen, int command, int arg1, int arg2){
+		int START_BIT = 0;//MSB is zero
+		int TRANSMISSION_BIT = 0x40;
+		int STOP_BIT = 0x01;				
+		int bytenum;
+		
+		MMCDEBUG("packetize\n");
+		
+		frame[0] = (u8)((command|START_BIT|TRANSMISSION_BIT)&(0xff));
+		frame[1] = (u8)((arg1>>8)&(0xff));
+		frame[2] = (u8)((arg1)&(0xff));
+		frame[3] = (u8)((arg2>>8)&(0xff));
+		frame[4] = (u8)((arg2)&(0xff));
+		frame[5] = (u8)(CRC7(frame)|STOP_BIT);
+		
+		for(bytenum=COMMAND_LENGTH;bytenum<framelen;bytenum++)frame[bytenum] = (u8)0xff;
+	
+		return 0;
+	}
+
+/**
+	 * move the received response into int format
+	 * @param Rnum 1,2 or 5 number of bytes received
+	 * @param frame packet frame array
+	 * @param bytestart index of the Rx data in the frame
+	 * @return The response in int format
+	 */
+static int get_response(int Rnum, char *frame, int bytestart){
+		//int Rx = frame[bytestart];
+		u8 Rx = frame[bytestart];
+		MMCDEBUG("get_response Rnum = %x bytestart=%x\n",Rnum, bytestart);
+		
+		switch(Rnum){
+		case 1://standard command/response
+			//do nothing data already read
+		break;
+		case 2://two byte response
+			Rx<<=8;
+			Rx|=frame[bytestart+1];
+		break;
+		case 5:// five byte response,currently only the READ_OCR command uses this.
+			Rx = frame[bytestart+1];
+			Rx<<=8;
+			Rx |= frame[bytestart+2];
+			Rx<<=8;
+			Rx |= frame[bytestart+3];
+			Rx<<=8;
+			Rx |= frame[bytestart+4];
+			Rx<<=8;
+		break;	
+			}
+		return Rx;
+	}	
+
+/**
+ * Wait functions, read a short burst of data, then if nothing has arrived yet, sleep for
+ * a clock tick and try again with an eventual timeout.
+ */	
+	
+	/**
+	 * wait until the MMC returns a non-zero result
+	 * assumes pre-existing tip
+	 * @return 1
+	 */
+#define POLLNUMBER 100	 
+	 
+static int busy_wait(mmcslot_t *s){
+		int tickloop;
+		int shortloop;
+		u8 status=0;
+		
+		s->exchange(s,NULL, &status, 1);
+			
+		for(tickloop=0;tickloop<100;tickloop++){
+			for(shortloop=0;shortloop<POLLNUMBER;shortloop++){
+				s->exchange(s,NULL, &status, 1);	
+				if(status==0xff){
+					s->exchange(s,NULL, &status, 1);	;
+					return 1;//success
+				}						
+			}
+		set_current_state(TASK_INTERRUPTIBLE);//may want to shorten this.
+	 	schedule_timeout(HZ/100 ? HZ/100 : 1);
+		}
+			MMCERROR(1);//error
+	}
+
+/**
+ * delay loop that waits for an Rxtoken
+ * assumes pre-existing tip
+ * @return 1 if successful
+ */	
+ 
+static int wait_for_Rxtoken(mmcslot_t *s) {
+	u8 status=0;
+	int BR_START_TOKEN = 0xFE;//MMC token for data start
+	int tickloop;
+	int shortloop;
+		
+	for(tickloop=0;tickloop<100;tickloop++){
+	 	for(shortloop=0;shortloop<POLLNUMBER;shortloop++){	 		
+			s->exchange(s,NULL, &status, 1);
+			if(status==(u8)BR_START_TOKEN)
+				return 1;
+			}
+	 	set_current_state(TASK_INTERRUPTIBLE);
+	 	schedule_timeout(HZ/100 ? HZ/100 : 1);
+	 	}
+		MMCERROR(1);
+		
+		return 1;
+}
+
+
+/**
+	 * interprete the command response and throw exceptions as appropriate
+	 * @param response the byte containing the response
+	 * @return 0 if nothing is wrong
+	 */
+	static int CommandResponse(int response){				
+		if(response==0){
+			MMCDEBUG("command successful\n");
+			return 0;//no problems command succeeded
+		}
+		
+		printk("command error\n");
+		
+		if((response&MMCCOM_IDLE)!=0)
+			printk("idle\n");
+		if((response&MMCCOM_ERASE_RES)!=0)
+			printk("erase reset\n");
+		if((response&MMCCOM_ILLEGAL)!=0)
+			printk("illegal\n");
+		if((response&MMCCOM_CRC)!=0)
+			printk("crc\n");
+		if((response&MMCCOM_ERASE_SEQ)!=0)
+			printk("erase sequence\n");		
+		if((response&MMCCOM_ADDRESS)!=0)
+			printk("address\n");
+		if((response&MMCCOM_PARAMETER)!=0)
+			printk("parameter\n");
+		
+		MMCERROR(1);				
+	}
+/**
+ * interprete the data response and throw exceptions as appropriate
+ * @param response the byte containing the response
+ * @return 0 if nothing is wrong
+ */
+ 	static int DataResponse(int response){
+		//System.out.println("response="+response);
+		
+		switch(response&MMCDAT_D_RESPONSE_MASK){
+		case MMCDAT_DATA_ACC:
+			//System.out.println("Data accepted");
+			return 0;//data was accepted, no need to complain
+		case MMCDAT_CRC_ERR:
+			printk("CRC error\n");
+			MMCERROR(1);
+		case MMCDAT_WRITE_ERR:
+			printk("Write error\n");
+			MMCERROR(1);
+		default:
+			printk("Communications error\n");
+			MMCERROR(1);
+		}
+		
+		MMCERROR(1);
+	}	
+
+/**
+	 * General purpose method for tranceiving a command/response
+	 * to the MMC
+	 * @param command command index, see table below
+	 * @param arg1 first arguement, high bits 31:16
+	 * @param arg2 second arguement, low bits 15:0
+	 * @param blocking block before returning?
+	 * @param response number of response bits expected
+	 * @return the command response
+	 */
+int mmctransaction(mmcslot_t *s, int command, int arg1, int arg2,int blocking,int response){ 
+		int Rx;
+		int bytenum;
+		
+		int framelen = COMMAND_LENGTH+Ncr_MAX+response;		
+		unsigned char readbuff[COMMAND_LENGTH+Ncr_MAX+MAX_RESPONSE];				
+		unsigned char writebuff[COMMAND_LENGTH+Ncr_MAX+MAX_RESPONSE];	
+						
+		packetize(writebuff,(COMMAND_LENGTH+Ncr_MAX+response),command,arg1,arg2);
+		
+		if((s->tip(s,TRUE))<0)MMCERROR(1);//could not obtain the bus
+			
+		MMCDEBUG("xmit\n");s->exchange(s,writebuff, readbuff, framelen);
+				
+		MMCDEBUG("interprete\n");
+		//locate and interprete the data
+		for(bytenum=COMMAND_LENGTH;bytenum<framelen;bytenum++)
+			if(readbuff[bytenum]!=(u8)0xff)
+				break;
+		
+		if(bytenum==(framelen)){
+			MMCDEBUG("no command response received\n");
+			s->tip(s,FALSE);
+			MMCERROR(1);
+			}
+			
+		MMCDEBUG("get_response\n");
+		Rx = get_response(response,readbuff,bytenum);
+		
+		if(blocking)busy_wait(s);
+		
+		s->tip(s,FALSE);//use caution inlining this as it turns off the transaction upon returning
+		return Rx;
+		
+	}
+
+/**
+	 * Block Read transaction
+	 * @param command - the initiating command
+	 * @param arg1 - arg1 of the initiating command
+	 * @param arg2 - arg2 of the initiating command
+	 * @param response - response size 
+	 * @param data - buffer to move received data into
+	 * @param blocknum - number of blocks to read
+	 * @param blocksize - size of blocks
+	 * @param Nac - Nac timing parameter
+	 * @return the total number of blocks read
+	 * 
+	 * major guts rewrite to accomodate new SPI bus method.
+	 * 
+	 */
+int mmcblockread(mmcslot_t *s, int command, int arg1, int arg2,int response, u8 *data,int blocksize, int blocknum,int Nac){
+		u8 frame[COMMAND_LENGTH+Ncr_MAX+MAX_RESPONSE];
+		int block;//current block being parsed
+		int frame_index;//frame index		
+		int Rx;
+		u8 CRC[CRC_LENGTH];
+		u8 commandbuffer[COMMAND_LENGTH];
+		
+		MMCDEBUG("BlockRead\n");	
+				
+		packetize(commandbuffer,COMMAND_LENGTH,command,arg1,arg2);
+
+		if((s->tip(s,TRUE))<0)MMCERROR(1);//could not obtain the bus
+		s->exchange(s,commandbuffer, frame, sizeof(commandbuffer));
+		
+		//new broken up method cannot grab response within single xmit as it can 
+		//accidentally pull data. 
+		//Check the bytes as they are tranceived instead
+		MMCDEBUG("exchange response\n");
+		for(frame_index=COMMAND_LENGTH;frame_index<(COMMAND_LENGTH+Ncr_MAX+response);frame_index++){	
+			s->exchange(s,NULL,&frame[frame_index],1);
+			if(frame[frame_index]!=(u8)0xff)break;//go ahead and interprete the response
+		}
+			
+		if(frame_index==(COMMAND_LENGTH+Ncr_MAX+response)){
+			printk("MMC READ:no command response received\n");
+			s->tip(s,FALSE);
+			MMCERROR(1);
+			}
+			
+		Rx = get_response(response,frame,frame_index);
+		
+		if(CommandResponse(Rx)<0){
+			printk("MMC_READ:command response error, Rx=%x\n",Rx);
+			s->tip(s,FALSE);
+			MMCERROR(1);//error
+		}
+		
+		MMCDEBUG("wait for rx token\n");
+		for(block=0;block<blocknum;block++){	
+			if(wait_for_Rxtoken(s)<0){
+				printk("MMC_READ:No Rx token received\n");
+				s->tip(s,FALSE);
+				MMCERROR(1);//error
+			}
+			
+			MMCDEBUG("exchange data block %u\n",block);	
+			//retrieve a block of data, passing null to tx assumes 0xff transmission
+			s->exchange(s,NULL,&data[block*blocksize],blocksize);
+			s->exchange(s,NULL,CRC,CRC_LENGTH);//not currently used
+											
+			}
+		
+		//Send extra 8 char NEC	
+		s->exchange(s,NULL, NULL,8);
+			
+		if(command==18)STOP_TRANSMISSION(s);//end open ended read		
+		s->tip(s,FALSE);		
+		return blocknum;
+		}
+
+	/**
+	 * Write Blocks of data;
+	 * @param command command index to initiate the transfer
+	 * @param arg1 first arguement to the command
+	 * @param arg2 second arguement to the commmand
+	 * @param response number of responses expected
+	 * @param data buffer holding the data to be transmitted
+	 * @param blocknum number of blocks
+	 * @param blocksize size of the blocks
+	 * @param Nwr timing parameter, typically 1
+	 * @return
+	 */
+int mmcblockwrite(mmcslot_t *s,int command, int arg1, int arg2, int response, u8 *data, int blocksize, int blocknum,int Nwr){		
+		int block;
+		int dataresponse;
+		u8 BW_STOP_TOKEN = 0xFD;	
+		u8 BW_START_TOKEN = 0xFD;
+		u8 commandbuffer[COMMAND_LENGTH+MAX_NWR+MAX_RESPONSE];
+		u8 responsebuffer[DATA_RESPONSE_LENGTH+CRC_LENGTH];
+		int index;
+
+		MMCDEBUG("BlockWrite:cmd %x arg1 %x arg2 %x size %x num%x\n",command,arg1,arg2,blocksize,blocknum);					
+				
+		//use the start correct token for single or multiple writes		
+		if(command==25)
+			BW_START_TOKEN = 0xFc;
+		else
+			BW_START_TOKEN = 0xFe;
+		
+		//transmit command and the first and possibly only block	
+		packetize(commandbuffer,sizeof(commandbuffer),command,arg1,arg2);
+			
+		if((s->tip(s,TRUE))<0)MMCERROR(1);//could not obtain the bus
+		//a simpler command exchange than read, is there a reason read doesn't use this?		
+		s->exchange(s,commandbuffer, NULL, COMMAND_LENGTH);
+		
+		for(index=COMMAND_LENGTH;
+		index<(COMMAND_LENGTH+MAX_NWR+MAX_RESPONSE);index++){
+			s->exchange(s,NULL, &commandbuffer[index], 1);
+			if(commandbuffer[index]!=(u8)0xff)break;//go ahead and interprete the response
+		}
+			
+		if(index==(COMMAND_LENGTH+MAX_NWR+MAX_RESPONSE)){
+			printk("MMC BWRITE:no command response received\n");
+			s->tip(s,FALSE);
+			MMCERROR(1);
+			}
+			
+		index = get_response(response,commandbuffer,index);
+		
+		if((CommandResponse(index))<0){
+			printk("MMC BWRITE command response error\n");
+			s->tip(s,FALSE);
+			MMCERROR(1);//error
+		}	
+		
+		s->exchange(s,NULL, NULL, 1);//NWR delay
+
+		for(block=0;block<blocknum;block++){
+			//send start token
+			s->exchange(s,&BW_START_TOKEN, NULL, START_TOKEN_LENGTH);
+			
+			//send data
+			s->exchange(s,&data[block*blocksize], NULL, blocksize);
+
+			//read dataresponse
+			s->exchange(s,NULL, responsebuffer, (DATA_RESPONSE_LENGTH+CRC_LENGTH));
+
+			dataresponse = responsebuffer[CRC_LENGTH];//gloss over the CRC for now	
+			if(DataResponse(dataresponse)<0){
+				 printk("MMC Data Response error\n");
+				s->tip(s,FALSE);
+				MMCERROR(1);//error
+			}
+			MMCDEBUG("Block %u\n",block);					
+			busy_wait(s);//wait for completion
+		}		
+
+		//send the end transmit command if it's a multiple block write(open ended)
+		if(command==25){
+			//send stop token
+			s->exchange(s,&BW_STOP_TOKEN, NULL, 1);				
+			busy_wait(s);
+		}		
+		
+		s->tip(s,FALSE);
+		return blocknum;
+	}
+
+
+/**
+	 * Initialize the MMC interface and the SPI interface controlling it.
+	 * Also read out the registers into shadow variables.
+	 */	
+int mmcinit(mmcslot_t *s){
+		u8 RegisterBuff[16];
+		int response,iteration,mult;
+		
+		s->setspeed(s,100000);//set spi speed to low for initial configuration as an spi device
+		
+		s->card.blocklength = 512;/*default, change later if appropriate*/
+
+		s->tip(s,FALSE);
+		mdelay(1);//make sure transaction has been off for at least 1ms
+		if((s->tip(s,TRUE))<0)MMCERROR(1);//could not obtain the bus, this may need to be a retry
+		s->exchange(s,NULL, NULL,72);//send string of NULLS (0xff for MMC/SD) to clear out the card
+		s->tip(s,FALSE);
+		
+		MMCDEBUG("GO_IDLE_STATE\n");
+		GO_IDLE_STATE(s);//reset and start SPI mode
+		
+		for(iteration=0;iteration<1000;iteration++){
+			MMCDEBUG("SEND_OP_COND\n");
+			response = SEND_OP_COND(s);//read OCR, a wait should be inserted here until the OCR indicates ready.
+			MMCDEBUG("response = %d\n",response);
+			if(response==0)
+				break;		
+		}		
+		
+		if(iteration==100){
+			s->state=INVALID;
+			s->tip(s,FALSE);
+			MMCERROR(1);
+		}
+
+		MMCDEBUG("SEND_CID\n");
+				
+		if(SEND_CID(s,RegisterBuff)<0){
+			printk("MMC: no CID register found\n");
+			s->state=INVALID;
+			s->tip(s,FALSE);
+			MMCERROR(1);
+		}
+		else
+			parse_CID(&s->card.CID,RegisterBuff);	
+
+		MMCDEBUG("SEND_CSD\n");
+		
+		if(SEND_CSD(s,RegisterBuff)<0){
+			s->state=INVALID;
+			s->tip(s,FALSE);
+			MMCERROR(1);
+		}
+			
+		parse_CSD(&s->card.CSD,RegisterBuff);		
+		
+		s->card.blocklength = (1<<(s->card.CSD.READ_BL_LEN));
+		s->card.sectors = s->card.CSD.C_SIZE+1;
+		MMCDEBUG("set sectors to %u\n",s->card.sectors);
+		mult = 1<<(s->card.CSD.C_SIZE_MULT+2);
+		MMCDEBUG("mult=%u\n",mult);		
+		s->card.sectors*=mult;
+		MMCDEBUG("set sectors to %u\n",s->card.sectors);
+		s->card.size = s->card.blocklength*s->card.sectors;
+		
+		switch(s->card.CSD.TRAN_SPEED&7){
+			case 1:
+			s->card.speed = 1000000;
+			break;
+			
+			case 2:			
+			s->card.speed = 10000000;//can't go faster than 10M
+			break;
+			
+			case 3:			
+			s->card.speed = 100000000;//can't go faster than 100M
+			break;
+			
+			default:
+			s->card.speed = 100000;
+			break;
+		}
+		s->setspeed(s,s->card.speed);//turn the socket speed up to the maximum the card can handle
+		
+	printk("MMC card detected: %s\n",s->card.CID.Product_name);
+	printk("revision: %u.%u\n",((s->card.CID.Product_revision&0xf0)>>4),(s->card.CID.Product_revision&0x0f));
+	printk("serial#: %lu\n",s->card.CID.Product_serial_number);	
+	printk("Block Length=%u\n",s->card.blocklength);	
+	printk("Size =%lu\n",s->card.size);	
+	printk("Speed=%lu\n",s->card.speed);
+		
+	s->state=VALID;
+	s->tip(s,FALSE);
+	return 0;											
+}
diff -uprN linux-2.6.20/drivers/misc/classes/pwm.c linux-2.6.20-at92_e1.5/drivers/misc/classes/pwm.c
--- linux-2.6.20/drivers/misc/classes/pwm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/pwm.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,194 @@
+/**
+ * A class for simple pwm ports
+ * Several types of devices are available 
+ * which all export the same basic functionity 
+ * through differnet underlying methods
+ */
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/kdev_t.h>
+#include <linux/chelper.h>
+#include <linux/class/pwm.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_PWMCLASS_RTDM
+#include <rtdm/rtdm_driver.h>
+#include <linux/class/rtdm/pwm_rtdm.h>
+#define ATOMIC(a) RTDM_EXECUTE_ATOMICALLY(a)
+#else
+#define ATOMIC(a) a
+#endif //CONFIG_PWMCLASS_RTDM
+
+/************************************************************
+ * the global device class
+ */
+static struct class *pwmclass = NULL;
+
+struct class *pwm_declare(void){
+	if(!pwmclass){
+		printk("registering PWM class\n");
+		pwmclass=class_create(THIS_MODULE,"pwm");
+	}
+return pwmclass;
+}
+
+/***************************************************************************
+ * typical low level methods
+ */
+
+/** need to ajust this to use a clock method rather than getsysclock 
+static inline int us2reg(__u32 *value, int Mhz){
+		switch(get_sclk()){
+			case 66000000:{
+				const __u32 regmax = (0xffff/66);
+				if(*value>regmax)*value=regmax;
+				else *value*=66;
+				// pwms seem to do funny things when zeros are written to period or width;
+				if(*value==0)*value=1;
+				return 0;
+			}
+			default:return SYSCLOCK_UNSUPPORTED;
+	}
+}
+
+static inline int reg2us(__u32 *value){
+		switch(get_sclk()){
+			case 66000000:
+				*value/=66;
+				return 0;		
+			default:return SYSCLOCK_UNSUPPORTED;
+	}
+}
+*/ 
+ 
+int  pwm_widthus_write8(pwm_t *pwm, pwm_data data){iowrite8(data,pwm->widthus);return 0;}
+
+int  pwm_widthus_write16(pwm_t *pwm, pwm_data data){iowrite16(data,pwm->widthus);return 0;}
+
+int  pwm_periodus_write8(pwm_t *pwm, pwm_data data){iowrite8(data,pwm->periodus);return 0;}
+
+int  pwm_periodus_write16(pwm_t *pwm, pwm_data data){iowrite16(data,pwm->periodus);return 0;}
+
+int  pwm_empty_write(pwm_t *pwm, pwm_data data){return 0;}
+
+pwm_data pwm_widthus_read8(pwm_t *pwm){return ioread8(pwm->widthus);}
+
+pwm_data pwm_widthus_read16(pwm_t *pwm){return ioread16(pwm->widthus);}
+
+pwm_data pwm_periodus_read8(pwm_t *pwm){return ioread8(pwm->periodus);}
+
+pwm_data pwm_periodus_read16(pwm_t *pwm){return ioread16(pwm->periodus);}
+
+pwm_data pwm_widthusshadow_read(pwm_t *pwm){return pwm->widthus_shadow;}
+
+pwm_data pwm_ff_read(pwm_t *pwm){return 0xff;}
+	
+pwm_data pwm_zero_read(pwm_t *pwm){return 0;}
+
+/***************************************************************************
+ * Atomic method wrappers
+ */
+int atomic_pwm_widthus_write(pwm_t *pwm,pwm_data data){
+	ATOMIC(pwm->widthus_write(pwm,data);)
+	return 0;
+}
+	
+int atomic_pwm_periodus_write(pwm_t *pwm,pwm_data data){
+	ATOMIC(pwm->periodus_write(pwm,data);)
+	return 0;
+}
+
+int atomic_pwm_invert_write(pwm_t *pwm,pwm_data data){
+	ATOMIC(pwm->invert_write(pwm,data);)
+	return 0;
+}	
+	
+pwm_data atomic_pwm_widthus_read(pwm_t *pwm){
+	pwm_data retval;
+	ATOMIC(retval = pwm->widthus_read(pwm);)
+	return retval;
+}
+
+pwm_data atomic_pwm_periodus_read(pwm_t *pwm){
+	pwm_data retval;
+	ATOMIC(retval = pwm->periodus_read(pwm);)
+	return retval;
+}
+
+pwm_data atomic_pwm_invert_read(pwm_t *pwm){
+	pwm_data retval;
+	ATOMIC(retval = pwm->invert_read(pwm);)
+	return retval;
+}
+
+/************************************************************************************
+ * gpio sysfs operations
+ */
+#ifdef CONFIG_PWMCLASS_SYSFS
+
+static ssize_t pwm_widthus_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	pwm_t *pwm = cls->class_data;
+	pwm_data data = sfs_getint(buf,count,&size);
+	atomic_pwm_widthus_write(pwm, data);
+	return size;
+}
+
+static ssize_t pwm_periodus_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	pwm_t *pwm = cls->class_data;
+	pwm_data data = sfs_getint(buf,count,&size);
+	atomic_pwm_periodus_write(pwm, data);
+	return size;
+}
+
+static ssize_t pwm_invert_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	pwm_t *pwm = cls->class_data;
+	pwm_data data = sfs_getint(buf,count,&size);
+	atomic_pwm_invert_write(pwm, data);
+	return size;
+}
+
+static ssize_t pwm_widthus_show(struct class_device *cls, char *buf){
+	pwm_t *pwm = cls->class_data;
+	return sprintf(buf,"%u\r\n",atomic_pwm_widthus_read(pwm));
+}
+
+static ssize_t pwm_periodus_show(struct class_device *cls, char *buf){
+	pwm_t *pwm = cls->class_data;
+	return sprintf(buf,"%u\r\n",atomic_pwm_periodus_read(pwm));
+}
+
+static ssize_t pwm_invert_show(struct class_device *cls, char *buf){
+	pwm_t *pwm = cls->class_data;
+	return sprintf(buf,"%x\r\n",atomic_pwm_invert_read(pwm));
+}
+
+static CLASS_DEVICE_ATTR(widthus,S_IRUGO|S_IWUGO,pwm_widthus_show,pwm_widthus_store);
+static CLASS_DEVICE_ATTR(periodus,S_IRUGO|S_IWUGO,pwm_periodus_show,pwm_periodus_store);
+static CLASS_DEVICE_ATTR(inversion,S_IRUGO|S_IWUGO,pwm_invert_show,pwm_invert_store);
+
+#endif //CONFIG_PWMCLASS_SYSFS
+/***************************************************************************
+* class instantiation
+*/
+struct class_device *pwm_register_class_device(pwm_t *pwm){		
+	struct class *pwm_master = pwm_declare();
+	struct class_device *dev = class_device_create(pwm_master, NULL, MKDEV(0, 0), NULL, pwm->name);
+	dev->class_data = pwm;
+
+#ifdef CONFIG_PWMCLASS_SYSFS
+	if((pwm->widthus_write)&&(pwm->widthus_read))class_device_create_file(dev,&class_device_attr_widthus);
+	if((pwm->periodus_write)&&(pwm->periodus_read))class_device_create_file(dev,&class_device_attr_periodus);
+	if((pwm->invert_write)&&(pwm->invert_read))class_device_create_file(dev,&class_device_attr_inversion);
+#endif	 
+	 
+#ifdef CONFIG_PWMCLASS_RTDM
+	rt_pwm_device_create(pwm);
+#endif 
+
+	return dev;			
+}
diff -uprN linux-2.6.20/drivers/misc/classes/rtdm/Makefile linux-2.6.20-at92_e1.5/drivers/misc/classes/rtdm/Makefile
--- linux-2.6.20/drivers/misc/classes/rtdm/Makefile	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/rtdm/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,8 @@
+#
+# Makefile for the misc classes
+#
+
+EXTRA_CFLAGS += -D__IN_XENOMAI__ -Iinclude/xenomai 
+obj-$(CONFIG_GPIOCLASS_RTDM)	+= gpio_rtdm.o
+obj-$(CONFIG_PWMCLASS_RTDM)		+= pwm_rtdm.o
+
diff -uprN linux-2.6.20/drivers/misc/classes/rtdm/gpio_rtdm.c linux-2.6.20-at92_e1.5/drivers/misc/classes/rtdm/gpio_rtdm.c
--- linux-2.6.20/drivers/misc/classes/rtdm/gpio_rtdm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/rtdm/gpio_rtdm.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,99 @@
+/**
+ * A class for simple gpio ports
+ * Several types of general purpose devices are available 
+ * which all export the same basic functionity 
+ * through differenet underlying methods
+ * This class can also be used to export simple interfaces
+ * to an 8 bit port into user space
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/class/gpio.h>
+#include <linux/class/rtdm/gpio_rtdm.h>
+#include <rtdm/rtdm_driver.h>
+
+typedef struct rtgpio_device_s {
+struct rtdm_device rtd;
+gpio_t *gpio;//pointer to parent gpio structure.
+}rtgpio_device_t; 
+
+static int rt_gpio_open(struct rtdm_dev_context *context,
+                  rtdm_user_info_t *user_info, int oflags){
+    return 0;
+}
+
+static int rt_gpio_close(struct rtdm_dev_context *context,
+                   rtdm_user_info_t *user_info){
+return 0;
+}
+
+static int rt_gpio_ioctl(struct rtdm_dev_context *context,
+                   rtdm_user_info_t *user_info, int request, void *umem){
+    rtgpio_device_t *dev = container_of(context->device,rtgpio_device_t,rtd);
+    gpio_t *gpio = dev->gpio;
+       
+    gpio_data kmem[1];
+             
+	switch(request){
+	case DDRREAD:
+	if(gpio->ddr_read) kmem[0] = atomic_gpio_ddr_read(gpio);
+	else return -2;
+	return rtdm_safe_copy_to_user (user_info, umem, kmem, sizeof(gpio_data));		
+	
+	case DDRWRITE:
+	rtdm_safe_copy_from_user (user_info, kmem, umem, sizeof(gpio_data));	
+	if(gpio->ddr_write) atomic_gpio_ddr_write(gpio,kmem[0]);
+	else return -2;
+	return 0;
+	
+	case DATAREAD:
+	if(gpio->data_read)kmem[0] = atomic_gpio_data_read(gpio);
+	else return -2;
+	return rtdm_safe_copy_to_user (user_info, umem, kmem, sizeof(gpio_data));
+	
+	case DATAWRITE:
+	rtdm_safe_copy_from_user (user_info, kmem, umem, sizeof(gpio_data));	
+	if(gpio->data_write)atomic_gpio_data_write(gpio,kmem[0]);	
+	else return -2;
+	return 0;
+	}             
+                   	                 	
+return -1;//no such op, need to find the right op code for this.
+}
+
+
+static const struct rtdm_device __initdata device_tmpl = {
+    struct_version:     RTDM_DEVICE_STRUCT_VER,
+
+    device_flags:       RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE,
+    device_name:        "",
+    open_rt:            rt_gpio_open,
+    ops: {
+        close_rt:      	rt_gpio_close,
+        ioctl_rt:       rt_gpio_ioctl,
+    },
+    device_class:       RTDM_CLASS_GPIO,
+    driver_name:        "gpio_rtd",
+    driver_version:     RTDM_DRIVER_VER(1, 0, 0),
+    peripheral_name:    "gpio",
+    provider_name:      "EMAC.Inc",
+};
+
+
+int rt_gpio_device_create(struct gpio_s *gpio){
+		rtgpio_device_t *dev = kmalloc(sizeof(rtgpio_device_t),GFP_KERNEL);
+		dev->gpio = gpio;
+		memcpy(&dev->rtd, &device_tmpl, sizeof(struct rtdm_device));
+		strncpy(dev->rtd.device_name, dev->gpio->name, RTDM_MAX_DEVNAME_LEN);
+		dev->rtd.device_sub_class = dev->gpio->subclass;
+		dev->rtd.proc_name = dev->gpio->name;
+		if(rtdm_dev_register(&dev->rtd)){
+			printk("couldn't register rtgpio device %s\n",dev->rtd.device_name);	
+			kfree(dev);
+			return -1;
+		}
+	return 	0;	
+}
+
+
diff -uprN linux-2.6.20/drivers/misc/classes/rtdm/pwm_rtdm.c linux-2.6.20-at92_e1.5/drivers/misc/classes/rtdm/pwm_rtdm.c
--- linux-2.6.20/drivers/misc/classes/rtdm/pwm_rtdm.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/rtdm/pwm_rtdm.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,95 @@
+/**
+ * A rtdm interface for pwm classes
+ */
+
+#include <linux/kernel.h>
+#include <linux/ctype.h>
+#include <linux/class/pwm.h>
+#include <linux/class/pwm.h>
+#include <linux/class/rtdm/pwm_rtdm.h>
+#include <rtdm/rtdm_driver.h>
+
+typedef struct rtpwm_device_s {
+struct rtdm_device rtd;
+pwm_t *pwm;//pointer to parent pwm structure.
+}rtpwm_device_t; 
+
+static int rt_pwm_open(struct rtdm_dev_context *context,
+                  rtdm_user_info_t *user_info, int oflags){
+    return 0;
+}
+
+static int rt_pwm_close(struct rtdm_dev_context *context,
+                   rtdm_user_info_t *user_info){
+return 0;
+}
+
+static int rt_pwm_ioctl(struct rtdm_dev_context *context,
+                   rtdm_user_info_t *user_info, int request, void *umem){
+    rtpwm_device_t *dev = container_of(context->device,rtpwm_device_t,rtd);
+    pwm_t *pwm = dev->pwm;
+       
+    pwm_data kmem[1];
+             
+	switch(request){
+	case PERIODUSREAD:
+	if(pwm->periodus_read) kmem[0] = atomic_pwm_periodus_read(pwm);
+	else return -2;
+	return rtdm_safe_copy_to_user (user_info, umem, kmem, sizeof(pwm_data));		
+	
+	case PERIODUSWRITE:
+	rtdm_safe_copy_from_user (user_info, kmem, umem, sizeof(pwm_data));	
+	if(pwm->periodus_write) atomic_pwm_periodus_write(pwm,kmem[0]);
+	else return -2;
+	return 0;
+	
+	case WIDTHUSREAD:
+	if(pwm->widthus_read)kmem[0] = atomic_pwm_widthus_read(pwm);
+	else return -2;
+	return rtdm_safe_copy_to_user (user_info, umem, kmem, sizeof(pwm_data));
+	
+	case WIDTHUSWRITE:
+	rtdm_safe_copy_from_user (user_info, kmem, umem, sizeof(pwm_data));	
+	if(pwm->widthus_write)atomic_pwm_widthus_write(pwm,kmem[0]);	
+	else return -2;
+	return 0;
+	}             
+                   	                 	
+return -1;//no such op, need to find the right op code for this.
+}
+
+
+static const struct rtdm_device __initdata device_tmpl = {
+    struct_version:     RTDM_DEVICE_STRUCT_VER,
+
+    device_flags:       RTDM_NAMED_DEVICE | RTDM_EXCLUSIVE,
+    device_name:        "",
+    open_rt:            rt_pwm_open,
+    ops: {
+        close_rt:      	rt_pwm_close,
+        ioctl_rt:       rt_pwm_ioctl,
+    },
+    device_class:       RTDM_CLASS_PWM,
+    driver_name:        "pwm_rtd",
+    driver_version:     RTDM_DRIVER_VER(1, 0, 0),
+    peripheral_name:    "pwm",
+    provider_name:      "EMAC.Inc",
+};
+
+
+int rt_pwm_device_create(struct pwm_s *pwm){
+		rtpwm_device_t *dev = kmalloc(sizeof(rtpwm_device_t),GFP_KERNEL);
+		dev->pwm = pwm;
+		memcpy(&dev->rtd, &device_tmpl, sizeof(struct rtdm_device));
+		strncpy(dev->rtd.device_name, dev->pwm->name, RTDM_MAX_DEVNAME_LEN);
+		dev->rtd.device_sub_class = dev->pwm->subclass;
+		dev->rtd.proc_name = dev->pwm->name;
+		if(rtdm_dev_register(&dev->rtd)){
+			printk("couldn't register rtpwm device %s\n",dev->rtd.device_name);	
+			kfree(dev);
+			return -1;
+		}
+	return 	0;	
+}
+
+
diff -uprN linux-2.6.20/drivers/misc/classes/spi.c linux-2.6.20-at92_e1.5/drivers/misc/classes/spi.c
--- linux-2.6.20/drivers/misc/classes/spi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/spi.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,211 @@
+/**
+ * A class for simple gpio ports
+ * Several types of general purpose devices are available 
+ * which all export the same basic functionity 
+ * through different underlying methods
+ * This class can also be used to export simple interfaces
+ * to an 8 bit port into user space
+ */
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/device.h>
+#include <linux/ctype.h>
+#include <linux/kdev_t.h>
+#include <linux/chelper.h>
+#include <linux/class/spi.h>
+#include <asm/io.h>
+
+#ifdef CONFIG_SPICLASS_RTDM
+#include <rtdm/rtdm_driver.h>
+#include <linux/class/rtdm/spi_rtdm.h>
+#define ATOMIC(a) RTDM_EXECUTE_ATOMICALLY(a)
+#else
+#define ATOMIC(a) a
+#endif //CONFIG_GPIOCLASS_RTDM
+
+#ifdef CONFIG_SPICLASS_CHAR
+#include <linux/class/char/spi_char.h>
+#endif
+
+/************************************************************
+ * the global device class
+ */
+static struct class *spiclass = NULL;
+
+struct class *spi_declare(void){
+	if(!spiclass){
+		printk("registering GPIO class\n");
+		spiclass=class_create(THIS_MODULE,"spi");
+#ifdef CONFIG_SPICLASS_CHAR
+		spi_char_init();
+#endif
+	}
+	return spiclass;
+}
+
+/***************************************************************************
+ * Atomic method wrappers
+ */
+int atomic_spi_tip(struct spi_s *s,int ofs){
+	spi_data retval;
+	ATOMIC(retval = s->tip(s,ofs);)
+	return retval;
+}
+
+int atomic_spi_xmit(struct spi_s *s,u8 *mosi, u8 *miso, int size){
+	ATOMIC(s->xmit(s,mosi, miso, size);)
+	return 0;
+}
+
+int atomic_spi_tip_write(struct spi_s *s,spi_control config){
+	ATOMIC(s->tip(s,(config>0));)
+	return 0;
+}
+
+spi_control atomic_spi_tip_read(struct spi_s *s){
+	spi_data retval;
+	ATOMIC(retval = s->tip(s,TIPSTATUS);)
+	return (retval>0);
+}
+
+int atomic_spi_conf_write(struct spi_s *s,spi_control config){
+	ATOMIC(s->confwrite(s, config);)
+	return 0;
+}
+
+spi_control atomic_spi_conf_read(struct spi_s *s){
+	spi_control retval;
+	ATOMIC(retval = s->confread(s);)
+	return retval;
+}
+
+int atomic_spi_speed_write(struct spi_s *s,spi_control speed){
+	ATOMIC(s->speedwrite(s, speed);)
+	return 0;
+}
+
+spi_control atomic_spi_speed_read(struct spi_s *s){
+	spi_control retval;
+	ATOMIC(retval = s->speedread(s);)
+	return retval;
+}
+
+
+/***************************************************************************
+ * gpio sysfs operations
+ */
+#ifdef CONFIG_SPICLASS_SYSFS
+#define SPIXMITDELIM ","
+
+static ssize_t spi_xmit_store(struct class_device *cls, const char *buf,size_t count){
+	spi_t *s = cls->class_data;
+	size_t size;	
+	//atomic_spi_tip(s,TIPON);
+	if(s->buf){kfree(s->buf);s->bsize=0;} /* this is not safe unless buf is set to NULL on init */
+	//worst case allocation, char-delim-char-delim = count/2 * 4 bytes per word
+	s->buf = kmalloc(count*2, GFP_KERNEL);
+	s->bsize = sfs_getstream(buf,count,&size,SPIXMITDELIM,s->buf);
+	{
+	int i;
+	printk("%s-data: ",__FUNCTION__);
+	for(i=0;i<s->bsize;i++)printk("0x%x ",s->buf[i]);
+	printk("\n");
+	}
+	atomic_spi_xmit(s,s->buf, s->buf, s->bsize);
+	//atomic_spi_tip(s,TIPOFF);
+
+	return size;
+}
+
+static ssize_t spi_xmit_show(struct class_device *cls, char *buf){
+	spi_t *s = cls->class_data;
+	int chars=0;
+	int i;
+	
+	for(i=0;i<s->bsize;i++){
+		if(chars>=(PAGE_SIZE-10)){
+			chars+=sprintf(&buf[chars],"...OVF");
+			return chars;
+		}
+		if(i)chars+=sprintf(&buf[chars],SPIXMITDELIM);
+		chars+=sprintf(&buf[chars],"%x",s->buf[i]);
+	}
+	chars+=sprintf(&buf[chars],"\n");
+	return chars;
+}
+
+static ssize_t spi_flags_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	spi_t *s = cls->class_data;
+	spi_control data = sfs_getint(buf,count,&size);
+	atomic_spi_conf_write(s, data);
+	return size;
+}
+
+static ssize_t spi_flags_show(struct class_device *cls, char *buf){
+	spi_t *s = cls->class_data;
+	return sprintf(buf,"%x\r\n",atomic_spi_conf_read(s));
+}	
+
+static ssize_t spi_speed_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	spi_t *s = cls->class_data;
+	spi_control data = sfs_getint(buf,count,&size);
+	atomic_spi_speed_write(s, data);
+	return size;
+}
+
+static ssize_t spi_speed_show(struct class_device *cls, char *buf){
+	spi_t *s = cls->class_data;
+	return sprintf(buf,"%d\r\n",atomic_spi_speed_read(s));
+}	
+
+static ssize_t spi_tip_store(struct class_device *cls, const char *buf,size_t count){
+	size_t size;
+	spi_t *s = cls->class_data;
+	spi_data data = sfs_getint(buf,count,&size);
+	atomic_spi_tip_write(s,data);
+	return size;
+}
+
+static ssize_t spi_tip_show(struct class_device *cls, char *buf){
+	spi_t *s = cls->class_data;
+	return sprintf(buf,"%x\r\n",(atomic_spi_tip_read(s)));
+}
+
+static CLASS_DEVICE_ATTR(xmit,S_IRUGO|S_IWUGO,spi_xmit_show,spi_xmit_store);
+static CLASS_DEVICE_ATTR(tip,S_IRUGO|S_IWUGO,spi_tip_show,spi_tip_store);
+static CLASS_DEVICE_ATTR(speed,S_IRUGO|S_IWUGO,spi_speed_show,spi_speed_store);
+static CLASS_DEVICE_ATTR(conf,S_IRUGO|S_IWUGO,spi_flags_show,spi_flags_store);
+#endif //CONFIG_SPICLASS_SYSFS
+/***************************************************************************
+* class instantiation
+*/
+struct class_device *spi_register_class_device(spi_t *s){		
+struct class *spi_master = spi_declare();
+struct class_device *dev;	
+dev_t devnum = MKDEV(0, 0);
+
+#ifdef CONFIG_SPICLASS_CHAR
+devnum = spi_char_create(s);
+#endif	
+	
+dev = class_device_create(spi_master, NULL, devnum, NULL, s->name);
+dev->class_data = s;
+
+s->bsize = 0;
+s->buf = NULL;
+
+#ifdef CONFIG_SPICLASS_SYSFS
+	if(s->xmit)class_device_create_file(dev,&class_device_attr_xmit);
+	if(s->tip)class_device_create_file(dev,&class_device_attr_tip);
+	if((s->speedwrite)&&(s->speedread))class_device_create_file(dev,&class_device_attr_speed);
+	if((s->confwrite)&&(s->confread))class_device_create_file(dev,&class_device_attr_conf);
+	#endif	 
+
+#ifdef CONFIG_SPICLASS_RTDM
+	rt_spi_device_create(s);
+#endif
+
+return dev;			
+}
diff -uprN linux-2.6.20/drivers/misc/classes/spi_interface.c linux-2.6.20-at92_e1.5/drivers/misc/classes/spi_interface.c
--- linux-2.6.20/drivers/misc/classes/spi_interface.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/misc/classes/spi_interface.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,214 @@
+#include <linux/class/spi_interface.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/spi/spi.h>
+
+/**
+ * Provides an interface betwee the Linux SPI interface and the
+ * EMAC SPI class (lsi2esc).
+ * 
+ * Copyright (C) 2007, EMAC Inc
+ */
+
+/**
+ * function to set/clear a transfer-in-progrees for
+ * the given device. This function should be implemented
+ * by the driver itself to make sure that the same device
+ * is being accessed and as such this function does nothing
+ */
+int lsi2esc_spi_tip(struct spi_s *s, int ofs)
+{
+    printk("lsi2esc_spi_tip\n");
+    return 0;
+}
+
+/**
+ * function to transfer data on the SPI bus
+ * Assumptions: MOSI and MISO can be the same buffer,
+ * if MOSI is NULL 0xFF is transmitted, if MISO is NULL
+ * received data is discarded, there is no limit on buffer
+ * size.
+ * @param s the EMAC SPI class device to tranfer data on
+ * @param mosi the transmit buffer (master->slave)
+ * @param miso the receive buffer (slave->master)
+ * @param size the size of the data to transfer
+ * @return 0 or negative error code
+ */ 
+int lsi2esc_spi_xmit(struct spi_s *s, u8 *mosi, u8 *miso, int size)
+{
+    int result = 0;
+    u8 *local_mosi = mosi;
+    u8 *local_miso = miso;
+    
+    printk("lsi2esc_spi_xmit\n");
+
+    if (!local_mosi) {
+        if (!(local_mosi = kmalloc(size, GFP_KERNEL)))
+            return -ENOMEM;
+        /* memset to 0xFF */
+        memset(local_mosi, 0xFF, size);
+    }
+    result = spi_write(s->lsi, local_mosi, size);
+    if ((result == 0) && local_miso) { /* success */
+        result = spi_read(s->lsi, local_miso, size);
+    }
+    if (!mosi)
+        kfree(local_mosi);
+    return result;
+}
+
+/**
+ * function to read the current configuration settings
+ * @param s the EMAC SPI class device to read from
+ * @return the current configuration
+ */
+spi_control lsi2esc_spi_confread(struct spi_s *s)
+{
+    spi_control flags = 0;
+    printk("lsi2esc_spi_confread\n");
+
+    flags = s->lsi->mode; /* SPI and SPICL same here */
+
+    printk("bits_per_word = %d\n", s->lsi->bits_per_word);
+    if (s->lsi->bits_per_word == 8)
+        flags |= SPICL_EIGHTBIT; /* actually does nothing */
+    else if (s->lsi->bits_per_word == 10)
+        flags |= SPICL_TENBIT;
+    else if (s->lsi->bits_per_word == 12)
+        flags |= SPICL_TWELVEBIT;
+    else if (s->lsi->bits_per_word == 16)
+        flags |= SPICL_SIXTEENBIT;
+    
+    return flags;
+}
+
+/**
+ * function to change the current configuration settings
+ * @param s the EMAC SPI class device to configure
+ * @param config the new configuration to write
+ * @return 0 or the result of spi_setup
+ */
+int lsi2esc_spi_confwrite(struct spi_s *s, spi_control config)
+{
+    printk("lsi2esc_spi_confwrite: %d\n", config);
+    
+    /* set the mode */
+    s->lsi->mode = 0;
+    if (config & SPI_CPOL)
+        s->lsi->mode |= SPI_CPOL;
+    if (config & SPI_CPHA)
+        s->lsi->mode |= SPI_CPHA;
+    
+    /* explicitly set the bits per word if specified
+     * otherwise leave unchanged */
+    if (config & SPICL_EIGHTBIT)
+        s->lsi->bits_per_word = 8;
+    else if (config & SPICL_TENBIT)
+        s->lsi->bits_per_word = 10;
+    else if (config & SPICL_TWELVEBIT)
+        s->lsi->bits_per_word = 12;
+    else if (config & SPICL_SIXTEENBIT)
+        s->lsi->bits_per_word = 16;
+    
+    return spi_setup(s->lsi);
+}
+
+/**
+ * function to get the current speed settings
+ * @param s the EMAC SPI class device
+ * @return the speed setting of the associated spi_device
+ */
+spi_control lsi2esc_spi_speedread(struct spi_s *s)
+{
+    printk("lsi2esc_spi_speedread\n");
+    return s->lsi->max_speed_hz;    
+}
+
+/**
+ * function to change the speed settings
+ * @param s the EMAC SPI class device
+ * @param speed the new speed to set
+ */
+int lsi2esc_spi_speedwrite(struct spi_s *s, spi_control speed)
+{
+    printk("lsi2esc_spi_speedwrite\n");
+    s->lsi->max_speed_hz = speed;
+    /* error checking and adjustment must be provided by
+     * the SPI controller driver to use this directly */
+    return spi_setup(s->lsi);
+}
+
+/******************************************************************************/
+
+/**
+ * The lsi2esc interface actually acts like an SPI protocol driver.
+ * It fakes as an SPI device, but performs generic access to SPI
+ * only through the EMAC class interface rather than device specific
+ * access. The following section provides the SPI protocol driver
+ * code.
+ */
+
+/**
+ * probe function to initialize the interface
+ */
+
+static int __devinit lsi2esc_probe(struct spi_device *spi)
+{
+    struct spi_s *esc;
+    /* the platform data of dev must be set to the spi_t in
+     * the board specific file */
+    /* kind of creates a loop... but thats OK */
+    esc = spi->dev.platform_data;
+    esc->lsi = spi;
+
+    if (!esc)
+        return -ENODEV;
+    if (!spi_register_class_device(esc))
+        return -ENOMEM;
+
+    return 0;    
+}
+
+/**
+ * remove function to provide a clean exit
+ */
+
+static int __devexit lsi2esc_remove(struct spi_device *spi)
+{
+    /* nothing to do here */
+    return 0;
+}
+
+static struct spi_driver lsi2esc_driver = {
+    .driver = {
+        .name   = "lsi2esc",
+        .bus    = &spi_bus_type,
+        .owner  = THIS_MODULE,
+    },
+    .probe  = lsi2esc_probe,
+    .remove = __devexit_p(lsi2esc_remove),
+};
+
+static __init int lsi2esc_init(void)
+{
+    printk("Registering LSI2ESC SPI driver\n");
+    return spi_register_driver(&lsi2esc_driver);
+}
+
+static __exit void lsi2esc_exit(void)
+{
+    spi_unregister_driver(&lsi2esc_driver);
+}
+
+module_init(lsi2esc_init);
+module_exit(lsi2esc_exit);
+
+MODULE_AUTHOR("EMAC.Inc (support@emacinc.com)");
+MODULE_DESCRIPTION("Generic EMAC SPI class to Linux SPI Interface Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+// EOF
diff -uprN linux-2.6.20/drivers/mmc/at91_mci.c linux-2.6.20-at92_e1.5/drivers/mmc/at91_mci.c
--- linux-2.6.20/drivers/mmc/at91_mci.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mmc/at91_mci.c	2008-02-07 10:24:58.000000000 -0500
@@ -64,6 +64,7 @@
 #include <linux/err.h>
 #include <linux/dma-mapping.h>
 #include <linux/clk.h>
+#include <linux/atmel_pdc.h>
 
 #include <linux/mmc/host.h>
 #include <linux/mmc/protocol.h>
@@ -75,7 +76,7 @@
 #include <asm/arch/cpu.h>
 #include <asm/arch/gpio.h>
 #include <asm/arch/at91_mci.h>
-#include <asm/arch/at91_pdc.h>
+
 
 #define DRIVER_NAME "at91_mci"
 
@@ -85,8 +86,8 @@
 #define FL_SENT_STOP	(1 << 1)
 
 #define AT91_MCI_ERRORS	(AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE	\
-		| AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE		\
-		| AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)			
+			| AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE	\
+			| AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)
 
 #define at91_mci_read(host, reg)	__raw_readl((host)->baseaddr + (reg))
 #define at91_mci_write(host, reg, val)	__raw_writel((val), (host)->baseaddr + (reg))
@@ -211,13 +212,13 @@ static void at91mci_pre_dma_read(struct 
 
 		/* Check to see if this needs filling */
 		if (i == 0) {
-			if (at91_mci_read(host, AT91_PDC_RCR) != 0) {
+			if (at91_mci_read(host, ATMEL_PDC_RCR) != 0) {
 				pr_debug("Transfer active in current\n");
 				continue;
 			}
 		}
 		else {
-			if (at91_mci_read(host, AT91_PDC_RNCR) != 0) {
+			if (at91_mci_read(host, ATMEL_PDC_RNCR) != 0) {
 				pr_debug("Transfer active in next\n");
 				continue;
 			}
@@ -234,12 +235,12 @@ static void at91mci_pre_dma_read(struct 
 		pr_debug("dma address = %08X, length = %d\n", sg->dma_address, sg->length);
 
 		if (i == 0) {
-			at91_mci_write(host, AT91_PDC_RPR, sg->dma_address);
-			at91_mci_write(host, AT91_PDC_RCR, sg->length / 4);
+			at91_mci_write(host, ATMEL_PDC_RPR, sg->dma_address);
+			at91_mci_write(host, ATMEL_PDC_RCR, sg->length / 4);
 		}
 		else {
-			at91_mci_write(host, AT91_PDC_RNPR, sg->dma_address);
-			at91_mci_write(host, AT91_PDC_RNCR, sg->length / 4);
+			at91_mci_write(host, ATMEL_PDC_RNPR, sg->dma_address);
+			at91_mci_write(host, ATMEL_PDC_RNCR, sg->length / 4);
 		}
 	}
 
@@ -303,37 +304,12 @@ static void at91mci_post_dma_read(struct
 		at91mci_pre_dma_read(host);
 	else {
 		at91_mci_write(host, AT91_MCI_IER, AT91_MCI_RXBUFF);
-		at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
 	}
 
 	pr_debug("post dma read done\n");
 }
 
-/*
- * Handle transmitted data
- */
-static void at91_mci_handle_transmitted(struct at91mci_host *host)
-{
-	struct mmc_command *cmd;
-	struct mmc_data *data;
-
-	pr_debug("Handling the transmit\n");
-
-	/* Disable the transfer */
-	at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
-
-	/* Now wait for cmd ready */
-	at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
-	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
-
-	cmd = host->cmd;
-	if (!cmd) return;
-
-	data = cmd->data;
-	if (!data) return;
-
-	data->bytes_xfered = host->total_length;
-}
 
 /*
  * Enable the controller
@@ -431,15 +407,15 @@ static unsigned int at91_mci_send_comman
 		cmd->opcode, cmdr, cmd->arg, blocks, block_length, at91_mci_read(host, AT91_MCI_MR));
 
 	if (!data) {
-		at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTDIS | AT91_PDC_RXTDIS);
-		at91_mci_write(host, AT91_PDC_RPR, 0);
-		at91_mci_write(host, AT91_PDC_RCR, 0);
-		at91_mci_write(host, AT91_PDC_RNPR, 0);
-		at91_mci_write(host, AT91_PDC_RNCR, 0);
-		at91_mci_write(host, AT91_PDC_TPR, 0);
-		at91_mci_write(host, AT91_PDC_TCR, 0);
-		at91_mci_write(host, AT91_PDC_TNPR, 0);
-		at91_mci_write(host, AT91_PDC_TNCR, 0);
+		at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTDIS | ATMEL_PDC_RXTDIS);
+		at91_mci_write(host, ATMEL_PDC_RPR, 0);
+		at91_mci_write(host, ATMEL_PDC_RCR, 0);
+		at91_mci_write(host, ATMEL_PDC_RNPR, 0);
+		at91_mci_write(host, ATMEL_PDC_RNCR, 0);
+		at91_mci_write(host, ATMEL_PDC_TPR, 0);
+		at91_mci_write(host, ATMEL_PDC_TCR, 0);
+		at91_mci_write(host, ATMEL_PDC_TNPR, 0);
+		at91_mci_write(host, ATMEL_PDC_TNCR, 0);
 
 		at91_mci_write(host, AT91_MCI_ARGR, cmd->arg);
 		at91_mci_write(host, AT91_MCI_CMDR, cmdr);
@@ -452,7 +428,7 @@ static unsigned int at91_mci_send_comman
 	/*
 	 * Disable the PDC controller
 	 */
-	at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTDIS | AT91_PDC_TXTDIS);
+	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
 
 	if (cmdr & AT91_MCI_TRCMD_START) {
 		data->bytes_xfered = 0;
@@ -474,15 +450,15 @@ static unsigned int at91_mci_send_comman
 			 */
 			host->total_length = block_length * blocks;
 			host->buffer = dma_alloc_coherent(NULL,
-						  host->total_length,
-						  &host->physical_address, GFP_KERNEL);
+						host->total_length,
+						&host->physical_address, GFP_KERNEL);
 
 			at91mci_sg_to_dma(host, data);
 
 			pr_debug("Transmitting %d bytes\n", host->total_length);
 
-			at91_mci_write(host, AT91_PDC_TPR, host->physical_address);
-			at91_mci_write(host, AT91_PDC_TCR, host->total_length / 4);
+			at91_mci_write(host, ATMEL_PDC_TPR, host->physical_address);
+			at91_mci_write(host, ATMEL_PDC_TCR, host->total_length / 4);
 			ier = AT91_MCI_TXBUFE;
 		}
 	}
@@ -497,9 +473,9 @@ static unsigned int at91_mci_send_comman
 
 	if (cmdr & AT91_MCI_TRCMD_START) {
 		if (cmdr & AT91_MCI_TRDIR)
-			at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_RXTEN);
+			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTEN);
 		else
-			at91_mci_write(host, AT91_PDC_PTCR, AT91_PDC_TXTEN);
+			at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_TXTEN);
 	}
 	return ier;
 }
@@ -561,9 +537,7 @@ static void at91mci_completed_command(st
 	pr_debug("Status = %08X [%08X %08X %08X %08X]\n",
 		 status, cmd->resp[0], cmd->resp[1], cmd->resp[2], cmd->resp[3]);
 
-	if (status & (AT91_MCI_RINDE | AT91_MCI_RDIRE | AT91_MCI_RCRCE |
-			AT91_MCI_RENDE | AT91_MCI_RTOE | AT91_MCI_DCRCE |
-			AT91_MCI_DTOE | AT91_MCI_OVRE | AT91_MCI_UNRE)) {
+	if (status & AT91_MCI_ERRORS) {
 		if ((status & AT91_MCI_RCRCE) &&
 			((cmd->opcode == MMC_SEND_OP_COND) || (cmd->opcode == SD_APP_OP_COND))) {
 			cmd->error = MMC_ERR_NONE;
@@ -601,6 +575,32 @@ static void at91_mci_request(struct mmc_
 }
 
 /*
+ * Handle transmitted data
+ */
+static void at91_mci_handle_transmitted(struct at91mci_host *host)
+{
+	struct mmc_command *cmd;
+	struct mmc_data *data;
+
+	pr_debug("Handling the transmit\n");
+
+	/* Disable the transfer */
+	at91_mci_write(host, ATMEL_PDC_PTCR, ATMEL_PDC_RXTDIS | ATMEL_PDC_TXTDIS);
+
+	/* Now wait for cmd ready */
+	at91_mci_write(host, AT91_MCI_IDR, AT91_MCI_TXBUFE);
+	at91_mci_write(host, AT91_MCI_IER, AT91_MCI_NOTBUSY);
+
+	cmd = host->cmd;
+	if (!cmd) return;
+
+	data = cmd->data;
+	if (!data) return;
+
+	data->bytes_xfered = host->total_length;
+}
+
+/*
  * Set the IOS
  */
 static void at91_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
@@ -665,15 +665,15 @@ static irqreturn_t at91_mci_irq(int irq,
 
 	int_status = at91_mci_read(host, AT91_MCI_SR);
 	int_mask = at91_mci_read(host, AT91_MCI_IMR);
-	
+
 	pr_debug("MCI irq: status = %08X, %08X, %08X\n", int_status, int_mask,
 		int_status & int_mask);
-	
+
 	int_status = int_status & int_mask;
 
 	if (int_status & AT91_MCI_ERRORS) {
 		completed = 1;
-		
+
 		if (int_status & AT91_MCI_UNRE)
 			pr_debug("MMC: Underrun error\n");
 		if (int_status & AT91_MCI_OVRE)
@@ -821,7 +821,7 @@ static int __init at91_mci_probe(struct 
 	mmc->f_min = 375000;
 	mmc->f_max = 25000000;
 	mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
-	mmc->caps = MMC_CAP_BYTEBLOCK;
+	mmc->caps = MMC_CAP_BYTEBLOCK | MMC_CAP_MULTIWRITE;
 
 	host = mmc_priv(mmc);
 	host->mmc = mmc;
@@ -853,15 +853,15 @@ static int __init at91_mci_probe(struct 
 	host->baseaddr = ioremap(res->start, res->end - res->start + 1);
 	if (!host->baseaddr) {
 		clk_put(host->mci_clk);
-		mmc_free_host(mmc);
 		release_mem_region(res->start, res->end - res->start + 1);
+		mmc_free_host(mmc);
 		return -ENOMEM;
 	}
 
 	/*
 	 * Reset hardware
 	 */
-	clk_enable(host->mci_clk);		/* Enable the peripheral clock */
+	clk_enable(host->mci_clk);	/* Enable the peripheral clock */
 	at91_mci_disable(host);
 	at91_mci_enable(host);
 
@@ -874,9 +874,9 @@ static int __init at91_mci_probe(struct 
 		printk(KERN_ERR "AT91 MMC: Failed to request MCI interrupt\n");
 		clk_disable(host->mci_clk);
 		clk_put(host->mci_clk);
-		mmc_free_host(mmc);
 		iounmap(host->baseaddr);
 		release_mem_region(res->start, res->end - res->start + 1);
+		mmc_free_host(mmc);
 		return ret;
 	}
 
@@ -930,13 +930,13 @@ static int __exit at91_mci_remove(struct
 	mmc_remove_host(mmc);
 	free_irq(host->irq, host);
 
-	clk_disable(host->mci_clk);			/* Disable the peripheral clock */
-	clk_put(host->mci_clk);
-
 	iounmap(host->baseaddr);
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	release_mem_region(res->start, res->end - res->start + 1);
 
+	clk_disable(host->mci_clk);			/* Disable the peripheral clock */
+	clk_put(host->mci_clk);
+
 	mmc_free_host(mmc);
 	platform_set_drvdata(pdev, NULL);
 	pr_debug("MCI Removed\n");
diff -uprN linux-2.6.20/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.6.20-at92_e1.5/drivers/mtd/chips/cfi_cmdset_0001.c
--- linux-2.6.20/drivers/mtd/chips/cfi_cmdset_0001.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mtd/chips/cfi_cmdset_0001.c	2008-02-07 10:24:59.000000000 -0500
@@ -99,8 +99,8 @@ static struct mtd_chip_driver cfi_intele
 	.module		= THIS_MODULE
 };
 
-/* #define DEBUG_LOCK_BITS */
-/* #define DEBUG_CFI_FEATURES */
+//#define DEBUG_LOCK_BITS
+//#define DEBUG_CFI_FEATURES
 
 #ifdef DEBUG_CFI_FEATURES
 static void cfi_tell_features(struct cfi_pri_intelext *extp)
@@ -1281,6 +1281,7 @@ static int cfi_intelext_read (struct mtd
 			thislen = len;
 
 		ret = do_read_onechip(map, &cfi->chips[chipnum], ofs, thislen, buf);
+
 		if (ret)
 			break;
 
diff -uprN linux-2.6.20/drivers/mtd/devices/Kconfig linux-2.6.20-at92_e1.5/drivers/mtd/devices/Kconfig
--- linux-2.6.20/drivers/mtd/devices/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mtd/devices/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -267,5 +267,11 @@ config MTD_DOCPROBE_55AA
 	  LinuxBIOS or if you need to recover a DiskOnChip Millennium on which
 	  you have managed to wipe the first block.
 
-endmenu
+config MTD_AT91_DATAFLASH
+	tristate "AT91RM9200 DataFlash AT45DBxxx (legacy driver)"
+	depends on MTD && ARCH_AT91RM9200 && AT91_SPI
+	help
+	  This enables access to the DataFlash (AT45DBxxx) on the AT91RM9200.
+	  If you have such a board, say 'Y'.
 
+endmenu
diff -uprN linux-2.6.20/drivers/mtd/devices/Makefile linux-2.6.20-at92_e1.5/drivers/mtd/devices/Makefile
--- linux-2.6.20/drivers/mtd/devices/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mtd/devices/Makefile	2008-02-07 10:24:58.000000000 -0500
@@ -17,3 +17,4 @@ obj-$(CONFIG_MTD_LART)		+= lart.o
 obj-$(CONFIG_MTD_BLOCK2MTD)	+= block2mtd.o
 obj-$(CONFIG_MTD_DATAFLASH)	+= mtd_dataflash.o
 obj-$(CONFIG_MTD_M25P80)	+= m25p80.o
+obj-$(CONFIG_MTD_AT91_DATAFLASH)+= at91_dataflash.o
diff -uprN linux-2.6.20/drivers/mtd/devices/at91_dataflash.c linux-2.6.20-at92_e1.5/drivers/mtd/devices/at91_dataflash.c
--- linux-2.6.20/drivers/mtd/devices/at91_dataflash.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mtd/devices/at91_dataflash.c	2008-02-07 10:24:58.000000000 -0500
@@ -0,0 +1,640 @@
+/*
+ * Atmel DataFlash driver for Atmel AT91RM9200 (Thunder)
+ *
+ *  Copyright (C) SAN People (Pty) Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
+
+#include <asm/arch/spi.h>
+
+#undef DEBUG_DATAFLASH
+
+#define DATAFLASH_MAX_DEVICES	4	/* max number of dataflash devices */
+#undef	DATAFLASH_ALWAYS_ADD_DEVICE	/* always add whole device when using partitions? */
+
+#define OP_READ_CONTINUOUS	0xE8
+#define OP_READ_PAGE		0xD2
+#define OP_READ_BUFFER1		0xD4
+#define OP_READ_BUFFER2		0xD6
+#define OP_READ_STATUS		0xD7
+
+#define OP_ERASE_PAGE		0x81
+#define OP_ERASE_BLOCK		0x50
+
+#define OP_TRANSFER_BUF1	0x53
+#define OP_TRANSFER_BUF2	0x55
+#define OP_COMPARE_BUF1		0x60
+#define OP_COMPARE_BUF2		0x61
+
+#define OP_PROGRAM_VIA_BUF1	0x82
+#define OP_PROGRAM_VIA_BUF2	0x85
+
+struct dataflash_local
+{
+	int spi;			/* SPI chip-select number */
+
+	unsigned int page_size;		/* number of bytes per page */
+	unsigned short page_offset;	/* page offset in flash address */
+};
+
+
+/* Detected DataFlash devices */
+static struct mtd_info* mtd_devices[DATAFLASH_MAX_DEVICES];
+static int nr_devices = 0;
+
+/* ......................................................................... */
+
+#ifdef CONFIG_MTD_PARTITIONS
+
+static struct mtd_partition static_partitions_2M[] =
+{
+	{
+		.name		= "bootloader",
+		.offset		= 0,
+		.size		= 1 * 32 * 8 * 528,	/* 1st sector = 32 blocks * 8 pages * 528 bytes */
+		.mask_flags	= MTD_WRITEABLE,	/* read-only */
+	},
+	{
+		.name		= "kernel",
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= 6 * 32 * 8 * 528,	/* 6 sectors */
+	},
+	{
+		.name		= "filesystem",
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= MTDPART_SIZ_FULL,	/* rest = 9 sectors */
+	}
+};
+
+static struct mtd_partition static_partitions_4M[] =
+{
+	{
+		.name		= "bootloader",
+		.offset		= 0,
+		.size		= 1 * 64 * 8 * 528,	/* 1st sector = 64 blocks * 8 pages * 528 bytes */
+		.mask_flags	= MTD_WRITEABLE,	/* read-only */
+	},
+	{
+		.name		= "kernel",
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= 4 * 64 * 8 * 528,	/* 4 sectors */
+	},
+	{
+		.name		= "filesystem",
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= MTDPART_SIZ_FULL,	/* rest = 11 sectors */
+	}
+};
+
+#if defined(CONFIG_MACH_KAFA)
+static struct mtd_partition static_partitions_8M[] =
+{
+	{
+		name:		"romboot",
+		offset:		0,
+		size:		16 * 1056,	/* 160 Kb */
+		mask_flags:	MTD_WRITEABLE,		/* read-only */
+	},
+	{
+		name:		"uboot",
+		offset:		MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */
+		size:		128 * 1056,		/* 1 MB */
+	},
+	{
+		name:		"kernel",
+		offset:		MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */
+		size:		1024 * 1056,		/* 1 MB */
+	},
+	{
+		name:		"filesystem",
+		offset:		MTDPART_OFS_APPEND, /* Sperry, NXTBLK is broken */
+		size:		MTDPART_SIZ_FULL,
+	}
+};
+
+#else
+
+static struct mtd_partition static_partitions_8M[] =
+{
+	{
+		.name		= "bootloader",
+		.offset		= 0,
+		.size		= 1 * 32 * 8 * 1056,	/* 1st sector = 32 blocks * 8 pages * 1056 bytes */
+		.mask_flags	= MTD_WRITEABLE,	/* read-only */
+	},
+	{
+		.name		= "kernel",
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= 5 * 32 * 8 * 1056,	/* 5 sectors */
+	},
+	{
+		.name		= "filesystem",
+		.offset		= MTDPART_OFS_NXTBLK,
+		.size		= MTDPART_SIZ_FULL,	/* rest = 26 sectors */
+	}
+};
+#endif
+
+static const char *part_probes[] = { "cmdlinepart", NULL, };
+
+#endif
+
+/* ......................................................................... */
+
+/* Allocate a single SPI transfer descriptor.  We're assuming that if multiple
+   SPI transfers occur at the same time, spi_access_bus() will serialize them.
+   If this is not valid, then either (i) each dataflash 'priv' structure
+   needs it's own transfer descriptor, (ii) we lock this one, or (iii) use
+   another mechanism.   */
+static struct spi_transfer_list* spi_transfer_desc;
+
+/*
+ * Perform a SPI transfer to access the DataFlash device.
+ */
+static int do_spi_transfer(int nr, char* tx, int tx_len, char* rx, int rx_len,
+		char* txnext, int txnext_len, char* rxnext, int rxnext_len)
+{
+	struct spi_transfer_list* list = spi_transfer_desc;
+
+	list->tx[0] = tx;	list->txlen[0] = tx_len;
+	list->rx[0] = rx;	list->rxlen[0] = rx_len;
+
+	list->tx[1] = txnext;	list->txlen[1] = txnext_len;
+	list->rx[1] = rxnext;	list->rxlen[1] = rxnext_len;
+
+	list->nr_transfers = nr;
+
+	return spi_transfer(list);
+}
+
+/* ......................................................................... */
+
+/*
+ * Poll the DataFlash device until it is READY.
+ */
+static void at91_dataflash_waitready(void)
+{
+	char* command = kmalloc(2, GFP_KERNEL);
+
+	if (!command)
+		return;
+
+	do {
+		command[0] = OP_READ_STATUS;
+		command[1] = 0;
+
+		do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
+	} while ((command[1] & 0x80) == 0);
+
+	kfree(command);
+}
+
+/*
+ * Return the status of the DataFlash device.
+ */
+static unsigned short at91_dataflash_status(void)
+{
+	unsigned short status;
+	char* command = kmalloc(2, GFP_KERNEL);
+
+	if (!command)
+		return 0;
+
+	command[0] = OP_READ_STATUS;
+	command[1] = 0;
+
+	do_spi_transfer(1, command, 2, command, 2, NULL, 0, NULL, 0);
+	status = command[1];
+
+	kfree(command);
+	return status;
+}
+
+/* ......................................................................... */
+
+/*
+ * Erase blocks of flash.
+ */
+static int at91_dataflash_erase(struct mtd_info *mtd, struct erase_info *instr)
+{
+	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+	unsigned int pageaddr;
+	char* command;
+
+#ifdef DEBUG_DATAFLASH
+	printk("dataflash_erase: addr=%i len=%i\n", instr->addr, instr->len);
+#endif
+
+	/* Sanity checks */
+	if (instr->addr + instr->len > mtd->size)
+		return -EINVAL;
+	if ((instr->len % mtd->erasesize != 0) || (instr->len % priv->page_size != 0))
+		return -EINVAL;
+	if ((instr->addr % priv->page_size) != 0)
+		return -EINVAL;
+
+	command = kmalloc(4, GFP_KERNEL);
+	if (!command)
+		return -ENOMEM;
+
+	while (instr->len > 0) {
+		/* Calculate flash page address */
+		pageaddr = (instr->addr / priv->page_size) << priv->page_offset;
+
+		command[0] = OP_ERASE_PAGE;
+		command[1] = (pageaddr & 0x00FF0000) >> 16;
+		command[2] = (pageaddr & 0x0000FF00) >> 8;
+		command[3] = 0;
+#ifdef DEBUG_DATAFLASH
+		printk("ERASE: (%x) %x %x %x [%i]\n", command[0], command[1], command[2], command[3], pageaddr);
+#endif
+
+		/* Send command to SPI device */
+		spi_access_bus(priv->spi);
+		do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
+
+		at91_dataflash_waitready();		/* poll status until ready */
+		spi_release_bus(priv->spi);
+
+		instr->addr += priv->page_size;		/* next page */
+		instr->len -= priv->page_size;
+	}
+
+	kfree(command);
+
+	/* Inform MTD subsystem that erase is complete */
+	instr->state = MTD_ERASE_DONE;
+	if (instr->callback)
+		instr->callback(instr);
+
+	return 0;
+}
+
+/*
+ * Read from the DataFlash device.
+ *   from   : Start offset in flash device
+ *   len    : Amount to read
+ *   retlen : About of data actually read
+ *   buf    : Buffer containing the data
+ */
+static int at91_dataflash_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
+{
+	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+	unsigned int addr;
+	char* command;
+
+#ifdef DEBUG_DATAFLASH
+	printk("dataflash_read: %lli .. %lli\n", from, from+len);
+#endif
+
+	*retlen = 0;
+
+	/* Sanity checks */
+	if (!len)
+		return 0;
+	if (from + len > mtd->size)
+		return -EINVAL;
+
+	/* Calculate flash page/byte address */
+	addr = (((unsigned)from / priv->page_size) << priv->page_offset) + ((unsigned)from % priv->page_size);
+
+	command = kmalloc(8, GFP_KERNEL);
+	if (!command)
+		return -ENOMEM;
+
+	command[0] = OP_READ_CONTINUOUS;
+	command[1] = (addr & 0x00FF0000) >> 16;
+	command[2] = (addr & 0x0000FF00) >> 8;
+	command[3] = (addr & 0x000000FF);
+#ifdef DEBUG_DATAFLASH
+	printk("READ: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
+#endif
+
+	/* Send command to SPI device */
+	spi_access_bus(priv->spi);
+	do_spi_transfer(2, command, 8, command, 8, buf, len, buf, len);
+	spi_release_bus(priv->spi);
+
+	*retlen = len;
+	kfree(command);
+	return 0;
+}
+
+/*
+ * Write to the DataFlash device.
+ *   to     : Start offset in flash device
+ *   len    : Amount to write
+ *   retlen : Amount of data actually written
+ *   buf    : Buffer containing the data
+ */
+static int at91_dataflash_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
+{
+	struct dataflash_local *priv = (struct dataflash_local *) mtd->priv;
+	unsigned int pageaddr, addr, offset, writelen;
+	size_t remaining;
+	u_char *writebuf;
+	unsigned short status;
+	int res = 0;
+	char* command;
+	char* tmpbuf = NULL;
+
+#ifdef DEBUG_DATAFLASH
+	printk("dataflash_write: %lli .. %lli\n", to, to+len);
+#endif
+
+	*retlen = 0;
+
+	/* Sanity checks */
+	if (!len)
+		return 0;
+	if (to + len > mtd->size)
+		return -EINVAL;
+
+	command = kmalloc(4, GFP_KERNEL);
+	if (!command)
+		return -ENOMEM;
+
+	pageaddr = ((unsigned)to / priv->page_size);
+	offset = ((unsigned)to % priv->page_size);
+	if (offset + len > priv->page_size)
+		writelen = priv->page_size - offset;
+	else
+		writelen = len;
+	writebuf = (u_char *)buf;
+	remaining = len;
+
+	/* Allocate temporary buffer */
+	tmpbuf = kmalloc(priv->page_size, GFP_KERNEL);
+	if (!tmpbuf) {
+		kfree(command);
+		return -ENOMEM;
+	}
+
+	/* Gain access to the SPI bus */
+	spi_access_bus(priv->spi);
+
+	while (remaining > 0) {
+#ifdef DEBUG_DATAFLASH
+		printk("write @ %i:%i len=%i\n", pageaddr, offset, writelen);
+#endif
+
+		/* (1) Transfer to Buffer1 */
+		if (writelen != priv->page_size) {
+			addr = pageaddr << priv->page_offset;
+			command[0] = OP_TRANSFER_BUF1;
+			command[1] = (addr & 0x00FF0000) >> 16;
+			command[2] = (addr & 0x0000FF00) >> 8;
+			command[3] = 0;
+#ifdef DEBUG_DATAFLASH
+			printk("TRANSFER: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
+#endif
+			do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
+			at91_dataflash_waitready();
+		}
+
+		/* (2) Program via Buffer1 */
+		addr = (pageaddr << priv->page_offset) + offset;
+		command[0] = OP_PROGRAM_VIA_BUF1;
+		command[1] = (addr & 0x00FF0000) >> 16;
+		command[2] = (addr & 0x0000FF00) >> 8;
+		command[3] = (addr & 0x000000FF);
+#ifdef DEBUG_DATAFLASH
+		printk("PROGRAM: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
+#endif
+		do_spi_transfer(2, command, 4, command, 4, writebuf, writelen, tmpbuf, writelen);
+		at91_dataflash_waitready();
+
+		/* (3) Compare to Buffer1 */
+		addr = pageaddr << priv->page_offset;
+		command[0] = OP_COMPARE_BUF1;
+		command[1] = (addr & 0x00FF0000) >> 16;
+		command[2] = (addr & 0x0000FF00) >> 8;
+		command[3] = 0;
+#ifdef DEBUG_DATAFLASH
+		printk("COMPARE: (%x) %x %x %x\n", command[0], command[1], command[2], command[3]);
+#endif
+		do_spi_transfer(1, command, 4, command, 4, NULL, 0, NULL, 0);
+		at91_dataflash_waitready();
+
+		/* Get result of the compare operation */
+		status = at91_dataflash_status();
+		if ((status & 0x40) == 1) {
+			printk("at91_dataflash: Write error on page %i\n", pageaddr);
+			remaining = 0;
+			res = -EIO;
+		}
+
+		remaining = remaining - writelen;
+		pageaddr++;
+		offset = 0;
+		writebuf += writelen;
+		*retlen += writelen;
+
+		if (remaining > priv->page_size)
+			writelen = priv->page_size;
+		else
+			writelen = remaining;
+	}
+
+	/* Release SPI bus */
+	spi_release_bus(priv->spi);
+
+	kfree(tmpbuf);
+	kfree(command);
+	return res;
+}
+
+/* ......................................................................... */
+
+/*
+ * Initialize and register DataFlash device with MTD subsystem.
+ */
+static int __init add_dataflash(int channel, char *name, int IDsize,
+		int nr_pages, int pagesize, int pageoffset)
+{
+	struct mtd_info *device;
+	struct dataflash_local *priv;
+#ifdef CONFIG_MTD_PARTITIONS
+	struct mtd_partition *mtd_parts = 0;
+	int mtd_parts_nr = 0;
+#endif
+
+	if (nr_devices >= DATAFLASH_MAX_DEVICES) {
+		printk(KERN_ERR "at91_dataflash: Too many devices detected\n");
+		return 0;
+	}
+
+	device = kmalloc(sizeof(struct mtd_info) + strlen(name) + 8, GFP_KERNEL);
+	if (!device)
+		return -ENOMEM;
+	memset(device, 0, sizeof(struct mtd_info));
+
+	device->name = (char *)&device[1];
+	sprintf(device->name, "%s.spi%d", name, channel);
+	device->size = nr_pages * pagesize;
+	device->erasesize = pagesize;
+	device->writesize = pagesize;
+	device->owner = THIS_MODULE;
+	device->type = MTD_DATAFLASH;
+	device->flags = MTD_WRITEABLE;
+	device->erase = at91_dataflash_erase;
+	device->read = at91_dataflash_read;
+	device->write = at91_dataflash_write;
+
+	priv = (struct dataflash_local *) kmalloc(sizeof(struct dataflash_local), GFP_KERNEL);
+	if (!priv) {
+		kfree(device);
+		return -ENOMEM;
+	}
+	memset(priv, 0, sizeof(struct dataflash_local));
+
+	priv->spi = channel;
+	priv->page_size = pagesize;
+	priv->page_offset = pageoffset;
+	device->priv = priv;
+
+	mtd_devices[nr_devices] = device;
+	nr_devices++;
+	printk("at91_dataflash: %s detected [spi%i] (%i bytes)\n", name, channel, device->size);
+
+#ifdef CONFIG_MTD_PARTITIONS
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+	mtd_parts_nr = parse_mtd_partitions(device, part_probes, &mtd_parts, 0);
+#endif
+	if (mtd_parts_nr <= 0) {
+		switch (IDsize) {
+			case SZ_2M:
+				mtd_parts = static_partitions_2M;
+				mtd_parts_nr = ARRAY_SIZE(static_partitions_2M);
+				break;
+			case SZ_4M:
+				mtd_parts = static_partitions_4M;
+				mtd_parts_nr = ARRAY_SIZE(static_partitions_4M);
+				break;
+			case SZ_8M:
+				mtd_parts = static_partitions_8M;
+				mtd_parts_nr = ARRAY_SIZE(static_partitions_8M);
+				break;
+		}
+	}
+
+	if (mtd_parts_nr > 0) {
+#ifdef DATAFLASH_ALWAYS_ADD_DEVICE
+		add_mtd_device(device);
+#endif
+		return add_mtd_partitions(device, mtd_parts, mtd_parts_nr);
+	}
+#endif
+	return add_mtd_device(device);		/* add whole device */
+}
+
+/*
+ * Detect and initialize DataFlash device connected to specified SPI channel.
+ *
+ *   Device            Density         ID code                 Nr Pages        Page Size       Page offset
+ *   AT45DB011B        1Mbit   (128K)  xx0011xx (0x0c)         512             264             9
+ *   AT45DB021B        2Mbit   (256K)  xx0101xx (0x14)         1025            264             9
+ *   AT45DB041B        4Mbit   (512K)  xx0111xx (0x1c)         2048            264             9
+ *   AT45DB081B        8Mbit   (1M)    xx1001xx (0x24)         4096            264             9
+ *   AT45DB0161B       16Mbit  (2M)    xx1011xx (0x2c)         4096            528             10
+ *   AT45DB0321B       32Mbit  (4M)    xx1101xx (0x34)         8192            528             10
+ *   AT45DB0642        64Mbit  (8M)    xx1111xx (0x3c)         8192            1056            11
+ *   AT45DB1282        128Mbit (16M)   xx0100xx (0x10)         16384           1056            11
+ */
+static int __init at91_dataflash_detect(int channel)
+{
+	int res = 0;
+	unsigned short status;
+
+	spi_access_bus(channel);
+	status = at91_dataflash_status();
+	spi_release_bus(channel);
+	if (status != 0xff) {			/* no dataflash device there */
+		switch (status & 0x3c) {
+			case 0x0c:	/* 0 0 1 1 */
+				res = add_dataflash(channel, "AT45DB011B", SZ_128K, 512, 264, 9);
+				break;
+			case 0x14:	/* 0 1 0 1 */
+				res = add_dataflash(channel, "AT45DB021B", SZ_256K, 1025, 264, 9);
+				break;
+			case 0x1c:	/* 0 1 1 1 */
+				res = add_dataflash(channel, "AT45DB041B", SZ_512K, 2048, 264, 9);
+				break;
+			case 0x24:	/* 1 0 0 1 */
+				res = add_dataflash(channel, "AT45DB081B", SZ_1M, 4096, 264, 9);
+				break;
+			case 0x2c:	/* 1 0 1 1 */
+				res = add_dataflash(channel, "AT45DB161B", SZ_2M, 4096, 528, 10);
+				break;
+			case 0x34:	/* 1 1 0 1 */
+				res = add_dataflash(channel, "AT45DB321B", SZ_4M, 8192, 528, 10);
+				break;
+			case 0x3c:	/* 1 1 1 1 */
+				res = add_dataflash(channel, "AT45DB642", SZ_8M, 8192, 1056, 11);
+				break;
+// Currently unsupported since Atmel removed the "Main Memory Program via Buffer" commands.
+//			case 0x10:	/* 0 1 0 0 */
+//				res = add_dataflash(channel, "AT45DB1282", SZ_16M, 16384, 1056, 11);
+//				break;
+			default:
+				printk(KERN_ERR "at91_dataflash: Unknown device (%x)\n", status & 0x3c);
+		}
+	}
+
+	return res;
+}
+
+static int __init at91_dataflash_init(void)
+{
+	spi_transfer_desc = kmalloc(sizeof(struct spi_transfer_list), GFP_KERNEL);
+	if (!spi_transfer_desc)
+		return -ENOMEM;
+
+	/* DataFlash (SPI chip select 0) */
+	at91_dataflash_detect(0);
+
+#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
+	/* DataFlash card (SPI chip select 3) */
+	at91_dataflash_detect(3);
+#endif
+
+	return 0;
+}
+
+static void __exit at91_dataflash_exit(void)
+{
+	int i;
+
+	for (i = 0; i < DATAFLASH_MAX_DEVICES; i++) {
+		if (mtd_devices[i]) {
+#ifdef CONFIG_MTD_PARTITIONS
+			del_mtd_partitions(mtd_devices[i]);
+#else
+			del_mtd_device(mtd_devices[i]);
+#endif
+			kfree(mtd_devices[i]->priv);
+			kfree(mtd_devices[i]);
+		}
+	}
+	nr_devices = 0;
+	kfree(spi_transfer_desc);
+}
+
+
+module_init(at91_dataflash_init);
+module_exit(at91_dataflash_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Andrew Victor");
+MODULE_DESCRIPTION("DataFlash driver for Atmel AT91RM9200");
diff -uprN linux-2.6.20/drivers/mtd/maps/physmap.c linux-2.6.20-at92_e1.5/drivers/mtd/maps/physmap.c
--- linux-2.6.20/drivers/mtd/maps/physmap.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mtd/maps/physmap.c	2008-02-07 10:24:59.000000000 -0500
@@ -83,7 +83,7 @@ static int physmap_flash_probe(struct pl
 	struct physmap_flash_info *info;
 	const char **probe_type;
 	int err;
-
+	
 	physmap_data = dev->dev.platform_data;
 	if (physmap_data == NULL)
 		return -ENODEV;
@@ -114,8 +114,9 @@ static int physmap_flash_probe(struct pl
 	info->map.size = dev->resource->end - dev->resource->start + 1;
 	info->map.bankwidth = physmap_data->width;
 	info->map.set_vpp = physmap_data->set_vpp;
+	
+	info->map.virt = ioremap_nocache(info->map.phys, info->map.size); 
 
-	info->map.virt = ioremap(info->map.phys, info->map.size);
 	if (info->map.virt == NULL) {
 		dev_err(&dev->dev, "Failed to ioremap flash region\n");
 		err = EIO;
diff -uprN linux-2.6.20/drivers/mtd/nand/at91_nand.c linux-2.6.20-at92_e1.5/drivers/mtd/nand/at91_nand.c
--- linux-2.6.20/drivers/mtd/nand/at91_nand.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mtd/nand/at91_nand.c	2008-02-07 10:24:58.000000000 -0500
@@ -82,6 +82,10 @@ static void at91_nand_disable(struct at9
 		at91_set_gpio_value(host->board->enable_pin, 1);
 }
 
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
 /*
  * Probe for the NAND device.
  */
@@ -151,6 +155,12 @@ static int __init at91_nand_probe(struct
 #ifdef CONFIG_MTD_PARTITIONS
 	if (host->board->partition_info)
 		partitions = host->board->partition_info(mtd->size, &num_partitions);
+#ifdef CONFIG_MTD_CMDLINE_PARTS
+	else {
+		mtd->name = "at91_nand";
+		num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0);
+	}
+#endif
 
 	if ((!partitions) || (num_partitions == 0)) {
 		printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n");
diff -uprN linux-2.6.20/drivers/mtd/nand/nand_base.c linux-2.6.20-at92_e1.5/drivers/mtd/nand/nand_base.c
--- linux-2.6.20/drivers/mtd/nand/nand_base.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mtd/nand/nand_base.c	2008-02-07 10:24:58.000000000 -0500
@@ -2307,6 +2307,8 @@ static struct nand_flash_dev *nand_get_f
 	       " 0x%02x, Chip ID: 0x%02x (%s %s)\n", *maf_id, dev_id,
 	       nand_manuf_ids[maf_idx].name, type->name);
 
+ 	printk(KERN_INFO "NAND: Pagesize: %u, Blocksize: %uK, OOBsize: %u\n",
+ 		mtd->writesize, mtd->erasesize/1024, mtd->oobsize);
 	return type;
 }
 
diff -uprN linux-2.6.20/drivers/mtd/nand/nand_ids.c linux-2.6.20-at92_e1.5/drivers/mtd/nand/nand_ids.c
--- linux-2.6.20/drivers/mtd/nand/nand_ids.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/mtd/nand/nand_ids.c	2008-02-07 10:24:58.000000000 -0500
@@ -137,6 +137,7 @@ struct nand_manufacturers nand_manuf_ids
 	{NAND_MFR_RENESAS, "Renesas"},
 	{NAND_MFR_STMICRO, "ST Micro"},
 	{NAND_MFR_HYNIX, "Hynix"},
+	{NAND_MFR_MICRON, "Micron"},
 	{0x0, "Unknown"}
 };
 
diff -uprN linux-2.6.20/drivers/net/Kconfig linux-2.6.20-at92_e1.5/drivers/net/Kconfig
--- linux-2.6.20/drivers/net/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/net/Kconfig	2008-02-07 10:24:58.000000000 -0500
@@ -190,7 +190,7 @@ config MII
 
 config MACB
 	tristate "Atmel MACB support"
-	depends on NET_ETHERNET && AVR32
+	depends on NET_ETHERNET && (AVR32 || ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
 	select MII
 	help
 	  The Atmel MACB ethernet interface is found on many AT32 and AT91
@@ -199,6 +199,12 @@ config MACB
 	  To compile this driver as a module, choose M here: the module
 	  will be called macb.
 
+config MACB_TX_SRAM
+	bool "Atmel MACB TX buffers in internal SRAM"
+	depends on NET_ETHERNET && MACB && (ARCH_AT91SAM9260 || ARCH_AT91SAM9263)
+	help
+	  Use internal SRAM for TX buffers.
+
 source "drivers/net/arm/Kconfig"
 
 config MACE
diff -uprN linux-2.6.20/drivers/net/arm/at91_ether.c linux-2.6.20-at92_e1.5/drivers/net/arm/at91_ether.c
--- linux-2.6.20/drivers/net/arm/at91_ether.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/net/arm/at91_ether.c	2008-02-07 10:24:58.000000000 -0500
@@ -943,14 +943,22 @@ static int __init at91ether_setup(unsign
 	struct net_device *dev;
 	struct at91_private *lp;
 	unsigned int val;
-	int res;
+	struct resource *res;
+	int ret;
 
 	dev = alloc_etherdev(sizeof(struct at91_private));
 	if (!dev)
 		return -ENOMEM;
 
-	dev->base_addr = AT91_VA_BASE_EMAC;
-	dev->irq = AT91RM9200_ID_EMAC;
+	/* Get I/O base address and IRQ */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res) {
+		free_netdev(dev);
+		return -ENODEV;
+	}
+	dev->base_addr = res->start;
+	dev->irq = platform_get_irq(pdev, 0);
+
 	SET_MODULE_OWNER(dev);
 
 	/* Install the interrupt handler */
@@ -1023,12 +1031,12 @@ static int __init at91ether_setup(unsign
 	lp->phy_address = phy_address;	/* MDI address of PHY */
 
 	/* Register the network interface */
-	res = register_netdev(dev);
-	if (res) {
+	ret = register_netdev(dev);
+	if (ret) {
 		free_irq(dev->irq, dev);
 		free_netdev(dev);
 		dma_free_coherent(NULL, sizeof(struct recv_desc_bufs), lp->dlist, (dma_addr_t)lp->dlist_phys);
-		return res;
+		return ret;
 	}
 
 	/* Determine current link speed */
@@ -1103,7 +1111,7 @@ static int __init at91ether_probe(struct
 			case MII_LXT971A_ID:		/* Intel LXT971A: PHY_ID1 = 0x13, PHY_ID2 = 78E0 */
 			case MII_RTL8201_ID:		/* Realtek RTL8201: PHY_ID1 = 0, PHY_ID2 = 0x8201 */
 			case MII_BCM5221_ID:		/* Broadcom BCM5221: PHY_ID1 = 0x40, PHY_ID2 = 0x61e0 */
-			case MII_DP83847_ID:		/* National Semiconductor DP83847:  */
+			case MII_DP83847_ID:		/* National Semiconductor DP83847: */
 			case MII_AC101L_ID:		/* Altima AC101L: PHY_ID1 = 0x22, PHY_ID2 = 0x5520 */
 			case MII_KS8721_ID:		/* Micrel KS8721: PHY_ID1 = 0x22, PHY_ID2 = 0x1610 */
 				detected = at91ether_setup(phy_id, phy_address, pdev, ether_clk);
diff -uprN linux-2.6.20/drivers/net/macb.c linux-2.6.20-at92_e1.5/drivers/net/macb.c
--- linux-2.6.20/drivers/net/macb.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/net/macb.c	2008-02-07 10:24:59.000000000 -0500
@@ -36,9 +36,21 @@
 /* Make the IP header word-aligned (the ethernet header is 14 bytes) */
 #define RX_OFFSET		2
 
-#define TX_RING_SIZE		128
+#if defined(CONFIG_ARCH_AT91) && defined(CONFIG_MACB_TX_SRAM) 
+  #if defined(CONFIG_ARCH_AT91SAM9260)
+    #define TX_RING_SIZE		2	
+  #elif defined(CONFIG_ARCH_AT91SAM9263)
+    #define TX_RING_SIZE		32	
+  #endif
+  #define TX_BUFFER_SIZE		1536
+  #define TX_RING_BYTES		(sizeof(struct dma_desc) * TX_RING_SIZE)
+  #define TX_DMA_SIZE		((TX_RING_BYTES) + (TX_RING_SIZE) * (TX_BUFFER_SIZE))
+#else
+  #define TX_RING_SIZE		128
+  #define TX_RING_BYTES		(sizeof(struct dma_desc) * TX_RING_SIZE)
+#endif
+
 #define DEF_TX_RING_PENDING	(TX_RING_SIZE - 1)
-#define TX_RING_BYTES		(sizeof(struct dma_desc) * TX_RING_SIZE)
 
 #define TX_RING_GAP(bp)						\
 	(TX_RING_SIZE - (bp)->tx_pending)
@@ -319,8 +331,10 @@ static void macb_tx(struct macb *bp)
 
 		dev_dbg(&bp->pdev->dev, "skb %u (data %p) TX complete\n",
 			tail, skb->data);
+#if !defined(CONFIG_MACB_TX_SRAM) 
 		dma_unmap_single(&bp->pdev->dev, rp->mapping, skb->len,
 				 DMA_TO_DEVICE);
+#endif
 		bp->stats.tx_packets++;
 		bp->stats.tx_bytes += skb->len;
 		rp->skb = NULL;
@@ -602,8 +616,13 @@ static int macb_start_xmit(struct sk_buf
 
 	entry = bp->tx_head;
 	dev_dbg(&bp->pdev->dev, "Allocated ring entry %u\n", entry);
+#if defined(CONFIG_ARCH_AT91) && defined(CONFIG_MACB_TX_SRAM)
+	mapping = bp->tx_ring[entry].addr;
+	memcpy(bp->tx_buffers + entry * TX_BUFFER_SIZE, skb->data, len);
+#else
 	mapping = dma_map_single(&bp->pdev->dev, skb->data,
 				 len, DMA_TO_DEVICE);
+#endif
 	bp->tx_skb[entry].skb = skb;
 	bp->tx_skb[entry].mapping = mapping;
 	dev_dbg(&bp->pdev->dev, "Mapped skb data %p to DMA addr %08lx\n",
@@ -614,7 +633,9 @@ static int macb_start_xmit(struct sk_buf
 	if (entry == (TX_RING_SIZE - 1))
 		ctrl |= MACB_BIT(TX_WRAP);
 
+#if !defined(CONFIG_MACB_TX_SRAM)
 	bp->tx_ring[entry].addr = mapping;
+#endif
 	bp->tx_ring[entry].ctrl = ctrl;
 	wmb();
 
@@ -645,8 +666,12 @@ static void macb_free_consistent(struct 
 		bp->rx_ring = NULL;
 	}
 	if (bp->tx_ring) {
+#if defined(CONFIG_ARCH_AT91) && defined(CONFIG_MACB_TX_SRAM)
+		iounmap((void *)bp->tx_ring);
+#else
 		dma_free_coherent(&bp->pdev->dev, TX_RING_BYTES,
 				  bp->tx_ring, bp->tx_ring_dma);
+#endif
 		bp->tx_ring = NULL;
 	}
 	if (bp->rx_buffers) {
@@ -655,6 +680,11 @@ static void macb_free_consistent(struct 
 				  bp->rx_buffers, bp->rx_buffers_dma);
 		bp->rx_buffers = NULL;
 	}
+
+#if defined(CONFIG_ARCH_AT91) && defined(CONFIG_MACB_TX_SRAM)
+	if (bp->tx_ring_dma)
+		release_mem_region(bp->tx_ring_dma, TX_DMA_SIZE);
+#endif
 }
 
 static int macb_alloc_consistent(struct macb *bp)
@@ -675,6 +705,34 @@ static int macb_alloc_consistent(struct 
 		"Allocated RX ring of %d bytes at %08lx (mapped %p)\n",
 		size, (unsigned long)bp->rx_ring_dma, bp->rx_ring);
 
+#if defined(CONFIG_ARCH_AT91) && defined(CONFIG_MACB_TX_SRAM) 
+#if defined(CONFIG_ARCH_AT91SAM9260)
+	if (request_mem_region(AT91SAM9260_SRAM0_BASE, TX_DMA_SIZE, "macb")) {
+		bp->tx_ring_dma = AT91SAM9260_SRAM0_BASE;
+	} else {
+		if (request_mem_region(AT91SAM9260_SRAM1_BASE, TX_DMA_SIZE, "macb")) {
+			bp->tx_ring_dma = AT91SAM9260_SRAM1_BASE;
+		} else {
+			printk(KERN_WARNING "Cannot request SRAM memory for TX ring, already used\n");
+			return -EBUSY;
+		}
+	}
+#elif defined(CONFIG_ARCH_AT91SAM9263)
+	if (request_mem_region(AT91SAM9263_SRAM0_BASE, TX_DMA_SIZE, "macb")) {
+		bp->tx_ring_dma = AT91SAM9263_SRAM0_BASE;
+	} else {
+		printk(KERN_WARNING "Cannot request SRAM memory for TX ring, already used\n");
+		return -EBUSY;
+	}
+#endif
+
+	bp->tx_ring = ioremap(bp->tx_ring_dma, TX_DMA_SIZE);
+	if (!bp->tx_ring)
+		return -ENOMEM;
+
+	bp->tx_buffers_dma = bp->tx_ring_dma + TX_RING_BYTES;
+	bp->tx_buffers = (char*) bp->tx_ring + TX_RING_BYTES;
+#else
 	size = TX_RING_BYTES;
 	bp->tx_ring = dma_alloc_coherent(&bp->pdev->dev, size,
 					 &bp->tx_ring_dma, GFP_KERNEL);
@@ -683,6 +741,7 @@ static int macb_alloc_consistent(struct 
 	dev_dbg(&bp->pdev->dev,
 		"Allocated TX ring of %d bytes at %08lx (mapped %p)\n",
 		size, (unsigned long)bp->tx_ring_dma, bp->tx_ring);
+#endif
 
 	size = RX_RING_SIZE * RX_BUFFER_SIZE;
 	bp->rx_buffers = dma_alloc_coherent(&bp->pdev->dev, size,
@@ -713,10 +772,18 @@ static void macb_init_rings(struct macb 
 	}
 	bp->rx_ring[RX_RING_SIZE - 1].addr |= MACB_BIT(RX_WRAP);
 
+#if defined(CONFIG_ARCH_AT91) && defined(CONFIG_MACB_TX_SRAM)  
+	for (i = 0; i < TX_RING_SIZE; i++) {
+		bp->tx_ring[i].addr = bp->tx_buffers_dma + i * TX_BUFFER_SIZE;
+		bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
+	}
+#else
 	for (i = 0; i < TX_RING_SIZE; i++) {
 		bp->tx_ring[i].addr = 0;
 		bp->tx_ring[i].ctrl = MACB_BIT(TX_USED);
 	}
+#endif
+
 	bp->tx_ring[TX_RING_SIZE - 1].ctrl |= MACB_BIT(TX_WRAP);
 
 	bp->rx_tail = bp->tx_head = bp->tx_tail = 0;
@@ -883,27 +950,15 @@ static struct net_device_stats *macb_get
 static int macb_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct macb *bp = netdev_priv(dev);
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&bp->lock, flags);
-	ret = mii_ethtool_gset(&bp->mii, cmd);
-	spin_unlock_irqrestore(&bp->lock, flags);
 
-	return ret;
+	return mii_ethtool_gset(&bp->mii, cmd);
 }
 
 static int macb_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
 	struct macb *bp = netdev_priv(dev);
-	int ret;
-	unsigned long flags;
-
-	spin_lock_irqsave(&bp->lock, flags);
-	ret = mii_ethtool_sset(&bp->mii, cmd);
-	spin_unlock_irqrestore(&bp->lock, flags);
 
-	return ret;
+	return mii_ethtool_sset(&bp->mii, cmd);
 }
 
 static void macb_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -932,17 +987,11 @@ static struct ethtool_ops macb_ethtool_o
 static int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
 {
 	struct macb *bp = netdev_priv(dev);
-	int ret;
-	unsigned long flags;
 
 	if (!netif_running(dev))
 		return -EINVAL;
 
-	spin_lock_irqsave(&bp->lock, flags);
-	ret = generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL);
-	spin_unlock_irqrestore(&bp->lock, flags);
-
-	return ret;
+	return generic_mii_ioctl(&bp->mii, if_mii(rq), cmd, NULL);
 }
 
 static ssize_t macb_mii_show(const struct class_device *cd, char *buf,
@@ -1046,6 +1095,14 @@ static int __devinit macb_probe(struct p
 
 	spin_lock_init(&bp->lock);
 
+#if defined(CONFIG_ARCH_AT91)
+	bp->macb_clk = clk_get(&pdev->dev, "macb_clk");
+	if (IS_ERR(bp->macb_clk)) {
+		dev_err(&pdev->dev, "failed to get macb_clk\n");
+		goto err_out_free_dev;
+	}
+	clk_enable(bp->macb_clk);
+#else
 	bp->pclk = clk_get(&pdev->dev, "pclk");
 	if (IS_ERR(bp->pclk)) {
 		dev_err(&pdev->dev, "failed to get pclk\n");
@@ -1059,6 +1116,7 @@ static int __devinit macb_probe(struct p
 
 	clk_enable(bp->pclk);
 	clk_enable(bp->hclk);
+#endif
 
 	bp->regs = ioremap(regs->start, regs->end - regs->start + 1);
 	if (!bp->regs) {
@@ -1093,7 +1151,12 @@ static int __devinit macb_probe(struct p
 	init_completion(&bp->mdio_complete);
 
 	/* Set MII management clock divider */
+#if defined(CONFIG_ARCH_AT91)
+	pclk_hz = clk_get_rate(bp->macb_clk);
+#else
 	pclk_hz = clk_get_rate(bp->pclk);
+#endif
+
 	if (pclk_hz <= 20000000)
 		config = MACB_BF(CLK, MACB_CLK_DIV8);
 	else if (pclk_hz <= 40000000)
@@ -1119,9 +1182,17 @@ static int __devinit macb_probe(struct p
 
 	pdata = pdev->dev.platform_data;
 	if (pdata && pdata->is_rmii)
+	#if defined(CONFIG_ARCH_AT91)
+		macb_writel(bp, USRIO, (MACB_BIT(RMII) | MACB_BIT(CLKEN)) );
+	#else
 		macb_writel(bp, USRIO, 0);
+	#endif
 	else
-		macb_writel(bp, USRIO, MACB_BIT(MII));
+	#if defined(CONFIG_ARCH_AT91)
+		macb_writel(bp, USRIO, MACB_BIT(CLKEN));
+	#else
+	 	macb_writel(bp, USRIO, MACB_BIT(MII));
+	#endif
 
 	bp->tx_pending = DEF_TX_RING_PENDING;
 
@@ -1148,11 +1219,15 @@ err_out_free_irq:
 err_out_iounmap:
 	iounmap(bp->regs);
 err_out_disable_clocks:
+#if defined(CONFIG_ARCH_AT91)
+	clk_disable(bp->macb_clk);	
+#else
 	clk_disable(bp->hclk);
 	clk_disable(bp->pclk);
 	clk_put(bp->hclk);
 err_out_put_pclk:
 	clk_put(bp->pclk);
+#endif
 err_out_free_dev:
 	free_netdev(dev);
 err_out:
diff -uprN linux-2.6.20/drivers/net/macb.h linux-2.6.20-at92_e1.5/drivers/net/macb.h
--- linux-2.6.20/drivers/net/macb.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/net/macb.h	2008-02-07 10:24:59.000000000 -0500
@@ -200,7 +200,7 @@
 #define MACB_SOF_OFFSET				30
 #define MACB_SOF_SIZE				2
 
-/* Bitfields in USRIO */
+/* Bitfields in USRIO (AVR32) */
 #define MACB_MII_OFFSET				0
 #define MACB_MII_SIZE				1
 #define MACB_EAM_OFFSET				1
@@ -210,6 +210,12 @@
 #define MACB_TX_PAUSE_ZERO_OFFSET		3
 #define MACB_TX_PAUSE_ZERO_SIZE			1
 
+/* Bitfields in USRIO (AT91) */
+#define MACB_RMII_OFFSET			0
+#define MACB_RMII_SIZE				1
+#define MACB_CLKEN_OFFSET			1
+#define MACB_CLKEN_SIZE				1
+
 /* Bitfields in WOL */
 #define MACB_IP_OFFSET				0
 #define MACB_IP_SIZE				16
@@ -362,9 +368,12 @@ struct macb {
 	unsigned int		tx_head, tx_tail;
 	struct dma_desc		*tx_ring;
 	struct ring_info	*tx_skb;
-
+#if defined(CONFIG_ARCH_AT91)
+	void			*tx_buffers;
+#endif
 	spinlock_t		lock;
 	struct platform_device	*pdev;
+	struct clk		*macb_clk;
 	struct clk		*pclk;
 	struct clk		*hclk;
 	struct net_device	*dev;
@@ -374,7 +383,9 @@ struct macb {
 	dma_addr_t		rx_ring_dma;
 	dma_addr_t		tx_ring_dma;
 	dma_addr_t		rx_buffers_dma;
-
+#if defined(CONFIG_ARCH_AT91)
+	dma_addr_t		tx_buffers_dma;
+#endif
 	unsigned int		rx_pending, tx_pending;
 
 	struct delayed_work	periodic_task;
diff -uprN linux-2.6.20/drivers/pcmcia/at91_cf.c linux-2.6.20-at92_e1.5/drivers/pcmcia/at91_cf.c
--- linux-2.6.20/drivers/pcmcia/at91_cf.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/pcmcia/at91_cf.c	2008-02-07 10:24:59.000000000 -0500
@@ -333,20 +333,27 @@ static int at91_cf_suspend(struct platfo
 	struct at91_cf_data	*board = cf->board;
 
 	pcmcia_socket_dev_suspend(&pdev->dev, mesg);
+
 	if (device_may_wakeup(&pdev->dev)) {
 		enable_irq_wake(board->det_pin);
 		if (board->irq_pin)
 			enable_irq_wake(board->irq_pin);
-	} else {
-		disable_irq_wake(board->det_pin);
-		if (board->irq_pin)
-			disable_irq_wake(board->irq_pin);
 	}
+
 	return 0;
 }
 
 static int at91_cf_resume(struct platform_device *pdev)
 {
+	struct at91_cf_socket	*cf = platform_get_drvdata(pdev);
+	struct at91_cf_data	*board = cf->board;
+
+	if (device_may_wakeup(&pdev->dev)) {
+		disable_irq_wake(board->det_pin);
+		if (board->irq_pin)
+			disable_irq_wake(board->irq_pin);
+	}
+
 	pcmcia_socket_dev_resume(&pdev->dev);
 	return 0;
 }
diff -uprN linux-2.6.20/drivers/rtc/Kconfig linux-2.6.20-at92_e1.5/drivers/rtc/Kconfig
--- linux-2.6.20/drivers/rtc/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/rtc/Kconfig	2008-02-07 10:24:59.000000000 -0500
@@ -1,4 +1,4 @@
-\#
+#
 # RTC class/drivers configuration
 #
 
@@ -294,6 +294,12 @@ config RTC_DRV_AT91RM9200
 	help
 	  Driver for the Atmel AT91RM9200's internal RTC (Realtime Clock).
 
+config RTC_DRV_AT91SAM926X
+	tristate "AT91SAM926X"
+	depends on RTC_CLASS
+	help
+	  Driver for the Atmel AT91RM926x's internal RTC (Realtime Clock).
+
 config RTC_DRV_TEST
 	tristate "Test driver/device"
 	depends on RTC_CLASS
diff -uprN linux-2.6.20/drivers/rtc/Makefile linux-2.6.20-at92_e1.5/drivers/rtc/Makefile
--- linux-2.6.20/drivers/rtc/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/rtc/Makefile	2008-02-07 10:24:59.000000000 -0500
@@ -36,4 +36,5 @@ obj-$(CONFIG_RTC_DRV_PL031)	+= rtc-pl031
 obj-$(CONFIG_RTC_DRV_MAX6902)	+= rtc-max6902.o
 obj-$(CONFIG_RTC_DRV_V3020)	+= rtc-v3020.o
 obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
+obj-$(CONFIG_RTC_DRV_AT91SAM926X)+= rtc-at91sam926x.o
 obj-$(CONFIG_RTC_DRV_SH)	+= rtc-sh.o
diff -uprN linux-2.6.20/drivers/rtc/rtc-at91sam926x.c linux-2.6.20-at92_e1.5/drivers/rtc/rtc-at91sam926x.c
--- linux-2.6.20/drivers/rtc/rtc-at91sam926x.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/rtc/rtc-at91sam926x.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,498 @@
+/*
+ *	Real Time Clock interface for Linux on Atmel AT91SAM926x family of SoC
+ *
+ *      Uses the RTT peripheral of the AT91SAM926x and a 32 bit word
+ *      of the General Purpose Backup Registers (GPBR). 
+ *
+ *	2007 Michel Benoit
+ *  2007 update by EMAC.Inc to support legacy alarm set calls and a minor bug fix.
+ * 
+ *      Based on rtc-at91rm9200.c by Rick Bronson
+ * 
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License
+ *	as published by the Free Software Foundation; either version
+ *	2 of the License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/time.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/completion.h>
+
+#include <asm/uaccess.h>
+#include <asm/rtc.h>
+
+#include <asm/mach/time.h>
+#include <asm/arch/board.h>
+#include <asm/arch/at91_rtt.h>
+#include <asm/arch/at91sam9260.h>
+
+#define AT91_RTC_FREQ		1
+
+static unsigned long gpbr_offset = 0;
+
+/*
+ * Read current time and date in RTC
+ */
+static int at91_rtc_readtime(struct device *dev, struct rtc_time *tm)
+{
+    unsigned long secs1;
+    unsigned long secs2;
+    unsigned long base;
+        
+    /* retrieve time base from battery backup register */ 
+    base = at91_sys_read( AT91_GPBR + gpbr_offset );
+    if( base == 0 ){
+        /* time has not been set */
+        return -1;
+    }
+
+    /* read the second counter twice as it can be about to change */
+    secs1 = at91_sys_read( AT91_RTT_VR ); 
+    secs2 = at91_sys_read( AT91_RTT_VR );
+    if( secs2!=secs1 ){
+        secs2 = at91_sys_read( AT91_RTT_VR );
+    } 
+    
+    rtc_time_to_tm( secs2+base, tm );
+
+    pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+             1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+             tm->tm_hour, tm->tm_min, tm->tm_sec);
+    
+    return 0;
+}
+
+/*
+ * Set current time and date in RTC
+ */
+static int at91_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+
+    unsigned long base;
+    unsigned long alarm;
+    unsigned long mr;
+    
+    mr = at91_sys_read( AT91_RTT_MR );
+
+    /* disable interrupts */
+    at91_sys_write( AT91_RTT_MR, 
+                    mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN) );
+
+    /* read old base time */
+    base = at91_sys_read( AT91_GPBR + gpbr_offset);
+
+    /* store the new base time in a battery backup register */
+    secs+=1;
+    at91_sys_write( AT91_GPBR + gpbr_offset, secs );
+
+    /* adjust the alarm time for the new base */
+    alarm = at91_sys_read( AT91_RTT_AR );
+    if( alarm != 0xffffffff ){
+        if( base > secs ){
+            /* time jumped backwards, increase time until alarm */
+            alarm += (base-secs);
+        } else if ((alarm+base) > secs){
+            /* time jumped forwards, decrease time until alarm */
+            alarm -= (secs-base);
+        } else {
+            /* time jumped past the alarm, disable alarm */
+            alarm = 0xffffffff;   
+        }
+        at91_sys_write( AT91_RTT_AR, alarm );
+    }
+
+    /* restart the timer, set the prescaler fo 1Hz and re-enable interrupts */
+    mr |= (0x8000 & AT91_RTT_RTPRES);
+    at91_sys_write( AT91_RTT_MR, mr | AT91_RTT_RTTRST );
+
+    return 0;
+}
+
+static int at91_rtc_settime(struct device *dev, struct rtc_time *tm)
+{
+	
+    int err;
+    unsigned long secs;
+
+    pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+             1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+             tm->tm_hour, tm->tm_min, tm->tm_sec);
+     	
+	err = rtc_tm_to_time(tm, &secs);
+	if (err != 0)
+		return err;
+
+	return at91_rtc_set_mmss(dev, secs);
+
+}
+
+/*
+ * Read alarm time and date in RTC
+ */
+static int at91_rtc_readalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	struct rtc_time *tm = &alrm->time;
+        unsigned long base;
+        unsigned long alarm;
+
+       alarm = at91_sys_read( AT91_RTT_AR );
+        
+        if( alarm == 0xffffffff ){
+         
+            memset( tm, 0, sizeof(tm) );
+            
+        } else {
+
+            base = at91_sys_read( AT91_GPBR + gpbr_offset );
+            
+            rtc_time_to_tm( alarm+base, tm );
+            
+            pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+                     1900 + tm->tm_year, tm->tm_mon, tm->tm_mday,
+                     tm->tm_hour, tm->tm_min, tm->tm_sec);
+        }
+
+	return 0;
+}
+
+/*
+ * Set alarm time and date in RTC
+ */
+static int at91_rtc_setalarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+		struct rtc_time *tm = &alrm->time;
+        unsigned long secs;
+        unsigned long base;
+        int err; 
+		struct rtc_time now;//alarm merge with current time to support legacy alarm calls
+        at91_rtc_readtime(dev, &now);//get current time
+        rtc_merge_alarm(&now, tm);//replace invalid fields with the current time
+     
+            err = rtc_tm_to_time(tm, &secs);
+            if (err != 0)
+		return err;
+            
+            base = at91_sys_read( AT91_GPBR + gpbr_offset );
+            if( base == 0 ){
+                /* time is not set */
+                return -1;
+            } 
+
+            if( secs > base ){
+                at91_sys_write( AT91_RTT_AR, secs-base );
+  
+                pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+                         tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+                         tm->tm_min, tm->tm_sec);           
+                
+            } else {
+                /* alarm is before base time, disable alarm */
+                at91_sys_write( AT91_RTT_AR, 0xffffffff );
+
+                pr_debug("%s(): INVALID %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+                         tm->tm_year, tm->tm_mon, tm->tm_mday, tm->tm_hour,
+                         tm->tm_min, tm->tm_sec);               
+                return -1;
+            }
+        
+	return 0;
+}
+
+/*
+ * Handle commands from user-space
+ */
+static int at91_rtc_ioctl(struct device *dev, unsigned int cmd,
+			unsigned long arg)
+{
+	int ret = 0;
+        unsigned long mr = at91_sys_read(AT91_RTT_MR);
+    
+	pr_debug("%s(): cmd=%08x, arg=%08lx.\n", __FUNCTION__, cmd, arg);
+
+	switch (cmd) {
+	case RTC_AIE_OFF:	/* alarm off */
+            at91_sys_write(AT91_RTT_MR, mr & ~AT91_RTT_ALMIEN);
+		break;
+	case RTC_AIE_ON:	/* alarm on */
+            at91_sys_write(AT91_RTT_MR, mr | AT91_RTT_ALMIEN);
+		break;
+	case RTC_UIE_OFF:	/* update off */
+	case RTC_PIE_OFF:	/* periodic off */
+            at91_sys_write(AT91_RTT_MR, mr & ~AT91_RTT_RTTINCIEN);
+		break;
+	case RTC_UIE_ON:	/* update on */
+	case RTC_PIE_ON:	/* periodic on */
+            at91_sys_write(AT91_RTT_MR, mr | AT91_RTT_RTTINCIEN);
+		break;
+	case RTC_IRQP_READ:	/* read periodic alarm frequency */
+		ret = put_user(AT91_RTC_FREQ, (unsigned long *) arg);
+		break;
+	case RTC_IRQP_SET:	/* set periodic alarm frequency */
+		if (arg != AT91_RTC_FREQ)
+			ret = -EINVAL;
+		break;
+	default:
+		ret = -ENOIOCTLCMD;
+		break;
+	}
+
+	return ret;
+}
+
+/*
+ * Provide additional RTC information in /proc/driver/rtc
+ */
+static int at91_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	unsigned long mr = at91_sys_read(AT91_RTT_MR);
+
+	seq_printf(seq, "alarm_IRQ\t: %s\n",
+			(mr & AT91_RTT_ALMIEN) ? "yes" : "no");
+	seq_printf(seq, "periodic_IRQ\t: %s\n",
+			(mr & AT91_RTT_RTTINCIEN) ? "yes" : "no");
+	seq_printf(seq, "periodic_freq\t: %ld\n",
+			(unsigned long) AT91_RTC_FREQ);
+        seq_printf(seq, "count\t\t: 0x%08x\n", 
+                   at91_sys_read( AT91_RTT_VR ) );
+        seq_printf(seq, "base\t\t: 0x%08x\n", 
+                   at91_sys_read( AT91_GPBR + gpbr_offset ));
+	return 0;
+}
+
+/*
+ * IRQ handler for the RTC
+ */
+static irqreturn_t at91_rtc_interrupt(int irq, void *dev_id)
+{
+	struct platform_device *pdev = dev_id;
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+	unsigned long sr;
+        unsigned long mr;
+	unsigned long events = 0;
+
+        mr = at91_sys_read(AT91_RTT_MR);
+	sr = at91_sys_read(AT91_RTT_SR);
+ 
+        if( (sr & AT91_RTT_ALMS) && (mr & AT91_RTT_ALMIEN) ){
+            events |= (RTC_AF | RTC_IRQF);
+        }
+ 
+        if( (sr & AT91_RTT_RTTINC) && (mr & AT91_RTT_RTTINCIEN) ){
+            events |= (RTC_UF | RTC_IRQF);
+        }
+
+         /* this interrupt is shared */
+        if( events ){	
+
+            rtc_update_irq(&rtc->class_dev, 1, events);
+
+            pr_debug("%s(): num=%ld, events=0x%02lx\n", __FUNCTION__,
+                     events >> 8, events & 0x000000FF);
+            
+            return IRQ_HANDLED;
+	}
+	/* not handled */
+	return IRQ_NONE;	
+}
+
+static const struct rtc_class_ops at91_rtc_ops = {
+	.ioctl		= at91_rtc_ioctl,
+	.read_time	= at91_rtc_readtime,
+        .set_mmss       = at91_rtc_set_mmss,
+	.set_time	= at91_rtc_settime,
+	.read_alarm	= at91_rtc_readalarm,
+	.set_alarm	= at91_rtc_setalarm,
+	.proc		= at91_rtc_proc,
+};
+
+/*
+ * Initialize and install RTC driver
+ */
+static int __init at91_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+	int ret;
+        unsigned long mr;
+        //struct at91_rtt_data *rtt_data = (struct at91_rtt_data*) pdev->dev.platform_data;     
+        /* save offset into GPBR to use for the base time */
+        //gpbr_offset = 1;//(pdev->dev.platform_data)->gpbr_offset;
+        //if( gpbr_offset > 3 ){
+        //    gpbr_offset = 0;
+        //}
+
+        printk(KERN_INFO "rtc: 0x%08x AT91_RTT_VR(%x) 0x%08x AT91_GPBR(%lx) \n",
+               at91_sys_read( AT91_RTT_VR ), AT91_RTT_VR,
+               at91_sys_read( AT91_GPBR + gpbr_offset ), AT91_GPBR + gpbr_offset);
+
+        /* set clock to 1Hz and disable interrupts */ 
+        mr = at91_sys_read(AT91_RTT_MR);
+        mr |= (0x8000 & AT91_RTT_RTPRES);
+        at91_sys_write( AT91_RTT_MR, 
+                        mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN) );
+
+	ret = request_irq(AT91_ID_SYS, at91_rtc_interrupt,
+				IRQF_DISABLED | IRQF_SHARED,
+				"at91_rtt", pdev);
+	if (ret) {
+		printk(KERN_ERR "at91_rtt: IRQ %d already in use.\n",
+				AT91_ID_SYS);
+		return ret;
+	}
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev,
+				&at91_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		free_irq(AT91_ID_SYS, pdev);
+                printk(KERN_INFO "rtc_device_register failed (%ld)\n",PTR_ERR(rtc));
+		return PTR_ERR(rtc);
+	}
+	platform_set_drvdata(pdev, rtc);
+	device_init_wakeup(&pdev->dev, 1);
+
+        /* TODO re-enable interrupts that were set? */
+
+	printk(KERN_INFO "AT91 Real Time Clock driver.\n");
+	return 0;
+}
+
+/*
+ * Disable and remove the RTC driver
+ */
+static int __devexit at91_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+        unsigned long mr;
+
+	/* disable all interrupts */
+        mr = at91_sys_read(AT91_RTT_MR);
+        at91_sys_write( AT91_RTT_MR, 
+                        mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN) );
+
+	free_irq(AT91_ID_SYS, pdev);
+
+	rtc_device_unregister(rtc);
+	platform_set_drvdata(pdev, NULL);
+	device_init_wakeup(&pdev->dev, 0);
+
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+/* AT91SAM9260 RTC Power management control */
+
+static struct timespec at91_rtc_delta;
+static u32 at91_rtc_imr;
+
+static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct rtc_time tm;
+	struct timespec time;
+        unsigned long mr;
+        
+	time.tv_nsec = 0;
+
+	/* calculate time delta for suspend */
+	at91_rtc_readtime(&pdev->dev, &tm);
+	rtc_tm_to_time(&tm, &time.tv_sec);
+	save_time_delta(&at91_rtc_delta, &time);
+
+	/* this IRQ is shared with DBGU and other hardware which isn't
+	 * necessarily doing PM like we are...
+	 */
+        mr = at91_sys_read(AT91_RTT_MR);
+	at91_rtc_imr = mr & (AT91_RTT_ALMIEN|AT91_RTT_RTTINCIEN);
+	if (at91_rtc_imr) {
+		if (device_may_wakeup(&pdev->dev))
+                    enable_irq_wake(AT91_ID_SYS);
+		else
+                    at91_sys_write(AT91_RTT_MR, 
+                                   mr & ~at91_rtc_imr );
+	}
+
+	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+		1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+		tm.tm_hour, tm.tm_min, tm.tm_sec);
+	
+	return 0;
+}
+
+static int at91_rtc_resume(struct platform_device *pdev)
+{
+	struct rtc_time tm;
+	struct timespec time;
+    unsigned long mr;
+    
+	time.tv_nsec = 0;
+
+	at91_rtc_readtime(&pdev->dev, &tm);
+	rtc_tm_to_time(&tm, &time.tv_sec);
+	restore_time_delta(&at91_rtc_delta, &time);
+
+	if (at91_rtc_imr) {
+		if (device_may_wakeup(&pdev->dev))
+			disable_irq_wake(AT91_ID_SYS);
+		else {
+                    mr = at91_sys_read(AT91_RTT_MR);
+		    at91_sys_write(AT91_RTT_MR, mr | at91_rtc_imr);
+                }
+	}
+
+	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
+		1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+		tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	return 0;
+}
+#else
+#define at91_rtc_suspend NULL
+#define at91_rtc_resume  NULL
+#endif
+
+static struct platform_driver at91_rtc_driver = {
+	.probe		= at91_rtc_probe,
+	.remove		= at91_rtc_remove,
+	.suspend	= at91_rtc_suspend,
+	.resume		= at91_rtc_resume,
+	.driver		= {
+		.name	= "at91_rtt",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91_rtc_init(void)
+{       
+  int retval;
+  
+  printk(KERN_INFO "at91_rtc_init called\n");
+  
+  retval = platform_driver_probe(&at91_rtc_driver, at91_rtc_probe);
+  
+  printk(KERN_INFO "platform_driver_probe return (%d)\n",retval);       
+  
+  return retval;
+}
+
+static void __exit at91_rtc_exit(void)
+{
+  printk(KERN_INFO "at91_rtc_exit called\n");
+
+  platform_driver_unregister(&at91_rtc_driver);
+}
+
+module_init(at91_rtc_init);
+module_exit(at91_rtc_exit);
+
+MODULE_AUTHOR("Michel Benoit");
+MODULE_DESCRIPTION("RTC driver for Atmel AT91SAM926x");
+MODULE_LICENSE("GPL");
+
diff -uprN linux-2.6.20/drivers/serial/atmel_serial.c linux-2.6.20-at92_e1.5/drivers/serial/atmel_serial.c
--- linux-2.6.20/drivers/serial/atmel_serial.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/serial/atmel_serial.c	2008-02-07 10:24:59.000000000 -0500
@@ -7,6 +7,8 @@
  *  Based on drivers/char/serial_sa1100.c, by Deep Blue Solutions Ltd.
  *  Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o.
  *
+ *  DMA support added by Chip Coldwell.
+ *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
@@ -33,12 +35,14 @@
 #include <linux/sysrq.h>
 #include <linux/tty_flip.h>
 #include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/atmel_pdc.h>
 
 #include <asm/io.h>
 
 #include <asm/mach/serial_at91.h>
 #include <asm/arch/board.h>
-#include <asm/arch/at91_pdc.h>
+
 #ifdef CONFIG_ARM
 #include <asm/arch/cpu.h>
 #include <asm/arch/gpio.h>
@@ -46,6 +50,11 @@
 
 #include "atmel_serial.h"
 
+#define SUPPORT_PDC
+#define PDC_BUFFER_SIZE		(L1_CACHE_BYTES << 3)
+#warning "Revisit"
+#define PDC_RX_TIMEOUT		(3 * 10)		/* 3 bytes */
+
 #if defined(CONFIG_SERIAL_ATMEL_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
 #define SUPPORT_SYSRQ
 #endif
@@ -106,6 +115,13 @@
 static int (*atmel_open_hook)(struct uart_port *);
 static void (*atmel_close_hook)(struct uart_port *);
 
+struct atmel_dma_buffer {
+	unsigned char	*buf;
+	dma_addr_t	dma_addr;
+	size_t		dma_size;
+	unsigned int	ofs;
+};
+
 /*
  * We wrap our port structure around the generic uart_port.
  */
@@ -113,10 +129,20 @@ struct atmel_uart_port {
 	struct uart_port	uart;		/* uart */
 	struct clk		*clk;		/* uart clock */
 	unsigned short		suspended;	/* is port suspended? */
+
+	short			use_dma_rx;	/* enable PDC receiver */
+	short			pdc_rx_idx;	/* current PDC RX buffer */
+	struct atmel_dma_buffer	pdc_rx[2];	/* PDC receier */
+
+	short			use_dma_tx;	/* enable PDC transmitter */
+	struct atmel_dma_buffer	pdc_tx;		/* PDC transmitter */
 };
 
 static struct atmel_uart_port atmel_ports[ATMEL_MAX_UART];
 
+#define PDC_RX_BUF(port)	&(port)->pdc_rx[(port)->pdc_rx_idx]
+#define PDC_RX_SWITCH(port)	(port)->pdc_rx_idx = !(port)->pdc_rx_idx
+
 #ifdef SUPPORT_SYSRQ
 static struct console atmel_console;
 #endif
@@ -204,7 +230,12 @@ static void atmel_stop_tx(struct uart_po
 {
 	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
 
-	UART_PUT_IDR(port, ATMEL_US_TXRDY);
+	if (atmel_port->use_dma_tx) {
+		UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);		/* disable PDC transmit */
+		UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+	}
+	else
+		UART_PUT_IDR(port, ATMEL_US_TXRDY);
 }
 
 /*
@@ -214,7 +245,17 @@ static void atmel_start_tx(struct uart_p
 {
 	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
 
-	UART_PUT_IER(port, ATMEL_US_TXRDY);
+	if (atmel_port->use_dma_tx) {
+		if (UART_GET_PTSR(port) & ATMEL_PDC_TXTEN)
+			/* The transmitter is already running.  Yes, we
+			   really need this.*/
+			return;
+
+		UART_PUT_IER(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+		UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);		/* re-enable PDC transmit */
+	}
+	else
+		UART_PUT_IER(port, ATMEL_US_TXRDY);
 }
 
 /*
@@ -224,7 +265,12 @@ static void atmel_stop_rx(struct uart_po
 {
 	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
 
-	UART_PUT_IDR(port, ATMEL_US_RXRDY);
+	if (atmel_port->use_dma_rx) {
+		UART_PUT_PTCR(port, ATMEL_PDC_RXTDIS);		/* disable PDC receive */
+		UART_PUT_IDR(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+	}
+	else
+		UART_PUT_IDR(port, ATMEL_US_RXRDY);
 }
 
 /*
@@ -247,6 +293,134 @@ static void atmel_break_ctl(struct uart_
 }
 
 /*
+ * Receive data via the PDC.  A buffer has been fulled.
+ */
+static void atmel_pdc_endrx(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+	struct tty_struct *tty = port->info->tty;
+	struct atmel_dma_buffer *pdc = PDC_RX_BUF(atmel_port);
+	unsigned int count;
+
+	count = pdc->dma_size - pdc->ofs;
+	if (likely(count > 0)) {
+		dma_sync_single_for_cpu(port->dev, pdc->dma_addr, pdc->dma_size, DMA_FROM_DEVICE);
+		tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
+		tty_flip_buffer_push(tty);
+
+		port->icount.rx += count;
+	}
+
+	/* Set this buffer as the next receive buffer */
+	pdc->ofs = 0;
+	UART_PUT_RNPR(port, pdc->dma_addr);
+	UART_PUT_RNCR(port, pdc->dma_size);
+
+	/* Switch to next buffer */
+	PDC_RX_SWITCH(atmel_port);		/* next PDC buffer */
+}
+
+/*
+ * Receive data via the PDC.  At least one byte was received, but the
+ * buffer was not full when the inter-character timeout expired.
+ */
+static void atmel_pdc_timeout(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+	struct tty_struct *tty = port->info->tty;
+	struct atmel_dma_buffer *pdc = PDC_RX_BUF(atmel_port);
+	/* unsigned */ int ofs, count;
+
+	ofs = UART_GET_RPR(port) - pdc->dma_addr;	/* current DMA adress */
+	count = ofs - pdc->ofs;
+
+	if (likely(count > 0)) {
+		dma_sync_single_for_cpu(port->dev, pdc->dma_addr, pdc->dma_size, DMA_FROM_DEVICE);
+		tty_insert_flip_string(tty, pdc->buf + pdc->ofs, count);
+		tty_flip_buffer_push(tty);
+
+		pdc->ofs = ofs;
+		port->icount.rx += count;
+	}
+
+	/* reset the UART timeout */
+	UART_PUT_CR(port, ATMEL_US_STTTO);
+}
+
+/*
+ * Deal with parity, framing and overrun errors.
+ */
+static void atmel_pdc_rxerr(struct uart_port *port, unsigned int status)
+{
+	/* clear error */
+	UART_PUT_CR(port, ATMEL_US_RSTSTA);
+
+	if (status & ATMEL_US_RXBRK) {
+		status &= ~(ATMEL_US_PARE | ATMEL_US_FRAME);	/* ignore side-effect */
+		port->icount.brk++;
+	}
+	if (status & ATMEL_US_PARE)
+		port->icount.parity++;
+	if (status & ATMEL_US_FRAME)
+		port->icount.frame++;
+	if (status & ATMEL_US_OVRE)
+		port->icount.overrun++;
+}
+
+/*
+ * A transmission via the PDC is complete.
+ */
+static void atmel_pdc_endtx(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+	struct circ_buf *xmit = &port->info->xmit;
+	struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+	xmit->tail += pdc->ofs;
+	if (xmit->tail >= SERIAL_XMIT_SIZE)
+		xmit->tail -= SERIAL_XMIT_SIZE;
+
+	port->icount.tx += pdc->ofs;
+	pdc->ofs = 0;
+
+	if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+		uart_write_wakeup(port);
+}
+
+/*
+ * The PDC transmitter is idle, so either start the next transfer or
+ * disable the transmitter.
+ */
+static void atmel_pdc_txbufe(struct uart_port *port)
+{
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
+	struct circ_buf *xmit = &port->info->xmit;
+	struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+	int count;
+
+	if (!uart_circ_empty(xmit)) {
+		/* more to transmit - setup next transfer */
+		UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);			/* disable PDC transmit */
+		dma_sync_single_for_device(port->dev, pdc->dma_addr, pdc->dma_size, DMA_TO_DEVICE);
+
+		if (xmit->tail < xmit->head)
+			count = xmit->head - xmit->tail;
+		else
+			count = SERIAL_XMIT_SIZE - xmit->tail;
+		pdc->ofs = count;
+
+		UART_PUT_TPR(port, pdc->dma_addr + xmit->tail);
+		UART_PUT_TCR(port, count);
+		UART_PUT_PTCR(port, ATMEL_PDC_TXTEN);			/* re-enable PDC transmit */
+	}
+	else {
+		/* nothing left to transmit - disable the transmitter */
+		UART_PUT_PTCR(port, ATMEL_PDC_TXTDIS);			/* disable PDC transmit */
+		UART_PUT_IDR(port, ATMEL_US_ENDTX | ATMEL_US_TXBUFE);
+	}
+}
+
+/*
  * Characters received (called from interrupt handler)
  */
 static void atmel_rx_chars(struct uart_port *port)
@@ -348,6 +522,14 @@ static irqreturn_t atmel_interrupt(int i
 	status = UART_GET_CSR(port);
 	pending = status & UART_GET_IMR(port);
 	while (pending) {
+		/* PDC receive */
+		if (pending & ATMEL_US_ENDRX)
+			atmel_pdc_endrx(port);
+		if (pending & ATMEL_US_TIMEOUT)
+			atmel_pdc_timeout(port);
+		if (atmel_port->use_dma_rx && pending & (ATMEL_US_RXBRK | ATMEL_US_OVRE | ATMEL_US_FRAME | ATMEL_US_PARE))
+			atmel_pdc_rxerr(port, pending);
+
 		/* Interrupt receive */
 		if (pending & ATMEL_US_RXRDY)
 			atmel_rx_chars(port);
@@ -362,6 +544,12 @@ static irqreturn_t atmel_interrupt(int i
 		if (pending & (ATMEL_US_RIIC | ATMEL_US_DSRIC | ATMEL_US_DCDIC | ATMEL_US_CTSIC))
 			wake_up_interruptible(&port->info->delta_msr_wait);
 
+		/* PDC transmit */
+		if (pending & ATMEL_US_ENDTX)
+			atmel_pdc_endtx(port);
+		if (pending & ATMEL_US_TXBUFE)
+			atmel_pdc_txbufe(port);
+
 		/* Interrupt transmit */
 		if (pending & ATMEL_US_TXRDY)
 			atmel_tx_chars(port);
@@ -400,6 +588,47 @@ static int atmel_startup(struct uart_por
 	}
 
 	/*
+	 * Initialize DMA (if necessary)
+	 */
+	if (atmel_port->use_dma_rx) {
+		int i;
+
+		for (i = 0; i < 2; i++) {
+			struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+			pdc->buf = kmalloc(PDC_BUFFER_SIZE, GFP_KERNEL);
+			if (pdc->buf == NULL) {
+				if (i != 0) {
+					dma_unmap_single(port->dev, atmel_port->pdc_rx[0].dma_addr, PDC_BUFFER_SIZE, DMA_FROM_DEVICE);
+					kfree(atmel_port->pdc_rx[0].buf);
+				}
+				free_irq(port->irq, port);
+				return -ENOMEM;
+			}
+			pdc->dma_addr = dma_map_single(port->dev, pdc->buf, PDC_BUFFER_SIZE, DMA_FROM_DEVICE);
+			pdc->dma_size = PDC_BUFFER_SIZE;
+			pdc->ofs = 0;
+		}
+
+		atmel_port->pdc_rx_idx = 0;
+
+		UART_PUT_RPR(port, atmel_port->pdc_rx[0].dma_addr);
+		UART_PUT_RCR(port, PDC_BUFFER_SIZE);
+
+		UART_PUT_RNPR(port, atmel_port->pdc_rx[1].dma_addr);
+		UART_PUT_RNCR(port, PDC_BUFFER_SIZE);
+	}
+	if (atmel_port->use_dma_tx) {
+		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+		struct circ_buf *xmit = &port->info->xmit;
+
+		pdc->buf = xmit->buf;
+		pdc->dma_addr = dma_map_single(port->dev, pdc->buf, SERIAL_XMIT_SIZE, DMA_TO_DEVICE);
+		pdc->dma_size = SERIAL_XMIT_SIZE;
+		pdc->ofs = 0;
+	}
+
+	/*
 	 * If there is a specific "open" function (to register
 	 * control line interrupts)
 	 */
@@ -417,7 +646,15 @@ static int atmel_startup(struct uart_por
 	UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
 	UART_PUT_CR(port, ATMEL_US_TXEN | ATMEL_US_RXEN);		/* enable xmit & rcvr */
 
-	UART_PUT_IER(port, ATMEL_US_RXRDY);		/* enable receive only */
+	if (atmel_port->use_dma_rx) {
+		UART_PUT_RTOR(port, PDC_RX_TIMEOUT);		/* set UART timeout */
+		UART_PUT_CR(port, ATMEL_US_STTTO);
+
+		UART_PUT_IER(port, ATMEL_US_ENDRX | ATMEL_US_TIMEOUT);
+		UART_PUT_PTCR(port, ATMEL_PDC_RXTEN);		/* enable PDC controller */
+	}
+	else
+		UART_PUT_IER(port, ATMEL_US_RXRDY);		/* enable receive only */
 
 	return 0;
 }
@@ -430,6 +667,25 @@ static void atmel_shutdown(struct uart_p
 	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
 
 	/*
+	 * Shut-down the DMA.
+	 */
+	if (atmel_port->use_dma_rx) {
+		int i;
+
+		for (i = 0; i < 2; i++) {
+			struct atmel_dma_buffer *pdc = &atmel_port->pdc_rx[i];
+
+			dma_unmap_single(port->dev, pdc->dma_addr, pdc->dma_size, DMA_FROM_DEVICE);
+			kfree(pdc->buf);
+		}
+	}
+	if (atmel_port->use_dma_tx) {
+		struct atmel_dma_buffer *pdc = &atmel_port->pdc_tx;
+
+		dma_unmap_single(port->dev, pdc->dma_addr, pdc->dma_size, DMA_TO_DEVICE);
+	}
+
+	/*
 	 * Disable all interrupts, port and break condition.
 	 */
 	UART_PUT_CR(port, ATMEL_US_RSTSTA);
@@ -480,6 +736,7 @@ static void atmel_serial_pm(struct uart_
  */
 static void atmel_set_termios(struct uart_port *port, struct ktermios * termios, struct ktermios * old)
 {
+	struct atmel_uart_port *atmel_port = (struct atmel_uart_port *) port;
 	unsigned long flags;
 	unsigned int mode, imr, quot, baud;
 
@@ -533,6 +790,9 @@ static void atmel_set_termios(struct uar
 	if (termios->c_iflag & (BRKINT | PARMRK))
 		port->read_status_mask |= ATMEL_US_RXBRK;
 
+	if (atmel_port->use_dma_rx)	/* need to enable error interrupts */
+		UART_PUT_IER(port, port->read_status_mask);
+
 	/*
 	 * Characters to ignore
 	 */
@@ -711,6 +971,11 @@ static void __devinit atmel_init_port(st
 		clk_enable(atmel_port->clk);
 		port->uartclk = clk_get_rate(atmel_port->clk);
 	}
+
+#ifdef SUPPORT_PDC
+	atmel_port->use_dma_rx = data->use_dma_rx;
+	atmel_port->use_dma_tx = data->use_dma_tx;
+#endif
 }
 
 /*
@@ -953,6 +1218,21 @@ static int __devexit atmel_serial_remove
 	return ret;
 }
 
+int atmel_auto485(struct uart_port *port,int fos){
+	unsigned int mode = UART_GET_MR(port);
+	
+	//printk("setting auto rts, current mode is %x\n",mode);
+	
+	if(fos==2)
+		return(((mode&ATMEL_US_USMODE_RS485)!=0));//return status option
+	mode = (fos ? (mode|ATMEL_US_USMODE_RS485):(mode&(~ATMEL_US_USMODE_RS485)));
+	
+	//printk("setting new mode to %x\n",mode);
+	UART_PUT_MR(port, mode);
+	return fos;
+}
+
+
 static struct platform_driver atmel_serial_driver = {
 	.probe		= atmel_serial_probe,
 	.remove		= __devexit_p(atmel_serial_remove),
diff -uprN linux-2.6.20/drivers/spi/Kconfig linux-2.6.20-at92_e1.5/drivers/spi/Kconfig
--- linux-2.6.20/drivers/spi/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/spi/Kconfig	2008-02-07 10:24:59.000000000 -0500
@@ -51,6 +51,14 @@ config SPI_MASTER
 comment "SPI Master Controller Drivers"
 	depends on SPI_MASTER
 
+config SPI_ATMEL
+	tristate "Atmel SPI Controller"
+	depends on (ARCH_AT91 || AVR32) && SPI_MASTER
+	select SPI_AT91_MANUAL_CS if ARCH_AT91RM9200
+	help
+	  This selects a driver for the Atmel SPI Controller, present on
+	  many AT32 (AVR32) and AT91 (ARM) chips.
+
 config SPI_BITBANG
 	tristate "Bitbanging SPI master"
 	depends on SPI_MASTER && EXPERIMENTAL
@@ -75,6 +83,24 @@ config SPI_BUTTERFLY
 	  inexpensive battery powered microcontroller evaluation board.
 	  This same cable can be used to flash new firmware.
 
+config SPI_AT91
+	tristate "AT91RM9200 Bitbang SPI Master"
+	depends on SPI_MASTER && ARCH_AT91RM9200 && !SPI_ATMEL && EXPERIMENTAL
+	select SPI_BITBANG
+	select SPI_AT91_MANUAL_CS
+	help
+	  This is dumb PIO bitbanging driver for the Atmel AT91RM9200.
+	  The SPI_ATMEL driver will be its replacement, using the native
+	  SPI hardware and its DMA controller.
+
+config SPI_AT91_MANUAL_CS
+	bool
+	depends on ARCH_AT91RM9200
+	help
+	  Works around an AT91RM9200 problem whereby the SPI chip-select
+	  will be wrongly disabled.  The workaround uses those pins as
+	  GPIOs instead of letting the SPI controller manage them.
+
 config SPI_MPC83xx
 	tristate "Freescale MPC83xx SPI controller"
 	depends on SPI_MASTER && PPC_83xx && EXPERIMENTAL
diff -uprN linux-2.6.20/drivers/spi/Makefile linux-2.6.20-at92_e1.5/drivers/spi/Makefile
--- linux-2.6.20/drivers/spi/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/spi/Makefile	2008-02-07 10:24:59.000000000 -0500
@@ -12,11 +12,14 @@ obj-$(CONFIG_SPI_MASTER)		+= spi.o
 
 # SPI master controller drivers (bus)
 obj-$(CONFIG_SPI_BITBANG)		+= spi_bitbang.o
+obj-$(CONFIG_SPI_ATMEL)			+= atmel_spi.o
 obj-$(CONFIG_SPI_BUTTERFLY)		+= spi_butterfly.o
 obj-$(CONFIG_SPI_PXA2XX)		+= pxa2xx_spi.o
 obj-$(CONFIG_SPI_MPC83xx)		+= spi_mpc83xx.o
 obj-$(CONFIG_SPI_S3C24XX_GPIO)		+= spi_s3c24xx_gpio.o
 obj-$(CONFIG_SPI_S3C24XX)		+= spi_s3c24xx.o
+obj-$(CONFIG_SPI_AT91)			+= spi_at91_bitbang.o
+obj-$(CONFIG_SPI_ATMEL)			+= atmel_spi.o
 # 	... add above this line ...
 
 # SPI protocol drivers (device/link on bus)
diff -uprN linux-2.6.20/drivers/spi/atmel_spi.c linux-2.6.20-at92_e1.5/drivers/spi/atmel_spi.c
--- linux-2.6.20/drivers/spi/atmel_spi.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/spi/atmel_spi.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,699 @@
+/*
+ * Driver for Atmel AT32 and AT91 SPI Controllers
+ *
+ * Copyright (C) 2006 Atmel 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/kernel.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+
+#include <asm/io.h>
+#include <asm/arch/board.h>
+#include <asm/arch/gpio.h>
+
+#ifdef CONFIG_ARCH_AT91
+#include <asm/arch/cpu.h>
+#endif
+
+#include "atmel_spi.h"
+
+/*
+ * The core SPI transfer engine just talks to a register bank to set up
+ * DMA transfers; transfer queue progress is driven by IRQs.  The clock
+ * framework provides the base clock, subdivided for each spi_device.
+ *
+ * Newer controllers, marked with "new_1" flag, have:
+ *  - CR.LASTXFER
+ *  - SPI_MR.DIV32 may become FDIV or must-be-zero (here: always zero)
+ *  - SPI_SR.TXEMPTY, SPI_SR.NSSR (and corresponding irqs)
+ *  - SPI_CSRx.CSAAT
+ *  - SPI_CSRx.SBCR allows faster clocking
+ */
+struct atmel_spi {
+	spinlock_t		lock;
+
+	void __iomem		*regs;
+	int			irq;
+	struct clk		*clk;
+	struct platform_device	*pdev;
+	unsigned		new_1:1;
+
+	u8			stopping;
+	struct list_head	queue;
+	struct spi_transfer	*current_transfer;
+	unsigned long		remaining_bytes;
+
+	void			*buffer;
+	dma_addr_t		buffer_dma;
+};
+
+#define BUFFER_SIZE		PAGE_SIZE
+#define INVALID_DMA_ADDRESS	0xffffffff
+
+/*
+ * Earlier SPI controllers (e.g. on at91rm9200) have a design bug whereby
+ * they assume that spi slave device state will not change on deselect, so
+ * that automagic deselection is OK.  Not so!  Workaround uses nCSx pins
+ * as GPIOs; or newer controllers have CSAAT and friends.
+ *
+ * Since the CSAAT functionality is a bit weird on newer controllers
+ * as well, we use GPIO to control nCSx pins on all controllers.
+ */
+
+static inline void cs_activate(struct spi_device *spi)
+{
+	unsigned gpio = (unsigned) spi->controller_data;
+	unsigned active = spi->mode & SPI_CS_HIGH;
+
+	dev_dbg(&spi->dev, "activate %u%s\n", gpio, active ? " (high)" : "");
+#ifdef CONFIG_ARCH_AT91
+	at91_set_gpio_value(gpio, active);
+#else
+	gpio_set_value(gpio, active);
+#endif
+}
+
+static inline void cs_deactivate(struct spi_device *spi)
+{
+	unsigned gpio = (unsigned) spi->controller_data;
+	unsigned active = spi->mode & SPI_CS_HIGH;
+
+	dev_dbg(&spi->dev, "DEactivate %u%s\n", gpio, active ? " (low)" : "");
+#ifdef CONFIG_ARCH_AT91
+	at91_set_gpio_value(gpio, !active);
+#else
+	gpio_set_value(gpio, !active);
+#endif
+}
+
+/*
+ * Submit next transfer for DMA.
+ * lock is held, spi irq is blocked
+ */
+static void atmel_spi_next_xfer(struct spi_master *master,
+				struct spi_message *msg)
+{
+	struct atmel_spi	*as = spi_master_get_devdata(master);
+	struct spi_transfer	*xfer;
+	u32			len;
+	dma_addr_t		tx_dma, rx_dma;
+
+	xfer = as->current_transfer;
+	if (!xfer || as->remaining_bytes == 0) {
+		if (xfer)
+			xfer = list_entry(xfer->transfer_list.next,
+					struct spi_transfer, transfer_list);
+		else
+			xfer = list_entry(msg->transfers.next,
+					struct spi_transfer, transfer_list);
+		as->remaining_bytes = xfer->len;
+		as->current_transfer = xfer;
+	}
+
+	len = as->remaining_bytes;
+
+	tx_dma = xfer->tx_dma;
+	rx_dma = xfer->rx_dma;
+
+	/* use scratch buffer only when rx or tx data is unspecified */
+	if (rx_dma == INVALID_DMA_ADDRESS) {
+		rx_dma = as->buffer_dma;
+		if (len > BUFFER_SIZE)
+			len = BUFFER_SIZE;
+	}
+	if (tx_dma == INVALID_DMA_ADDRESS) {
+		tx_dma = as->buffer_dma;
+		if (len > BUFFER_SIZE)
+			len = BUFFER_SIZE;
+		memset(as->buffer, 0, len);
+		dma_sync_single_for_device(&as->pdev->dev,
+				as->buffer_dma, len, DMA_TO_DEVICE);
+	}
+
+	spi_writel(as, RPR, rx_dma);
+	spi_writel(as, TPR, tx_dma);
+
+	as->remaining_bytes -= len;
+	if (msg->spi->bits_per_word > 8)
+		len >>= 1;
+
+	/* REVISIT: when xfer->delay_usecs == 0, the PDC "next transfer"
+	 * mechanism might help avoid the IRQ latency between transfers
+	 *
+	 * We're also waiting for ENDRX before we start the next
+	 * transfer because we need to handle some difficult timing
+	 * issues otherwise. If we wait for ENDTX in one transfer and
+	 * then starts waiting for ENDRX in the next, it's difficult
+	 * to tell the difference between the ENDRX interrupt we're
+	 * actually waiting for and the ENDRX interrupt of the
+	 * previous transfer.
+	 *
+	 * It should be doable, though. Just not now...
+	 */
+	spi_writel(as, TNCR, 0);
+	spi_writel(as, RNCR, 0);
+	spi_writel(as, IER, SPI_BIT(ENDRX) | SPI_BIT(OVRES));
+
+	dev_dbg(&msg->spi->dev,
+		"  start xfer %p: len %u tx %p/%08x rx %p/%08x imr %03x\n",
+		xfer, xfer->len, xfer->tx_buf, xfer->tx_dma,
+		xfer->rx_buf, xfer->rx_dma, spi_readl(as, IMR));
+
+	wmb();
+	spi_writel(as, TCR, len);
+	spi_writel(as, RCR, len);
+	spi_writel(as, PTCR, SPI_BIT(TXTEN) | SPI_BIT(RXTEN));
+}
+
+static void atmel_spi_next_message(struct spi_master *master)
+{
+	struct atmel_spi	*as = spi_master_get_devdata(master);
+	struct spi_message	*msg;
+	u32			mr;
+
+	BUG_ON(as->current_transfer);
+
+	msg = list_entry(as->queue.next, struct spi_message, queue);
+
+	/* Select the chip */
+	mr = spi_readl(as, MR);
+	mr = SPI_BFINS(PCS, ~(1 << msg->spi->chip_select), mr);
+	spi_writel(as, MR, mr);
+	cs_activate(msg->spi);
+
+	atmel_spi_next_xfer(master, msg);
+}
+
+static void
+atmel_spi_dma_map_xfer(struct atmel_spi *as, struct spi_transfer *xfer)
+{
+	xfer->tx_dma = xfer->rx_dma = INVALID_DMA_ADDRESS;
+	if (xfer->tx_buf)
+		xfer->tx_dma = dma_map_single(&as->pdev->dev,
+				(void *) xfer->tx_buf, xfer->len,
+				DMA_TO_DEVICE);
+	if (xfer->rx_buf)
+		xfer->rx_dma = dma_map_single(&as->pdev->dev,
+				xfer->rx_buf, xfer->len,
+				DMA_FROM_DEVICE);
+}
+
+static void atmel_spi_dma_unmap_xfer(struct spi_master *master,
+				     struct spi_transfer *xfer)
+{
+	if (xfer->tx_dma != INVALID_DMA_ADDRESS)
+		dma_unmap_single(master->cdev.dev, xfer->tx_dma,
+				 xfer->len, DMA_TO_DEVICE);
+	if (xfer->rx_dma != INVALID_DMA_ADDRESS)
+		dma_unmap_single(master->cdev.dev, xfer->rx_dma,
+				 xfer->len, DMA_FROM_DEVICE);
+}
+
+static void
+atmel_spi_msg_done(struct spi_master *master, struct atmel_spi *as,
+		   struct spi_message *msg, int status)
+{
+	cs_deactivate(msg->spi);
+	list_del(&msg->queue);
+	msg->status = status;
+
+	dev_dbg(master->cdev.dev,
+		"xfer complete: %u bytes transferred\n",
+		msg->actual_length);
+
+	spin_unlock(&as->lock);
+	msg->complete(msg->context);
+	spin_lock(&as->lock);
+
+	as->current_transfer = NULL;
+
+	/* continue if needed */
+	if (list_empty(&as->queue) || as->stopping)
+		spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+	else
+		atmel_spi_next_message(master);
+}
+
+static irqreturn_t
+atmel_spi_interrupt(int irq, void *dev_id)
+{
+	struct spi_master	*master = dev_id;
+	struct atmel_spi	*as = spi_master_get_devdata(master);
+	struct spi_message	*msg;
+	struct spi_transfer	*xfer;
+	u32			status, pending, imr;
+	int			ret = IRQ_NONE;
+
+	spin_lock(&as->lock);
+
+	xfer = as->current_transfer;
+	msg = list_entry(as->queue.next, struct spi_message, queue);
+
+	imr = spi_readl(as, IMR);
+	status = spi_readl(as, SR);
+	pending = status & imr;
+
+	if (pending & SPI_BIT(OVRES)) {
+		int timeout;
+
+		ret = IRQ_HANDLED;
+
+		spi_writel(as, IDR, (SPI_BIT(ENDTX) | SPI_BIT(ENDRX)
+				     | SPI_BIT(OVRES)));
+
+		/*
+		 * When we get an overrun, we disregard the current
+		 * transfer. Data will not be copied back from any
+		 * bounce buffer and msg->actual_len will not be
+		 * updated with the last xfer.
+		 *
+		 * We will also not process any remaning transfers in
+		 * the message.
+		 *
+		 * First, stop the transfer and unmap the DMA buffers.
+		 */
+		spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+		if (!msg->is_dma_mapped)
+			atmel_spi_dma_unmap_xfer(master, xfer);
+
+		/* REVISIT: udelay in irq is unfriendly */
+		if (xfer->delay_usecs)
+			udelay(xfer->delay_usecs);
+
+		dev_warn(master->cdev.dev, "fifo overrun (%u/%u remaining)\n",
+			 spi_readl(as, TCR), spi_readl(as, RCR));
+
+		/*
+		 * Clean up DMA registers and make sure the data
+		 * registers are empty.
+		 */
+		spi_writel(as, RNCR, 0);
+		spi_writel(as, TNCR, 0);
+		spi_writel(as, RCR, 0);
+		spi_writel(as, TCR, 0);
+		for (timeout = 1000; timeout; timeout--)
+			if (spi_readl(as, SR) & SPI_BIT(TXEMPTY))
+				break;
+		if (!timeout)
+			dev_warn(master->cdev.dev,
+				 "timeout waiting for TXEMPTY");
+		while (spi_readl(as, SR) & SPI_BIT(RDRF))
+			spi_readl(as, RDR);
+
+		/* Clear any overrun happening while cleaning up */
+		spi_readl(as, SR);
+
+		atmel_spi_msg_done(master, as, msg, -EIO);
+	} else if (pending & SPI_BIT(ENDRX)) {
+		ret = IRQ_HANDLED;
+
+		spi_writel(as, IDR, pending);
+
+		if (as->remaining_bytes == 0) {
+			msg->actual_length += xfer->len;
+
+			if (!msg->is_dma_mapped)
+				atmel_spi_dma_unmap_xfer(master, xfer);
+
+			/* REVISIT: udelay in irq is unfriendly */
+			if (xfer->delay_usecs)
+				udelay(xfer->delay_usecs);
+
+			if (msg->transfers.prev == &xfer->transfer_list) {
+				/* report completed message */
+				atmel_spi_msg_done(master, as, msg, 0);
+			} else {
+				if (xfer->cs_change) {
+					cs_deactivate(msg->spi);
+					udelay(1);
+					cs_activate(msg->spi);
+				}
+
+				/*
+				 * Not done yet. Submit the next transfer.
+				 *
+				 * FIXME handle protocol options for xfer
+				 */
+				atmel_spi_next_xfer(master, msg);
+			}
+		} else {
+			/*
+			 * Keep going, we still have data to send in
+			 * the current transfer.
+			 */
+			atmel_spi_next_xfer(master, msg);
+		}
+	}
+
+	spin_unlock(&as->lock);
+
+	return ret;
+}
+
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_CS_HIGH)
+
+static int atmel_spi_setup(struct spi_device *spi)
+{
+	struct atmel_spi	*as;
+	u32			scbr, csr;
+	unsigned int		bits = spi->bits_per_word;
+	unsigned long		bus_hz, sck_hz;
+	unsigned int		npcs_pin;
+	int			ret;
+
+	as = spi_master_get_devdata(spi->master);
+
+	if (as->stopping)
+		return -ESHUTDOWN;
+
+	if (spi->chip_select > spi->master->num_chipselect) {
+		dev_dbg(&spi->dev,
+				"setup: invalid chipselect %u (%u defined)\n",
+				spi->chip_select, spi->master->num_chipselect);
+		return -EINVAL;
+	}
+
+	if (bits == 0)
+		bits = 8;
+	if (bits < 8 || bits > 16) {
+		dev_dbg(&spi->dev,
+				"setup: invalid bits_per_word %u (8 to 16)\n",
+				bits);
+		return -EINVAL;
+	}
+
+	if (spi->mode & ~MODEBITS) {
+		dev_dbg(&spi->dev, "setup: unsupported mode bits %x\n",
+			spi->mode & ~MODEBITS);
+		return -EINVAL;
+	}
+
+	/* speed zero convention is used by some upper layers */
+	bus_hz = clk_get_rate(as->clk);
+	if (spi->max_speed_hz) {
+		/* assume div32/fdiv/mbz == 0 */
+		if (!as->new_1)
+			bus_hz /= 2;
+		scbr = ((bus_hz + spi->max_speed_hz - 1)
+			/ spi->max_speed_hz);
+		if (scbr >= (1 << SPI_SCBR_SIZE)) {
+			dev_dbg(&spi->dev, "setup: %d Hz too slow, scbr %u\n",
+					spi->max_speed_hz, scbr);
+			return -EINVAL;
+		}
+	} else
+		scbr = 0xff;
+	sck_hz = bus_hz / scbr;
+
+	csr = SPI_BF(SCBR, scbr) | SPI_BF(BITS, bits - 8);
+	if (spi->mode & SPI_CPOL)
+		csr |= SPI_BIT(CPOL);
+	if (!(spi->mode & SPI_CPHA))
+		csr |= SPI_BIT(NCPHA);
+
+	/* TODO: DLYBS and DLYBCT */
+	csr |= SPI_BF(DLYBS, 10);
+	csr |= SPI_BF(DLYBCT, 10);
+
+	/* chipselect must have been muxed as GPIO (e.g. in board setup) */
+	npcs_pin = (unsigned int)spi->controller_data;
+	if (!spi->controller_state) {
+#ifndef CONFIG_ARCH_AT91
+		ret = gpio_request(npcs_pin, "spi_npcs");
+		if (ret)
+			return ret;
+#endif
+		spi->controller_state = (void *)npcs_pin;
+#ifdef CONFIG_ARCH_AT91
+		at91_set_gpio_output(npcs_pin, 0);
+#else
+		gpio_direction_output(npcs_pin);
+#endif
+	}
+
+	dev_dbg(&spi->dev,
+		"setup: %lu Hz bpw %u mode 0x%x -> csr%d %08x\n",
+		sck_hz, bits, spi->mode, spi->chip_select, csr);
+
+	spi_writel(as, CSR0 + 4 * spi->chip_select, csr);
+
+	return 0;
+}
+
+static int atmel_spi_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+	struct atmel_spi	*as;
+	struct spi_transfer	*xfer;
+	unsigned long		flags;
+	struct device		*controller = spi->master->cdev.dev;
+
+	as = spi_master_get_devdata(spi->master);
+
+	dev_dbg(controller, "new message %p submitted for %s\n",
+			msg, spi->dev.bus_id);
+
+	if (unlikely(list_empty(&msg->transfers)
+			|| !spi->max_speed_hz))
+		return -EINVAL;
+
+	if (as->stopping)
+		return -ESHUTDOWN;
+
+	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		if (!(xfer->tx_buf || xfer->rx_buf)) {
+			dev_dbg(&spi->dev, "missing rx or tx buf\n");
+			return -EINVAL;
+		}
+
+		/* FIXME implement these protocol options!! */
+		if (xfer->bits_per_word || xfer->speed_hz) {
+			dev_dbg(&spi->dev, "no protocol options yet\n");
+			return -ENOPROTOOPT;
+		}
+	}
+
+	/* scrub dcache "early" */
+	if (!msg->is_dma_mapped) {
+		list_for_each_entry(xfer, &msg->transfers, transfer_list)
+			atmel_spi_dma_map_xfer(as, xfer);
+	}
+
+	list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+		dev_dbg(controller,
+			"  xfer %p: len %u tx %p/%08x rx %p/%08x\n",
+			xfer, xfer->len,
+			xfer->tx_buf, xfer->tx_dma,
+			xfer->rx_buf, xfer->rx_dma);
+	}
+
+	msg->status = -EINPROGRESS;
+	msg->actual_length = 0;
+
+	spin_lock_irqsave(&as->lock, flags);
+	list_add_tail(&msg->queue, &as->queue);
+	if (!as->current_transfer)
+		atmel_spi_next_message(spi->master);
+	spin_unlock_irqrestore(&as->lock, flags);
+
+	return 0;
+}
+
+static void atmel_spi_cleanup(const struct spi_device *spi)
+{
+#ifndef CONFIG_ARCH_AT91
+	if (spi->controller_state)
+		gpio_free((unsigned int)spi->controller_data);
+#endif
+}
+
+/*-------------------------------------------------------------------------*/
+
+static int __init atmel_spi_probe(struct platform_device *pdev)
+{
+	struct resource		*regs;
+	int			irq;
+	struct clk		*clk;
+	int			ret;
+	struct spi_master	*master;
+	struct atmel_spi	*as;
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+
+	clk = clk_get(&pdev->dev, "spi_clk");
+	if (IS_ERR(clk))
+		return PTR_ERR(clk);
+
+	/* setup spi core then atmel-specific driver state */
+	ret = -ENOMEM;
+	master = spi_alloc_master(&pdev->dev, sizeof *as);
+	if (!master)
+		goto out_free;
+
+	master->bus_num = pdev->id;
+	master->num_chipselect = 4;
+	master->setup = atmel_spi_setup;
+	master->transfer = atmel_spi_transfer;
+	master->cleanup = atmel_spi_cleanup;
+	platform_set_drvdata(pdev, master);
+
+	as = spi_master_get_devdata(master);
+
+	as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
+					&as->buffer_dma, GFP_KERNEL);
+	if (!as->buffer)
+		goto out_free;
+
+	spin_lock_init(&as->lock);
+	INIT_LIST_HEAD(&as->queue);
+	as->pdev = pdev;
+	as->regs = ioremap(regs->start, (regs->end - regs->start) + 1);
+	if (!as->regs)
+		goto out_free_buffer;
+	as->irq = irq;
+	as->clk = clk;
+#ifdef CONFIG_ARCH_AT91
+	if (!cpu_is_at91rm9200())
+		as->new_1 = 1;
+#endif
+
+	ret = request_irq(irq, atmel_spi_interrupt, 0,
+			pdev->dev.bus_id, master);
+	if (ret)
+		goto out_unmap_regs;
+
+	/* Initialize the hardware */
+	clk_enable(clk);
+	spi_writel(as, CR, SPI_BIT(SWRST));
+	spi_writel(as, MR, SPI_BIT(MSTR) | SPI_BIT(MODFDIS));
+	spi_writel(as, PTCR, SPI_BIT(RXTDIS) | SPI_BIT(TXTDIS));
+	spi_writel(as, CR, SPI_BIT(SPIEN));
+
+	/* go! */
+	dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n",
+			(unsigned long)regs->start, irq);
+
+	ret = spi_register_master(master);
+	if (ret)
+		goto out_reset_hw;
+
+	return 0;
+
+out_reset_hw:
+	spi_writel(as, CR, SPI_BIT(SWRST));
+	clk_disable(clk);
+	free_irq(irq, master);
+out_unmap_regs:
+	iounmap(as->regs);
+out_free_buffer:
+	dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
+			as->buffer_dma);
+out_free:
+	clk_put(clk);
+	spi_master_put(master);
+	return ret;
+}
+
+static int __exit atmel_spi_remove(struct platform_device *pdev)
+{
+	struct spi_master	*master = platform_get_drvdata(pdev);
+	struct atmel_spi	*as = spi_master_get_devdata(master);
+	struct spi_message	*msg;
+
+	/* reset the hardware and block queue progress */
+	spin_lock_irq(&as->lock);
+	as->stopping = 1;
+	spi_writel(as, CR, SPI_BIT(SWRST));
+	spi_readl(as, SR);
+	spin_unlock_irq(&as->lock);
+
+	/* Terminate remaining queued transfers */
+	list_for_each_entry(msg, &as->queue, queue) {
+		/* REVISIT unmapping the dma is a NOP on ARM and AVR32
+		 * but we shouldn't depend on that...
+		 */
+		msg->status = -ESHUTDOWN;
+		msg->complete(msg->context);
+	}
+
+	dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
+			as->buffer_dma);
+
+	clk_disable(as->clk);
+	clk_put(as->clk);
+	free_irq(as->irq, master);
+	iounmap(as->regs);
+
+	spi_unregister_master(master);
+
+	return 0;
+}
+
+#ifdef	CONFIG_PM
+
+static int atmel_spi_suspend(struct platform_device *pdev, pm_message_t mesg)
+{
+	struct spi_master	*master = platform_get_drvdata(pdev);
+	struct atmel_spi	*as = spi_master_get_devdata(master);
+
+	clk_disable(as->clk);
+	return 0;
+}
+
+static int atmel_spi_resume(struct platform_device *pdev)
+{
+	struct spi_master	*master = platform_get_drvdata(pdev);
+	struct atmel_spi	*as = spi_master_get_devdata(master);
+
+	clk_enable(as->clk);
+	return 0;
+}
+
+#else
+#define	atmel_spi_suspend	NULL
+#define	atmel_spi_resume	NULL
+#endif
+
+
+static struct platform_driver atmel_spi_driver = {
+	.driver		= {
+		.name	= "atmel_spi",
+		.owner	= THIS_MODULE,
+	},
+	.suspend	= atmel_spi_suspend,
+	.resume		= atmel_spi_resume,
+	.remove		= __exit_p(atmel_spi_remove),
+};
+
+static int __init atmel_spi_init(void)
+{
+	return platform_driver_probe(&atmel_spi_driver, atmel_spi_probe);
+}
+module_init(atmel_spi_init);
+
+static void __exit atmel_spi_exit(void)
+{
+	platform_driver_unregister(&atmel_spi_driver);
+}
+module_exit(atmel_spi_exit);
+
+MODULE_DESCRIPTION("Atmel AT32/AT91 SPI Controller driver");
+MODULE_AUTHOR("Haavard Skinnemoen <hskinnemoen@atmel.com>");
+MODULE_LICENSE("GPL");
diff -uprN linux-2.6.20/drivers/spi/atmel_spi.h linux-2.6.20-at92_e1.5/drivers/spi/atmel_spi.h
--- linux-2.6.20/drivers/spi/atmel_spi.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/spi/atmel_spi.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,167 @@
+/*
+ * Register definitions for Atmel Serial Peripheral Interface (SPI)
+ *
+ * Copyright (C) 2006 Atmel 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.
+ */
+#ifndef __ATMEL_SPI_H__
+#define __ATMEL_SPI_H__
+
+/* SPI register offsets */
+#define SPI_CR					0x0000
+#define SPI_MR					0x0004
+#define SPI_RDR					0x0008
+#define SPI_TDR					0x000c
+#define SPI_SR					0x0010
+#define SPI_IER					0x0014
+#define SPI_IDR					0x0018
+#define SPI_IMR					0x001c
+#define SPI_CSR0				0x0030
+#define SPI_CSR1				0x0034
+#define SPI_CSR2				0x0038
+#define SPI_CSR3				0x003c
+#define SPI_RPR					0x0100
+#define SPI_RCR					0x0104
+#define SPI_TPR					0x0108
+#define SPI_TCR					0x010c
+#define SPI_RNPR				0x0110
+#define SPI_RNCR				0x0114
+#define SPI_TNPR				0x0118
+#define SPI_TNCR				0x011c
+#define SPI_PTCR				0x0120
+#define SPI_PTSR				0x0124
+
+/* Bitfields in CR */
+#define SPI_SPIEN_OFFSET			0
+#define SPI_SPIEN_SIZE				1
+#define SPI_SPIDIS_OFFSET			1
+#define SPI_SPIDIS_SIZE				1
+#define SPI_SWRST_OFFSET			7
+#define SPI_SWRST_SIZE				1
+#define SPI_LASTXFER_OFFSET			24
+#define SPI_LASTXFER_SIZE			1
+
+/* Bitfields in MR */
+#define SPI_MSTR_OFFSET				0
+#define SPI_MSTR_SIZE				1
+#define SPI_PS_OFFSET				1
+#define SPI_PS_SIZE				1
+#define SPI_PCSDEC_OFFSET			2
+#define SPI_PCSDEC_SIZE				1
+#define SPI_FDIV_OFFSET				3
+#define SPI_FDIV_SIZE				1
+#define SPI_MODFDIS_OFFSET			4
+#define SPI_MODFDIS_SIZE			1
+#define SPI_LLB_OFFSET				7
+#define SPI_LLB_SIZE				1
+#define SPI_PCS_OFFSET				16
+#define SPI_PCS_SIZE				4
+#define SPI_DLYBCS_OFFSET			24
+#define SPI_DLYBCS_SIZE				8
+
+/* Bitfields in RDR */
+#define SPI_RD_OFFSET				0
+#define SPI_RD_SIZE				16
+
+/* Bitfields in TDR */
+#define SPI_TD_OFFSET				0
+#define SPI_TD_SIZE				16
+
+/* Bitfields in SR */
+#define SPI_RDRF_OFFSET				0
+#define SPI_RDRF_SIZE				1
+#define SPI_TDRE_OFFSET				1
+#define SPI_TDRE_SIZE				1
+#define SPI_MODF_OFFSET				2
+#define SPI_MODF_SIZE				1
+#define SPI_OVRES_OFFSET			3
+#define SPI_OVRES_SIZE				1
+#define SPI_ENDRX_OFFSET			4
+#define SPI_ENDRX_SIZE				1
+#define SPI_ENDTX_OFFSET			5
+#define SPI_ENDTX_SIZE				1
+#define SPI_RXBUFF_OFFSET			6
+#define SPI_RXBUFF_SIZE				1
+#define SPI_TXBUFE_OFFSET			7
+#define SPI_TXBUFE_SIZE				1
+#define SPI_NSSR_OFFSET				8
+#define SPI_NSSR_SIZE				1
+#define SPI_TXEMPTY_OFFSET			9
+#define SPI_TXEMPTY_SIZE			1
+#define SPI_SPIENS_OFFSET			16
+#define SPI_SPIENS_SIZE				1
+
+/* Bitfields in CSR0 */
+#define SPI_CPOL_OFFSET				0
+#define SPI_CPOL_SIZE				1
+#define SPI_NCPHA_OFFSET			1
+#define SPI_NCPHA_SIZE				1
+#define SPI_CSAAT_OFFSET			3
+#define SPI_CSAAT_SIZE				1
+#define SPI_BITS_OFFSET				4
+#define SPI_BITS_SIZE				4
+#define SPI_SCBR_OFFSET				8
+#define SPI_SCBR_SIZE				8
+#define SPI_DLYBS_OFFSET			16
+#define SPI_DLYBS_SIZE				8
+#define SPI_DLYBCT_OFFSET			24
+#define SPI_DLYBCT_SIZE				8
+
+/* Bitfields in RCR */
+#define SPI_RXCTR_OFFSET			0
+#define SPI_RXCTR_SIZE				16
+
+/* Bitfields in TCR */
+#define SPI_TXCTR_OFFSET			0
+#define SPI_TXCTR_SIZE				16
+
+/* Bitfields in RNCR */
+#define SPI_RXNCR_OFFSET			0
+#define SPI_RXNCR_SIZE				16
+
+/* Bitfields in TNCR */
+#define SPI_TXNCR_OFFSET			0
+#define SPI_TXNCR_SIZE				16
+
+/* Bitfields in PTCR */
+#define SPI_RXTEN_OFFSET			0
+#define SPI_RXTEN_SIZE				1
+#define SPI_RXTDIS_OFFSET			1
+#define SPI_RXTDIS_SIZE				1
+#define SPI_TXTEN_OFFSET			8
+#define SPI_TXTEN_SIZE				1
+#define SPI_TXTDIS_OFFSET			9
+#define SPI_TXTDIS_SIZE				1
+
+/* Constants for BITS */
+#define SPI_BITS_8_BPT				0
+#define SPI_BITS_9_BPT				1
+#define SPI_BITS_10_BPT				2
+#define SPI_BITS_11_BPT				3
+#define SPI_BITS_12_BPT				4
+#define SPI_BITS_13_BPT				5
+#define SPI_BITS_14_BPT				6
+#define SPI_BITS_15_BPT				7
+#define SPI_BITS_16_BPT				8
+
+/* Bit manipulation macros */
+#define SPI_BIT(name) \
+	(1 << SPI_##name##_OFFSET)
+#define SPI_BF(name,value) \
+	(((value) & ((1 << SPI_##name##_SIZE) - 1)) << SPI_##name##_OFFSET)
+#define SPI_BFEXT(name,value) \
+	(((value) >> SPI_##name##_OFFSET) & ((1 << SPI_##name##_SIZE) - 1))
+#define SPI_BFINS(name,value,old) \
+	( ((old) & ~(((1 << SPI_##name##_SIZE) - 1) << SPI_##name##_OFFSET)) \
+	  | SPI_BF(name,value))
+
+/* Register access macros */
+#define spi_readl(port,reg) \
+	__raw_readl((port)->regs + SPI_##reg)
+#define spi_writel(port,reg,value) \
+	__raw_writel((value), (port)->regs + SPI_##reg)
+
+#endif /* __ATMEL_SPI_H__ */
diff -uprN linux-2.6.20/drivers/spi/spi_at91_bitbang.c linux-2.6.20-at92_e1.5/drivers/spi/spi_at91_bitbang.c
--- linux-2.6.20/drivers/spi/spi_at91_bitbang.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/spi/spi_at91_bitbang.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,207 @@
+/*
+ * at91_spi.c - at91 SPI driver (BOOTSTRAP/BITBANG VERSION)
+ *
+ * Copyright (C) 2006 David Brownell
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/platform_device.h>
+
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+#include <asm/arch/gpio.h>
+
+
+/*
+ * FIXME this bitbanging version is just to help bootstrap systems until
+ * there's a native SPI+IRQ+DMA controller driver ... such a driver should
+ * be a drop-in replacement for this one, and much faster.
+ *
+ * remember:
+ *
+ *	- other at91 parts (like at91sam9) have multiple controllers
+ *	  and different pin muxing; this version is at91rm9200 specfic.
+ *
+ *	- at91sam9261 SPI0 pins are directly muxed with MMC/SD pins.
+ *
+ *	- rm9200 spi chipselects drop wrongly, so the native driver
+ *	  will need to use gpios much like this does.
+ *
+ *	- real hardware only allows 8..16 bits per word, while this
+ *	  bitbanger allows 1..32 (incompatible superset).
+ *
+ *	- this disregards clock parameters.  with inlined gpio calls,
+ *	  gcc 3.4.4 produces about 1.5 mbit/sec, more than 2x faster
+ *	  than using the subroutined veresion from txrx_word().
+ *
+ *	- suspend/resume and <linux/clk.h> support is missing ...
+ */
+
+#define	spi_miso_bit	AT91_PIN_PA0
+#define	spi_mosi_bit	AT91_PIN_PA1
+#define	spi_sck_bit	AT91_PIN_PA2
+
+struct at91_spi {
+	struct spi_bitbang	bitbang;
+	struct platform_device	*pdev;
+};
+
+/*----------------------------------------------------------------------*/
+
+static inline void setsck(struct spi_device *spi, int is_on)
+{
+	at91_set_gpio_value(spi_sck_bit, is_on);
+}
+
+static inline void setmosi(struct spi_device *spi, int is_on)
+{
+	at91_set_gpio_value(spi_mosi_bit, is_on);
+}
+
+static inline int getmiso(struct spi_device *spi)
+{
+	return at91_get_gpio_value(spi_miso_bit);
+}
+
+static void at91_spi_chipselect(struct spi_device *spi, int is_active)
+{
+	unsigned long cs = (unsigned long) spi->controller_data;
+
+	/* set default clock polarity */
+	if (is_active)
+		setsck(spi, spi->mode & SPI_CPOL);
+
+	/* only support active-low (default) */
+	at91_set_gpio_value(cs, !is_active);
+}
+
+/*
+ * NOTE:  this is "as fast as we can"; it should be a function of
+ * the device clock ...
+ */
+#define	spidelay(X)	do{} while(0)
+
+#define	EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32 at91_spi_txrx_word_mode0(struct spi_device *spi,
+		unsigned nsecs, u32 word, u8 bits)
+{
+	return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, 8);
+}
+
+static u32 at91_spi_txrx_word_mode1(struct spi_device *spi,
+		unsigned nsecs, u32 word, u8 bits)
+{
+	return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, 8);
+}
+
+static u32 at91_spi_txrx_word_mode2(struct spi_device *spi,
+		unsigned nsecs, u32 word, u8 bits)
+{
+	return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, 8);
+}
+
+static u32 at91_spi_txrx_word_mode3(struct spi_device *spi,
+		unsigned nsecs, u32 word, u8 bits)
+{
+	return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, 8);
+}
+
+/*----------------------------------------------------------------------*/
+
+static int __init at91_spi_probe(struct platform_device *pdev)
+{
+	int			status;
+	struct spi_master	*master;
+	struct at91_spi		*at91_spi;
+
+	if (pdev->id != 0)	/* SPI0 bus */
+		return -EINVAL;
+
+	master = spi_alloc_master(&pdev->dev, sizeof *at91_spi);
+	if (!master)
+		return -ENOMEM;
+
+	at91_spi = spi_master_get_devdata(master);
+	at91_spi->pdev = pdev;
+	platform_set_drvdata(pdev, at91_spi);
+
+	/* SPI and bitbang hookup */
+	master->bus_num = 0;
+	master->num_chipselect = 4;
+
+	at91_spi->bitbang.master = spi_master_get(master);
+	at91_spi->bitbang.chipselect = at91_spi_chipselect;
+	at91_spi->bitbang.txrx_word[SPI_MODE_0] = at91_spi_txrx_word_mode0;
+	at91_spi->bitbang.txrx_word[SPI_MODE_1] = at91_spi_txrx_word_mode1;
+	at91_spi->bitbang.txrx_word[SPI_MODE_2] = at91_spi_txrx_word_mode2;
+	at91_spi->bitbang.txrx_word[SPI_MODE_3] = at91_spi_txrx_word_mode3;
+
+	status = spi_bitbang_start(&at91_spi->bitbang);
+	if (status < 0)
+		(void) spi_master_put(at91_spi->bitbang.master);
+
+	return status;
+}
+
+static int __exit at91_spi_remove(struct platform_device *pdev)
+{
+	struct at91_spi	*at91_spi = platform_get_drvdata(pdev);
+	int status;
+
+	/* stop() unregisters child devices too */
+	status = spi_bitbang_stop(&at91_spi->bitbang);
+	(void) spi_master_put(at91_spi->bitbang.master);
+
+	platform_set_drvdata(pdev, NULL);
+	return status;
+}
+
+static struct platform_driver at91_spi_driver = {
+	.probe		= at91_spi_probe,
+	.remove		= __exit_p(at91_spi_remove),
+	.driver		= {
+		.name	= "at91_spi",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init at91_spi_init(void)
+{
+	at91_set_gpio_output(spi_sck_bit, 0);
+	at91_set_gpio_output(spi_mosi_bit, 0);
+	at91_set_gpio_input(spi_miso_bit, 1 /* pullup */);
+
+	/* register driver */
+	return platform_driver_register(&at91_spi_driver);
+}
+
+static void __exit at91_spi_exit(void)
+{
+	platform_driver_unregister(&at91_spi_driver);
+}
+
+device_initcall(at91_spi_init);
+module_exit(at91_spi_exit);
+
+MODULE_ALIAS("at91_spi.0");
+
+MODULE_DESCRIPTION("AT91 SPI support (BOOTSTRAP/BITBANG VERSION)");
+MODULE_AUTHOR("David Brownell");
+MODULE_LICENSE("GPL");
diff -uprN linux-2.6.20/drivers/usb/gadget/at91_udc.c linux-2.6.20-at92_e1.5/drivers/usb/gadget/at91_udc.c
--- linux-2.6.20/drivers/usb/gadget/at91_udc.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/usb/gadget/at91_udc.c	2008-02-07 10:24:59.000000000 -0500
@@ -287,8 +287,8 @@ static void done(struct at91_ep *ep, str
 	ep->stopped = stopped;
 
 	/* ep0 is always ready; other endpoints need a non-empty queue */
-	if (list_empty(&ep->queue) && ep->int_mask != (1 << 0))
-		at91_udp_write(udc, AT91_UDP_IDR, ep->int_mask);
+	if (list_empty(&ep->queue) && (ep->id != 0))
+		at91_udp_write(udc, AT91_UDP_IDR, 1 << ep->id);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -541,7 +541,7 @@ ok:
 	 * reset/init endpoint fifo.  NOTE:  leaves fifo_bank alone,
 	 * since endpoint resets don't reset hw pingpong state.
 	 */
-	at91_udp_write(dev, AT91_UDP_RST_EP, ep->int_mask);
+	at91_udp_write(dev, AT91_UDP_RST_EP, 1 << ep->id);
 	at91_udp_write(dev, AT91_UDP_RST_EP, 0);
 
 	local_irq_restore(flags);
@@ -567,7 +567,7 @@ static int at91_ep_disable (struct usb_e
 
 	/* reset fifos and endpoint */
 	if (ep->udc->clocked) {
-		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_RST_EP, 1 << ep->id);
 		at91_udp_write(udc, AT91_UDP_RST_EP, 0);
 		__raw_writel(0, ep->creg);
 	}
@@ -715,7 +715,7 @@ ep0_in_status:
 
 	if (req && !status) {
 		list_add_tail (&req->queue, &ep->queue);
-		at91_udp_write(dev, AT91_UDP_IER, ep->int_mask);
+		at91_udp_write(dev, AT91_UDP_IER, 1 << ep->id);
 	}
 done:
 	local_irq_restore(flags);
@@ -774,7 +774,7 @@ static int at91_ep_set_halt(struct usb_e
 			csr |= AT91_UDP_FORCESTALL;
 			VDBG("halt %s\n", ep->ep.name);
 		} else {
-			at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+			at91_udp_write(udc, AT91_UDP_RST_EP, 1 << ep->id);
 			at91_udp_write(udc, AT91_UDP_RST_EP, 0);
 			csr &= ~AT91_UDP_FORCESTALL;
 		}
@@ -913,14 +913,15 @@ static void pullup(struct at91_udc *udc,
 		at91_udp_write(udc, AT91_UDP_TXVC, 0);
 		if (cpu_is_at91rm9200())
 			at91_set_gpio_value(udc->board.pullup_pin, 1);
-		else if (cpu_is_at91sam9260()) {
+		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
 			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
-
+			
 			txvc |= AT91_UDP_TXVC_PUON;
 			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
-		} else if (cpu_is_at91sam9261()) {
+		}
+		else if (cpu_is_at91sam9261()) {
 			u32	usbpucr;
-
+			
 			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
 			usbpucr |= AT91_MATRIX_USBPUCR_PUON;
 			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
@@ -928,20 +929,20 @@ static void pullup(struct at91_udc *udc,
 	} else {
 		stop_activity(udc);
 		at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
-		if (cpu_is_at91rm9200())
-			at91_set_gpio_value(udc->board.pullup_pin, 0);
-		else if (cpu_is_at91sam9260()) {
-			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
-
-			txvc &= ~AT91_UDP_TXVC_PUON;
-			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
-		} else if (cpu_is_at91sam9261()) {
-			u32	usbpucr;
-
-			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
-			usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
-			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
-		}
+ 		if (cpu_is_at91rm9200())
+ 			at91_set_gpio_value(udc->board.pullup_pin, 0);
+ 		else if (cpu_is_at91sam9260() || cpu_is_at91sam9263()) {
+ 			u32	txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+ 
+ 			txvc &= ~AT91_UDP_TXVC_PUON;
+ 			at91_udp_write(udc, AT91_UDP_TXVC, txvc);
+ 		} else if (cpu_is_at91sam9261()) {
+ 			u32	usbpucr;
+ 
+ 			usbpucr = at91_sys_read(AT91_MATRIX_USBPUCR);
+ 			usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
+ 			at91_sys_write(AT91_MATRIX_USBPUCR, usbpucr);
+ 		}
 		clk_off(udc);
 	}
 }
@@ -1228,7 +1229,7 @@ static void handle_setup(struct at91_udc
 		} else if (ep->is_in)
 			goto stall;
 
-		at91_udp_write(udc, AT91_UDP_RST_EP, ep->int_mask);
+		at91_udp_write(udc, AT91_UDP_RST_EP, 1 << ep->id);
 		at91_udp_write(udc, AT91_UDP_RST_EP, 0);
 		tmp = __raw_readl(ep->creg);
 		tmp |= CLR_FX;
@@ -1504,15 +1505,16 @@ static struct at91_udc controller = {
 		}
 	},
 	.ep[0] = {
+		.id		= 0,
 		.ep = {
 			.name	= ep0name,
 			.ops	= &at91_ep_ops,
 		},
 		.udc		= &controller,
 		.maxpacket	= 8,
-		.int_mask	= 1 << 0,
 	},
 	.ep[1] = {
+		.id		= 1,
 		.ep = {
 			.name	= "ep1",
 			.ops	= &at91_ep_ops,
@@ -1520,9 +1522,9 @@ static struct at91_udc controller = {
 		.udc		= &controller,
 		.is_pingpong	= 1,
 		.maxpacket	= 64,
-		.int_mask	= 1 << 1,
 	},
 	.ep[2] = {
+		.id		= 2,
 		.ep = {
 			.name	= "ep2",
 			.ops	= &at91_ep_ops,
@@ -1530,9 +1532,9 @@ static struct at91_udc controller = {
 		.udc		= &controller,
 		.is_pingpong	= 1,
 		.maxpacket	= 64,
-		.int_mask	= 1 << 2,
 	},
 	.ep[3] = {
+		.id		= 3,
 		.ep = {
 			/* could actually do bulk too */
 			.name	= "ep3-int",
@@ -1540,9 +1542,9 @@ static struct at91_udc controller = {
 		},
 		.udc		= &controller,
 		.maxpacket	= 8,
-		.int_mask	= 1 << 3,
 	},
 	.ep[4] = {
+		.id		= 4,
 		.ep = {
 			.name	= "ep4",
 			.ops	= &at91_ep_ops,
@@ -1550,9 +1552,9 @@ static struct at91_udc controller = {
 		.udc		= &controller,
 		.is_pingpong	= 1,
 		.maxpacket	= 256,
-		.int_mask	= 1 << 4,
 	},
 	.ep[5] = {
+		.id		= 5,
 		.ep = {
 			.name	= "ep5",
 			.ops	= &at91_ep_ops,
@@ -1560,7 +1562,6 @@ static struct at91_udc controller = {
 		.udc		= &controller,
 		.is_pingpong	= 1,
 		.maxpacket	= 256,
-		.int_mask	= 1 << 5,
 	},
 	/* ep6 and ep7 are also reserved (custom silicon might use them) */
 };
@@ -1679,9 +1680,7 @@ static int __devinit at91udc_probe(struc
 	if (!res)
 		return -ENXIO;
 
-	if (!request_mem_region(res->start,
-			res->end - res->start + 1,
-			driver_name)) {
+	if (!request_mem_region(res->start, res->end - res->start + 1, driver_name)) {
 		DBG("someone's using UDC memory\n");
 		return -EBUSY;
 	}
@@ -1807,16 +1806,13 @@ static int at91udc_suspend(struct platfo
 			|| !wake
 			|| at91_suspend_entering_slow_clock()) {
 		pullup(udc, 0);
-		disable_irq_wake(udc->udp_irq);
+		wake = 0;
 	} else
 		enable_irq_wake(udc->udp_irq);
 
-	if (udc->board.vbus_pin > 0) {
-		if (wake)
-			enable_irq_wake(udc->board.vbus_pin);
-		else
-			disable_irq_wake(udc->board.vbus_pin);
-	}
+	udc->active_suspend = wake;
+	if (udc->board.vbus_pin > 0 && wake)
+		enable_irq_wake(udc->board.vbus_pin);
 	return 0;
 }
 
@@ -1824,8 +1820,14 @@ static int at91udc_resume(struct platfor
 {
 	struct at91_udc *udc = platform_get_drvdata(pdev);
 
+	if (udc->board.vbus_pin > 0 && udc->active_suspend)
+		disable_irq_wake(udc->board.vbus_pin);
+
 	/* maybe reconnect to host; if so, clocks on */
-	pullup(udc, 1);
+	if (udc->active_suspend)
+		disable_irq_wake(udc->udp_irq);
+	else
+		pullup(udc, 1);
 	return 0;
 }
 #else
diff -uprN linux-2.6.20/drivers/usb/gadget/at91_udc.h linux-2.6.20-at92_e1.5/drivers/usb/gadget/at91_udc.h
--- linux-2.6.20/drivers/usb/gadget/at91_udc.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/usb/gadget/at91_udc.h	2008-02-07 10:24:59.000000000 -0500
@@ -105,10 +105,10 @@ struct at91_ep {
 	struct usb_ep			ep;
 	struct list_head		queue;
 	struct at91_udc			*udc;
+	u8				id;
 	void __iomem			*creg;
 
 	unsigned			maxpacket:16;
-	u8				int_mask;
 	unsigned			is_pingpong:1;
 
 	unsigned			stopped:1;
@@ -136,6 +136,7 @@ struct at91_udc {
 	unsigned			wait_for_addr_ack:1;
 	unsigned			wait_for_config_ack:1;
 	unsigned			selfpowered:1;
+	unsigned			active_suspend:1;
 	u8				addr;
 	struct at91_udc_data		board;
 	struct clk			*iclk, *fclk;
diff -uprN linux-2.6.20/drivers/usb/host/ohci-at91.c linux-2.6.20-at92_e1.5/drivers/usb/host/ohci-at91.c
--- linux-2.6.20/drivers/usb/host/ohci-at91.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/usb/host/ohci-at91.c	2008-02-07 10:24:59.000000000 -0500
@@ -18,19 +18,38 @@
 #include <asm/mach-types.h>
 #include <asm/hardware.h>
 #include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
 
 #ifndef CONFIG_ARCH_AT91
 #error "CONFIG_ARCH_AT91 must be defined."
 #endif
 
 /* interface and function clocks */
-static struct clk *iclk, *fclk;
+static struct clk *iclk, *fclk, *hclock;
 static int clocked;
 
 extern int usb_disabled(void);
 
 /*-------------------------------------------------------------------------*/
 
+static void at91_start_clock(void)
+{
+	if (cpu_is_at91sam9261())
+		clk_enable(hclock);
+	clk_enable(iclk);
+	clk_enable(fclk);
+	clocked = 1;
+}
+
+static void at91_stop_clock(void)
+{
+	clk_disable(fclk);
+	clk_disable(iclk);
+	if (cpu_is_at91sam9261())
+		clk_disable(hclock);
+	clocked = 0;
+}
+
 static void at91_start_hc(struct platform_device *pdev)
 {
 	struct usb_hcd *hcd = platform_get_drvdata(pdev);
@@ -41,9 +60,7 @@ static void at91_start_hc(struct platfor
 	/*
 	 * Start the USB clocks.
 	 */
-	clk_enable(iclk);
-	clk_enable(fclk);
-	clocked = 1;
+	at91_start_clock();
 
 	/*
 	 * The USB host controller must remain in reset.
@@ -66,9 +83,7 @@ static void at91_stop_hc(struct platform
 	/*
 	 * Stop the USB clocks.
 	 */
-	clk_disable(fclk);
-	clk_disable(iclk);
-	clocked = 0;
+	at91_stop_clock();
 }
 
 
@@ -126,6 +141,8 @@ static int usb_hcd_at91_probe(const stru
 
 	iclk = clk_get(&pdev->dev, "ohci_clk");
 	fclk = clk_get(&pdev->dev, "uhpck");
+	if (cpu_is_at91sam9261())
+		hclock = clk_get(&pdev->dev, "hck0");
 
 	at91_start_hc(pdev);
 	ohci_hcd_init(hcd_to_ohci(hcd));
@@ -137,6 +154,8 @@ static int usb_hcd_at91_probe(const stru
 	/* Error handling */
 	at91_stop_hc(pdev);
 
+	if (cpu_is_at91sam9261())
+		clk_put(hclock);
 	clk_put(fclk);
 	clk_put(iclk);
 
@@ -170,11 +189,12 @@ static int usb_hcd_at91_remove(struct us
 	at91_stop_hc(pdev);
 	iounmap(hcd->regs);
 	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
-	disable_irq_wake(hcd->irq);
 
+	if (cpu_is_at91sam9261())
+		clk_put(hclock);
 	clk_put(fclk);
 	clk_put(iclk);
-	fclk = iclk = NULL;
+	fclk = iclk = hclock = NULL;
 
 	dev_set_drvdata(&pdev->dev, NULL);
 	return 0;
@@ -271,8 +291,6 @@ ohci_hcd_at91_drv_suspend(struct platfor
 
 	if (device_may_wakeup(&pdev->dev))
 		enable_irq_wake(hcd->irq);
-	else
-		disable_irq_wake(hcd->irq);
 
 	/*
 	 * The integrated transceivers seem unable to notice disconnect,
@@ -283,9 +301,7 @@ ohci_hcd_at91_drv_suspend(struct platfor
 	 */
 	if (at91_suspend_entering_slow_clock()) {
 		ohci_usb_reset (ohci);
-		clk_disable(fclk);
-		clk_disable(iclk);
-		clocked = 0;
+		at91_stop_clock();
 	}
 
 	return 0;
@@ -293,11 +309,13 @@ ohci_hcd_at91_drv_suspend(struct platfor
 
 static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
 {
-	if (!clocked) {
-		clk_enable(iclk);
-		clk_enable(fclk);
-		clocked = 1;
-	}
+	struct usb_hcd	*hcd = platform_get_drvdata(pdev);
+
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(hcd->irq);
+
+	if (!clocked)
+		at91_start_clock();
 
 	return 0;
 }
diff -uprN linux-2.6.20/drivers/usb/net/usbnet.c linux-2.6.20-at92_e1.5/drivers/usb/net/usbnet.c
--- linux-2.6.20/drivers/usb/net/usbnet.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/usb/net/usbnet.c	2008-02-07 10:24:59.000000000 -0500
@@ -1182,6 +1182,8 @@ usbnet_probe (struct usb_interface *udev
 	// NOTE net->name still not usable ...
 	if (info->bind) {
 		status = info->bind (dev, udev);
+		if (status < 0)
+		goto out1;		
 		// heuristic:  "usb%d" for links we know are two-host,
 		// else "eth%d" when there's reasonable doubt.  userspace
 		// can rename the link if it knows better.
@@ -1208,7 +1210,7 @@ usbnet_probe (struct usb_interface *udev
 	if (status == 0 && dev->status)
 		status = init_status (dev, udev);
 	if (status < 0)
-		goto out1;
+		goto out3;
 
 	if (!dev->rx_urb_size)
 		dev->rx_urb_size = dev->hard_mtu;
diff -uprN linux-2.6.20/drivers/video/Kconfig linux-2.6.20-at92_e1.5/drivers/video/Kconfig
--- linux-2.6.20/drivers/video/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/video/Kconfig	2008-02-07 10:24:59.000000000 -0500
@@ -698,6 +698,22 @@ config FB_S1D13XXX
 	  working with S1D13806). Product specs at
 	  <http://www.erd.epson.com/vdc/html/legacy_13xxx.htm>
 
+config FB_ATMEL
+	tristate "AT91/AT32 LCD Controller support"
+	depends on FB && (ARCH_AT91SAM9261 || ARCH_AT91SAM9263 || AVR32)
+	select FB_CFB_FILLRECT
+	select FB_CFB_COPYAREA
+	select FB_CFB_IMAGEBLIT
+	help
+	  This enables support for the AT91/AT32 LCD Controller.
+
+config FB_INTSRAM
+	bool "Frame Buffer in internal SRAM"
+	depends on FB_ATMEL && ARCH_AT91SAM9261
+	help
+	  Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
+	  to let frame buffer in external SDRAM.
+
 config FB_NVIDIA
 	tristate "nVidia Framebuffer Support"
 	depends on FB && PCI
diff -uprN linux-2.6.20/drivers/video/Makefile linux-2.6.20-at92_e1.5/drivers/video/Makefile
--- linux-2.6.20/drivers/video/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/video/Makefile	2008-02-07 10:24:59.000000000 -0500
@@ -78,6 +78,7 @@ obj-$(CONFIG_FB_SA1100)           += sa1
 obj-$(CONFIG_FB_SUN3)             += sun3fb.o
 obj-$(CONFIG_FB_HIT)              += hitfb.o
 obj-$(CONFIG_FB_EPSON1355)	  += epson1355fb.o
+obj-$(CONFIG_FB_ATMEL)		  += atmel_lcdfb.o
 obj-$(CONFIG_FB_PVR2)             += pvr2fb.o
 obj-$(CONFIG_FB_VOODOO1)          += sstfb.o
 obj-$(CONFIG_FB_ARMCLCD)	  += amba-clcd.o
diff -uprN linux-2.6.20/drivers/video/atmel_lcdfb.c linux-2.6.20-at92_e1.5/drivers/video/atmel_lcdfb.c
--- linux-2.6.20/drivers/video/atmel_lcdfb.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/drivers/video/atmel_lcdfb.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,781 @@
+/*
+ *  drivers/video/atmel_lcdfb.c
+ *
+ *  Driver for AT91/AVR32 LCD Controller
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/fb.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <asm/arch/board.h>
+#include <asm/arch/cpu.h>
+#include <asm/arch/gpio.h>
+
+#include <video/atmel_lcdc.h>
+
+#define lcdc_readl(sinfo, reg)		__raw_readl((sinfo)->mmio+(reg))
+#define lcdc_writel(sinfo, reg, val)	__raw_writel((val), (sinfo)->mmio+(reg))
+
+/* More or less configurable parameters */
+#define ATMEL_LCDC_FIFO_SIZE		512
+#define ATMEL_LCDC_CRST_VAL_DEFAULT	0xc8
+#define ATMEL_LCDC_DMA_BURST_LEN	16
+
+#define LCD_POWER_ON	0
+#define LCD_POWER_OFF	1
+
+#if defined(CONFIG_ARCH_AT91)
+static inline void atmel_lcdfb_update_dma2d(struct fb_info *info,
+					struct fb_var_screeninfo *var) { }
+static inline void atmel_lcdfb_set_2dcfg(struct fb_info *info) { }
+#elif defined(CONFIG_AVR32)
+static void atmel_lcdfb_update_dma2d(struct fb_info *info,
+					struct fb_var_screeninfo *var)
+{
+	dma2dcfg = lcdc_readl(sinfo, ATMEL_LCDC_DMA2DCFG);
+	dma2dcfg = LCDC_INSBF(DMA2DCFG_PIXELOFF, pixeloff, dma2dcfg);
+	lcdc_writel(sinfo, ATMEL_LCDC_DMA2DCFG, dma2dcfg);
+
+	/* Update configuration */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON,
+		lcdc_readl(sinfo, ATMEL_LCDC_DMACON) | LCDC_BIT(DMACON_DMAUPDT));
+}
+
+static void atmel_lcdfb_set_2dcfg(struct fb_info *info)
+{
+	/* ...set 2D configuration (necessary for xres_virtual != xres) */
+	value = LCDC_MKBF(DMA2DCFG_ADDRINC,
+			  info->var.xres_virtual - info->var.xres);
+	lcdc_writel(sinfo, DMA2DCFG, value);
+
+	/* ...wait for DMA engine to become idle... */
+	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & LCDC_BIT(DMACON_DMABUSY))
+		msleep(10);
+}
+#endif
+
+
+static struct fb_fix_screeninfo atmel_lcdfb_fix __initdata = {
+	.type		= FB_TYPE_PACKED_PIXELS,
+	.visual		= FB_VISUAL_TRUECOLOR,
+	.xpanstep	= 0,
+	.ypanstep	= 0,
+	.ywrapstep	= 0,
+	.accel		= FB_ACCEL_NONE,
+};
+
+static u32 pseudo_palette[16] = {
+	0x000000,
+	0xaa0000,
+	0x00aa00,
+	0xaa5500,
+	0x0000aa,
+	0xaa00aa,
+	0x00aaaa,
+	0xaaaaaa,
+	0x555555,
+	0xff5555,
+	0x55ff55,
+	0xffff55,
+	0x5555ff,
+	0xff55ff,
+	0x55ffff,
+	0xffffff
+};
+
+static void atmel_lcdfb_update_dma(struct fb_info *info,
+			       struct fb_var_screeninfo *var)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	struct fb_fix_screeninfo *fix = &info->fix;
+	unsigned long dma_addr;
+
+	dma_addr = (fix->smem_start + var->yoffset * fix->line_length
+		    + var->xoffset * var->bits_per_pixel / 8);
+
+	dma_addr &= ~3UL;
+
+	/* Set framebuffer DMA base address and pixel offset */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMABADDR1, dma_addr);
+
+	atmel_lcdfb_update_dma2d(info, var);
+}
+
+static inline void atmel_lcdfb_unmap_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+
+	dma_free_writecombine(info->device, sinfo->map_size,
+				sinfo->map_cpu, sinfo->map_dma);
+}
+
+/**
+ *	atmel_lcdfb_alloc_framebuffer - Allocate framebuffer memory
+ *	@sinfo: the frame buffer to allocate memory for
+ */
+static int atmel_lcdfb_map_video_memory(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+	struct fb_var_screeninfo *var = &info->var;
+
+	sinfo->map_size = (var->xres_virtual * var->yres_virtual
+			    * ((var->bits_per_pixel + 7) / 8));
+
+	sinfo->map_cpu = dma_alloc_writecombine(info->device, sinfo->map_size,
+					      &sinfo->map_dma, GFP_KERNEL);
+
+	if (!sinfo->map_cpu) {
+		return -ENOMEM;
+	}
+
+	return 0;
+}
+
+/**
+ *      atmel_lcdfb_check_var - Validates a var passed in.
+ *      @var: frame buffer variable screen structure
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Checks to see if the hardware supports the state requested by
+ *	var passed in. This function does not alter the hardware
+ *	state!!!  This means the data stored in struct fb_info and
+ *	struct atmel_lcdfb_info do not change. This includes the var
+ *	inside of struct fb_info.  Do NOT change these. This function
+ *	can be called on its own if we intent to only test a mode and
+ *	not actually set it. The stuff in modedb.c is a example of
+ *	this. If the var passed in is slightly off by what the
+ *	hardware can support then we alter the var PASSED in to what
+ *	we can do. If the hardware doesn't support mode change a
+ *	-EINVAL will be returned by the upper layers. You don't need
+ *	to implement this function then. If you hardware doesn't
+ *	support changing the resolution then this function is not
+ *	needed. In this case the driver would just provide a var that
+ *	represents the static state the screen is in.
+ *
+ *	Returns negative errno on error, or zero on success.
+ */
+static int atmel_lcdfb_check_var(struct fb_var_screeninfo *var,
+			     struct fb_info *info)
+{
+	struct device *dev = info->device;
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned long clk_value_khz = 0;
+
+	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+	dev_dbg(dev, "%s:\n", __func__);
+	dev_dbg(dev, "  resolution: %ux%u\n", var->xres, var->yres);
+	dev_dbg(dev, "  pixclk:     %lu KHz\n", PICOS2KHZ(var->pixclock));
+	dev_dbg(dev, "  bpp:        %u\n", var->bits_per_pixel);
+	dev_dbg(dev, "  clk:        %lu KHz\n", clk_value_khz);
+
+	if ((PICOS2KHZ(var->pixclock) * var->bits_per_pixel / 8) > clk_value_khz) {
+		dev_err(dev, "%lu KHz pixel clock is too fast\n", PICOS2KHZ(var->pixclock));
+		return -EINVAL;
+	}
+
+	/* Force same alignment for each line */
+	var->xres = (var->xres + 3) & ~3UL;
+	var->xres_virtual = (var->xres_virtual + 3) & ~3UL;
+
+	var->red.msb_right = var->green.msb_right = var->blue.msb_right = 0;
+	var->transp.offset = var->transp.length = 0;
+
+	switch (var->bits_per_pixel) {
+	case 2:
+	case 4:
+	case 8:
+		var->red.offset = var->green.offset = var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length
+			= var->bits_per_pixel;
+		break;
+	case 15:
+	case 16:
+		var->red.offset = 0;
+		var->green.offset = 5;
+		var->blue.offset = 10;
+		var->red.length = var->green.length = var->blue.length = 5;
+		break;
+	case 24:
+	case 32:
+		var->red.offset = 16;
+		var->green.offset = 8;
+		var->blue.offset = 0;
+		var->red.length = var->green.length = var->blue.length = 8;
+		break;
+	default:
+		dev_err(dev, "color depth %d not supported\n",
+					var->bits_per_pixel);
+		return -EINVAL;
+	}
+
+	var->xoffset = var->yoffset = 0;
+	var->red.msb_right = var->green.msb_right = var->blue.msb_right =
+		var->transp.msb_right = 0;
+
+	return 0;
+}
+
+/**
+ *      atmel_lcdfb_set_par - Alters the hardware state.
+ *      @info: frame buffer structure that represents a single frame buffer
+ *
+ *	Using the fb_var_screeninfo in fb_info we set the resolution
+ *	of the this particular framebuffer. This function alters the
+ *	par AND the fb_fix_screeninfo stored in fb_info. It doesn't
+ *	not alter var in fb_info since we are using that data. This
+ *	means we depend on the data in var inside fb_info to be
+ *	supported by the hardware.  atmel_lcdfb_check_var is always called
+ *	before atmel_lcdfb_set_par to ensure this.  Again if you can't
+ *	change the resolution you don't need this function.
+ *
+ */
+static int atmel_lcdfb_set_par(struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned long value;
+	unsigned long clk_value_khz = 0;
+
+	dev_dbg(info->device, "%s:\n", __func__);
+	dev_dbg(info->device, "  * resolution: %ux%u (%ux%u virtual)\n",
+		 info->var.xres, info->var.yres,
+		 info->var.xres_virtual, info->var.yres_virtual);
+
+	/* Turn off the LCD controller and the DMA controller */
+	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON, sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET);
+
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, 0);
+
+	/* Reset LCDC DMA*/
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, ATMEL_LCDC_DMARST);
+
+	if (info->var.bits_per_pixel <= 8)
+		info->fix.visual = FB_VISUAL_PSEUDOCOLOR;
+	else
+		info->fix.visual = FB_VISUAL_TRUECOLOR;
+
+	info->fix.line_length = info->var.xres_virtual * (info->var.bits_per_pixel / 8);
+
+	/* Re-initialize the DMA engine... */
+	dev_dbg(info->device, "  * update DMA engine\n");
+	atmel_lcdfb_update_dma(info, &info->var);
+
+	/* ...set frame size and burst length = 8 words (?) */
+	value = (info->var.yres * info->var.xres * info->var.bits_per_pixel) / 32;
+	value |= ((ATMEL_LCDC_DMA_BURST_LEN - 1) << ATMEL_LCDC_BLENGTH_OFFSET);
+	lcdc_writel(sinfo, ATMEL_LCDC_DMAFRMCFG, value);
+
+	atmel_lcdfb_set_2dcfg(info);
+
+	/* Now, the LCDC core... */
+
+	/* Set pixel clock */
+	clk_value_khz = clk_get_rate(sinfo->lcdc_clk) / 1000;
+
+	value = clk_value_khz / PICOS2KHZ(info->var.pixclock);
+
+	if (clk_value_khz % PICOS2KHZ(info->var.pixclock))
+		value++;
+
+	value = (value / 2) - 1;
+
+	if (value == 0) {
+		dev_notice(info->device, "Bypassing pixel clock divider\n");
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, ATMEL_LCDC_BYPASS);
+	} else
+		lcdc_writel(sinfo, ATMEL_LCDC_LCDCON1, value << ATMEL_LCDC_CLKVAL_OFFSET);
+
+	/* Initialize control register 2 */
+	value = sinfo->default_lcdcon2;
+
+	if (!(info->var.sync & FB_SYNC_HOR_HIGH_ACT))
+		value |= ATMEL_LCDC_INVLINE_INVERTED;
+	if (!(info->var.sync & FB_SYNC_VERT_HIGH_ACT))
+		value |= ATMEL_LCDC_INVFRAME_INVERTED;
+
+	switch (info->var.bits_per_pixel) {
+		case 1:	value |= ATMEL_LCDC_PIXELSIZE_1; break;
+		case 2: value |= ATMEL_LCDC_PIXELSIZE_2; break;
+		case 4: value |= ATMEL_LCDC_PIXELSIZE_4; break;
+		case 8: value |= ATMEL_LCDC_PIXELSIZE_8; break;
+		case 15: /* fall through */
+		case 16: value |= ATMEL_LCDC_PIXELSIZE_16; break;
+		case 24: value |= ATMEL_LCDC_PIXELSIZE_24; break;
+		case 32: value |= ATMEL_LCDC_PIXELSIZE_32; break;
+		default: BUG(); break;
+	}
+	dev_dbg(info->device, "  * LCDCON2 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_LCDCON2, value);
+
+	/* Vertical timing */
+	value = (info->var.vsync_len - 1) << ATMEL_LCDC_VPW_OFFSET;
+	value |= info->var.upper_margin << ATMEL_LCDC_VBP_OFFSET;
+	value |= info->var.lower_margin;
+	dev_dbg(info->device, "  * LCDTIM1 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_TIM1, value);
+
+	/* Horizontal timing */
+	value = (info->var.right_margin - 1) << ATMEL_LCDC_HFP_OFFSET;
+	value |= (info->var.hsync_len - 1) << ATMEL_LCDC_HPW_OFFSET;
+	value |= (info->var.left_margin - 1);
+	dev_dbg(info->device, "  * LCDTIM2 = %08lx\n", value);
+	lcdc_writel(sinfo, ATMEL_LCDC_TIM2, value);
+
+	/* Display size */
+	value = (info->var.xres - 1) << ATMEL_LCDC_HOZVAL_OFFSET;
+	value |= info->var.yres - 1;
+	lcdc_writel(sinfo, ATMEL_LCDC_LCDFRMCFG, value);
+
+	/* FIFO Threshold: Use formula from data sheet */
+	value = ATMEL_LCDC_FIFO_SIZE - (2 * ATMEL_LCDC_DMA_BURST_LEN + 3);
+	lcdc_writel(sinfo, ATMEL_LCDC_FIFO, value);
+
+	/* Toggle LCD_MODE every frame */
+	lcdc_writel(sinfo, ATMEL_LCDC_MVAL, 0);
+
+	/* Disable all interrupts */
+	lcdc_writel(sinfo, ATMEL_LCDC_IDR, ~0UL);
+
+	// Set contrast
+	value = ATMEL_LCDC_PS_DIV8 | ATMEL_LCDC_POL_POSITIVE | ATMEL_LCDC_ENA_PWMENABLE;
+	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_CTR, value);
+	lcdc_writel(sinfo, ATMEL_LCDC_CONTRAST_VAL, ATMEL_LCDC_CRST_VAL_DEFAULT);
+	/* ...wait for DMA engine to become idle... */
+	while (lcdc_readl(sinfo, ATMEL_LCDC_DMACON) & ATMEL_LCDC_DMABUSY)
+		msleep(10);
+
+	dev_dbg(info->device, "  * re-enable DMA engine\n");
+	/* ...and enable it with updated configuration */
+	lcdc_writel(sinfo, ATMEL_LCDC_DMACON, sinfo->default_dmacon);
+
+	dev_dbg(info->device, "  * re-enable LCDC core\n");
+	lcdc_writel(sinfo, ATMEL_LCDC_PWRCON,
+		(sinfo->guard_time << ATMEL_LCDC_GUARDT_OFFSET) | ATMEL_LCDC_PWR);
+
+	dev_dbg(info->device, "  * DONE\n");
+
+	return 0;
+}
+
+static inline u_int chan_to_field(u_int chan, const struct fb_bitfield *bf)
+{
+	chan &= 0xffff;
+	chan >>= 16 - bf->length;
+	return chan << bf->offset;
+}
+
+/**
+ *  	atmel_lcdfb_setcolreg - Optional function. Sets a color register.
+ *      @regno: Which register in the CLUT we are programming
+ *      @red: The red value which can be up to 16 bits wide
+ *	@green: The green value which can be up to 16 bits wide
+ *	@blue:  The blue value which can be up to 16 bits wide.
+ *	@transp: If supported the alpha value which can be up to 16 bits wide.
+ *      @info: frame buffer info structure
+ *
+ *  	Set a single color register. The values supplied have a 16 bit
+ *  	magnitude which needs to be scaled in this function for the hardware.
+ *	Things to take into consideration are how many color registers, if
+ *	any, are supported with the current color visual. With truecolor mode
+ *	no color palettes are supported. Here a psuedo palette is created
+ *	which we store the value in pseudo_palette in struct fb_info. For
+ *	pseudocolor mode we have a limited color palette. To deal with this
+ *	we can program what color is displayed for a particular pixel value.
+ *	DirectColor is similar in that we can program each color field. If
+ *	we have a static colormap we don't need to implement this function.
+ *
+ *	Returns negative errno on error, or zero on success. In an
+ *	ideal world, this would have been the case, but as it turns
+ *	out, the other drivers return 1 on failure, so that's what
+ *	we're going to do.
+ */
+static int atmel_lcdfb_setcolreg(unsigned int regno, unsigned int red,
+			     unsigned int green, unsigned int blue,
+			     unsigned int transp, struct fb_info *info)
+{
+	struct atmel_lcdfb_info *sinfo = info->par;
+	unsigned int val;
+	u32 *pal;
+	int ret = 1;
+
+	if (info->var.grayscale)
+		red = green = blue = (19595 * red + 38470 * green
+				      + 7471 * blue) >> 16;
+
+	switch (info->fix.visual) {
+	case FB_VISUAL_TRUECOLOR:
+		if (regno < 16) {
+			pal = info->pseudo_palette;
+
+			val  = chan_to_field(red, &info->var.red);
+			val |= chan_to_field(green, &info->var.green);
+			val |= chan_to_field(blue, &info->var.blue);
+
+			pal[regno] = val;
+			ret = 0;
+		}
+		break;
+
+	case FB_VISUAL_PSEUDOCOLOR:
+		if (regno < 256) {
+			val  = ((red   >> 11) & 0x001f);
+			val |= ((green >>  6) & 0x03e0);
+			val |= ((blue  >>  1) & 0x7c00);
+
+			/*
+			 * TODO: intensity bit. Maybe something like
+			 *   ~(red[10] ^ green[10] ^ blue[10]) & 1
+			 */
+
+			lcdc_writel(sinfo, ATMEL_LCDC_LUT_(regno), val);
+			ret = 0;
+		}
+		break;
+	}
+
+	return ret;
+}
+
+static int atmel_lcdfb_pan_display(struct fb_var_screeninfo *var,
+			       struct fb_info *info)
+{
+	dev_dbg(info->device, "%s\n", __func__);
+
+	atmel_lcdfb_update_dma(info, var);
+
+	return 0;
+}
+
+static struct fb_ops atmel_lcdfb_ops = {
+	.owner		= THIS_MODULE,
+	.fb_check_var	= atmel_lcdfb_check_var,
+	.fb_set_par	= atmel_lcdfb_set_par,
+	.fb_setcolreg	= atmel_lcdfb_setcolreg,
+	.fb_pan_display	= atmel_lcdfb_pan_display,
+	.fb_fillrect	= cfb_fillrect,
+	.fb_copyarea	= cfb_copyarea,
+	.fb_imageblit	= cfb_imageblit,
+};
+
+static irqreturn_t atmel_lcdfb_interrupt(int irq, void *dev_id)
+{
+	struct fb_info *info = dev_id;
+	struct atmel_lcdfb_info *sinfo = info->par;
+	u32 status;
+
+	status = lcdc_readl(sinfo, ATMEL_LCDC_ISR);
+	lcdc_writel(sinfo, ATMEL_LCDC_IDR, status);
+	return IRQ_HANDLED;
+}
+
+static int atmel_lcdfb_init_fbinfo(struct atmel_lcdfb_info *sinfo)
+{
+	struct fb_info *info = sinfo->info;
+	int ret = 0;
+
+	info->screen_base = sinfo->map_cpu;
+	info->fix.smem_start = sinfo->map_dma;
+	info->fix.smem_len = sinfo->map_size;
+
+	memset(info->screen_base, 0, info->fix.smem_len);
+	info->var.activate |= FB_ACTIVATE_FORCE | FB_ACTIVATE_NOW;
+
+	dev_info(info->device,
+	       "%luKiB frame buffer at %08lx (mapped at %p)\n",
+	       (unsigned long)info->fix.smem_len / 1024,
+	       (unsigned long)info->fix.smem_start,
+	       info->screen_base);
+
+	/* Allocate colormap */
+	ret = fb_alloc_cmap(&info->cmap, 256, 0);
+	if (ret < 0)
+		dev_err(info->device, "Alloc color map failed\n");
+
+	return ret;
+}
+
+static int atmel_lcdfb_start_clock(struct atmel_lcdfb_info *sinfo)
+{
+	int ret = 0;
+
+	if (sinfo->bus_clk && !IS_ERR(sinfo->bus_clk))
+		clk_enable(sinfo->bus_clk);
+	else {
+		if (cpu_is_at91sam9261()) {
+			/* not an error for other cpus */
+			ret = -ENXIO;
+		}
+	}
+
+	if (sinfo->lcdc_clk && !IS_ERR(sinfo->lcdc_clk))
+		clk_enable(sinfo->lcdc_clk);
+	else
+		ret = -ENXIO;
+
+	return ret;
+}
+
+static void atmel_lcdfb_stop_clock(struct atmel_lcdfb_info *sinfo)
+{
+	if (sinfo->bus_clk && !IS_ERR(sinfo->bus_clk))
+		clk_disable(sinfo->bus_clk);
+	if (sinfo->lcdc_clk && !IS_ERR(sinfo->lcdc_clk))
+		clk_disable(sinfo->lcdc_clk);
+}
+
+
+static int atmel_lcdfb_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct fb_info *info;
+	struct atmel_lcdfb_info *sinfo;
+	struct resource *regs = NULL;
+	struct resource *map = NULL;
+	int ret;
+
+	dev_dbg(dev, "%s BEGIN\n", __func__);
+
+	ret = -ENOMEM;
+	info = framebuffer_alloc(sizeof(struct atmel_lcdfb_info), dev);
+	if (!info) {
+		dev_err(dev, "cannot allocate memory\n");
+		goto out;
+	}
+
+	sinfo = info->par;
+	memcpy(sinfo, dev->platform_data, sizeof(struct atmel_lcdfb_info));
+	sinfo->info = info;
+	sinfo->pdev = pdev;
+
+	strcpy(info->fix.id, sinfo->pdev->name);
+	info->flags = sinfo->default_flags;
+	info->pseudo_palette = pseudo_palette;
+	info->fbops = &atmel_lcdfb_ops;
+
+	memcpy(&info->monspecs, sinfo->default_monspecs, sizeof(info->monspecs));
+	info->fix = atmel_lcdfb_fix;
+
+	/* Enable LCDC Clocks */
+	if (cpu_is_at91sam9261())
+		sinfo->bus_clk = clk_get(dev, "hck1");
+	sinfo->lcdc_clk = clk_get(dev, "lcdc_clk");
+	if (atmel_lcdfb_start_clock(sinfo)) {
+		dev_err(dev, "unable to clock LCDC\n");
+		goto free_info;
+	}
+
+	ret = fb_find_mode(&info->var, info, NULL, info->monspecs.modedb,
+			info->monspecs.modedb_len, info->monspecs.modedb,
+			sinfo->default_bpp);
+	if (!ret) {
+		dev_err(dev, "no suitable video mode found\n");
+		goto stop_clk;
+	}
+
+
+	regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!regs) {
+		dev_err(dev, "resources unusable\n");
+		ret = -ENXIO;
+		goto stop_clk;
+	}
+
+	sinfo->irq_base = platform_get_irq(pdev, 0);
+	if (sinfo->irq_base < 0) {
+		dev_err(dev, "unable to get irq\n");
+		ret = sinfo->irq_base;
+		goto stop_clk;
+	}
+
+	/* Initialize video memory */
+	map = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+	if (map) {
+		/* use a pre-allocated memory buffer */
+		sinfo->map_dma = map->start;
+		sinfo->map_size = map->end - map->start + 1;
+		if (!request_mem_region(sinfo->map_dma,
+					sinfo->map_size, pdev->name)) {
+			ret = -EBUSY;
+			goto stop_clk;
+		}
+
+		sinfo->map_cpu = ioremap(sinfo->map_dma, sinfo->map_size);
+		if (!sinfo->map_cpu)
+			goto release_intmem;
+	} else {
+		/* alocate memory buffer */
+		ret = atmel_lcdfb_map_video_memory(sinfo);
+		if (ret < 0) {
+			dev_err(dev, "cannot allocate framebuffer: %d\n", ret);
+			goto stop_clk;
+		}
+	}
+
+	/* LCDC registers */
+	info->fix.mmio_start = regs->start;
+	info->fix.mmio_len = regs->end - regs->start + 1;
+
+	if (!request_mem_region(info->fix.mmio_start,
+				info->fix.mmio_len, pdev->name)) {
+		ret = -EBUSY;
+		goto free_fb;
+	}
+
+	sinfo->mmio = ioremap(info->fix.mmio_start, info->fix.mmio_len);
+	if (!sinfo->mmio) {
+		dev_err(dev, "cannot map LCDC registers\n");
+		goto release_mem;
+	}
+
+	/* interrupt */
+	ret = request_irq(sinfo->irq_base, atmel_lcdfb_interrupt, 0, pdev->name, info);
+	if (ret) {
+		dev_err(dev, "request_irq failed: %d\n", ret);
+		goto unmap_mmio;
+	}
+
+	ret = atmel_lcdfb_init_fbinfo(sinfo);
+	if (ret < 0) {
+		dev_err(dev, "init fbinfo failed: %d\n", ret);
+		goto unregister_irqs;
+	}
+
+	/*
+	 * This makes sure that our colour bitfield
+	 * descriptors are correctly initialised.
+	 */
+	atmel_lcdfb_check_var(&info->var, info);
+	atmel_lcdfb_set_par(info);
+
+	ret = fb_set_var(info, &info->var);
+	if (ret) {
+		dev_warn(dev, "unable to set display parameters\n");
+		goto free_cmap;
+	}
+
+	dev_set_drvdata(dev, info);
+
+	/*
+	 * Tell the world that we're ready to go
+	 */
+	ret = register_framebuffer(info);
+	if (ret < 0) {
+		dev_err(dev, "failed to register framebuffer device: %d\n", ret);
+		goto free_cmap;
+	}
+
+	/* Power up the LCDC screen */
+	if (sinfo->power_control_pin)
+		at91_set_gpio_value(sinfo->power_control_pin, LCD_POWER_ON);
+
+	dev_info(dev, "fb%d: Atmel LCDC at 0x%08lx (mapped at %p), irq %lu\n",
+		       info->node, info->fix.mmio_start, sinfo->mmio, sinfo->irq_base);
+
+	return 0;
+
+
+free_cmap:
+	fb_dealloc_cmap(&info->cmap);
+unregister_irqs:
+	free_irq(sinfo->irq_base, info);
+unmap_mmio:
+	iounmap(sinfo->mmio);
+release_mem:
+ 	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+free_fb:
+	if (map) {
+		iounmap(sinfo->map_cpu);
+	} else {
+		atmel_lcdfb_unmap_video_memory(sinfo);
+	}
+
+release_intmem:
+	if (map) {
+		release_mem_region(sinfo->map_dma, sinfo->map_size);
+	}
+stop_clk:
+	atmel_lcdfb_stop_clock(sinfo);
+free_info:
+	framebuffer_release(info);
+out:
+	dev_dbg(dev, "%s FAILED\n", __func__);
+	return ret;
+}
+
+static int atmel_lcdfb_remove(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct fb_info *info = dev_get_drvdata(dev);
+	struct atmel_lcdfb_info *sinfo = info->par;
+
+	if (!sinfo)
+		return 0;
+
+	if (sinfo->power_control_pin)
+		at91_set_gpio_value(sinfo->power_control_pin, LCD_POWER_OFF);
+	unregister_framebuffer(info);
+	atmel_lcdfb_stop_clock(sinfo);
+	fb_dealloc_cmap(&info->cmap);
+	free_irq(sinfo->irq_base, info);
+	iounmap(sinfo->mmio);
+ 	release_mem_region(info->fix.mmio_start, info->fix.mmio_len);
+	if (platform_get_resource(pdev, IORESOURCE_MEM, 1)) {
+		iounmap(sinfo->map_cpu);
+		release_mem_region(sinfo->map_dma, sinfo->map_size);
+	} else {
+		atmel_lcdfb_unmap_video_memory(sinfo);
+	}
+
+	dev_set_drvdata(dev, NULL);
+	framebuffer_release(info);
+
+	return 0;
+}
+
+static struct platform_driver atmel_lcdfb_driver = {
+	.probe		= atmel_lcdfb_probe,
+	.remove		= atmel_lcdfb_remove,
+	.driver		= {
+		.name	= "atmel_lcdfb",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init atmel_lcdfb_init(void)
+{
+	return platform_driver_register(&atmel_lcdfb_driver);
+}
+
+static void __exit atmel_lcdfb_exit(void)
+{
+	platform_driver_unregister(&atmel_lcdfb_driver);
+}
+
+module_init(atmel_lcdfb_init);
+module_exit(atmel_lcdfb_exit);
+
+MODULE_AUTHOR("Atmel Corporation");
+MODULE_DESCRIPTION("AT91/AT32 LCD Controller framebuffer driver");
+MODULE_LICENSE("GPL");
diff -uprN linux-2.6.20/fs/jffs2/scan.c linux-2.6.20-at92_e1.5/fs/jffs2/scan.c
--- linux-2.6.20/fs/jffs2/scan.c	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/fs/jffs2/scan.c	2008-02-07 10:24:59.000000000 -0500
@@ -97,8 +97,15 @@ int jffs2_scan_medium(struct jffs2_sb_in
 #ifndef __ECOS
 	size_t pointlen;
 
+	D1(printk(KERN_DEBUG "*******************************************************not ECOS\n"));
+
 	if (c->mtd->point) {
+		D1(printk(KERN_DEBUG "*******************************************************not ECOS point valid\n"));
+
 		ret = c->mtd->point (c->mtd, 0, c->mtd->size, &pointlen, &flashbuf);
+
+		D1(printk(KERN_DEBUG "*******************************************************Buffer Address %p Length %x\n",flashbuf,pointlen));
+
 		if (!ret && pointlen < c->mtd->size) {
 			/* Don't muck about if it won't let us point to the whole flash */
 			D1(printk(KERN_DEBUG "MTD point returned len too short: 0x%zx\n", pointlen));
@@ -447,6 +454,9 @@ static int jffs2_scan_eraseblock (struct
 	prevofs = jeb->offset - 1;
 
 	D1(printk(KERN_DEBUG "jffs2_scan_eraseblock(): Scanning block at 0x%x\n", ofs));
+	D1(printk(KERN_DEBUG "**************************************************** Buffer Size = 0x%x\n",buf_size));
+	D1(printk(KERN_DEBUG "**************************************************** Buffer Address = 0x%p\n",buf));
+
 
 #ifdef CONFIG_JFFS2_FS_WRITEBUFFER
 	if (jffs2_cleanmarker_oob(c)) {
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/ac97c.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/ac97c.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/ac97c.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/ac97c.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,282 @@
+/* linux/include/asm-arm/arch-at91rm9200/ac97c.h
+ *
+ * Hardware definition for the ac97c peripheral in the ATMEL at91sam926x processor
+ *
+ * Generated  12/09/2005 (11:54:20) AT91 SW Application Group from AC97C_XXXX V1.3
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
+ * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * You should have received a copy of the  GNU General Public License along
+ * with this program; if not, write  to the Free Software Foundation, Inc.,
+ * 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+
+#ifndef __AC97C_H
+#define __AC97C_H
+
+/* -------------------------------------------------------- */
+/* AC97C ID definitions for  AT91SAM926x           */
+/* -------------------------------------------------------- */
+#ifndef AT91C_ID_AC97C
+#define AT91C_ID_AC97C 	18 /**< AC97 Controller id */
+#endif /* AT91C_ID_AC97C */
+
+/* -------------------------------------------------------- */
+/* AC97C Base Address definitions for  AT91SAM926x   */
+/* -------------------------------------------------------- */
+#define AT91C_BASE_AC97C     	0xFFFA0000 /**< AC97C base address */
+
+/* -------------------------------------------------------- */
+/* PIO definition for AC97C hardware peripheral */
+/* -------------------------------------------------------- */
+#define AT91C_PB1_AC97CK   	(1 << 1) /**<  */
+#define AT91C_PB0_AC97FS   	(1 << 0) /**<  */
+#define AT91C_PB3_AC97RX   	(1 << 3) /**<  */
+#define AT91C_PB2_AC97TX   	(1 << 2) /**<  */
+
+
+/* -------------------------------------------------------- */
+/* Register offset definition for AC97C hardware peripheral */
+/* -------------------------------------------------------- */
+#define AC97C_MR 	(0x0008) 	/**< Mode Register */
+#define AC97C_ICA 	(0x0010) 	/**< Input Channel AssignementRegister */
+#define AC97C_OCA 	(0x0014) 	/**< Output Channel Assignement Register */
+#define AC97C_CARHR 	(0x0020) 	/**< Channel A Receive Holding Register */
+#define AC97C_CATHR 	(0x0024) 	/**< Channel A Transmit Holding Register */
+#define AC97C_CASR 	(0x0028) 	/**< Channel A Status Register */
+#define AC97C_CAMR 	(0x002C) 	/**< Channel A Mode Register */
+#define AC97C_CBRHR 	(0x0030) 	/**< Channel B Receive Holding Register (optional) */
+#define AC97C_CBTHR 	(0x0034) 	/**< Channel B Transmit Holding Register (optional) */
+#define AC97C_CBSR 	(0x0038) 	/**< Channel B Status Register */
+#define AC97C_CBMR 	(0x003C) 	/**< Channel B Mode Register */
+#define AC97C_CORHR 	(0x0040) 	/**< COdec Transmit Holding Register */
+#define AC97C_COTHR 	(0x0044) 	/**< COdec Transmit Holding Register */
+#define AC97C_COSR 	(0x0048) 	/**< CODEC Status Register */
+#define AC97C_COMR 	(0x004C) 	/**< CODEC Mask Status Register */
+#define AC97C_SR 	(0x0050) 	/**< Status Register */
+#define AC97C_IER 	(0x0054) 	/**< Interrupt Enable Register */
+#define AC97C_IDR 	(0x0058) 	/**< Interrupt Disable Register */
+#define AC97C_IMR 	(0x005C) 	/**< Interrupt Mask Register */
+#define AC97C_VERSION 	(0x00FC) 	/**< Version Register */
+
+/* -------------------------------------------------------- */
+/* Bitfields definition for AC97C hardware peripheral */
+/* -------------------------------------------------------- */
+/* --- Register AC97C_MR */
+#define AT91C_AC97C_ENA       (0x1 << 0 ) /**< (AC97C) AC97 Controller Global Enable */
+#define AT91C_AC97C_WRST      (0x1 << 1 ) /**< (AC97C) Warm Reset */
+#define AT91C_AC97C_VRA       (0x1 << 2 ) /**< (AC97C) Variable RAte (for Data Slots) */
+/* --- Register AC97C_ICA */
+#define AT91C_AC97C_CHID3     (0x7 << 0 ) /**< (AC97C) Channel Id for the input slot 3 */
+#define 	AT91C_AC97C_CHID3_NONE                 0x0 /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CA                   0x1 /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CB                   0x2 /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CC                   0x3 /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID4     (0x7 << 3 ) /**< (AC97C) Channel Id for the input slot 4 */
+#define 	AT91C_AC97C_CHID4_NONE                 (0x0 <<  3) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CA                   (0x1 <<  3) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CB                   (0x2 <<  3) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CC                   (0x3 <<  3) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID5     (0x7 << 6 ) /**< (AC97C) Channel Id for the input slot 5 */
+#define 	AT91C_AC97C_CHID5_NONE                 (0x0 <<  6) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CA                   (0x1 <<  6) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CB                   (0x2 <<  6) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CC                   (0x3 <<  6) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID6     (0x7 << 9 ) /**< (AC97C) Channel Id for the input slot 6 */
+#define 	AT91C_AC97C_CHID6_NONE                 (0x0 <<  9) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CA                   (0x1 <<  9) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CB                   (0x2 <<  9) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CC                   (0x3 <<  9) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID7     (0x7 << 12) /**< (AC97C) Channel Id for the input slot 7 */
+#define 	AT91C_AC97C_CHID7_NONE                 (0x0 << 12) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CA                   (0x1 << 12) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CB                   (0x2 << 12) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CC                   (0x3 << 12) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID8     (0x7 << 15) /**< (AC97C) Channel Id for the input slot 8 */
+#define 	AT91C_AC97C_CHID8_NONE                 (0x0 << 15) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CA                   (0x1 << 15) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CB                   (0x2 << 15) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CC                   (0x3 << 15) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID9     (0x7 << 18) /**< (AC97C) Channel Id for the input slot 9 */
+#define 	AT91C_AC97C_CHID9_NONE                 (0x0 << 18) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CA                   (0x1 << 18) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CB                   (0x2 << 18) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CC                   (0x3 << 18) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID10    (0x7 << 21) /**< (AC97C) Channel Id for the input slot 10 */
+#define 	AT91C_AC97C_CHID10_NONE                 (0x0 << 21) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CA                   (0x1 << 21) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CB                   (0x2 << 21) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CC                   (0x3 << 21) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID11    (0x7 << 24) /**< (AC97C) Channel Id for the input slot 11 */
+#define 	AT91C_AC97C_CHID11_NONE                 (0x0 << 24) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CA                   (0x1 << 24) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CB                   (0x2 << 24) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CC                   (0x3 << 24) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID12    (0x7 << 27) /**< (AC97C) Channel Id for the input slot 12 */
+#define 	AT91C_AC97C_CHID12_NONE                 (0x0 << 27) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CA                   (0x1 << 27) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CB                   (0x2 << 27) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CC                   (0x3 << 27) /**< (AC97C) Channel C data will be transmitted during this slot */
+/* --- Register AC97C_OCA */
+#define AT91C_AC97C_CHID3     (0x7 << 0 ) /**< (AC97C) Channel Id for the input slot 3 */
+#define 	AT91C_AC97C_CHID3_NONE                 0x0 /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CA                   0x1 /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CB                   0x2 /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID3_CC                   0x3 /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID4     (0x7 << 3 ) /**< (AC97C) Channel Id for the input slot 4 */
+#define 	AT91C_AC97C_CHID4_NONE                 (0x0 <<  3) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CA                   (0x1 <<  3) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CB                   (0x2 <<  3) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID4_CC                   (0x3 <<  3) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID5     (0x7 << 6 ) /**< (AC97C) Channel Id for the input slot 5 */
+#define 	AT91C_AC97C_CHID5_NONE                 (0x0 <<  6) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CA                   (0x1 <<  6) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CB                   (0x2 <<  6) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID5_CC                   (0x3 <<  6) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID6     (0x7 << 9 ) /**< (AC97C) Channel Id for the input slot 6 */
+#define 	AT91C_AC97C_CHID6_NONE                 (0x0 <<  9) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CA                   (0x1 <<  9) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CB                   (0x2 <<  9) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID6_CC                   (0x3 <<  9) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID7     (0x7 << 12) /**< (AC97C) Channel Id for the input slot 7 */
+#define 	AT91C_AC97C_CHID7_NONE                 (0x0 << 12) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CA                   (0x1 << 12) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CB                   (0x2 << 12) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID7_CC                   (0x3 << 12) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID8     (0x7 << 15) /**< (AC97C) Channel Id for the input slot 8 */
+#define 	AT91C_AC97C_CHID8_NONE                 (0x0 << 15) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CA                   (0x1 << 15) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CB                   (0x2 << 15) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID8_CC                   (0x3 << 15) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID9     (0x7 << 18) /**< (AC97C) Channel Id for the input slot 9 */
+#define 	AT91C_AC97C_CHID9_NONE                 (0x0 << 18) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CA                   (0x1 << 18) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CB                   (0x2 << 18) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID9_CC                   (0x3 << 18) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID10    (0x7 << 21) /**< (AC97C) Channel Id for the input slot 10 */
+#define 	AT91C_AC97C_CHID10_NONE                 (0x0 << 21) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CA                   (0x1 << 21) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CB                   (0x2 << 21) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID10_CC                   (0x3 << 21) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID11    (0x7 << 24) /**< (AC97C) Channel Id for the input slot 11 */
+#define 	AT91C_AC97C_CHID11_NONE                 (0x0 << 24) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CA                   (0x1 << 24) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CB                   (0x2 << 24) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID11_CC                   (0x3 << 24) /**< (AC97C) Channel C data will be transmitted during this slot */
+#define AT91C_AC97C_CHID12    (0x7 << 27) /**< (AC97C) Channel Id for the input slot 12 */
+#define 	AT91C_AC97C_CHID12_NONE                 (0x0 << 27) /**< (AC97C) No data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CA                   (0x1 << 27) /**< (AC97C) Channel A data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CB                   (0x2 << 27) /**< (AC97C) Channel B data will be transmitted during this slot */
+#define 	AT91C_AC97C_CHID12_CC                   (0x3 << 27) /**< (AC97C) Channel C data will be transmitted during this slot */
+/* --- Register AC97C_CARHR */
+#define AT91C_AC97C_RDATA     (0xFFFFF << 0 ) /**< (AC97C) Receive data */
+/* --- Register AC97C_CATHR */
+#define AT91C_AC97C_TDATA     (0xFFFFF << 0 ) /**< (AC97C) Transmit data */
+/* --- Register AC97C_CASR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4 ) /**< (AC97C)  */
+#define AT91C_AC97C_OVRUN     (0x1 << 5 ) /**< (AC97C)  */
+#define AT91C_AC97C_ENDTX     (0x1 << 10) /**< (AC97C)  */
+#define AT91C_AC97C_TXBUFE    (0x1 << 11) /**< (AC97C)  */
+#define AT91C_AC97C_ENDRX     (0x1 << 14) /**< (AC97C)  */
+#define AT91C_AC97C_RXBUFF    (0x1 << 15) /**< (AC97C)  */
+/* --- Register AC97C_CAMR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4 ) /**< (AC97C)  */
+#define AT91C_AC97C_OVRUN     (0x1 << 5 ) /**< (AC97C)  */
+#define AT91C_AC97C_ENDTX     (0x1 << 10) /**< (AC97C)  */
+#define AT91C_AC97C_TXBUFE    (0x1 << 11) /**< (AC97C)  */
+#define AT91C_AC97C_ENDRX     (0x1 << 14) /**< (AC97C)  */
+#define AT91C_AC97C_RXBUFF    (0x1 << 15) /**< (AC97C)  */
+#define AT91C_AC97C_SIZE      (0x3 << 16) /**< (AC97C)  */
+#define 	AT91C_AC97C_SIZE_20_BITS              (0x0 << 16) /**< (AC97C) Data size is 20 bits */
+#define 	AT91C_AC97C_SIZE_18_BITS              (0x1 << 16) /**< (AC97C) Data size is 18 bits */
+#define 	AT91C_AC97C_SIZE_16_BITS              (0x2 << 16) /**< (AC97C) Data size is 16 bits */
+#define 	AT91C_AC97C_SIZE_10_BITS              (0x3 << 16) /**< (AC97C) Data size is 10 bits */
+#define AT91C_AC97C_CEM       (0x1 << 18) /**< (AC97C)  */
+#define AT91C_AC97C_CEN       (0x1 << 21) /**< (AC97C)  */
+#define AT91C_AC97C_PDCEN     (0x1 << 22) /**< (AC97C)  */
+/* --- Register AC97C_CBRHR */
+#define AT91C_AC97C_RDATA     (0xFFFFF << 0 ) /**< (AC97C) Receive data */
+/* --- Register AC97C_CBTHR */
+#define AT91C_AC97C_TDATA     (0xFFFFF << 0 ) /**< (AC97C) Transmit data */
+/* --- Register AC97C_CBSR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4 ) /**< (AC97C)  */
+#define AT91C_AC97C_OVRUN     (0x1 << 5 ) /**< (AC97C)  */
+/* --- Register AC97C_CBMR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4 ) /**< (AC97C)  */
+#define AT91C_AC97C_OVRUN     (0x1 << 5 ) /**< (AC97C)  */
+#define AT91C_AC97C_SIZE      (0x3 << 16) /**< (AC97C)  */
+#define 	AT91C_AC97C_SIZE_20_BITS              (0x0 << 16) /**< (AC97C) Data size is 20 bits */
+#define 	AT91C_AC97C_SIZE_18_BITS              (0x1 << 16) /**< (AC97C) Data size is 18 bits */
+#define 	AT91C_AC97C_SIZE_16_BITS              (0x2 << 16) /**< (AC97C) Data size is 16 bits */
+#define 	AT91C_AC97C_SIZE_10_BITS              (0x3 << 16) /**< (AC97C) Data size is 10 bits */
+#define AT91C_AC97C_CEM       (0x1 << 18) /**< (AC97C)  */
+#define AT91C_AC97C_CEN       (0x1 << 21) /**< (AC97C)  */
+/* --- Register AC97C_CORHR */
+#define AT91C_AC97C_SDATA     (0xFFFF << 0 ) /**< (AC97C) Status Data */
+/* --- Register AC97C_COTHR */
+#define AT91C_AC97C_CDATA     (0xFFFF << 0 ) /**< (AC97C) Command Data */
+#define AT91C_AC97C_CADDR     (0x7F << 16) /**< (AC97C) COdec control register index */
+#define AT91C_AC97C_READ      (0x1 << 23) /**< (AC97C) Read/Write command */
+/* --- Register AC97C_COSR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4 ) /**< (AC97C)  */
+/* --- Register AC97C_COMR */
+#define AT91C_AC97C_TXRDY     (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_TXEMPTY   (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_UNRUN     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_RXRDY     (0x1 << 4 ) /**< (AC97C)  */
+/* --- Register AC97C_SR */
+#define AT91C_AC97C_SOF       (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_WKUP      (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_COEVT     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_CAEVT     (0x1 << 3 ) /**< (AC97C)  */
+#define AT91C_AC97C_CBEVT     (0x1 << 4 ) /**< (AC97C)  */
+/* --- Register AC97C_IER */
+#define AT91C_AC97C_SOF       (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_WKUP      (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_COEVT     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_CAEVT     (0x1 << 3 ) /**< (AC97C)  */
+#define AT91C_AC97C_CBEVT     (0x1 << 4 ) /**< (AC97C)  */
+/* --- Register AC97C_IDR */
+#define AT91C_AC97C_SOF       (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_WKUP      (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_COEVT     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_CAEVT     (0x1 << 3 ) /**< (AC97C)  */
+#define AT91C_AC97C_CBEVT     (0x1 << 4 ) /**< (AC97C)  */
+/* --- Register AC97C_IMR */
+#define AT91C_AC97C_SOF       (0x1 << 0 ) /**< (AC97C)  */
+#define AT91C_AC97C_WKUP      (0x1 << 1 ) /**< (AC97C)  */
+#define AT91C_AC97C_COEVT     (0x1 << 2 ) /**< (AC97C)  */
+#define AT91C_AC97C_CAEVT     (0x1 << 3 ) /**< (AC97C)  */
+#define AT91C_AC97C_CBEVT     (0x1 << 4 ) /**< (AC97C)  */
+
+#endif /* __AC97C_H */
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91_dbgu.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91_dbgu.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91_dbgu.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91_dbgu.h	2008-02-07 10:24:59.000000000 -0500
@@ -35,6 +35,20 @@
 #define		AT91_CIDR_NVPSIZ	(0xf  << 8)		/* Nonvolatile Program Memory Size */
 #define		AT91_CIDR_NVPSIZ2	(0xf  << 12)		/* Second Nonvolatile Program Memory Size */
 #define		AT91_CIDR_SRAMSIZ	(0xf  << 16)		/* Internal SRAM Size */
+#define			AT91_CIDR_SRAMSIZ_1K	(1 << 16)
+#define			AT91_CIDR_SRAMSIZ_2K	(2 << 16)
+#define			AT91_CIDR_SRAMSIZ_112K	(4 << 16)
+#define			AT91_CIDR_SRAMSIZ_4K	(5 << 16)
+#define			AT91_CIDR_SRAMSIZ_80K	(6 << 16)
+#define			AT91_CIDR_SRAMSIZ_160K	(7 << 16)
+#define			AT91_CIDR_SRAMSIZ_8K	(8 << 16)
+#define			AT91_CIDR_SRAMSIZ_16K	(9 << 16)
+#define			AT91_CIDR_SRAMSIZ_32K	(10 << 16)
+#define			AT91_CIDR_SRAMSIZ_64K	(11 << 16)
+#define			AT91_CIDR_SRAMSIZ_128K	(12 << 16)
+#define			AT91_CIDR_SRAMSIZ_256K	(13 << 16)
+#define			AT91_CIDR_SRAMSIZ_96K	(14 << 16)
+#define			AT91_CIDR_SRAMSIZ_512K	(15 << 16)
 #define		AT91_CIDR_ARCH		(0xff << 20)		/* Architecture Identifier */
 #define		AT91_CIDR_NVPTYP	(7    << 28)		/* Nonvolatile Program Memory Type */
 #define		AT91_CIDR_EXT		(1    << 31)		/* Extension Flag */
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91_mci.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91_mci.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91_mci.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91_mci.h	2008-02-07 10:24:59.000000000 -0500
@@ -26,6 +26,9 @@
 #define AT91_MCI_MR		0x04		/* Mode Register */
 #define		AT91_MCI_CLKDIV		(0xff  <<  0)	/* Clock Divider */
 #define		AT91_MCI_PWSDIV		(7     <<  8)	/* Power Saving Divider */
+#define		AT91_MCI_RDPROOF	(1     << 11)	/* Read Proof Enable [SAM926[03] only] */
+#define		AT91_MCI_WRPROOF	(1     << 12)	/* Write Proof Enable [SAM926[03] only] */
+#define		AT91_MCI_PDCFBYTE	(1     << 13)	/* PDC Force Byte Transfer [SAM926[03] only] */
 #define		AT91_MCI_PDCPADV	(1     << 14)	/* PDC Padding Value */
 #define		AT91_MCI_PDCMODE	(1     << 15)	/* PDC-orientated Mode */
 #define		AT91_MCI_BLKLEN		(0xfff << 18)	/* Data Block Length */
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91_pdc.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91_pdc.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91_pdc.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91_pdc.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,36 +0,0 @@
-/*
- * include/asm-arm/arch-at91rm9200/at91_pdc.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Peripheral Data Controller (PDC) registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_PDC_H
-#define AT91_PDC_H
-
-#define AT91_PDC_RPR		0x100	/* Receive Pointer Register */
-#define AT91_PDC_RCR		0x104	/* Receive Counter Register */
-#define AT91_PDC_TPR		0x108	/* Transmit Pointer Register */
-#define AT91_PDC_TCR		0x10c	/* Transmit Counter Register */
-#define AT91_PDC_RNPR		0x110	/* Receive Next Pointer Register */
-#define AT91_PDC_RNCR		0x114	/* Receive Next Counter Register */
-#define AT91_PDC_TNPR		0x118	/* Transmit Next Pointer Register */
-#define AT91_PDC_TNCR		0x11c	/* Transmit Next Counter Register */
-
-#define AT91_PDC_PTCR		0x120	/* Transfer Control Register */
-#define		AT91_PDC_RXTEN		(1 << 0)	/* Receiver Transfer Enable */
-#define		AT91_PDC_RXTDIS		(1 << 1)	/* Receiver Transfer Disable */
-#define		AT91_PDC_TXTEN		(1 << 8)	/* Transmitter Transfer Enable */
-#define		AT91_PDC_TXTDIS		(1 << 9)	/* Transmitter Transfer Disable */
-
-#define AT91_PDC_PTSR		0x124	/* Transfer Status Register */
-
-#endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91_rstc.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91_rstc.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91_rstc.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91_rstc.h	2008-02-07 10:24:59.000000000 -0500
@@ -17,7 +17,7 @@
 #define		AT91_RSTC_PROCRST	(1 << 0)		/* Processor Reset */
 #define		AT91_RSTC_PERRST	(1 << 2)		/* Peripheral Reset */
 #define		AT91_RSTC_EXTRST	(1 << 3)		/* External Reset */
-#define		AT91_RSTC_KEY		(0xff << 24)		/* KEY Password */
+#define		AT91_RSTC_KEY		(0xa5 << 24)		/* KEY Password */
 
 #define AT91_RSTC_SR		(AT91_RSTC + 0x04)	/* Reset Controller Status Register */
 #define		AT91_RSTC_URSTS		(1 << 0)		/* User Reset Status */
@@ -34,6 +34,5 @@
 #define		AT91_RSTC_URSTEN	(1 << 0)		/* User Reset Enable */
 #define		AT91_RSTC_URSTIEN	(1 << 4)		/* User Reset Interrupt Enable */
 #define		AT91_RSTC_ERSTL		(0xf << 8)		/* External Reset Length */
-#define		AT91_RSTC_KEY		(0xff << 24)		/* KEY Password */
 
 #endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam9260.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam9260.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam9260.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam9260.h	2008-02-07 10:24:59.000000000 -0500
@@ -113,12 +113,16 @@
 
 #define AT91SAM9260_UHP_BASE	0x00500000	/* USB Host controller */
 
-#if 0
+#define AT91SAM9XE_FLASH_BASE	0x00200000	/* Internal FLASH base address */
+#define AT91SAM9XE_SRAM_BASE	0x00300000	/* Internal SRAM base address */
+
+
+#if 1
 /*
  * PIO pin definitions (peripheral A/B multiplexing).
  */
-
-// TODO: Add
+#define AT91C_PIOC_PDR  (AT91_PIOC + 4)
+#define AT91C_PIOC_OER  (AT91_PIOC + 10)
 
 #endif
 
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam9260_matrix.h	2008-02-07 10:24:59.000000000 -0500
@@ -18,7 +18,7 @@
 #define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
 #define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
 #define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
-#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x04)	/* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
 #define		AT91_MATRIX_ULBT		(7 << 0)	/* Undefined Length Burst Type */
 #define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
 #define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam9263.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam9263.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam9263.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam9263.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,131 @@
+/*
+ * include/asm-arm/arch-at91rm9200/at91sam9263.h
+ *
+ * (C) 2007 Atmel Corporation.
+ *
+ * Common definitions.
+ * Based on AT91SAM9263 datasheet revision B (Preliminary).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91SAM9263_H
+#define AT91SAM9263_H
+
+/*
+ * Peripheral identifiers/interrupts.
+ */
+#define AT91_ID_FIQ		0	/* Advanced Interrupt Controller (FIQ) */
+#define AT91_ID_SYS		1	/* System Peripherals */
+#define AT91SAM9263_ID_PIOA	2	/* Parallel IO Controller A */
+#define AT91SAM9263_ID_PIOB	3	/* Parallel IO Controller B */
+#define AT91SAM9263_ID_PIOCDE	4	/* Parallel IO Controller C, D and E */
+#define AT91SAM9263_ID_US0	7	/* USART 0 */
+#define AT91SAM9263_ID_US1	8	/* USART 1 */
+#define AT91SAM9263_ID_US2	9	/* USART 2 */
+#define AT91SAM9263_ID_MCI0	10	/* Multimedia Card Interface 0 */
+#define AT91SAM9263_ID_MCI1	11	/* Multimedia Card Interface 1 */
+#define AT91SAM9263_ID_CAN	12	/* CAN */
+#define AT91SAM9263_ID_TWI	13	/* Two-Wire Interface */
+#define AT91SAM9263_ID_SPI0	14	/* Serial Peripheral Interface 0 */
+#define AT91SAM9263_ID_SPI1	15	/* Serial Peripheral Interface 1 */
+#define AT91SAM9263_ID_SSC0	16	/* Serial Synchronous Controller 0 */
+#define AT91SAM9263_ID_SSC1	17	/* Serial Synchronous Controller 1 */
+#define AT91SAM9263_ID_AC97C	18	/* AC97 Controller */
+#define AT91SAM9263_ID_TCB	19	/* Timer Counter 0, 1 and 2 */
+#define AT91SAM9263_ID_PWMC	20	/* Pulse Width Modulation Controller */
+#define AT91SAM9263_ID_EMAC	21	/* Ethernet */
+#define AT91SAM9263_ID_2DGE	23	/* 2D Graphic Engine */
+#define AT91SAM9263_ID_UDP	24	/* USB Device Port */
+#define AT91SAM9263_ID_ISI	25	/* Image Sensor Interface */
+#define AT91SAM9263_ID_LCDC	26	/* LCD Controller */
+#define AT91SAM9263_ID_DMA	27	/* DMA Controller */
+#define AT91SAM9263_ID_UHP	29	/* USB Host port */
+#define AT91SAM9263_ID_IRQ0	30	/* Advanced Interrupt Controller (IRQ0) */
+#define AT91SAM9263_ID_IRQ1	31	/* Advanced Interrupt Controller (IRQ1) */
+
+
+/*
+ * User Peripheral physical base addresses.
+ */
+#define AT91SAM9263_BASE_UDP		0xfff78000
+#define AT91SAM9263_BASE_TCB0		0xfff7c000
+#define AT91SAM9263_BASE_TC0		0xfff7c000
+#define AT91SAM9263_BASE_TC1		0xfff7c040
+#define AT91SAM9263_BASE_TC2		0xfff7c080
+#define AT91SAM9263_BASE_MCI0		0xfff80000
+#define AT91SAM9263_BASE_MCI1		0xfff84000
+#define AT91SAM9263_BASE_TWI		0xfff88000
+#define AT91SAM9263_BASE_US0		0xfff8c000
+#define AT91SAM9263_BASE_US1		0xfff90000
+#define AT91SAM9263_BASE_US2		0xfff94000
+#define AT91SAM9263_BASE_SSC0		0xfff98000
+#define AT91SAM9263_BASE_SSC1		0xfff9c000
+#define AT91SAM9263_BASE_AC97C		0xfffa0000
+#define AT91SAM9263_BASE_SPI0		0xfffa4000
+#define AT91SAM9263_BASE_SPI1		0xfffa8000
+#define AT91SAM9263_BASE_CAN		0xfffac000
+#define AT91SAM9263_BASE_PWMC		0xfffb8000
+#define AT91SAM9263_BASE_EMAC		0xfffbc000
+#define AT91SAM9263_BASE_ISI		0xfffc4000
+#define AT91SAM9263_BASE_2DGE		0xfffc8000
+#define AT91_BASE_SYS			0xffffe000
+
+/*
+ * System Peripherals (offset from AT91_BASE_SYS)
+ */
+#define AT91_ECC0	(0xffffe000 - AT91_BASE_SYS)
+#define AT91_SDRAMC0	(0xffffe200 - AT91_BASE_SYS)
+#define AT91_SMC0	(0xffffe400 - AT91_BASE_SYS)
+#define AT91_ECC1	(0xffffe600 - AT91_BASE_SYS)
+#define AT91_SDRAMC1	(0xffffe800 - AT91_BASE_SYS)
+#define AT91_SMC1	(0xffffea00 - AT91_BASE_SYS)
+#define AT91_MATRIX	(0xffffec00 - AT91_BASE_SYS)
+#define AT91_CCFG	(0xffffed10 - AT91_BASE_SYS)
+#define AT91_DBGU	(0xffffee00 - AT91_BASE_SYS)
+#define AT91_AIC	(0xfffff000 - AT91_BASE_SYS)
+#define AT91_PIOA	(0xfffff200 - AT91_BASE_SYS)
+#define AT91_PIOB	(0xfffff400 - AT91_BASE_SYS)
+#define AT91_PIOC	(0xfffff600 - AT91_BASE_SYS)
+#define AT91_PIOD	(0xfffff800 - AT91_BASE_SYS)
+#define AT91_PIOE	(0xfffffa00 - AT91_BASE_SYS)
+#define AT91_PMC	(0xfffffc00 - AT91_BASE_SYS)
+#define AT91_RSTC	(0xfffffd00 - AT91_BASE_SYS)
+#define AT91_SHDWC	(0xfffffd10 - AT91_BASE_SYS)
+#define AT91_RTT0	(0xfffffd20 - AT91_BASE_SYS)
+#define AT91_PIT	(0xfffffd30 - AT91_BASE_SYS)
+#define AT91_WDT	(0xfffffd40 - AT91_BASE_SYS)
+#define AT91_RTT1	(0xfffffd50 - AT91_BASE_SYS)
+#define AT91_GPBR	(0xfffffd60 - AT91_BASE_SYS)
+
+#define AT91_SMC	AT91_SMC0
+
+/*
+ * Internal Memory.
+ */
+#define AT91SAM9263_SRAM0_BASE	0x00300000	/* Internal SRAM 0 base address */
+#define AT91SAM9263_SRAM0_SIZE	(80 * SZ_1K)	/* Internal SRAM 0 size (80Kb) */
+
+#define AT91SAM9263_ROM_BASE	0x00400000	/* Internal ROM base address */
+#define AT91SAM9263_ROM_SIZE	SZ_128K		/* Internal ROM size (128Kb) */
+
+#define AT91SAM9263_SRAM1_BASE	0x00500000	/* Internal SRAM 1 base address */
+#define AT91SAM9263_SRAM1_SIZE	SZ_16K		/* Internal SRAM 1 size (16Kb) */
+
+#define AT91SAM9263_LCDC_BASE	0x00700000	/* LCD Controller */
+#define AT91SAM9263_DMAC_BASE	0x00800000	/* DMA Controller */
+#define AT91SAM9263_UHP_BASE	0x00a00000	/* USB Host controller */
+
+#if 0
+/*
+ * PIO pin definitions (peripheral A/B multiplexing).
+ */
+
+// TODO: Add
+
+#endif
+
+#endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam9263_matrix.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam9263_matrix.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam9263_matrix.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam9263_matrix.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,129 @@
+/*
+ * include/asm-arm/arch-at91rm9200/at91sam9263_matrix.h
+ *
+ *  Copyright (C) 2006 Atmel Corporation.
+ *
+ * Memory Controllers (MATRIX, EBI) - System peripherals registers.
+ * Based on AT91SAM9263 datasheet revision B (Preliminary).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef AT91SAM9263_MATRIX_H
+#define AT91SAM9263_MATRIX_H
+
+#define AT91_MATRIX_MCFG0	(AT91_MATRIX + 0x00)	/* Master Configuration Register 0 */
+#define AT91_MATRIX_MCFG1	(AT91_MATRIX + 0x04)	/* Master Configuration Register 1 */
+#define AT91_MATRIX_MCFG2	(AT91_MATRIX + 0x08)	/* Master Configuration Register 2 */
+#define AT91_MATRIX_MCFG3	(AT91_MATRIX + 0x0C)	/* Master Configuration Register 3 */
+#define AT91_MATRIX_MCFG4	(AT91_MATRIX + 0x10)	/* Master Configuration Register 4 */
+#define AT91_MATRIX_MCFG5	(AT91_MATRIX + 0x14)	/* Master Configuration Register 5 */
+#define AT91_MATRIX_MCFG6	(AT91_MATRIX + 0x18)	/* Master Configuration Register 6 */
+#define AT91_MATRIX_MCFG7	(AT91_MATRIX + 0x1C)	/* Master Configuration Register 7 */
+#define AT91_MATRIX_MCFG8	(AT91_MATRIX + 0x20)	/* Master Configuration Register 8 */
+#define		AT91_MATRIX_ULBT	(7 << 0)	/* Undefined Length Burst Type */
+#define			AT91_MATRIX_ULBT_INFINITE	(0 << 0)
+#define			AT91_MATRIX_ULBT_SINGLE		(1 << 0)
+#define			AT91_MATRIX_ULBT_FOUR		(2 << 0)
+#define			AT91_MATRIX_ULBT_EIGHT		(3 << 0)
+#define			AT91_MATRIX_ULBT_SIXTEEN	(4 << 0)
+
+#define AT91_MATRIX_SCFG0	(AT91_MATRIX + 0x40)	/* Slave Configuration Register 0 */
+#define AT91_MATRIX_SCFG1	(AT91_MATRIX + 0x44)	/* Slave Configuration Register 1 */
+#define AT91_MATRIX_SCFG2	(AT91_MATRIX + 0x48)	/* Slave Configuration Register 2 */
+#define AT91_MATRIX_SCFG3	(AT91_MATRIX + 0x4C)	/* Slave Configuration Register 3 */
+#define AT91_MATRIX_SCFG4	(AT91_MATRIX + 0x50)	/* Slave Configuration Register 4 */
+#define AT91_MATRIX_SCFG5	(AT91_MATRIX + 0x54)	/* Slave Configuration Register 5 */
+#define AT91_MATRIX_SCFG6	(AT91_MATRIX + 0x58)	/* Slave Configuration Register 6 */
+#define AT91_MATRIX_SCFG7	(AT91_MATRIX + 0x5C)	/* Slave Configuration Register 7 */
+#define		AT91_MATRIX_SLOT_CYCLE		(0xff << 0)	/* Maximum Number of Allowed Cycles for a Burst */
+#define		AT91_MATRIX_DEFMSTR_TYPE	(3    << 16)	/* Default Master Type */
+#define			AT91_MATRIX_DEFMSTR_TYPE_NONE	(0 << 16)
+#define			AT91_MATRIX_DEFMSTR_TYPE_LAST	(1 << 16)
+#define			AT91_MATRIX_DEFMSTR_TYPE_FIXED	(2 << 16)
+#define		AT91_MATRIX_FIXED_DEFMSTR	(7    << 18)	/* Fixed Index of Default Master */
+#define		AT91_MATRIX_ARBT		(3    << 24)	/* Arbitration Type */
+#define			AT91_MATRIX_ARBT_ROUND_ROBIN	(0 << 24)
+#define			AT91_MATRIX_ARBT_FIXED_PRIORITY	(1 << 24)
+
+#define AT91_MATRIX_PRAS0	(AT91_MATRIX + 0x80)	/* Priority Register A for Slave 0 */
+#define AT91_MATRIX_PRBS0	(AT91_MATRIX + 0x84)	/* Priority Register B for Slave 0 */
+#define AT91_MATRIX_PRAS1	(AT91_MATRIX + 0x88)	/* Priority Register A for Slave 1 */
+#define AT91_MATRIX_PRBS1	(AT91_MATRIX + 0x8C)	/* Priority Register B for Slave 1 */
+#define AT91_MATRIX_PRAS2	(AT91_MATRIX + 0x90)	/* Priority Register A for Slave 2 */
+#define AT91_MATRIX_PRBS2	(AT91_MATRIX + 0x94)	/* Priority Register B for Slave 2 */
+#define AT91_MATRIX_PRAS3	(AT91_MATRIX + 0x98)	/* Priority Register A for Slave 3 */
+#define AT91_MATRIX_PRBS3	(AT91_MATRIX + 0x9C)	/* Priority Register B for Slave 3 */
+#define AT91_MATRIX_PRAS4	(AT91_MATRIX + 0xA0)	/* Priority Register A for Slave 4 */
+#define AT91_MATRIX_PRBS4	(AT91_MATRIX + 0xA4)	/* Priority Register B for Slave 4 */
+#define AT91_MATRIX_PRAS5	(AT91_MATRIX + 0xA8)	/* Priority Register A for Slave 5 */
+#define AT91_MATRIX_PRBS5	(AT91_MATRIX + 0xAC)	/* Priority Register B for Slave 5 */
+#define AT91_MATRIX_PRAS6	(AT91_MATRIX + 0xB0)	/* Priority Register A for Slave 6 */
+#define AT91_MATRIX_PRBS6	(AT91_MATRIX + 0xB4)	/* Priority Register B for Slave 6 */
+#define AT91_MATRIX_PRAS7	(AT91_MATRIX + 0xB8)	/* Priority Register A for Slave 7 */
+#define AT91_MATRIX_PRBS7	(AT91_MATRIX + 0xBC)	/* Priority Register B for Slave 7 */
+#define		AT91_MATRIX_M0PR		(3 << 0)	/* Master 0 Priority */
+#define		AT91_MATRIX_M1PR		(3 << 4)	/* Master 1 Priority */
+#define		AT91_MATRIX_M2PR		(3 << 8)	/* Master 2 Priority */
+#define		AT91_MATRIX_M3PR		(3 << 12)	/* Master 3 Priority */
+#define		AT91_MATRIX_M4PR		(3 << 16)	/* Master 4 Priority */
+#define		AT91_MATRIX_M5PR		(3 << 20)	/* Master 5 Priority */
+#define		AT91_MATRIX_M6PR		(3 << 24)	/* Master 6 Priority */
+#define		AT91_MATRIX_M7PR		(3 << 28)	/* Master 7 Priority */
+#define		AT91_MATRIX_M8PR		(3 << 0)	/* Master 8 Priority (in Register B) */
+
+#define AT91_MATRIX_MRCR	(AT91_MATRIX + 0x100)	/* Master Remap Control Register */
+#define		AT91_MATRIX_RCB0		(1 << 0)	/* Remap Command for AHB Master 0 (ARM926EJ-S Instruction Master) */
+#define		AT91_MATRIX_RCB1		(1 << 1)	/* Remap Command for AHB Master 1 (ARM926EJ-S Data Master) */
+#define		AT91_MATRIX_RCB2		(1 << 2)
+#define		AT91_MATRIX_RCB3		(1 << 3)
+#define		AT91_MATRIX_RCB4		(1 << 4)
+#define		AT91_MATRIX_RCB5		(1 << 5)
+#define		AT91_MATRIX_RCB6		(1 << 6)
+#define		AT91_MATRIX_RCB7		(1 << 7)
+#define		AT91_MATRIX_RCB8		(1 << 8)
+
+#define AT91_MATRIX_TCMR	(AT91_MATRIX + 0x114)	/* TCM Configuration Register */
+#define		AT91_MATRIX_ITCM_SIZE		(0xf << 0)	/* Size of ITCM enabled memory block */
+#define			AT91_MATRIX_ITCM_0		(0 << 0)
+#define			AT91_MATRIX_ITCM_16		(5 << 0)
+#define			AT91_MATRIX_ITCM_32		(6 << 0)
+#define		AT91_MATRIX_DTCM_SIZE		(0xf << 4)	/* Size of DTCM enabled memory block */
+#define			AT91_MATRIX_DTCM_0		(0 << 4)
+#define			AT91_MATRIX_DTCM_16		(5 << 4)
+#define			AT91_MATRIX_DTCM_32		(6 << 4)
+
+#define AT91_MATRIX_EBI0CSA	(AT91_MATRIX + 0x120)	/* EBI0 Chip Select Assignment Register */
+#define		AT91_MATRIX_EBI0_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
+#define			AT91_MATRIX_EBI0_CS1A_SMC		(0 << 1)
+#define			AT91_MATRIX_EBI0_CS1A_SDRAMC		(1 << 1)
+#define		AT91_MATRIX_EBI0_CS3A		(1 << 3)	/* Chip Select 3 Assignment */
+#define			AT91_MATRIX_EBI0_CS3A_SMC		(0 << 3)
+#define			AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA	(1 << 3)
+#define		AT91_MATRIX_EBI0_CS4A		(1 << 4)	/* Chip Select 4 Assignment */
+#define			AT91_MATRIX_EBI0_CS4A_SMC		(0 << 4)
+#define			AT91_MATRIX_EBI0_CS4A_SMC_CF1		(1 << 4)
+#define		AT91_MATRIX_EBI0_CS5A		(1 << 5)	/* Chip Select 5 Assignment */
+#define			AT91_MATRIX_EBI0_CS5A_SMC		(0 << 5)
+#define			AT91_MATRIX_EBI0_CS5A_SMC_CF2		(1 << 5)
+#define		AT91_MATRIX_EBI0_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
+#define		AT91_MATRIX_EBI0_VDDIOMSEL	(1 << 16)	/* Memory voltage selection */
+#define			AT91_MATRIX_EBI0_VDDIOMSEL_1_8V		(0 << 16)
+#define			AT91_MATRIX_EBI0_VDDIOMSEL_3_3V		(1 << 16)
+
+#define AT91_MATRIX_EBI1CSA	(AT91_MATRIX + 0x124)	/* EBI1 Chip Select Assignment Register */
+#define		AT91_MATRIX_EBI1_CS1A		(1 << 1)	/* Chip Select 1 Assignment */
+#define			AT91_MATRIX_EBI1_CS1A_SMC		(0 << 1)
+#define			AT91_MATRIX_EBI1_CS1A_SDRAMC		(1 << 1)
+#define		AT91_MATRIX_EBI1_CS2A		(1 << 3)	/* Chip Select 3 Assignment */
+#define			AT91_MATRIX_EBI1_CS2A_SMC		(0 << 3)
+#define			AT91_MATRIX_EBI1_CS2A_SMC_SMARTMEDIA	(1 << 3)
+#define		AT91_MATRIX_EBI1_DBPUC		(1 << 8)	/* Data Bus Pull-up Configuration */
+#define		AT91_MATRIX_EBI1_VDDIOMSEL	(1 << 16)	/* Memory voltage selection */
+#define			AT91_MATRIX_EBI1_VDDIOMSEL_1_8V		(0 << 16)
+#define			AT91_MATRIX_EBI1_VDDIOMSEL_3_3V		(1 << 16)
+
+#endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/at91sam926x_mc.h	2008-02-07 10:24:59.000000000 -0500
@@ -131,4 +131,11 @@
 #define			AT91_SMC_PS_16			(2 << 28)
 #define			AT91_SMC_PS_32			(3 << 28)
 
+#if defined(AT91_SMC1)		/* The AT91SAM9263 has 2 Static Memory contollers */
+#define AT91_SMC1_SETUP(n)	(AT91_SMC1 + 0x00 + ((n)*0x10))	/* Setup Register for CS n */
+#define AT91_SMC1_PULSE(n)	(AT91_SMC1 + 0x04 + ((n)*0x10))	/* Pulse Register for CS n */
+#define AT91_SMC1_CYCLE(n)	(AT91_SMC1 + 0x08 + ((n)*0x10))	/* Cycle Register for CS n */
+#define AT91_SMC1_MODE(n)	(AT91_SMC1 + 0x0c + ((n)*0x10))	/* Mode Register for CS n */
+#endif
+
 #endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/board.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/board.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/board.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/board.h	2008-02-07 10:24:59.000000000 -0500
@@ -34,6 +34,7 @@
 #include <linux/mtd/partitions.h>
 #include <linux/device.h>
 #include <linux/spi/spi.h>
+#include <video/atmel_lcdc.h>
 
  /* USB Device */
 struct at91_udc_data {
@@ -60,18 +61,28 @@ struct at91_mmc_data {
 	u8		wp_pin;		/* (SD) writeprotect detect */
 	u8		vcc_pin;	/* power switching (high == on) */
 };
-extern void __init at91_add_device_mmc(struct at91_mmc_data *data);
+extern void __init at91_add_device_mmc(short mmc_id, struct at91_mmc_data *data);
 
  /* Ethernet */
 struct at91_eth_data {
 	u8		phy_irq_pin;	/* PHY IRQ */
 	u8		is_rmii;	/* using RMII interface? */
 };
+
+#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263)
+#define eth_platform_data       at91_eth_data
+#endif
+
 extern void __init at91_add_device_eth(struct at91_eth_data *data);
 
+#if defined(CONFIG_ARCH_AT91SAM9260) || defined(CONFIG_ARCH_AT91SAM9263)
+#define eth_platform_data	at91_eth_data
+#endif
+
  /* USB Host */
 struct at91_usbh_data {
 	u8		ports;		/* number of ports on root hub */
+  	u8		vbus_pin[];	/* port power switch */
 };
 extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
 
@@ -93,6 +104,9 @@ extern void __init at91_add_device_i2c(v
  /* SPI */
 extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices);
 
+ /* LCD Controler */
+extern void __init at91_add_device_lcdc(struct atmel_lcdfb_info *data);
+
  /* Serial */
 struct at91_uart_config {
 	unsigned short	console_tty;	/* tty number of serial console */
@@ -114,4 +128,27 @@ extern u8 at91_leds_cpu;
 extern u8 at91_leds_timer;
 extern void __init at91_init_leds(u8 cpu_led, u8 timer_led);
 
+struct at91_gpio_led {
+	u8		index;		/* index of LED */
+	char*		name;		/* name of LED */
+	u8		gpio;		/* AT91_PIN_xx */
+	u8		flags;		/* 1=active-high */
+	char*		trigger;	/* default trigger */
+};
+extern void __init at91_gpio_leds(struct at91_gpio_led *leds, int nr);
+
+/* SSC + AT73C213 */
+struct atmel_at73c213_data {
+	struct clk *at73_mck; 	// MCK AT73C213 clock   
+	unsigned int ssc_div;   // ssc divisor
+};
+extern void __init at91_add_device_ssc_at71c213(void);
+
+/* AC97 */
+struct atmel_ac97_data {
+	u8 reset_pin;
+};
+
+extern void __init at91_add_device_ac97(struct atmel_ac97_data *ek_data);
+
 #endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/cpu.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/cpu.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/cpu.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/cpu.h	2008-02-07 10:24:59.000000000 -0500
@@ -20,7 +20,11 @@
 #define ARCH_ID_AT91RM9200	0x09290780
 #define ARCH_ID_AT91SAM9260	0x019803a0
 #define ARCH_ID_AT91SAM9261	0x019703a0
+#define ARCH_ID_AT91SAM9263	0x019607a0
 
+#define ARCH_ID_AT91SAM9XE128	0x329973a0
+#define ARCH_ID_AT91SAM9XE256	0x329a93a0
+#define ARCH_ID_AT91SAM9XE512	0x329aa3a0
 
 static inline unsigned long at91_cpu_identify(void)
 {
@@ -28,6 +32,16 @@ static inline unsigned long at91_cpu_ide
 }
 
 
+#define ARCH_FAMILY_AT91X92	0x09200000
+#define ARCH_FAMILY_AT91SAM9	0x01900000
+#define ARCH_FAMILY_AT91SAM9XE	0x02900000
+
+static inline unsigned long at91_arch_identify(void)
+{
+	return (at91_sys_read(AT91_DBGU_CIDR) & AT91_CIDR_ARCH);
+}
+
+
 #ifdef CONFIG_ARCH_AT91RM9200
 #define cpu_is_at91rm9200()	(at91_cpu_identify() == ARCH_ID_AT91RM9200)
 #else
@@ -35,8 +49,10 @@ static inline unsigned long at91_cpu_ide
 #endif
 
 #ifdef CONFIG_ARCH_AT91SAM9260
-#define cpu_is_at91sam9260()	(at91_cpu_identify() == ARCH_ID_AT91SAM9260)
+#define cpu_is_at91sam9xe()	(at91_arch_identify() == ARCH_FAMILY_AT91SAM9XE)
+#define cpu_is_at91sam9260()	((at91_cpu_identify() == ARCH_ID_AT91SAM9260) || cpu_is_at91sam9xe())
 #else
+#define cpu_is_at91sam9xe()	(0)
 #define cpu_is_at91sam9260()	(0)
 #endif
 
@@ -46,4 +62,10 @@ static inline unsigned long at91_cpu_ide
 #define cpu_is_at91sam9261()	(0)
 #endif
 
+#ifdef CONFIG_ARCH_AT91SAM9263
+#define cpu_is_at91sam9263()	(at91_cpu_identify() == ARCH_ID_AT91SAM9263)
+#else
+#define cpu_is_at91sam9263()	(0)
+#endif
+
 #endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/debug-macro.S linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/debug-macro.S
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/debug-macro.S	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/debug-macro.S	2008-02-07 10:24:59.000000000 -0500
@@ -16,24 +16,24 @@
 
 	.macro	addruart,rx
 	mrc	p15, 0, \rx, c1, c0
-	tst	\rx, #1				@ MMU enabled?
-	ldreq	\rx, =AT91_BASE_SYS		@ System peripherals (phys address)
-	ldrne	\rx, =AT91_VA_BASE_SYS		@ System peripherals (virt address)
+	tst	\rx, #1						@ MMU enabled?
+	ldreq	\rx, =(AT91_BASE_SYS + AT91_DBGU)		@ System peripherals (phys address)
+	ldrne	\rx, =(AT91_VA_BASE_SYS	+ AT91_DBGU)		@ System peripherals (virt address)
 	.endm
 
 	.macro	senduart,rd,rx
-	strb	\rd, [\rx, #AT91_DBGU_THR]	@ Write to Transmitter Holding Register
+	strb	\rd, [\rx, #(AT91_DBGU_THR - AT91_DBGU)]	@ Write to Transmitter Holding Register
 	.endm
 
 	.macro	waituart,rd,rx
-1001:	ldr	\rd, [\rx, #AT91_DBGU_SR]	@ Read Status Register
-	tst	\rd, #AT91_DBGU_TXRDY		@ DBGU_TXRDY = 1 when ready to transmit
+1001:	ldr	\rd, [\rx, #(AT91_DBGU_SR - AT91_DBGU)]		@ Read Status Register
+	tst	\rd, #AT91_DBGU_TXRDY				@ DBGU_TXRDY = 1 when ready to transmit
 	beq	1001b
 	.endm
 
 	.macro	busyuart,rd,rx
-1001:	ldr	\rd, [\rx, #AT91_DBGU_SR]	@ Read Status Register
-	tst	\rd, #AT91_DBGU_TXEMPTY		@ DBGU_TXEMPTY = 1 when transmission complete
+1001:	ldr	\rd, [\rx, #(AT91_DBGU_SR - AT91_DBGU)]		@ Read Status Register
+	tst	\rd, #AT91_DBGU_TXEMPTY				@ DBGU_TXEMPTY = 1 when transmission complete
 	beq	1001b
 	.endm
 
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/entry-macro.S linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/entry-macro.S
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/entry-macro.S	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/entry-macro.S	2008-02-07 10:24:59.000000000 -0500
@@ -17,10 +17,10 @@
 	.endm
 
 	.macro	get_irqnr_and_base, irqnr, irqstat, base, tmp
-	ldr	\base, =(AT91_VA_BASE_SYS)		@ base virtual address of SYS peripherals
-	ldr	\irqnr, [\base, #AT91_AIC_IVR]		@ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
-	ldr	\irqstat, [\base, #AT91_AIC_ISR]	@ read interrupt source number
-	teq	\irqstat, #0				@ ISR is 0 when no current interrupt, or spurious interrupt
-	streq	\tmp, [\base, #AT91_AIC_EOICR]		@ not going to be handled further, then ACK it now.
+	ldr	\base, =(AT91_VA_BASE_SYS + AT91_AIC)		@ base virtual address of AIC peripheral
+	ldr	\irqnr, [\base, #(AT91_AIC_IVR - AT91_AIC)]	@ read IRQ vector register: de-asserts nIRQ to processor (and clears interrupt)
+	ldr	\irqstat, [\base, #(AT91_AIC_ISR - AT91_AIC)]	@ read interrupt source number
+	teq	\irqstat, #0					@ ISR is 0 when no current interrupt, or spurious interrupt
+	streq	\tmp, [\base, #(AT91_AIC_EOICR - AT91_AIC)]	@ not going to be handled further, then ACK it now.
 	.endm
 
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/gpio.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/gpio.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/gpio.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/gpio.h	2008-02-07 10:24:59.000000000 -0500
@@ -17,7 +17,7 @@
 
 #define PIN_BASE		NR_AIC_IRQS
 
-#define MAX_GPIO_BANKS		4
+#define MAX_GPIO_BANKS		5
 
 /* these pin numbers double as IRQ numbers, like AT91xxx_ID_* values */
 
@@ -26,37 +26,31 @@
 #define	AT91_PIN_PA2	(PIN_BASE + 0x00 + 2)
 #define	AT91_PIN_PA3	(PIN_BASE + 0x00 + 3)
 #define	AT91_PIN_PA4	(PIN_BASE + 0x00 + 4)
-
 #define	AT91_PIN_PA5	(PIN_BASE + 0x00 + 5)
 #define	AT91_PIN_PA6	(PIN_BASE + 0x00 + 6)
 #define	AT91_PIN_PA7	(PIN_BASE + 0x00 + 7)
 #define	AT91_PIN_PA8	(PIN_BASE + 0x00 + 8)
 #define	AT91_PIN_PA9	(PIN_BASE + 0x00 + 9)
-
 #define	AT91_PIN_PA10	(PIN_BASE + 0x00 + 10)
 #define	AT91_PIN_PA11	(PIN_BASE + 0x00 + 11)
 #define	AT91_PIN_PA12	(PIN_BASE + 0x00 + 12)
 #define	AT91_PIN_PA13	(PIN_BASE + 0x00 + 13)
 #define	AT91_PIN_PA14	(PIN_BASE + 0x00 + 14)
-
 #define	AT91_PIN_PA15	(PIN_BASE + 0x00 + 15)
 #define	AT91_PIN_PA16	(PIN_BASE + 0x00 + 16)
 #define	AT91_PIN_PA17	(PIN_BASE + 0x00 + 17)
 #define	AT91_PIN_PA18	(PIN_BASE + 0x00 + 18)
 #define	AT91_PIN_PA19	(PIN_BASE + 0x00 + 19)
-
 #define	AT91_PIN_PA20	(PIN_BASE + 0x00 + 20)
 #define	AT91_PIN_PA21	(PIN_BASE + 0x00 + 21)
 #define	AT91_PIN_PA22	(PIN_BASE + 0x00 + 22)
 #define	AT91_PIN_PA23	(PIN_BASE + 0x00 + 23)
 #define	AT91_PIN_PA24	(PIN_BASE + 0x00 + 24)
-
 #define	AT91_PIN_PA25	(PIN_BASE + 0x00 + 25)
 #define	AT91_PIN_PA26	(PIN_BASE + 0x00 + 26)
 #define	AT91_PIN_PA27	(PIN_BASE + 0x00 + 27)
 #define	AT91_PIN_PA28	(PIN_BASE + 0x00 + 28)
 #define	AT91_PIN_PA29	(PIN_BASE + 0x00 + 29)
-
 #define	AT91_PIN_PA30	(PIN_BASE + 0x00 + 30)
 #define	AT91_PIN_PA31	(PIN_BASE + 0x00 + 31)
 
@@ -65,37 +59,31 @@
 #define	AT91_PIN_PB2	(PIN_BASE + 0x20 + 2)
 #define	AT91_PIN_PB3	(PIN_BASE + 0x20 + 3)
 #define	AT91_PIN_PB4	(PIN_BASE + 0x20 + 4)
-
 #define	AT91_PIN_PB5	(PIN_BASE + 0x20 + 5)
 #define	AT91_PIN_PB6	(PIN_BASE + 0x20 + 6)
 #define	AT91_PIN_PB7	(PIN_BASE + 0x20 + 7)
 #define	AT91_PIN_PB8	(PIN_BASE + 0x20 + 8)
 #define	AT91_PIN_PB9	(PIN_BASE + 0x20 + 9)
-
 #define	AT91_PIN_PB10	(PIN_BASE + 0x20 + 10)
 #define	AT91_PIN_PB11	(PIN_BASE + 0x20 + 11)
 #define	AT91_PIN_PB12	(PIN_BASE + 0x20 + 12)
 #define	AT91_PIN_PB13	(PIN_BASE + 0x20 + 13)
 #define	AT91_PIN_PB14	(PIN_BASE + 0x20 + 14)
-
 #define	AT91_PIN_PB15	(PIN_BASE + 0x20 + 15)
 #define	AT91_PIN_PB16	(PIN_BASE + 0x20 + 16)
 #define	AT91_PIN_PB17	(PIN_BASE + 0x20 + 17)
 #define	AT91_PIN_PB18	(PIN_BASE + 0x20 + 18)
 #define	AT91_PIN_PB19	(PIN_BASE + 0x20 + 19)
-
 #define	AT91_PIN_PB20	(PIN_BASE + 0x20 + 20)
 #define	AT91_PIN_PB21	(PIN_BASE + 0x20 + 21)
 #define	AT91_PIN_PB22	(PIN_BASE + 0x20 + 22)
 #define	AT91_PIN_PB23	(PIN_BASE + 0x20 + 23)
 #define	AT91_PIN_PB24	(PIN_BASE + 0x20 + 24)
-
 #define	AT91_PIN_PB25	(PIN_BASE + 0x20 + 25)
 #define	AT91_PIN_PB26	(PIN_BASE + 0x20 + 26)
 #define	AT91_PIN_PB27	(PIN_BASE + 0x20 + 27)
 #define	AT91_PIN_PB28	(PIN_BASE + 0x20 + 28)
 #define	AT91_PIN_PB29	(PIN_BASE + 0x20 + 29)
-
 #define	AT91_PIN_PB30	(PIN_BASE + 0x20 + 30)
 #define	AT91_PIN_PB31	(PIN_BASE + 0x20 + 31)
 
@@ -104,37 +92,31 @@
 #define	AT91_PIN_PC2	(PIN_BASE + 0x40 + 2)
 #define	AT91_PIN_PC3	(PIN_BASE + 0x40 + 3)
 #define	AT91_PIN_PC4	(PIN_BASE + 0x40 + 4)
-
 #define	AT91_PIN_PC5	(PIN_BASE + 0x40 + 5)
 #define	AT91_PIN_PC6	(PIN_BASE + 0x40 + 6)
 #define	AT91_PIN_PC7	(PIN_BASE + 0x40 + 7)
 #define	AT91_PIN_PC8	(PIN_BASE + 0x40 + 8)
 #define	AT91_PIN_PC9	(PIN_BASE + 0x40 + 9)
-
 #define	AT91_PIN_PC10	(PIN_BASE + 0x40 + 10)
 #define	AT91_PIN_PC11	(PIN_BASE + 0x40 + 11)
 #define	AT91_PIN_PC12	(PIN_BASE + 0x40 + 12)
 #define	AT91_PIN_PC13	(PIN_BASE + 0x40 + 13)
 #define	AT91_PIN_PC14	(PIN_BASE + 0x40 + 14)
-
 #define	AT91_PIN_PC15	(PIN_BASE + 0x40 + 15)
 #define	AT91_PIN_PC16	(PIN_BASE + 0x40 + 16)
 #define	AT91_PIN_PC17	(PIN_BASE + 0x40 + 17)
 #define	AT91_PIN_PC18	(PIN_BASE + 0x40 + 18)
 #define	AT91_PIN_PC19	(PIN_BASE + 0x40 + 19)
-
 #define	AT91_PIN_PC20	(PIN_BASE + 0x40 + 20)
 #define	AT91_PIN_PC21	(PIN_BASE + 0x40 + 21)
 #define	AT91_PIN_PC22	(PIN_BASE + 0x40 + 22)
 #define	AT91_PIN_PC23	(PIN_BASE + 0x40 + 23)
 #define	AT91_PIN_PC24	(PIN_BASE + 0x40 + 24)
-
 #define	AT91_PIN_PC25	(PIN_BASE + 0x40 + 25)
 #define	AT91_PIN_PC26	(PIN_BASE + 0x40 + 26)
 #define	AT91_PIN_PC27	(PIN_BASE + 0x40 + 27)
 #define	AT91_PIN_PC28	(PIN_BASE + 0x40 + 28)
 #define	AT91_PIN_PC29	(PIN_BASE + 0x40 + 29)
-
 #define	AT91_PIN_PC30	(PIN_BASE + 0x40 + 30)
 #define	AT91_PIN_PC31	(PIN_BASE + 0x40 + 31)
 
@@ -143,40 +125,67 @@
 #define	AT91_PIN_PD2	(PIN_BASE + 0x60 + 2)
 #define	AT91_PIN_PD3	(PIN_BASE + 0x60 + 3)
 #define	AT91_PIN_PD4	(PIN_BASE + 0x60 + 4)
-
 #define	AT91_PIN_PD5	(PIN_BASE + 0x60 + 5)
 #define	AT91_PIN_PD6	(PIN_BASE + 0x60 + 6)
 #define	AT91_PIN_PD7	(PIN_BASE + 0x60 + 7)
 #define	AT91_PIN_PD8	(PIN_BASE + 0x60 + 8)
 #define	AT91_PIN_PD9	(PIN_BASE + 0x60 + 9)
-
 #define	AT91_PIN_PD10	(PIN_BASE + 0x60 + 10)
 #define	AT91_PIN_PD11	(PIN_BASE + 0x60 + 11)
 #define	AT91_PIN_PD12	(PIN_BASE + 0x60 + 12)
 #define	AT91_PIN_PD13	(PIN_BASE + 0x60 + 13)
 #define	AT91_PIN_PD14	(PIN_BASE + 0x60 + 14)
-
 #define	AT91_PIN_PD15	(PIN_BASE + 0x60 + 15)
 #define	AT91_PIN_PD16	(PIN_BASE + 0x60 + 16)
 #define	AT91_PIN_PD17	(PIN_BASE + 0x60 + 17)
 #define	AT91_PIN_PD18	(PIN_BASE + 0x60 + 18)
 #define	AT91_PIN_PD19	(PIN_BASE + 0x60 + 19)
-
 #define	AT91_PIN_PD20	(PIN_BASE + 0x60 + 20)
 #define	AT91_PIN_PD21	(PIN_BASE + 0x60 + 21)
 #define	AT91_PIN_PD22	(PIN_BASE + 0x60 + 22)
 #define	AT91_PIN_PD23	(PIN_BASE + 0x60 + 23)
 #define	AT91_PIN_PD24	(PIN_BASE + 0x60 + 24)
-
 #define	AT91_PIN_PD25	(PIN_BASE + 0x60 + 25)
 #define	AT91_PIN_PD26	(PIN_BASE + 0x60 + 26)
 #define	AT91_PIN_PD27	(PIN_BASE + 0x60 + 27)
 #define	AT91_PIN_PD28	(PIN_BASE + 0x60 + 28)
 #define	AT91_PIN_PD29	(PIN_BASE + 0x60 + 29)
-
 #define	AT91_PIN_PD30	(PIN_BASE + 0x60 + 30)
 #define	AT91_PIN_PD31	(PIN_BASE + 0x60 + 31)
 
+#define	AT91_PIN_PE0	(PIN_BASE + 0x80 + 0)
+#define	AT91_PIN_PE1	(PIN_BASE + 0x80 + 1)
+#define	AT91_PIN_PE2	(PIN_BASE + 0x80 + 2)
+#define	AT91_PIN_PE3	(PIN_BASE + 0x80 + 3)
+#define	AT91_PIN_PE4	(PIN_BASE + 0x80 + 4)
+#define	AT91_PIN_PE5	(PIN_BASE + 0x80 + 5)
+#define	AT91_PIN_PE6	(PIN_BASE + 0x80 + 6)
+#define	AT91_PIN_PE7	(PIN_BASE + 0x80 + 7)
+#define	AT91_PIN_PE8	(PIN_BASE + 0x80 + 8)
+#define	AT91_PIN_PE9	(PIN_BASE + 0x80 + 9)
+#define	AT91_PIN_PE10	(PIN_BASE + 0x80 + 10)
+#define	AT91_PIN_PE11	(PIN_BASE + 0x80 + 11)
+#define	AT91_PIN_PE12	(PIN_BASE + 0x80 + 12)
+#define	AT91_PIN_PE13	(PIN_BASE + 0x80 + 13)
+#define	AT91_PIN_PE14	(PIN_BASE + 0x80 + 14)
+#define	AT91_PIN_PE15	(PIN_BASE + 0x80 + 15)
+#define	AT91_PIN_PE16	(PIN_BASE + 0x80 + 16)
+#define	AT91_PIN_PE17	(PIN_BASE + 0x80 + 17)
+#define	AT91_PIN_PE18	(PIN_BASE + 0x80 + 18)
+#define	AT91_PIN_PE19	(PIN_BASE + 0x80 + 19)
+#define	AT91_PIN_PE20	(PIN_BASE + 0x80 + 20)
+#define	AT91_PIN_PE21	(PIN_BASE + 0x80 + 21)
+#define	AT91_PIN_PE22	(PIN_BASE + 0x80 + 22)
+#define	AT91_PIN_PE23	(PIN_BASE + 0x80 + 23)
+#define	AT91_PIN_PE24	(PIN_BASE + 0x80 + 24)
+#define	AT91_PIN_PE25	(PIN_BASE + 0x80 + 25)
+#define	AT91_PIN_PE26	(PIN_BASE + 0x80 + 26)
+#define	AT91_PIN_PE27	(PIN_BASE + 0x80 + 27)
+#define	AT91_PIN_PE28	(PIN_BASE + 0x80 + 28)
+#define	AT91_PIN_PE29	(PIN_BASE + 0x80 + 29)
+#define	AT91_PIN_PE30	(PIN_BASE + 0x80 + 30)
+#define	AT91_PIN_PE31	(PIN_BASE + 0x80 + 31)
+
 #ifndef __ASSEMBLY__
 /* setup setup routines, called from board init or driver probe() */
 extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/hardware.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/hardware.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/hardware.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/hardware.h	2008-02-07 10:24:59.000000000 -0500
@@ -22,21 +22,23 @@
 #include <asm/arch/at91sam9260.h>
 #elif defined(CONFIG_ARCH_AT91SAM9261)
 #include <asm/arch/at91sam9261.h>
+#elif defined(CONFIG_ARCH_AT91SAM9263)
+#include <asm/arch/at91sam9263.h>
 #else
 #error "Unsupported AT91 processor"
 #endif
 
 
 /*
- * Remap the peripherals from address 0xFFFA0000 .. 0xFFFFFFFF
- * to 0xFEFA0000 .. 0xFF000000.  (384Kb)
+ * Remap the peripherals from address 0xFFF78000 .. 0xFFFFFFFF
+ * to 0xFEF78000 .. 0xFF000000.  (544Kb)
  */
-#define AT91_IO_PHYS_BASE	0xFFFA0000
+#define AT91_IO_PHYS_BASE	0xFFF78000
 #define AT91_IO_SIZE		(0xFFFFFFFF - AT91_IO_PHYS_BASE + 1)
 #define AT91_IO_VIRT_BASE	(0xFF000000 - AT91_IO_SIZE)
 
  /* Convert a physical IO address to virtual IO address */
-#define AT91_IO_P2V(x)	((x) - AT91_IO_PHYS_BASE + AT91_IO_VIRT_BASE)
+#define AT91_IO_P2V(x)		((x) - AT91_IO_PHYS_BASE + AT91_IO_VIRT_BASE)
 
 /*
  * Virtual to Physical Address mapping for IO devices.
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/ics1523.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/ics1523.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/ics1523.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/ics1523.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,154 @@
+//*----------------------------------------------------------------------------
+//*         ATMEL Microcontroller Software Support  -  ROUSSET  -
+//*----------------------------------------------------------------------------
+//* The software is delivered "AS IS" without warranty or condition of any
+//* kind, either express, implied or statutory. This includes without
+//* limitation any warranty or condition with respect to merchantability or
+//* fitness for any particular purpose, or against the infringements of
+//* intellectual property rights of others.
+//*----------------------------------------------------------------------------
+//* File Name           : ics1523.h
+//* Object              : Clock Generator Prototyping File.
+//*
+//* 1.0 08/28/02 ED     : Creation
+//* 1.2 13/01/03 FB		: Update on lib V3
+//*----------------------------------------------------------------------------
+
+#ifndef ics1523_h
+#define ics1523_h
+
+/*-------------------------------------------*/
+/* ICS1523 TWI Serial Clock Definition       */
+/*-------------------------------------------*/
+
+#define		ICS_MIN_CLOCK		100		/* Min Frequency Access Clock KHz */
+#define		ICS_MAX_CLOCK		400		/* Max Frequency Access Clock KHz */
+#define		ICS_TRANSFER_RATE	ICS_MAX_CLOCK	/* Transfer speed to apply */
+
+#define		ICS_WRITE_CLK_PNB	30		/* TWCK Clock Periods required to write */
+#define		ICS_READ_CLK_PNB	40		/* TWCK Clock Periods required to read */
+
+/*-------------------------------------------*/
+/* ICS1523 Write Operation Definition        */
+/*-------------------------------------------*/
+
+#define		ICS1523_ACCESS_OK	0		/* OK */
+#define		ICS1523_ACCESS_ERROR	-1		/* NOK */
+
+/*-------------------------------------------*/
+/* ICS1523 Device Addresses Definition       */
+/*-------------------------------------------*/
+
+#define		ICS_ADDR		0x26		/* Device Address */
+
+/*--------------------------------------------------*/
+/* ICS1523 Registers Internal Addresses Definition  */
+/*--------------------------------------------------*/
+
+#define		ICS_ICR			0x0		/* Input Control Register */
+#define		ICS_LCR			0x1		/* Loop Control Register */
+#define		ICS_FD0			0x2		/* PLL FeedBack Divider LSBs */
+#define		ICS_FD1			0x3		/* PLL FeedBack Divider MSBs */
+#define		ICS_DPAO		0x4		/* Dynamic Phase Aligner Offset */
+#define		ICS_DPAC		0x5		/* Dynamic Phase Aligner Resolution */
+#define		ICS_OE			0x6		/* Output Enables Register */
+#define		ICS_OD			0x7		/* Osc Divider Register */
+#define		ICS_SWRST		0x8		/* DPA & PLL Reset Register */
+#define		ICS_VID			0x10		/* Chip Version Register */
+#define		ICS_RID			0x11		/* Chip Revision Register */
+#define		ICS_SR			0x12		/* Status Register */
+
+/*------------------------------------------------------*/
+/* ICS1523 Input Control Register Bits Definition       */
+/*------------------------------------------------------*/
+
+#define		ICS_PDEN		0x1		/* Phase Detector Enable */
+#define		ICS_PDPOL		0x2		/* Phase Detector Enable Polarity */
+#define		ICS_REFPOL		0x4		/* External Reference Polarity */
+#define		ICS_FBKPOL		0x8		/* External Feedback Polarity */
+#define		ICS_FBKSEL		0x10		/* External Feedback Select */
+#define		ICS_FUNCSEL		0x20		/* Function Out Select */
+#define		ICS_ENPLS		0x40		/* Enable PLL Lock/Ref Status Output */
+#define		ICS_ENDLS		0x80		/* Enable DPA Lock/Ref Status Output */
+
+/*-----------------------------------------------------*/
+/* ICS1523 Loop Control Register Bits Definition       */
+/*-----------------------------------------------------*/
+
+#define		ICS_PFD			0x7		/* Phase Detector Gain */
+#define		ICS_PSD			0x30		/* Post-Scaler Divider */
+
+/*----------------------------------------------------*/
+/* ICS1523 PLL FeedBack Divider LSBs Definition       */
+/*----------------------------------------------------*/
+
+#define		ICS_FBDL		0xFF		/* PLL FeedBack Divider LSBs */
+
+/*----------------------------------------------------*/
+/* ICS1523 PLL FeedBack Divider MSBs Definition       */
+/*----------------------------------------------------*/
+
+#define		ICS_FBDM		0xF		/* PLL FeedBack Divider MSBs */
+
+/*------------------------------------------------------------*/
+/* ICS1523 Dynamic Phase Aligner Offset Bits Definition       */
+/*------------------------------------------------------------*/
+
+#define		ICS_DPAOS		0x2F		/* Dynamic Phase Aligner Offset */
+#define		ICS_FILSEL		0x80		/* Loop Filter Select */
+
+/*----------------------------------------------------------------*/
+/* ICS1523 Dynamic Phase Aligner Resolution Bits Definition       */
+/*----------------------------------------------------------------*/
+
+#define		ICS_DPARES		0x3		/* Dynamic Phase Aligner Resolution */
+#define		ICS_MMREV		0xFC		/* Metal Mask Revision Number */
+
+/*-------------------------------------------------------*/
+/* ICS1523 Output Enables Register Bits Definition       */
+/*-------------------------------------------------------*/
+
+#define		ICS_OEPCK		0x1		/* Output Enable for PECL PCLK Outputs */
+#define		ICS_OETCK		0x2		/* Output Enable for STTL CLK Output */
+#define		ICS_OEP2		0x4		/* Output Enable for PECL CLK/2 Outputs */
+#define		ICS_OET2		0x8		/* Output Enable for STTL CLK/2 Output */
+#define		ICS_OEF			0x10		/* Output Enable for STTL FUNC Output */
+#define		ICS_CLK2INV		0x20		/* CLK/2 Invert */
+#define		ICS_OSCL		0xC0		/* SSTL Clock Scaler */
+
+/*----------------------------------------------------*/
+/* ICS1523 Osc Divider Register Bits Definition       */
+/*----------------------------------------------------*/
+
+#define		ICS_OSCDIV		0x7F		/* Oscillator Divider Modulus */
+#define		ICS_INSEL		0x80		/* Input Select */
+
+/*---------------------------------------------------*/
+/* ICS1523 DPA & PLL Reset Register Definition       */
+/*---------------------------------------------------*/
+
+#define		ICS_DPAR		0x0A		/* DPA Reset Command */
+#define		ICS_PLLR		0x50		/* PLL Reset Command */
+
+/*------------------------------------------------*/
+/* ICS1523 Chip Version Register Definition       */
+/*------------------------------------------------*/
+
+#define		ICS_CHIPV		0xFF		/* Chip Version */
+
+/*-------------------------------------------------*/
+/* ICS1523 Chip Revision Register Definition       */
+/*-------------------------------------------------*/
+
+#define		ICS_CHIPR		0xFF		/* Chip Revision */
+
+/*------------------------------------------*/
+/* ICS1523 Status Register Definition       */
+/*------------------------------------------*/
+
+#define		ICS_DPALOCK		0x1		/* DPA Lock Status */
+#define		ICS_PLLLOCK		0x2		/* PLL Lock Status */
+
+int at91_ics1523_init(void);
+
+#endif /* ics1523_h */
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/irqs.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/irqs.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/irqs.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/irqs.h	2008-02-07 10:24:59.000000000 -0500
@@ -37,8 +37,8 @@
  * IRQ interrupt symbols are the AT91xxx_ID_* symbols
  * for IRQs handled directly through the AIC, or else the AT91_PIN_*
  * symbols in gpio.h for ones handled indirectly as GPIOs.
- * We make provision for 4 banks of GPIO.
+ * We make provision for 5 banks of GPIO.
  */
-#define	NR_IRQS		(NR_AIC_IRQS + (4 * 32))
+#define	NR_IRQS		(NR_AIC_IRQS + (5 * 32))
 
 #endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/spi.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/spi.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/spi.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/spi.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,54 @@
+/*
+ * Serial Peripheral Interface (SPI) driver for the Atmel AT91RM9200
+ *
+ * (c) SAN People (Pty) Ltd
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef AT91_LEGACY_SPI_H
+#define AT91_LEGACY_SPI_H
+
+#define SPI_MAJOR		153	/* registered device number */
+
+#define DEFAULT_SPI_CLK		6000000
+
+
+/* Maximum number of buffers in a single SPI transfer.
+ *  DataFlash uses maximum of 2
+ *  spidev interface supports up to 8.
+ */
+#define MAX_SPI_TRANSFERS	8
+#define NR_SPI_DEVICES		4	/* number of devices on SPI bus */
+
+/*
+ * Describes the buffers for a SPI transfer.
+ * A transmit & receive buffer must be specified for each transfer
+ */
+struct spi_transfer_list {
+	void* tx[MAX_SPI_TRANSFERS];	/* transmit */
+	int txlen[MAX_SPI_TRANSFERS];
+	void* rx[MAX_SPI_TRANSFERS];	/* receive */
+	int rxlen[MAX_SPI_TRANSFERS];
+	int nr_transfers;		/* number of transfers */
+	int curr;			/* current transfer */
+};
+
+struct spi_local {
+	unsigned int pcs;		/* Peripheral Chip Select value */
+
+	struct spi_transfer_list *xfers;	/* current transfer list */
+	dma_addr_t tx, rx;		/* DMA address for current transfer */
+	dma_addr_t txnext, rxnext;	/* DMA address for next transfer */
+};
+
+
+/* Exported functions */
+extern void spi_access_bus(short device);
+extern void spi_release_bus(short device);
+extern int spi_transfer(struct spi_transfer_list* list);
+
+#endif
diff -uprN linux-2.6.20/include/asm-arm/arch-at91rm9200/timex.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/timex.h
--- linux-2.6.20/include/asm-arm/arch-at91rm9200/timex.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-at91rm9200/timex.h	2008-02-07 10:24:59.000000000 -0500
@@ -32,6 +32,11 @@
 #define AT91SAM9_MASTER_CLOCK	99300000
 #define CLOCK_TICK_RATE		(AT91SAM9_MASTER_CLOCK/16)
 
+#elif defined(CONFIG_ARCH_AT91SAM9263)
+
+#define AT91SAM9_MASTER_CLOCK	99959500
+#define CLOCK_TICK_RATE		(AT91SAM9_MASTER_CLOCK/16)
+
 #endif
 
 #endif
diff -uprN linux-2.6.20/include/asm-arm/arch-ep93xx/ep93xx-regs.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-ep93xx/ep93xx-regs.h
--- linux-2.6.20/include/asm-arm/arch-ep93xx/ep93xx-regs.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-ep93xx/ep93xx-regs.h	2008-02-07 10:24:59.000000000 -0500
@@ -84,9 +84,21 @@
 #define EP93XX_GPIO_B_INT_ENABLE	EP93XX_GPIO_REG(0xb8)
 #define EP93XX_GPIO_B_INT_STATUS	EP93XX_GPIO_REG(0xbc)
 
+//NZG GPIO additions
+#define EP93XX_GPIO_B_DDR		(EP93XX_GPIO_REG(0x14))
+#define EP93XX_GPIO_B_DR		(EP93XX_GPIO_REG(0x04))
+
 #define EP93XX_AAC_BASE			(EP93XX_APB_VIRT_BASE + 0x00080000)
 
 #define EP93XX_SPI_BASE			(EP93XX_APB_VIRT_BASE + 0x000a0000)
+#define EP93XX_SPI_REG(x)		(EP93XX_SPI_BASE + (x))
+#define EP93XX_SPI_CR0			(EP93XX_SPI_REG(0))
+#define EP93XX_SPI_CR1			(EP93XX_SPI_REG(4))
+#define EP93XX_SPI_DR			(EP93XX_SPI_REG(8))
+#define EP93XX_SPI_SR			(EP93XX_SPI_REG(0x0C))
+#define EP93XX_SPI_CPSR			(EP93XX_SPI_REG(0x10))
+#define EP93XX_SPI_IIR			(EP93XX_SPI_REG(0x14))
+#define EP93XX_SPI_FIFO_SIZE	(8)
 
 #define EP93XX_IRDA_BASE		(EP93XX_APB_VIRT_BASE + 0x000b0000)
 
@@ -101,28 +113,47 @@
 
 #define EP93XX_KEY_MATRIX_BASE		(EP93XX_APB_VIRT_BASE + 0x000f0000)
 
-#define EP93XX_ADC_BASE			(EP93XX_APB_VIRT_BASE + 0x00100000)
-#define EP93XX_TOUCHSCREEN_BASE		(EP93XX_APB_VIRT_BASE + 0x00100000)
-
-#define EP93XX_PWM_BASE			(EP93XX_APB_VIRT_BASE + 0x00110000)
+#define EP93XX_ADC_BASE						(EP93XX_APB_VIRT_BASE + 0x00100000)
+#define EP93XX_ADC_REG(x)					(EP93XX_ADC_BASE + (x))
+#define EP93XX_ADCRESULT					EP93XX_ADC_REG(0x08)
+#define EP93XX_ADCSWITCH					EP93XX_ADC_REG(0x18)
+#define EP93XX_ADCSWLOCK					EP93XX_ADC_REG(0x20)
+#define EP93XX_ADCINTEN						EP93XX_ADC_REG(0x24)
+#define EP93XX_ADCSETUP1					EP93XX_ADC_REG(0)
+
+#define EP93XX_TOUCHSCREEN_BASE				(EP93XX_APB_VIRT_BASE + 0x00100000)
+
+#define EP93XX_PWM_BASE						(EP93XX_APB_VIRT_BASE + 0x00110000)
+#define EP93XX_PWM_SIZE						(0x20)
+#define EP93XX_PWM(x)						(EP93XX_PWM_BASE + (x*EP93XX_PWM_SIZE))
+
+#define EP93XX_RTC_BASE						(EP93XX_APB_VIRT_BASE + 0x00120000)
+
+#define EP93XX_SYSCON_BASE					(EP93XX_APB_VIRT_BASE + 0x00130000)
+#define EP93XX_SYSCON_REG(x)				(EP93XX_SYSCON_BASE + (x))
+#define EP93XX_SYSCON_POWER_STATE			EP93XX_SYSCON_REG(0x00)
+#define EP93XX_SYSCON_CLOCK_CONTROL			EP93XX_SYSCON_REG(0x04)
+#define EP93XX_SYSCON_CLOCK_UARTBAUD		0x20000000
+#define EP93XX_SYSCON_CLOCK_USH_EN			0x10000000
+#define EP93XX_SYSCON_HALT					EP93XX_SYSCON_REG(0x08)
+#define EP93XX_SYSCON_STANDBY				EP93XX_SYSCON_REG(0x0c)
+#define EP93XX_SYSCON_CLOCK_SET1			EP93XX_SYSCON_REG(0x20)
+#define EP93XX_SYSCON_CLOCK_SET2			EP93XX_SYSCON_REG(0x24)
+#define EP93XX_SYSCON_DEVICE_CONFIG			EP93XX_SYSCON_REG(0x80)
+#define EP93XX_SYSCON_SWLOCK				EP93XX_SYSCON_REG(0xc0)
+#define EP93XX_SYSCON_CHIPID        		EP93XX_SYSCON_REG(0x94)
+#define EP93XX_SYSCON_ADCCLKDIV				EP93XX_SYSCON_REG(0x90)
+
+#define EP93XX_SYSCON_DEVICE_CONFIG_PONG 			(0x00000200)
+#define EP93XX_SYSCON_DEVICE_CONFIG_ADCPD			(0x00000004)
+#define EP93XX_SYSCON_DEVICE_CONFIG_ADCEN			(0x00020000)
+#define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE	(0x00800000)
 
-#define EP93XX_RTC_BASE			(EP93XX_APB_VIRT_BASE + 0x00120000)
+#define EP93XX_SYSCON_ADCCLKDIV_ADCEN				(0x80000000)
+#define EP93XX_SYSCON_ADCCLKDIV_ADIV				(0x00010000)
 
-#define EP93XX_SYSCON_BASE		(EP93XX_APB_VIRT_BASE + 0x00130000)
-#define EP93XX_SYSCON_REG(x)		(EP93XX_SYSCON_BASE + (x))
-#define EP93XX_SYSCON_POWER_STATE	EP93XX_SYSCON_REG(0x00)
-#define EP93XX_SYSCON_CLOCK_CONTROL	EP93XX_SYSCON_REG(0x04)
-#define EP93XX_SYSCON_CLOCK_UARTBAUD	0x20000000
-#define EP93XX_SYSCON_CLOCK_USH_EN	0x10000000
-#define EP93XX_SYSCON_HALT		EP93XX_SYSCON_REG(0x08)
-#define EP93XX_SYSCON_STANDBY		EP93XX_SYSCON_REG(0x0c)
-#define EP93XX_SYSCON_CLOCK_SET1	EP93XX_SYSCON_REG(0x20)
-#define EP93XX_SYSCON_CLOCK_SET2	EP93XX_SYSCON_REG(0x24)
-#define EP93XX_SYSCON_DEVICE_CONFIG	EP93XX_SYSCON_REG(0x80)
-#define EP93XX_SYSCON_DEVICE_CONFIG_CRUNCH_ENABLE	0x00800000
-#define EP93XX_SYSCON_SWLOCK		EP93XX_SYSCON_REG(0xc0)
+#define EP93XX_ADCRESULT_SDR						(0x80000000)
 
 #define EP93XX_WATCHDOG_BASE		(EP93XX_APB_VIRT_BASE + 0x00140000)
 
-
 #endif
diff -uprN linux-2.6.20/include/asm-arm/arch-ep93xx/ep93xx_util.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-ep93xx/ep93xx_util.h
--- linux-2.6.20/include/asm-arm/arch-ep93xx/ep93xx_util.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-ep93xx/ep93xx_util.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,15 @@
+#ifndef EP93XX_UTIL_H_
+#define EP93XX_UTIL_H_
+
+#define KEY			(0xAA)
+
+static inline void EP93XX_SYSUNLOCK(void){
+	iowrite32(KEY,(void *)EP93XX_SYSCON_SWLOCK);
+}
+
+static inline void EP93XX_DEVCFG_WRITE(u32 x) {
+	EP93XX_SYSUNLOCK();
+	iowrite32(x,(void *)EP93XX_SYSCON_DEVICE_CONFIG);
+}
+
+#endif /*EP93XX_UTIL_H_*/
diff -uprN linux-2.6.20/include/asm-arm/arch-ep93xx/memory.h linux-2.6.20-at92_e1.5/include/asm-arm/arch-ep93xx/memory.h
--- linux-2.6.20/include/asm-arm/arch-ep93xx/memory.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/arch-ep93xx/memory.h	2008-02-07 10:24:59.000000000 -0500
@@ -5,7 +5,9 @@
 #ifndef __ASM_ARCH_MEMORY_H
 #define __ASM_ARCH_MEMORY_H
 
+#ifndef CONFIG_RUNTIME_PHYS_OFFSET
 #define PHYS_OFFSET		UL(0x00000000)
+#endif
 
 #define __bus_to_virt(x)	__phys_to_virt(x)
 #define __virt_to_bus(x)	__virt_to_phys(x)
diff -uprN linux-2.6.20/include/asm-arm/mach/ep93xx_pwm.h linux-2.6.20-at92_e1.5/include/asm-arm/mach/ep93xx_pwm.h
--- linux-2.6.20/include/asm-arm/mach/ep93xx_pwm.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/mach/ep93xx_pwm.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,7 @@
+#ifndef EP93XX_PWM_H_
+#define EP93XX_PWM_H_
+#include <linux/class/pwm.h>
+
+struct class_device *ep93xx_pwm_device_create(unsigned long base, const char *name);
+
+#endif /*EP93XX_PWM_H_*/
diff -uprN linux-2.6.20/include/asm-arm/mach/serial_at91.h linux-2.6.20-at92_e1.5/include/asm-arm/mach/serial_at91.h
--- linux-2.6.20/include/asm-arm/mach/serial_at91.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/mach/serial_at91.h	2008-02-07 10:24:59.000000000 -0500
@@ -26,8 +26,10 @@ struct atmel_port_fns {
 
 #if defined(CONFIG_SERIAL_ATMEL)
 void atmel_register_uart_fns(struct atmel_port_fns *fns);
+int atmel_auto485(struct uart_port *port,int fos);//auto 485 off/on/status
 #else
 #define atmel_register_uart_fns(fns) do { } while (0)
+int atmel_auto485(struct uart_port *port,int ofs) do { } while (0)
 #endif
 
 
diff -uprN linux-2.6.20/include/asm-arm/memory.h linux-2.6.20-at92_e1.5/include/asm-arm/memory.h
--- linux-2.6.20/include/asm-arm/memory.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-arm/memory.h	2008-02-07 10:24:59.000000000 -0500
@@ -73,6 +73,14 @@
  */
 #define IOREMAP_MAX_ORDER	24
 
+/*
+ * PHYS_OFFSET determined at run time?
+ */
+#if defined(CONFIG_RUNTIME_PHYS_OFFSET) && !defined(__ASSEMBLY__)
+extern unsigned long phys_offset;
+#define PHYS_OFFSET		(phys_offset)
+#endif
+
 #else /* CONFIG_MMU */
 
 /*
diff -uprN linux-2.6.20/include/asm-avr32/arch-at32ap/at91_pdc.h linux-2.6.20-at92_e1.5/include/asm-avr32/arch-at32ap/at91_pdc.h
--- linux-2.6.20/include/asm-avr32/arch-at32ap/at91_pdc.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/asm-avr32/arch-at32ap/at91_pdc.h	1969-12-31 19:00:00.000000000 -0500
@@ -1,36 +0,0 @@
-/*
- * include/asm-arm/arch-at91rm9200/at91_pdc.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Peripheral Data Controller (PDC) registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_PDC_H
-#define AT91_PDC_H
-
-#define AT91_PDC_RPR		0x100	/* Receive Pointer Register */
-#define AT91_PDC_RCR		0x104	/* Receive Counter Register */
-#define AT91_PDC_TPR		0x108	/* Transmit Pointer Register */
-#define AT91_PDC_TCR		0x10c	/* Transmit Counter Register */
-#define AT91_PDC_RNPR		0x110	/* Receive Next Pointer Register */
-#define AT91_PDC_RNCR		0x114	/* Receive Next Counter Register */
-#define AT91_PDC_TNPR		0x118	/* Transmit Next Pointer Register */
-#define AT91_PDC_TNCR		0x11c	/* Transmit Next Counter Register */
-
-#define AT91_PDC_PTCR		0x120	/* Transfer Control Register */
-#define		AT91_PDC_RXTEN		(1 << 0)	/* Receiver Transfer Enable */
-#define		AT91_PDC_RXTDIS		(1 << 1)	/* Receiver Transfer Disable */
-#define		AT91_PDC_TXTEN		(1 << 8)	/* Transmitter Transfer Enable */
-#define		AT91_PDC_TXTDIS		(1 << 9)	/* Transmitter Transfer Disable */
-
-#define AT91_PDC_PTSR		0x124	/* Transfer Status Register */
-
-#endif
diff -uprN linux-2.6.20/include/linux/atmel_pdc.h linux-2.6.20-at92_e1.5/include/linux/atmel_pdc.h
--- linux-2.6.20/include/linux/atmel_pdc.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/atmel_pdc.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,36 @@
+/*
+ * include/linux/atmel_pdc.h
+ *
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Peripheral Data Controller (PDC) registers.
+ * Based on AT91RM9200 datasheet revision E.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef ATMEL_PDC_H
+#define ATMEL_PDC_H
+
+#define ATMEL_PDC_RPR		0x100	/* Receive Pointer Register */
+#define ATMEL_PDC_RCR		0x104	/* Receive Counter Register */
+#define ATMEL_PDC_TPR		0x108	/* Transmit Pointer Register */
+#define ATMEL_PDC_TCR		0x10c	/* Transmit Counter Register */
+#define ATMEL_PDC_RNPR		0x110	/* Receive Next Pointer Register */
+#define ATMEL_PDC_RNCR		0x114	/* Receive Next Counter Register */
+#define ATMEL_PDC_TNPR		0x118	/* Transmit Next Pointer Register */
+#define ATMEL_PDC_TNCR		0x11c	/* Transmit Next Counter Register */
+
+#define ATMEL_PDC_PTCR		0x120	/* Transfer Control Register */
+#define		ATMEL_PDC_RXTEN		(1 << 0)	/* Receiver Transfer Enable */
+#define		ATMEL_PDC_RXTDIS	(1 << 1)	/* Receiver Transfer Disable */
+#define		ATMEL_PDC_TXTEN		(1 << 8)	/* Transmitter Transfer Enable */
+#define		ATMEL_PDC_TXTDIS	(1 << 9)	/* Transmitter Transfer Disable */
+
+#define ATMEL_PDC_PTSR		0x124	/* Transfer Status Register */
+
+#endif
diff -uprN linux-2.6.20/include/linux/chelper.h linux-2.6.20-at92_e1.5/include/linux/chelper.h
--- linux-2.6.20/include/linux/chelper.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/chelper.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,71 @@
+#ifndef CHELPER_H_
+#define CHELPER_H_
+
+#include <asm/io.h>
+
+/************************************************************
+ * helper functions
+ */
+ 
+ static inline ssize_t sfs_getint(const char *buf,size_t count,size_t *size){
+ 	char *endp;
+	u32 data = simple_strtoul(buf,&endp,0);	
+	*size = (size_t)(endp - buf);
+	if (*endp && isspace(*endp))(*size)++;
+	if (*size != count)*size = -EINVAL;
+	return data;
+ }
+
+ /** 
+  * converts a stream of separated integers into an allocated array.
+  * returns the number of integers converted
+  * stores the number of characters converted to integers in size
+  */
+ static inline  int sfs_getstream(const char *buf,size_t count,size_t *size,const char *delim,u8 *data){
+	char *tokenstring = strcpy(kmalloc(count,GFP_KERNEL),buf);
+	char *mark = tokenstring;
+	char *endp;
+	char *token;
+	int index=0;
+	
+	//printk("%s - mark:%s\n",__FUNCTION__,mark);
+	
+	while((token=strsep(&mark, delim))!=NULL){
+		//printk("mark:%s\n",mark);
+		data[index++] = simple_strtoul(token,&endp,0);
+	}
+		
+	*size = (size_t)(endp - tokenstring);
+	if (*endp && isspace(*endp))(*size)++;
+	if (*size != count)*size = -EINVAL;
+	
+	//printk("size = %d\n",*size);
+	
+	kfree(tokenstring);
+	return index;
+ }
+ 
+ 
+/**
+ * depreciated
+ */
+static inline ssize_t store8(const char *buf,size_t count,void *address,u8 *shadow){
+	size_t size;
+	u8 data = sfs_getint(buf,count,&size);
+	if(address)iowrite8(data,address);
+	if(shadow)*shadow=data;
+	return size;
+}
+
+/**
+ * depreciated
+ */
+static inline ssize_t store16(const char *buf,size_t count,void *address,u16 *shadow){
+	size_t size;
+	u16 data = sfs_getint(buf,count,&size);
+	if(address)iowrite16(data,address);
+	if(shadow)*shadow=data;
+	return size;
+}
+
+#endif /*CHELPER_H_*/
diff -uprN linux-2.6.20/include/linux/class/char/gpio_char.h linux-2.6.20-at92_e1.5/include/linux/class/char/gpio_char.h
--- linux-2.6.20/include/linux/class/char/gpio_char.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/char/gpio_char.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,31 @@
+#ifndef GPIO_CHAR_H_
+#define GPIO_CHAR_H_
+
+#ifdef __KERNEL__
+int gpio_char_init(void);
+int gpio_char_create(struct gpio_s *gpio);
+
+#ifndef GPIO_MAJOR
+#define GPIO_MAJOR 0
+#endif
+
+/* we use the max_devs define to register a region on init */
+#define GPIO_MAX_DEVS 15
+#endif /*__KERNEL__*/
+
+/* This header defines the ioctl commands */
+#include <linux/class/rtdm/gpio_rtdm.h>
+
+#define CHAR_CLASS_GPIO RTDM_CLASS_GPIO
+/* the following are defined in gpio_rtdm.h */
+/*
+ * #define DDRREAD         _IOR(RTDM_CLASS_GPIO,0,char)
+ * #define DDRWRITE        _IOW(RTDM_CLASS_GPIO,0,char)
+ * #define DATAREAD        _IOR(RTDM_CLASS_GPIO,1,char)
+ * #define DATAWRITE       _IOW(RTDM_CLASS_GPIO,1,char)
+ // additions for the char driver
+ * #define INDEXREAD       _IOR(RTDM_CLASS_GPIO,2,char)
+ * #define INDEXWRITE      _IOW(RTDM_CLASS_GPIO,2,char)
+ */
+
+#endif /*GPIO_CHAR_H_*/
diff -uprN linux-2.6.20/include/linux/class/char/spi_char.h linux-2.6.20-at92_e1.5/include/linux/class/char/spi_char.h
--- linux-2.6.20/include/linux/class/char/spi_char.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/char/spi_char.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,27 @@
+#ifndef SPI_CHAR_H_
+#define SPI_CHAR_H_
+
+#ifdef __KERNEL__
+int spi_char_init(void);
+int spi_char_create(struct spi_s *spi);
+
+#ifndef SPI_MAJOR
+#define SPI_MAJOR 0
+#endif
+
+/* we use the max_devs define to register a region on init */
+#define SPI_MAX_DEVS 15
+#endif /*__KERNEL__*/
+
+typedef struct spi_transfer_s{
+	spi_data *mosi;
+	spi_data *miso;
+	ssize_t size;
+}spi_transfer_t;
+
+/* This header defines the ioctl commands */
+#include <linux/class/rtdm/spi_rtdm.h>
+
+#define CHAR_CLASS_SPI RTDM_CLASS_SPI
+
+#endif /*SPI_CHAR_H_*/
diff -uprN linux-2.6.20/include/linux/class/gpio.h linux-2.6.20-at92_e1.5/include/linux/class/gpio.h
--- linux-2.6.20/include/linux/class/gpio.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/gpio.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,198 @@
+#ifndef GPIO_H_
+#define GPIO_H_
+
+#include <linux/autoconf.h>
+#include <linux/device.h>
+
+#ifdef CONFIG_GPIOCLASS	
+
+typedef u32 gpio_data;
+
+/**********************
+ * gpio class structure
+ */
+typedef struct gpio_s{
+	const char *name;
+	int subclass;
+	gpio_data index;
+	gpio_data range;
+	void *ddr;
+	void *data;
+	gpio_data shadow;
+	gpio_data (*data_read)(struct gpio_s *gpio);
+	int (*data_write)(struct gpio_s *gpio,gpio_data data);
+	gpio_data (*ddr_read)(struct gpio_s *gpio);	
+	int (*ddr_write)(struct gpio_s *gpio,gpio_data data);
+	gpio_data (*index_read)(struct gpio_s *gpio);	
+	int (*index_write)(struct gpio_s *gpio,gpio_data data);
+}gpio_t;
+
+#define GPIO_BASECLASNUM	0xA0
+#define GPIO_SUBCLASS 	(GPIO_BASECLASNUM+0)
+#define GPI_SUBCLASS 	(GPIO_BASECLASNUM+1)
+#define GPO_SUBCLASS 	(GPIO_BASECLASNUM+2)
+
+/***************************************************************************
+ * typical low level methods for accessing 8 bit ports
+ */
+int  gpio_ddr_write8(gpio_t *gpio, gpio_data data);
+int  gpio_data_write8(gpio_t *gpio, gpio_data data);
+int  gpio_index_write(gpio_t *gpio, gpio_data data);
+int  gpio_empty_write(gpio_t *gpio, gpio_data data);
+gpio_data gpio_ddr_read8(gpio_t *gpio);
+gpio_data gpio_data_read8(gpio_t *gpio);
+gpio_data gpio_index_read(gpio_t *gpio);
+gpio_data gpio_shadow_read8(gpio_t *gpio);
+gpio_data gpio_ff_read(gpio_t *gpio);
+gpio_data gpio_zero_read(gpio_t *gpio);
+
+/***************************************************************************
+ * initial class declaration, doesn't hurt to call it mulitiple times,
+ * automatically checked during device instantiation 
+ */
+struct class *gpio_declare(void);
+
+/***************************************************************************
+* class instantiation
+*/
+struct class_device *gpio_register_class_device(gpio_t *gpio);
+
+
+/***************************************************************************
+ * atomic method wrappers
+ * these should be used for all method calls to maintain sychronization across the
+ * various interfaces
+ */
+int atomic_gpio_ddr_write(gpio_t *gpio,gpio_data data);
+gpio_data atomic_gpio_ddr_read(gpio_t *gpio);
+int atomic_gpio_data_write(gpio_t *gpio,gpio_data data);
+gpio_data atomic_gpio_data_read(gpio_t *gpio);
+int atomic_gpio_index_write(gpio_t *gpio,gpio_data data);
+gpio_data atomic_gpio_index_read(gpio_t *gpio);
+
+
+/************************************************************************************
+ * full gpio ports, 
+ * bit configurable gpio ports with a bidirectional data register
+ * if the data register or ddr are NULL their interfaces are not created.
+ */
+static inline struct class_device *gpio_device_create(void *data, void *ddr,const char *name){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	gpio->name = name;
+	gpio->subclass = GPIO_SUBCLASS;
+	gpio->ddr = ddr;
+	gpio->data = data;
+	gpio->shadow = 0;	
+	gpio->data_write = gpio_data_write8;
+    gpio->data_read = gpio_data_read8;
+    
+    if(ddr){
+    	gpio->ddr_write = gpio_ddr_write8;
+    	gpio->ddr_read = gpio_ddr_read8;
+	}
+	printk("registering gpio device: %s\n",name);
+    return gpio_register_class_device(gpio);
+}
+
+/* create a gpio_s struct and initialize for gpio port without registering it */
+
+static inline struct gpio_s *gpio_device_create_unregistered(void *data, void *ddr,const char *name){
+    gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+    memset(gpio,0,sizeof(gpio_t));
+    gpio->name = name;
+    gpio->subclass = GPIO_SUBCLASS;
+    gpio->ddr = ddr;
+    gpio->data = data;
+    gpio->shadow = 0;   
+    gpio->data_write = gpio_data_write8;
+    gpio->data_read = gpio_data_read8;
+    
+    if(ddr){
+        gpio->ddr_write = gpio_ddr_write8;
+        gpio->ddr_read = gpio_ddr_read8;
+    }
+    return gpio;
+}
+
+/************************************************************************************
+ * shadow gpo ports, 
+ * these ports are write only and have no register to read back the current state
+ * a shadow port is therefore created to keep track of the current state in software.
+ * this is not as complete an implementation from a hardware standpoint as a user can only
+ * see the hardware changes if a rogue process if it "plays fair" and modifies the shadow register.
+ * It is, however, much cheaper from a gate implementation standpoint and probably just fine for
+ * most applications.
+ */
+ 
+static inline struct class_device *gpo_device_create(void *data,const char *name){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	gpio->name = name;
+	gpio->subclass = GPO_SUBCLASS;
+	gpio->data = data;
+	gpio->shadow = 0;
+	gpio->data_write = gpio_data_write8;
+    gpio->data_read = gpio_shadow_read8;
+    gpio->ddr_write = gpio_empty_write;
+    gpio->ddr_read = gpio_ff_read;
+    printk("registering gpo device: %s\n",name);
+    return gpio_register_class_device(gpio);
+}
+
+static inline struct gpio_s *gpo_device_create_unregistered(void *data, const char *name)
+{
+    gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+    memset(gpio,0,sizeof(gpio_t));
+    gpio->name = name;
+    gpio->subclass = GPO_SUBCLASS;
+    gpio->data = data;
+    gpio->shadow = 0;
+    gpio->data_write = gpio_data_write8;
+    gpio->data_read = gpio_shadow_read8;
+    gpio->ddr_write = gpio_empty_write;
+    gpio->ddr_read = gpio_ff_read;
+    return gpio;
+}
+
+
+/************************************************************************************
+ * gpi ports, gpi ports are functionally the same as gpio input only ports,
+ * but their ddr ports are not implemented in hardware 
+ * and are assumed based upon the PLD key. 
+ * This is a cheaper gate implementation. 
+ */
+static inline struct class_device *gpi_device_create(void *data,const char *name){
+	gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+	memset(gpio,0,sizeof(gpio_t));
+	gpio->name = name;
+	gpio->subclass = GPI_SUBCLASS;
+	gpio->data = data;
+	gpio->shadow = 0;
+	gpio->data_write = gpio_empty_write;
+    gpio->data_read = gpio_data_read8;
+    gpio->ddr_write = gpio_empty_write;
+    gpio->ddr_read = gpio_zero_read;
+    printk("registering gpi device: %s\n",name);
+    return gpio_register_class_device(gpio);
+}
+
+/* create a gpio_s struct and initialize for gpi port without registering it */
+
+static inline struct gpio_s *gpi_device_create_unregistered(void *data,const char *name){
+    gpio_t *gpio = kmalloc(sizeof(gpio_t),GFP_KERNEL);
+    memset(gpio,0,sizeof(gpio_t));
+    gpio->name = name;
+    gpio->subclass = GPI_SUBCLASS;
+    gpio->data = data;
+    gpio->shadow = 0;
+    gpio->data_write = gpio_empty_write;
+    gpio->data_read = gpio_data_read8;
+    gpio->ddr_write = gpio_empty_write;
+    gpio->ddr_read = gpio_zero_read;
+    return gpio;
+}   
+
+#endif
+
+#endif /*GPIO_H_*/
diff -uprN linux-2.6.20/include/linux/class/mmcblock.h linux-2.6.20-at92_e1.5/include/linux/class/mmcblock.h
--- linux-2.6.20/include/linux/class/mmcblock.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/mmcblock.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,19 @@
+#ifndef MMCBLOCK_H_
+#define MMCBLOCK_H_
+
+//#define MMCB_DEBUG 
+ 
+#undef MMCBDEBUG
+#ifdef MMCB_DEBUG
+	#define MMCBDEBUG(x...)  {printk("%s(): %d ",__PRETTY_FUNCTION__, __LINE__);printk(x);}
+#else
+	#define MMCBDEBUG(x...)	do { } while (0)
+#endif 
+
+int mmc_bdriver_init(void);
+void mmc_bdriver_exit(void);
+int mmc_diskize(mmcslot_t *s);
+void checkmedia_start(mmcslot_t *s);
+void checkmedia_stop(mmcslot_t *s);
+
+#endif /*MMCBLOCK_H_*/
diff -uprN linux-2.6.20/include/linux/class/mmcprot.h linux-2.6.20-at92_e1.5/include/linux/class/mmcprot.h
--- linux-2.6.20/include/linux/class/mmcprot.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/mmcprot.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,388 @@
+#ifndef MMCPROT_H_
+#define MMCPROT_H_
+
+#include <linux/types.h>
+#include <linux/timer.h>
+
+#define INVALID		0
+#define VALID		1
+#define CHANGED		2
+#define READY		4
+
+#define TRUE		1
+#define FALSE		(!TRUE)
+
+/**
+ * Debug statement defines
+ */
+ 
+//#define MMC_DEBUG 
+ 
+#undef MMCDEBUG
+#ifdef MMC_DEBUG
+#define MMCDEBUG(fmt, args...) printk(fmt"\n", ## args)
+#else 
+#define MMCDEBUG(fmt, args...) 
+#endif
+
+//packet defines
+#define MAX_RESPONSE 5
+#define CRC_LENGTH  2	
+#define START_TOKEN_LENGTH 1
+#define BR_STOP_TOKEN 0xFD
+#define DATA_RESPONSE_LENGTH  1
+#define MAX_NWR 8
+#define COMMAND_LENGTH  6
+#define Ncr_MAX  8
+		
+//command response defines		
+#define MMCCOM_IDLE  0x01
+#define MMCCOM_ERASE_RES  0x02
+#define MMCCOM_ILLEGAL  0x04
+#define MMCCOM_CRC  0x08
+#define MMCCOM_ERASE_SEQ  0x10
+#define MMCCOM_ADDRESS  0x20
+#define MMCCOM_PARAMETER  0x40
+
+//data responses
+#define MMCDAT_D_RESPONSE_MASK  0x1F
+#define MMCDAT_DATA_ACC  0x05
+#define MMCDAT_CRC_ERR 0x0B
+#define MMCDAT_WRITE_ERR 0x0D	
+
+typedef struct CSD_register{
+		int	SPEC_VERS;
+		int	TAAC;
+		int	NSAC;
+		int	TRAN_SPEED;
+		int	CCC;
+		int	READ_BL_LEN;
+		int	READ_BL_PARTIAL;
+		int	WRITE_BLK_MISALIGN;
+		int	READ_BLK_MISALIGN;
+		int	DSR_IMP;
+		int	C_SIZE;
+		int	VDD_R_CURR_MIN;
+		int	VDD_R_CURR_MAX;
+		int	VDD_W_CURR_MIN;
+		int	VDD_W_CURR_MAX;
+		int	C_SIZE_MULT;
+		int	ERASE_GRP_SIZE;
+		int	ERASE_GRP_MULT;
+		int	WP_GRP_SIZE;
+		int	WP_GRP_ENABLE;
+		int	DEFAULT_ECC;
+		int	R2W_FACTOR;
+		int	WRITE_BL_LEN;
+		int	WRITE_BL_PARTIAL;
+		int	FILE_FORMAT_GRP;
+		int	COPY;
+		int	PERM_WRITE_PROTECT;
+		int	TMP_WRITE_PROTECT;
+		int	FILE_FORMAT;
+		int	ECC;
+		int	CRC;	
+	}CSD_register;	
+
+typedef struct CID_register{
+		int Manufacturer_ID; 
+		int OEM_Application_ID; 
+		char Product_name[7]; 
+		int Product_revision;
+		long Product_serial_number; 
+		int Manufacturing_date; 			   							  		
+	}CID_register;
+
+typedef struct cardinfo_s {
+	unsigned int blocklength;
+	unsigned int sectors;
+	unsigned long size;
+	unsigned long speed;//maximum clock speed of the card
+	unsigned int media_detect;
+	CSD_register CSD;
+	CID_register CID;
+}cardinfo_t;
+
+#define MAXSLOTNUM 4
+
+enum MMCMETHODS {
+    MMCCD		= 0,
+	MMCWP,
+	MMCTP,
+	MMCEX,
+	MMCSS,
+};
+
+typedef struct mmcslot_s {
+	int slotnumber;
+	const char *name;
+	int users;
+	int state;
+	cardinfo_t card;
+	spinlock_t lock;
+	struct gendisk *disk;
+	struct timer_list timer;
+	int (*carddetect)(struct mmcslot_s *s);
+	int (*writeprotect)(struct mmcslot_s *s);
+	int (*tip)(struct mmcslot_s *s,int onoff);//declare transfer in progress true/false (moves chip select, potentially turns off the clock)
+	int (*exchange)(struct mmcslot_s *s,u8 *mosi, u8 *miso, int size);//bidirectional transfer
+	int (*setspeed)(struct mmcslot_s *s,unsigned long speed);
+	void *pd[5];//individual private data pointers for methods
+}mmcslot_t;
+
+
+/**
+ * Prototypes for the core functions
+ */
+int mmcinit(mmcslot_t *s);
+mmcslot_t *mmcgetslot(int i);
+int mmcreleaseslot(mmcslot_t *s);
+int mmctransaction(mmcslot_t *s, int command, int arg1, int arg2,int blocking,int response);
+int mmcblockread(mmcslot_t *s, int command, int arg1, int arg2,int response, u8 *data,int blocksize, int blocknum,int Nac);
+int mmcblockwrite(mmcslot_t *s,int command, int arg1, int arg2, int response, u8 *data, int blocksize, int blocknum,int Nwr);
+
+#define CARDREGTOP 15
+
+static inline int parse_CSD(CSD_register *reg, u8 *CSD){
+		reg->SPEC_VERS= (CSD[CARDREGTOP-15]&0x3C)>>2;
+		reg->TAAC= CSD[CARDREGTOP-14];
+		reg->NSAC= CSD[CARDREGTOP-13];
+		reg->TRAN_SPEED= CSD[CARDREGTOP-12];
+		reg->CCC= ((CSD[CARDREGTOP-11])<<4)|((CSD[CARDREGTOP-10]&0xf0)>>4);
+		reg->READ_BL_LEN= (CSD[CARDREGTOP-10]&0x0f);
+		reg->READ_BL_PARTIAL= (CSD[CARDREGTOP-9]&0x80>>7);
+		reg->WRITE_BLK_MISALIGN= (CSD[CARDREGTOP-9]&0x40>>6);
+		reg->READ_BLK_MISALIGN= (CSD[CARDREGTOP-9]&0x20>>5);
+		reg->DSR_IMP= (CSD[CARDREGTOP-9]&0x10>>4);
+		reg->C_SIZE= ((CSD[CARDREGTOP-9]&0x03)<<10)|(CSD[CARDREGTOP-8]<<2)|((CSD[CARDREGTOP-7]&0xC0)>>6);		
+		reg->VDD_R_CURR_MIN= (CSD[CARDREGTOP-7]&0x38)>>3;
+		reg->VDD_R_CURR_MAX= (CSD[CARDREGTOP-7]&0x07);
+		reg->VDD_W_CURR_MIN= (CSD[CARDREGTOP-6]&0xE0)>>5;
+		reg->VDD_W_CURR_MAX= (CSD[CARDREGTOP-6]&0x1C)>>2;
+		reg->C_SIZE_MULT= ((CSD[CARDREGTOP-6]&0x03)<<1)|((CSD[CARDREGTOP-5]&0x80)>>7);
+		reg->ERASE_GRP_SIZE= (CSD[CARDREGTOP-5]&0x7c)>>2;
+		reg->ERASE_GRP_MULT= ((CSD[CARDREGTOP-5]&0x03)<<3)|((CSD[CARDREGTOP-4]&0xe0)>>5);
+		reg->WP_GRP_SIZE= (CSD[CARDREGTOP-4]&0x1f);
+		reg->WP_GRP_ENABLE= (CSD[CARDREGTOP-3]&0x80)>>7;;
+		reg->DEFAULT_ECC= (CSD[CARDREGTOP-3]&0x60)>>5;
+		reg->R2W_FACTOR= (CSD[CARDREGTOP-3]&0x8c)>>2;
+		reg->WRITE_BL_LEN= ((CSD[CARDREGTOP-3]&0x03)<<2)|((CSD[CARDREGTOP-2]&0xc0)>>6);
+		reg->WRITE_BL_PARTIAL= (CSD[CARDREGTOP-2]&0x20)>>5;
+		reg->FILE_FORMAT_GRP= (CSD[CARDREGTOP-1]&0x80)>>7;
+		reg->COPY= (CSD[CARDREGTOP-1]&0x40)>>6;
+		reg->PERM_WRITE_PROTECT= (CSD[CARDREGTOP-1]&0x20)>>5;
+		reg->TMP_WRITE_PROTECT= (CSD[CARDREGTOP-1]&0x10)>>4;
+		reg->FILE_FORMAT= (CSD[CARDREGTOP-1]&0x0C)>>2 ;
+		reg->ECC= CSD[CARDREGTOP-1]&0x03;
+		reg->CRC= CSD[CARDREGTOP-0]&0xfe;	
+		return 0;
+	}
+
+
+static inline int parse_CID(CID_register *reg,u8 *CSD){
+		reg->Manufacturer_ID = CSD[CARDREGTOP-15]; 
+		reg->OEM_Application_ID = (CSD[CARDREGTOP-14]<<8)|(CSD[CARDREGTOP-13]); 		
+		reg->Product_name[5] = CSD[CARDREGTOP-7]; 
+		reg->Product_name[4] = CSD[CARDREGTOP-8]; 
+		reg->Product_name[3] = CSD[CARDREGTOP-9]; 
+		reg->Product_name[2] = CSD[CARDREGTOP-10]; 
+		reg->Product_name[1] = CSD[CARDREGTOP-11];
+		reg->Product_name[0] = CSD[CARDREGTOP-12];
+		reg->Product_name[6] = 0;//NULL termination for string manipulation
+		reg->Product_revision = CSD[CARDREGTOP-6];
+		reg->Product_serial_number = ((long)CSD[CARDREGTOP-5]<<24)|(((long)CSD[CARDREGTOP-4]<<16)&
+			0xff0000)|(((long)CSD[CARDREGTOP-3]<<8)&0xff00)|(((long)CSD[CARDREGTOP-2])&0xff); 
+		reg->Manufacturing_date = CSD[CARDREGTOP-1]; 
+		return 0;
+	}
+
+
+/**
+ * MMC Commands
+ * -----------------------------------------------------------------------------
+ */
+
+/**
+ * resets the MultiMedia card
+ */
+#define GO_IDLE_STATE(dev)	mmctransaction(dev,0,0,0,0,1)												
+/**
+ * activates the card's initialization process
+ * @return command response
+ */
+#define	SEND_OP_COND(dev)	mmctransaction(dev,1,0,0,0,1)
+/**
+ * Asks the selected card to send its cardspecific data (CSD)
+ * @param data a 16 bit array to store the CSD register in
+ * @return the command response
+ */
+#define SEND_CSD(dev,data)  mmcblockread(dev,9,0,0,1,data,16,1,8 )
+/**
+ * asks the selected card to send its card identification (CID)
+ * @param data data a 16 bit array to store the CID register in
+ * @return
+ */
+#define SEND_CID(dev,data)  mmcblockread(dev,10,0,0,1,data,16,1, 8)
+/**
+ * Stop transmission on multiple block read 
+ * automatically called by the READ_MULTIPLE_BLOCK function
+ * @return command response
+ */
+#define STOP_TRANSMISSION(dev) mmctransaction(dev,12,0,0,0,1)
+/**
+ * Asks the selected card to send its status register
+ * This is an untested command 
+ * @return command response(in this case status)
+ */
+#define SEND_STATUS(dev) mmctransaction(dev,13,0,0,0,2)
+/**
+ * selects a block length (in bytes) for all following 
+ * block operations (read and write)1
+ * this is an untested command
+ * @param arg1 top half of block length
+ * @param arg2 bottom half of block length
+ * @return command response
+ */
+#define SET_BLOCKLEN(dev,arg1,arg2) mmctransaction(dev,16,arg1,arg2,0,1)
+/**
+ * reads a block of the size selected by the SET_BLOCKLEN command2
+ * changing the block size outside of the default has not been tested
+ * @param address the byte address to start the read at(block aligned)
+ * @param data array to move the data into
+ * @param blocksize size of the blocks. If it hasn't been modified with SET_BLOCKLEN this will be BLOCKLEN
+ * @return 1
+ */
+#define READ_SINGLE_BLOCK(dev,address,data,blocksize) mmcblockread(dev,17,(int)(address>>16),(int)(address&0xffff),1, data,blocksize,1,8 )
+/**
+ * continuously transfers data blocks from card to host until interrupted by a 
+ * stop command or the requested number of data blocks transmitted
+ * Currently this command is implemented to automatically stop transmission after the 
+ * number of blocks specified by blocknum is read
+ * @param address starting block aligned byte address
+ * @param data array to transfer the data into linearly
+ * @param blocksize size of the blocks. If it hasn't been modified with 
+ * SET_BLOCKLEN this will be BLOCKLEN
+ * @param blocknum number of blocks to read
+ * @return the number of blocks read
+ */
+#define READ_MULTIPLE_BLOCK(dev,address,data,blocksize,blocknum) mmcblockread(dev,18,(int)(address>>16),(int)(address&0xffff),1,data,blocksize,blocknum,8)
+/**
+ * Defines the number of blocks which are going to be transferred in the immediately exceeding multiple block read or write command.
+ * this command is untested, and probably won't work with the current read/write
+ * implementation
+ * @param number of blocks
+ * @return command response
+ */
+#define SET_BLOCK_COUNT(dev,arg1) mmctransaction(dev,23,arg1,0,0,1)
+/**
+ * writes a block of the size selected by the SET_BLOCKLEN command
+ * if BLOCKLEN has not been set, then the default is used (read from the CSD)
+ * @param address starting block aligned byte address
+ * @param data linear data array to write
+ * @param blocksize size of the blocks. 
+ * @return 1
+ */
+#define	WRITE_BLOCK(dev,address,data,blocksize)	mmcblockwrite(dev,24,(int)(address>>16),(int)(address&0xffff),1,data,blocksize,1,1)
+/**
+ * continuously writes blocks of data until a "Stop Tran" Token or the requested number of blocks received.
+ * stop tran is automatically thrown by the method when the requested
+ * number of blocks has been written
+ * @param address address starting block aligned byte address
+ * @param data linear data array to write
+ * @param blocksize size of the blocks. If it hasn't been modified with SET_BLOCKLEN this will be BLOCKLEN
+ * @param blocknum number of blocks to write
+ * @return number of blocks written
+ */
+#define WRITE_MULTIPLE_BLOCK(dev,address, data, blocksize, blocknum) mmcblockwrite(dev,25,(int)(address>>16),(int)(address&0xffff),1,data,blocksize,blocknum,1)
+/**
+ * programming of the programmable bits of the CSD
+ * not currently supported
+ * probably a write_block method, but more research will
+ * be needed.
+ * @return command response
+ */
+#define PROGRAM_CSD(dev) mmctransaction(dev,27,0,0,0,1)
+/**
+ * if the card has write protection this command sets the write protection bit of the addressed group.
+ * The properties of write protection are coded in the card specific data (WP_GRP_SIZE).
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define SET_WRITE_PROT(dev,arg1, arg2) mmctransaction(dev,28,arg1,arg2,0,1)
+/**
+ * if the card has write protection this command clears the write protection bit of the addressed group
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define CLR_WRITE_PROT(dev,arg1, arg2) mmctransaction(dev,29,arg1,arg2,true,1)
+/**
+ * "if the card has write protection this command asks the card to send the status of the write protection bits 
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define SEND_WRITE_PROT(dev,arg1, arg2) mmctransaction(dev,30,arg1,arg2,0,1)
+/**
+ * sets the address of the first erase group within a range to be selected for erase
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define TAG_ERASE_GROUP_START(dev,arg1, arg2) mmctransaction(dev,35,arg1,arg2,0,1)
+/**
+ * erases all previously selected erase groups  
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define	ERASE(dev,arg1,arg2) mmctransaction(dev,38,arg1,arg2,1,1)	
+/**
+ * used to Set/Reset the Password or lock/unlock the card. 
+ * The size of the Data Block is defined by the SET_BLOCK_LEN command.
+ * untested 
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define	LOCK_UNLOCK(dev,arg1,arg2) mmctransaction(dev,42,arg1,arg2,1,1)
+/**
+ * defines to the card that the next command is an application specific command 
+ * rather than a standard command
+ * untested
+ * @param arg1 see data sheet
+ * @return command response
+ */
+#define	APP_CMD(dev,arg1) mmctransaction(dev,55,arg1,0,false,1)
+/**
+ * used either to transfer a data block to the card or to get a data block from 
+ * the card for general purpose / application specific commands. The size of the 
+ * data block is defined by the SET_BLOCK_LEN command.
+ * untested
+ * @param arg1 high address bits
+ * @param arg2 low address bits
+ * @return command response
+ */
+#define GEN_CMD(dev,arg1, arg2)	mmctransaction(dev,56,arg1,arg2,true,1)
+/**
+ * reads the OCR register of a card 
+ * untested as status bits are returned in the command response of all mmctransactions
+ * @return command response
+ */
+#define READ_OCR(dev) mmctransaction(dev,58,0,0,0,5)
+/**
+ * "turns the CRC option on or off. A ?1? in the CRC option bit will turn the option on, a ?0? will turn it off"
+ * CRC's are currently unsupported, turning on the CRC option will break all further mmctransaction until a reset
+ * @param arg1 see data sheet
+ * @param arg2 see data sheet
+ * @return command response
+ */
+#define CRC_ON_OFF(dev,arg1,arg2) mmctransaction(dev,59,arg1,arg2,0,1)
+
+#endif /*MMCPROT_H_*/
diff -uprN linux-2.6.20/include/linux/class/pwm.h linux-2.6.20-at92_e1.5/include/linux/class/pwm.h
--- linux-2.6.20/include/linux/class/pwm.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/pwm.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,69 @@
+#ifndef PWM_H_
+#define PWM_H_
+#include <linux/autoconf.h>
+#include <linux/device.h>
+
+
+#ifdef CONFIG_PWMCLASS
+
+//SUBCLASS assignment currently unused and arbitrary
+#define PWMD_SUBCLASS 77 
+
+typedef u32 pwm_data;
+
+/**********************
+ * pwm class structure
+ */
+typedef struct pwm_s{
+	const char *name;
+	int subclass;
+	void *widthus;
+	void *periodus;
+	void *control;
+	pwm_data widthus_shadow;
+	pwm_data periodus_shadow;
+	pwm_data (*widthus_read)(struct pwm_s *pwm);//width us
+	int (*widthus_write)(struct pwm_s *pwm,pwm_data data);
+	pwm_data (*periodus_read)(struct pwm_s *pwm);	//period us
+	int (*periodus_write)(struct pwm_s *pwm,pwm_data data);
+	pwm_data (*invert_read)(struct pwm_s *pwm);	//pulse inversion
+	int (*invert_write)(struct pwm_s *pwm,pwm_data data);
+	pwm_data (*read_pwmclock)(struct pwm_s *pwm);
+	int (*write_pwmclock)(struct pwm_s *pwm,pwm_data data);
+}pwm_t;
+
+
+struct class *pwm_declare(void);
+struct class_device *pwm_register_class_device(pwm_t *pwm);
+
+/***************************************************************************
+ * typical low level methods
+ */
+int  pwm_widthus_write8(pwm_t *pwm, pwm_data data);
+int  pwm_widthus_write16(pwm_t *pwm, pwm_data data);
+int  pwm_periodus_write8(pwm_t *pwm, pwm_data data);
+int  pwm_periodus_write16(pwm_t *pwm, pwm_data data);
+int  pwm_empty_write(pwm_t *pwm, pwm_data data);
+pwm_data pwm_widthus_read8(pwm_t *pwm);
+pwm_data pwm_widthus_read16(pwm_t *pwm);
+pwm_data pwm_periodus_read8(pwm_t *pwm);
+pwm_data pwm_periodus_read16(pwm_t *pwm);
+pwm_data pwm_ff_read(pwm_t *pwm);
+pwm_data pwm_zero_read(pwm_t *pwm);
+pwm_data pwm_widthusshadow_read(pwm_t *pwm);
+
+/***************************************************************************
+ * atomic method wrappers
+ * these should be used for all method calls to maintain sychronization across the
+ * various interfaces
+ */
+int atomic_pwm_widthus_write(pwm_t *pwm,pwm_data data);
+int atomic_pwm_periodus_write(pwm_t *pwm,pwm_data data);
+int atomic_pwm_invert_write(pwm_t *pwm,pwm_data data);
+pwm_data atomic_pwm_widthus_read(pwm_t *pwm);
+pwm_data atomic_pwm_periodus_read(pwm_t *pwm);
+pwm_data atomic_pwm_invert_read(pwm_t *pwm);
+
+#endif //CONFIG_PWMCLASS
+
+#endif /*PWM_H_*/
diff -uprN linux-2.6.20/include/linux/class/rtdm/gpio_rtdm.h linux-2.6.20-at92_e1.5/include/linux/class/rtdm/gpio_rtdm.h
--- linux-2.6.20/include/linux/class/rtdm/gpio_rtdm.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/rtdm/gpio_rtdm.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,21 @@
+#ifndef GPIO_RTDM_H_
+#define GPIO_RTDM_H_
+
+#include <linux/ioctl.h>
+
+//arbitrary assignment, come back to this later
+#define RTDM_CLASS_GPIO 0x80 
+
+#ifdef __KERNEL__	
+int rt_gpio_device_create(struct gpio_s *gpio);
+#endif//__KERNEL__
+
+#define DDRREAD			_IOR(RTDM_CLASS_GPIO,0,char)
+#define DDRWRITE 		_IOW(RTDM_CLASS_GPIO,0,char)
+#define DATAREAD		_IOR(RTDM_CLASS_GPIO,1,char)
+#define DATAWRITE 		_IOW(RTDM_CLASS_GPIO,1,char)
+/* additions for the char driver */
+#define INDEXREAD       _IOR(RTDM_CLASS_GPIO,2,char)
+#define INDEXWRITE      _IOW(RTDM_CLASS_GPIO,2,char)
+
+#endif //GPIO_RTDM_H_
diff -uprN linux-2.6.20/include/linux/class/rtdm/pwm_rtdm.h linux-2.6.20-at92_e1.5/include/linux/class/rtdm/pwm_rtdm.h
--- linux-2.6.20/include/linux/class/rtdm/pwm_rtdm.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/rtdm/pwm_rtdm.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,18 @@
+#ifndef PWM_RTDM_H_
+#define PWM_RTDM_H_
+
+#include <linux/ioctl.h>
+
+//arbitrary assignment, come back to this later
+#define RTDM_CLASS_PWM 0x90 
+
+#ifdef __KERNEL__	
+int rt_pwm_device_create(struct pwm_s *pwm);
+#endif//__KERNEL__
+
+#define PERIODUSREAD		_IOR(RTDM_CLASS_PWM,0,char)
+#define PERIODUSWRITE 		_IOW(RTDM_CLASS_PWM,0,char)
+#define WIDTHUSREAD			_IOR(RTDM_CLASS_PWM,1,char)
+#define WIDTHUSWRITE 		_IOW(RTDM_CLASS_PWM,1,char)
+
+#endif //PWM_RTDM_H_
diff -uprN linux-2.6.20/include/linux/class/rtdm/spi_rtdm.h linux-2.6.20-at92_e1.5/include/linux/class/rtdm/spi_rtdm.h
--- linux-2.6.20/include/linux/class/rtdm/spi_rtdm.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/rtdm/spi_rtdm.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,21 @@
+#ifndef SPI_RTDM_H_
+#define SPI_RTDM_H_
+
+#include <linux/ioctl.h>
+
+//arbitrary assignment, come back to this later
+#define RTDM_CLASS_SPI 0x90 
+
+#ifdef __KERNEL__	
+int rt_spi_device_create(struct spi_s *spi);
+#endif//__KERNEL__
+
+#define CONFREAD		_IOR(RTDM_CLASS_SPI,0,spi_control)
+#define CONFWRITE		_IOW(RTDM_CLASS_SPI,0,spi_control)
+#define SPEEDREAD		_IOR(RTDM_CLASS_SPI,1,spi_control)
+#define SPEEDWRITE		_IOW(RTDM_CLASS_SPI,1,spi_control)
+#define TIPREAD			_IOR(RTDM_CLASS_SPI,2,spi_control)
+#define TIPWRITE		_IOW(RTDM_CLASS_SPI,2,spi_control)
+#define XMIT			_IOW(RTDM_CLASS_SPI,3,spi_transfer_t)
+
+#endif //SPI_RTDM_H_
diff -uprN linux-2.6.20/include/linux/class/spi.h linux-2.6.20-at92_e1.5/include/linux/class/spi.h
--- linux-2.6.20/include/linux/class/spi.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/spi.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,85 @@
+#ifndef SPI_H_
+#define SPI_H_
+#include <linux/autoconf.h>
+#include <linux/device.h>
+#if defined(CONFIG_LSI2ESC)
+#include <linux/spi/spi.h>
+#endif
+
+#ifdef CONFIG_SPICLASS	
+
+#define SPICL_CPHA			(0x01)
+#define SPICL_CPOL			(0x02)
+/* common bit settings -- should be mutually exclusive */
+/* it would be possible to let 8 bit mode be 0x00 and let
+ * this be the default, but this does not work well for the
+ * LSI2ESC interface as the default controller setting is to
+ * leave bits_per_word set to 0. Leave 8 bit as an explicit
+ * setting. */
+#define SPICL_EIGHTBIT		(0x04) /* 8 bit is default */
+#define SPICL_TENBIT        (0x08) /* 10 bits per transfer */ 
+#define SPICL_TWELVEBIT     (0x10) /* 12 bits per transfer */
+#define SPICL_SIXTEENBIT    (0x20) /* 16 bits per transfer */
+
+typedef u8 spi_data;
+typedef u32 spi_control;
+
+//control definitions for the tip function
+#define TIPOFF		0
+#define TIPON		1
+#define TIPSTATUS	2
+
+/**********************
+ * spi class structure
+ */
+typedef struct spi_s{
+	const char *name;
+	int subclass;
+	spi_data *buf; 
+	int bsize;
+	/* if the SPI interface is used there needs to be a pointer to
+	 * the associated spi_device struct used by the Linux SPI layer
+	 */
+#if defined(CONFIG_LSI2ESC)
+	struct spi_device *lsi;
+#endif
+	int (*tip)(struct spi_s *s,int ofs);//declare transfer in process, for locking purposes
+	int (*xmit)(struct spi_s *s,u8 *mosi, u8 *miso, int size);
+	int (*confwrite)(struct spi_s *s,spi_control config);
+	spi_control (*confread)(struct spi_s *s);
+	int (*speedwrite)(struct spi_s *s,spi_control speed);
+	spi_control (*speedread)(struct spi_s *s);
+}spi_t;
+
+#define SPI_BASECLASNUM	0xC0
+#define SPI_SUBCLASS 	(SPI_BASECLASNUM+0)
+
+/***************************************************************************
+ * initial class declaration, doesn't hurt to call it mulitiple times,
+ * automatically checked during device instantiation 
+ */
+struct class *spi_declare(void);
+
+/***************************************************************************
+* class instantiation
+*/
+struct class_device *spi_register_class_device(spi_t *s);
+
+
+/***************************************************************************
+ * atomic method wrappers
+ * these should be used for all method calls to maintain sychronization across the
+ * various interfaces
+ */
+int atomic_spi_xmit(struct spi_s *s,u8 *mosi, u8 *miso, int size);
+int atomic_spi_conf_write(struct spi_s *s,spi_control config);
+spi_control atomic_spi_conf_read(struct spi_s *s);
+int atomic_spi_speed_write(struct spi_s *s,spi_control config);
+spi_control atomic_spi_speed_read(struct spi_s *s);
+int atomic_spi_tip_write(struct spi_s *s,spi_control config);
+spi_control atomic_spi_tip_read(struct spi_s *s);
+
+
+#endif
+
+#endif /*SPI_H_*/
diff -uprN linux-2.6.20/include/linux/class/spi_interface.h linux-2.6.20-at92_e1.5/include/linux/class/spi_interface.h
--- linux-2.6.20/include/linux/class/spi_interface.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/class/spi_interface.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,28 @@
+#ifndef SPI_INTERFACE_H_
+#define SPI_INTERFACE_H_
+
+/**
+ * Provides an interface between the SPI class
+ * driver and the Linux SPI layer for devices that
+ * already implement a device specific driver and
+ * register this interface in the mach.
+ * Naming convention:
+ * Linux SPI Interface: lsi
+ * EMAC SPI Class: esc
+ * -> lsi2esc
+ * 
+ * Copyright (C) 2007, EMAC Inc
+ */
+
+#include <linux/device.h>
+#include <linux/spi/spi.h>
+#include <linux/class/spi.h>
+
+int lsi2esc_spi_tip(struct spi_s *s,int ofs);
+int lsi2esc_spi_xmit(struct spi_s *s, u8 *mosi, u8 *miso, int size);
+int lsi2esc_spi_confwrite(struct spi_s *s, spi_control config);
+spi_control lsi2esc_spi_confread(struct spi_s *s);
+int lsi2esc_spi_speedwrite(struct spi_s *s, spi_control speed);
+spi_control lsi2esc_spi_speedread(struct spi_s *s);
+
+#endif /*SPI_INTERFACE_H_*/
diff -uprN linux-2.6.20/include/linux/ioex/ecoreex.h linux-2.6.20-at92_e1.5/include/linux/ioex/ecoreex.h
--- linux-2.6.20/include/linux/ioex/ecoreex.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/ioex/ecoreex.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,62 @@
+#ifndef ECOREEX_H_
+#define ECOREEX_H_
+
+#include <linux/class/pwm.h>
+#include <linux/class/gpio.h>
+#include <linux/class/mmcprot.h>
+
+
+#ifdef CONFIG_ECOREEX_KEY
+#define VERSION_KEY CONFIG_ECOREEX_STATIC_KEY
+#else
+#define VERSION_KEY -1
+#endif
+
+/* Use this structure to specify read/write commands
+ * that differ from the direct ioread/write functions
+ * in the gpio class. If these members are not specified,
+ * the corresponding gpio function will be used as the
+ * default
+ */
+struct ecoreex_access_s
+{
+    gpio_data (*ecoreex_data_read)(struct gpio_s *gpio);
+    int (*ecoreex_data_write)(struct gpio_s *gpio,gpio_data data);
+    gpio_data (*ecoreex_ddr_read)(struct gpio_s *gpio); 
+    int (*ecoreex_ddr_write)(struct gpio_s *gpio,gpio_data data);
+    gpio_data (*ecoreex_index_read)(struct gpio_s *gpio);   
+    int (*ecoreex_index_write)(struct gpio_s *gpio,gpio_data data);
+    u8 (*ecoreex_key_read)(u8 index, u8 *virt_addr); /* function to read the key offset -- defaults to ioread8 */
+};
+
+struct ecoreex_data
+{
+    int key_offset;
+#ifdef CONFIG_PWMCLASS
+    __u32 (*read_periodusa)(pwm_t *pwm);//a pwm input clock, defined as a period to minimize calculation
+#endif
+    mmcslot_t *mmcslot;//structure for implementing mmc connections.
+    unsigned int irq;
+    struct ecoreex_access_s *e_access;  
+};
+
+static inline u8 ecoreex_default_key_read(u8 index, u8 *virt_addr)
+{
+    return ioread8(&(virt_addr[index]));
+}
+
+static inline int ecoreex_setup_data_access(struct ecoreex_access_s *e_access, struct gpio_s *gpio)
+{
+    if (!e_access || !gpio) return -1;
+    if (e_access->ecoreex_data_read) gpio->data_read = e_access->ecoreex_data_read;
+    if (e_access->ecoreex_data_write) gpio->data_write = e_access->ecoreex_data_write;
+    if (e_access->ecoreex_ddr_read) gpio->ddr_read = e_access->ecoreex_ddr_read;
+    if (e_access->ecoreex_ddr_write) gpio->ddr_write = e_access->ecoreex_ddr_write;
+    if (e_access->ecoreex_index_read) gpio->index_read = e_access->ecoreex_index_read;
+    if (e_access->ecoreex_index_write) gpio->index_write = e_access->ecoreex_index_write;
+    if (!e_access->ecoreex_key_read) e_access->ecoreex_key_read = ecoreex_default_key_read;
+    
+    return 0;
+}
+
+#endif /*ECOREEX_H_*/
diff -uprN linux-2.6.20/include/linux/ioex/pwmd.h linux-2.6.20-at92_e1.5/include/linux/ioex/pwmd.h
--- linux-2.6.20/include/linux/ioex/pwmd.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/ioex/pwmd.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,6 @@
+#ifndef PWMD_H_
+#define PWMD_H_
+
+struct class_device *pwmd_device_create(void *widthus,const char *name,pwm_data (*read_pwmclock)(pwm_t *pwm));
+
+#endif /*PWMD_H_*/
diff -uprN linux-2.6.20/include/linux/mtd/nand.h linux-2.6.20-at92_e1.5/include/linux/mtd/nand.h
--- linux-2.6.20/include/linux/mtd/nand.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/mtd/nand.h	2008-02-07 10:24:59.000000000 -0500
@@ -425,6 +425,7 @@ struct nand_chip {
  */
 #define NAND_MFR_TOSHIBA	0x98
 #define NAND_MFR_SAMSUNG	0xec
+#define NAND_MFR_MICRON         0x2c
 #define NAND_MFR_FUJITSU	0x04
 #define NAND_MFR_NATIONAL	0x8f
 #define NAND_MFR_RENESAS	0x07
diff -uprN linux-2.6.20/include/linux/spi/ads7846.h linux-2.6.20-at92_e1.5/include/linux/spi/ads7846.h
--- linux-2.6.20/include/linux/spi/ads7846.h	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/linux/spi/ads7846.h	2008-02-07 10:24:59.000000000 -0500
@@ -5,9 +5,17 @@
  *
  * It's OK if the min/max values are zero.
  */
+enum ads7846_filter {
+	ADS7846_FILTER_OK,
+	ADS7846_FILTER_REPEAT,
+	ADS7846_FILTER_IGNORE,
+};
+
 struct ads7846_platform_data {
 	u16	model;			/* 7843, 7845, 7846. */
 	u16	vref_delay_usecs;	/* 0 for external vref; etc */
+	int	keep_vref_on:1;		/* set to keep vref on for differential
+					 * measurements as well */
 	u16	x_plate_ohms;
 	u16	y_plate_ohms;
 
@@ -21,5 +29,9 @@ struct ads7846_platform_data {
 	u16	debounce_rep;		/* additional consecutive good readings
 					 * required after the first two */
 	int	(*get_pendown_state)(void);
+	int	(*filter_init)	(struct ads7846_platform_data *pdata,
+				 void **filter_data);
+	int	(*filter)	(void *filter_data, int data_idx, int *val);
+	void	(*filter_cleanup)(void *filter_data);
 };
 
diff -uprN linux-2.6.20/include/video/atmel_lcdc.h linux-2.6.20-at92_e1.5/include/video/atmel_lcdc.h
--- linux-2.6.20/include/video/atmel_lcdc.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/include/video/atmel_lcdc.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,193 @@
+/*
+ *  include/video/atmel_lcdc.h
+ *
+ *  Header file for AT91/AT32 LCD Controller
+ *
+ *  Data structure and register user interface
+ *
+ *  Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+#ifndef __ATMEL_LCDC_H__
+#define __ATMEL_LCDC_H__
+
+ /* LCD Controller info data structure */
+struct atmel_lcdfb_info {
+	spinlock_t		lock;
+	struct fb_info		*info;
+	void __iomem		*mmio;
+	unsigned long		irq_base;
+	dma_addr_t		map_dma;
+	void			*map_cpu;
+	size_t			map_size;
+
+	unsigned int		guard_time;
+	struct platform_device	*pdev;
+	struct clk		*bus_clk;
+	struct clk		*lcdc_clk;
+	unsigned int		default_bpp;
+	unsigned int		default_lcdcon2;
+	unsigned int		default_dmacon;
+	int			default_flags;
+	u8			power_control_pin;
+	struct fb_monspecs	 *default_monspecs;
+};
+
+#define ATMEL_LCDC_DMABADDR1	0x00		/* DMA Base Address Register 1 */
+#define ATMEL_LCDC_DMABADDR2	0x04		/* DMA Base Address Register 2 */
+#define ATMEL_LCDC_DMAFRMPT1	0x08		/* DMA Frame Pointer Register 1 */
+#define ATMEL_LCDC_DMAFRMPT2	0x0c		/* DMA Frame Pointer Register 2 */
+#define ATMEL_LCDC_DMAFRMADD1	0x10		/* DMA Frame Address Register 1 */
+#define ATMEL_LCDC_DMAFRMADD2	0x14		/* DMA Frame Address Register 2 */
+
+#define ATMEL_LCDC_DMAFRMCFG	0x18		/* DMA Frame Configuration Register */
+#define		ATMEL_LCDC_FRSIZE	(0x7fffff <<  0)	/* Frame Size */
+#define		ATMEL_LCDC_BLENGTH_OFFSET	24		/* Burst Length */
+#define		ATMEL_LCDC_BLENGTH	(0x7f     << ATMEL_LCDC_BLENGTH_OFFSET)
+
+#define ATMEL_LCDC_DMACON	0x1c		/* DMA Control Register */
+#define		ATMEL_LCDC_DMAEN	(0x1 << 0)	/* DMA Enable */
+#define		ATMEL_LCDC_DMARST	(0x1 << 1)	/* DMA Reset */
+#define		ATMEL_LCDC_DMABUSY	(0x1 << 2)	/* DMA Busy */
+
+#define ATMEL_LCDC_LCDCON1	0x0800		/* LCD Control Register 1 */
+#define		ATMEL_LCDC_BYPASS	(1     <<  0)	/* Bypass lcd_dotck divider */
+#define		ATMEL_LCDC_CLKVAL_OFFSET	12	/* Clock Divider */
+#define		ATMEL_LCDC_CLKVAL	(0x1ff << ATMEL_LCDC_CLKVAL_OFFSET)
+#define		ATMEL_LCDC_LINCNT	(0x7ff << 21)	/* Line Counter */
+
+#define ATMEL_LCDC_LCDCON2	0x0804		/* LCD Control Register 2 */
+#define		ATMEL_LCDC_DISTYPE	(3 << 0)	/* Display Type */
+#define			ATMEL_LCDC_DISTYPE_STNMONO	(0 << 0)
+#define			ATMEL_LCDC_DISTYPE_STNCOLOR	(1 << 0)
+#define			ATMEL_LCDC_DISTYPE_TFT		(2 << 0)
+#define		ATMEL_LCDC_SCANMOD	(1 << 2)	/* Scan Mode */
+#define			ATMEL_LCDC_SCANMOD_SINGLE	(0 << 2)
+#define			ATMEL_LCDC_SCANMOD_DUAL		(1 << 2)
+#define		ATMEL_LCDC_IFWIDTH	(3 << 3)	/*Interface Width */
+#define			ATMEL_LCDC_IFWIDTH_4		(0 << 3)
+#define			ATMEL_LCDC_IFWIDTH_8		(1 << 3)
+#define			ATMEL_LCDC_IFWIDTH_16		(2 << 3)
+#define		ATMEL_LCDC_PIXELSIZE	(7 << 5)	/* Bits per pixel */
+#define			ATMEL_LCDC_PIXELSIZE_1		(0 << 5)
+#define			ATMEL_LCDC_PIXELSIZE_2		(1 << 5)
+#define			ATMEL_LCDC_PIXELSIZE_4		(2 << 5)
+#define			ATMEL_LCDC_PIXELSIZE_8		(3 << 5)
+#define			ATMEL_LCDC_PIXELSIZE_16		(4 << 5)
+#define			ATMEL_LCDC_PIXELSIZE_24		(5 << 5)
+#define			ATMEL_LCDC_PIXELSIZE_32		(6 << 5)
+#define		ATMEL_LCDC_INVVD	(1 << 8)	/* LCD Data polarity */
+#define			ATMEL_LCDC_INVVD_NORMAL		(0 << 8)
+#define			ATMEL_LCDC_INVVD_INVERTED	(1 << 8)
+#define		ATMEL_LCDC_INVFRAME	(1 << 9 )	/* LCD VSync polarity */
+#define			ATMEL_LCDC_INVFRAME_NORMAL	(0 << 9)
+#define			ATMEL_LCDC_INVFRAME_INVERTED	(1 << 9)
+#define		ATMEL_LCDC_INVLINE	(1 << 10)	/* LCD HSync polarity */
+#define			ATMEL_LCDC_INVLINE_NORMAL	(0 << 10)
+#define			ATMEL_LCDC_INVLINE_INVERTED	(1 << 10)
+#define		ATMEL_LCDC_INVCLK	(1 << 11)	/* LCD dotclk polarity */
+#define			ATMEL_LCDC_INVCLK_NORMAL	(0 << 11)
+#define			ATMEL_LCDC_INVCLK_INVERTED	(1 << 11)
+#define		ATMEL_LCDC_INVDVAL	(1 << 12)	/* LCD dval polarity */
+#define			ATMEL_LCDC_INVDVAL_NORMAL	(0 << 12)
+#define			ATMEL_LCDC_INVDVAL_INVERTED	(1 << 12)
+#define		ATMEL_LCDC_CLKMOD	(1 << 15)	/* LCD dotclk mode */
+#define			ATMEL_LCDC_CLKMOD_ACTIVEDISPLAY	(0 << 15)
+#define			ATMEL_LCDC_CLKMOD_ALWAYSACTIVE	(1 << 15)
+#define		ATMEL_LCDC_MEMOR	(1 << 31)	/* Memory Ordering Format */
+#define			ATMEL_LCDC_MEMOR_BIG		(0 << 31)
+#define			ATMEL_LCDC_MEMOR_LITTLE		(1 << 31)
+
+#define ATMEL_LCDC_TIM1		0x0808		/* LCD Timing Register 1 */
+#define		ATMEL_LCDC_VFP		(0xff <<  0)	/* Vertical Front Porch */
+#define		ATMEL_LCDC_VBP_OFFSET		8	/* Vertical Back Porch */
+#define		ATMEL_LCDC_VBP		(0xff <<  ATMEL_LCDC_VBP_OFFSET)
+#define		ATMEL_LCDC_VPW_OFFSET		16	/* Vertical Synchronization Pulse Width */
+#define		ATMEL_LCDC_VPW		(0x3f << ATMEL_LCDC_VPW_OFFSET)
+#define		ATMEL_LCDC_VHDLY_OFFSET		24	/* Vertical to Horizontal Delay */
+#define		ATMEL_LCDC_VHDLY	(0xf  << ATMEL_LCDC_VHDLY_OFFSET)
+
+#define ATMEL_LCDC_TIM2		0x080c		/* LCD Timing Register 2 */
+#define		ATMEL_LCDC_HBP		(0xff  <<  0)	/* Horizontal Back Porch */
+#define		ATMEL_LCDC_HPW_OFFSET		8	/* Horizontal Synchronization Pulse Width */
+#define		ATMEL_LCDC_HPW		(0x3f  <<  ATMEL_LCDC_HPW_OFFSET)
+#define		ATMEL_LCDC_HFP_OFFSET		21	/* Horizontal Front Porch */
+#define		ATMEL_LCDC_HFP		(0x7ff << ATMEL_LCDC_HFP_OFFSET)
+
+#define ATMEL_LCDC_LCDFRMCFG	0x0810		/* LCD Frame Configuration Register */
+#define		ATMEL_LCDC_LINEVAL	(0x7ff <<  0)	/* Vertical Size of LCD Module */
+#define		ATMEL_LCDC_HOZVAL_OFFSET	21	/* Horizontal Size of LCD Module */
+#define		ATMEL_LCDC_HOZVAL	(0x7ff << ATMEL_LCDC_HOZVAL_OFFSET)
+
+#define ATMEL_LCDC_FIFO		0x0814		/* LCD FIFO Register */
+#define		ATMEL_LCDC_FIFOTH	(0xffff)	/* FIFO Threshold */
+
+#define ATMEL_LCDC_MVAL		0x0818		/* LCD Mode Toggle Rate Value Register */
+
+#define ATMEL_LCDC_DP1_2		0x081c		/* Dithering Pattern DP1_2 Register */
+#define ATMEL_LCDC_DP4_7		0x0820		/* Dithering Pattern DP4_7 Register */
+#define ATMEL_LCDC_DP3_5		0x0824		/* Dithering Pattern DP3_5 Register */
+#define ATMEL_LCDC_DP2_3		0x0828		/* Dithering Pattern DP2_3 Register */
+#define ATMEL_LCDC_DP5_7		0x082c		/* Dithering Pattern DP5_7 Register */
+#define ATMEL_LCDC_DP3_4		0x0830		/* Dithering Pattern DP3_4 Register */
+#define ATMEL_LCDC_DP4_5		0x0834		/* Dithering Pattern DP4_5 Register */
+#define ATMEL_LCDC_DP6_7		0x0838		/* Dithering Pattern DP6_7 Register */
+#define		ATMEL_LCDC_DP1_2_VAL	(0xff)
+#define		ATMEL_LCDC_DP4_7_VAL	(0xfffffff)
+#define		ATMEL_LCDC_DP3_5_VAL	(0xfffff)
+#define		ATMEL_LCDC_DP2_3_VAL	(0xfff)
+#define		ATMEL_LCDC_DP5_7_VAL	(0xfffffff)
+#define		ATMEL_LCDC_DP3_4_VAL	(0xffff)
+#define		ATMEL_LCDC_DP4_5_VAL	(0xfffff)
+#define		ATMEL_LCDC_DP6_7_VAL	(0xfffffff)
+
+#define ATMEL_LCDC_PWRCON	0x083c		/* Power Control Register */
+#define		ATMEL_LCDC_PWR		(1    <<  0)	/* LCD Module Power Control */
+#define		ATMEL_LCDC_GUARDT_OFFSET	1	/* Delay in Frame Period */
+#define		ATMEL_LCDC_GUARDT	(0x7f <<  ATMEL_LCDC_GUARDT_OFFSET)
+#define		ATMEL_LCDC_BUSY		(1    << 31)	/* LCD Busy */
+
+#define ATMEL_LCDC_CONTRAST_CTR	0x0840		/* Contrast Control Register */
+#define		ATMEL_LCDC_PS		(3 << 0)	/* Contrast Counter Prescaler */
+#define			ATMEL_LCDC_PS_DIV1		(0 << 0)
+#define			ATMEL_LCDC_PS_DIV2		(1 << 0)
+#define			ATMEL_LCDC_PS_DIV4		(2 << 0)
+#define			ATMEL_LCDC_PS_DIV8		(3 << 0)
+#define		ATMEL_LCDC_POL		(1 << 2)	/* Polarity of output Pulse */
+#define			ATMEL_LCDC_POL_NEGATIVE		(0 << 2)
+#define			ATMEL_LCDC_POL_POSITIVE		(1 << 2)
+#define		ATMEL_LCDC_ENA		(1 << 3)	/* PWM generator Control */
+#define			ATMEL_LCDC_ENA_PWMDISABLE	(0 << 3)
+#define			ATMEL_LCDC_ENA_PWMENABLE	(1 << 3)
+
+#define ATMEL_LCDC_CONTRAST_VAL	0x0844		/* Contrast Value Register */
+#define		ATMEL_LCDC_CVAL	(0xff)		/* PWM compare value */
+
+#define ATMEL_LCDC_IER		0x0848		/* Interrupt Enable Register */
+#define ATMEL_LCDC_IDR		0x084c		/* Interrupt Disable Register */
+#define ATMEL_LCDC_IMR		0x0850		/* Interrupt Mask Register */
+#define ATMEL_LCDC_ISR		0x0854		/* Interrupt Status Register */
+#define ATMEL_LCDC_ICR		0x0858		/* Interrupt Clear Register */
+#define		ATMEL_LCDC_LNI		(1 << 0)	/* Line Interrupt */
+#define		ATMEL_LCDC_LSTLNI	(1 << 1)	/* Last Line Interrupt */
+#define		ATMEL_LCDC_EOFI		(1 << 2)	/* DMA End Of Frame Interrupt */
+#define		ATMEL_LCDC_UFLWI	(1 << 4)	/* FIFO Underflow Interrupt */
+#define		ATMEL_LCDC_OWRI		(1 << 5)	/* FIFO Overwrite Interrupt */
+#define		ATMEL_LCDC_MERI		(1 << 6)	/* DMA Memory Error Interrupt */
+
+#define ATMEL_LCDC_LUT_(n)	(0x0c00 + ((n)*4))	/* Palette Entry 0..255 */
+
+#endif /* __ATMEL_LCDC_H__ */
diff -uprN linux-2.6.20/sound/arm/Kconfig linux-2.6.20-at92_e1.5/sound/arm/Kconfig
--- linux-2.6.20/sound/arm/Kconfig	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/sound/arm/Kconfig	2008-02-07 10:24:59.000000000 -0500
@@ -33,4 +33,20 @@ config SND_PXA2XX_AC97
 	  Say Y or M if you want to support any AC97 codec attached to
 	  the PXA2xx AC97 interface.
 
+config SND_AT73C213
+	tristate "Atmel AT73C213 DAC driver"
+ 	depends on SND && SPI_ATMEL && ARCH_AT91 && AT91_PROGRAMMABLE_CLOCKS
+	select SND_PCM
+	help
+	  Say Y here if you want to use the Atmel AT73C213 external DAC.
+
+config SND_AT91_AC97
+	tristate "AC97 Controller driver for SAM926X familly from ATMEL"
+	depends on SND && ARCH_AT91
+	select SND_PCM
+	select SND_AC97_CODEC
+	help
+	  Say Y or M if you want to support any AC97 codec attached to
+	  the SAM926X AC97 Controller.
+
 endmenu
diff -uprN linux-2.6.20/sound/arm/Makefile linux-2.6.20-at92_e1.5/sound/arm/Makefile
--- linux-2.6.20/sound/arm/Makefile	2007-02-04 13:44:54.000000000 -0500
+++ linux-2.6.20-at92_e1.5/sound/arm/Makefile	2008-02-07 10:24:59.000000000 -0500
@@ -13,3 +13,10 @@ snd-pxa2xx-pcm-objs		:= pxa2xx-pcm.o
 
 obj-$(CONFIG_SND_PXA2XX_AC97)	+= snd-pxa2xx-ac97.o
 snd-pxa2xx-ac97-objs		:= pxa2xx-ac97.o
+
+obj-$(CONFIG_SND_AT73C213)	+= snd-at73c213.o
+snd-at73c213-objs		:= at73c213.o
+
+obj-$(CONFIG_SND_AT91_AC97)	+= snd-at91-ac97.o
+snd-at91-ac97-objs		:= at91-ac97.o
+
diff -uprN linux-2.6.20/sound/arm/at73c213.c linux-2.6.20-at92_e1.5/sound/arm/at73c213.c
--- linux-2.6.20/sound/arm/at73c213.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/sound/arm/at73c213.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,668 @@
+/*
+ * Driver for the at73c213 16-bit stereo DAC on Atmel SSC
+ *
+ * Copyright (C) 2006 Atmel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/spi/spi.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/kmod.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <sound/initval.h>
+#include <sound/control.h>
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include <asm/io.h>
+#include <asm/io.h>
+#include <asm/processor.h>
+#include <linux/atmel_pdc.h>
+#include <asm/arch/board.h>
+
+#include "at73c213.h"
+
+/*-----------------------------------------------------------------------------
+ *  AT73C213 SPI
+ *-----------------------------------------------------------------------------*/
+static struct spi_device *at73c213_spi_device;
+static unsigned char at73c213_regs[0x11];
+static unsigned char at73c213_spi_wbuffer[2];
+static unsigned char at73c213_spi_rbuffer[2];
+
+/*-----------------------------------------------------------------------------
+ *  AT73C213 SPI write regs
+ *-----------------------------------------------------------------------------*/
+static int at73c213_write_reg(u8 reg, u8 val)
+{
+    struct spi_message msg;
+    struct spi_transfer msg_xfer =
+    {
+        .len        = 2,
+        .cs_change  = 0,
+    };
+
+    spi_message_init(&msg);
+
+    at73c213_spi_wbuffer[0] = reg;
+    at73c213_spi_wbuffer[1] = val;
+
+    msg_xfer.tx_buf = at73c213_spi_wbuffer;
+    msg_xfer.rx_buf = at73c213_spi_rbuffer;
+    spi_message_add_tail(&msg_xfer, &msg);
+
+    at73c213_regs[reg] = val;
+
+    return spi_sync(at73c213_spi_device, &msg);
+}
+
+/*-----------------------------------------------------------------------------
+ *  AT73C213 SPI read regs
+ *-----------------------------------------------------------------------------*/
+static unsigned char at73c213_read_reg(unsigned char reg)
+{
+    return at73c213_regs[reg];
+}
+
+/*-----------------------------------------------------------------------------
+ *  AT73C213 - Init
+ *-----------------------------------------------------------------------------*/
+static void at73c213_hw_init(void)
+{
+/*
+	From AT73C213 datasheet
+	Path DAC to headset output
+	1. Write @0x10 => 0x03 (deassert the reset)
+	2. Write @0x0C => 0xFF (precharge + master on)
+	3. Write @0x00 => 0x30 (ONLNOL and ONLONOR set to 1)
+	4. Delay 500 ms
+	5. Write @0x0C => 0x01 (precharge off + master on)
+	6. Delay 1ms
+	7. Write @0x00 => 0x3C (ONLNOL, ONLNOR, ONDACR and ONDACL set to 1)
+*/
+	/* Make sure everything is off */
+	at73c213_write_reg(DAC_CTRL, 0x00);
+
+	msleep(500);
+
+	/* de-reset the device */
+    	at73c213_write_reg(DAC_RST, 0x03);
+
+	/* Turn on precharge */
+	at73c213_write_reg(DAC_PRECH, 0xFF);
+	at73c213_write_reg(DAC_CTRL, 0x30);
+
+    	/* Wait 500 ms*/
+    	msleep(500);
+
+	at73c213_write_reg(DAC_PRECH, 0x01);
+
+	msleep(1);
+
+	at73c213_write_reg(DAC_CTRL, 0x3C);
+	at73c213_write_reg(DAC_LLOG, 0x1f);
+	at73c213_write_reg(DAC_RLOG, 0x1f);
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_probe
+ *----------------------------------------------------------------------------*/
+static int __devinit at73c213_probe(struct spi_device *spi)
+{
+	int retval = 0;
+
+	if(!spi)
+		return -ENXIO;
+
+	at73c213_spi_device = spi;
+
+	return retval;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_remove
+ *----------------------------------------------------------------------------*/
+static int __devexit at73c213_remove(struct spi_device *spi)
+{
+	return 0;
+}
+
+#ifdef CONFIG_PM
+/*-----------------------------------------------------------------------------
+* snd_at73c213_suspend
+*----------------------------------------------------------------------------*/
+static int at73c213_suspend(struct spi_device *spi)
+{
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+* snd_at73c213_resume
+*----------------------------------------------------------------------------*/
+static int at73c213_resume(struct spi_device *spi)
+{
+	return 0;
+}
+#endif /* CONFIG_PM */
+
+/*-----------------------------------------------------------------------------
+ * AT73C213 Driver
+ *----------------------------------------------------------------------------*/
+static struct spi_driver at73c213_driver =
+{
+	.driver =
+	{
+		.name       = "at73c213",
+		.bus        = &spi_bus_type,
+		.owner      = THIS_MODULE,
+	}
+	,
+		.probe      = at73c213_probe,
+		.remove     = __devexit_p(at73c213_remove),
+		/* TODO:  investigate suspend and resume... */
+	#ifdef CONFIG_PM
+		.resume     = at73c213_resume,
+		.suspend    = at73c213_suspend,
+	#endif
+};
+
+/********************************************************************************
+*   Mixer
+********************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ *  Info functions
+ *----------------------------------------------------------------------------*/
+static int at73c213_info_pcm_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_info_t * uinfo)
+{
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 2;
+	uinfo->value.integer.min = 0x0;
+	uinfo->value.integer.max = 0x1f;
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ *  Get functions
+ *----------------------------------------------------------------------------*/
+static int at73c213_get_pcm_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	ucontrol->value.integer.value[0] = (0x1f - at73c213_read_reg(DAC_LLOG)); /*left */
+	ucontrol->value.integer.value[1] = (0x1f - at73c213_read_reg(DAC_RLOG)); /*right*/
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ *  Put functions
+ *----------------------------------------------------------------------------*/
+static int at73c213_put_pcm_volume(snd_kcontrol_t *kcontrol, snd_ctl_elem_value_t * ucontrol)
+{
+	at73c213_write_reg(DAC_LLOG,(0x1f - ucontrol->value.integer.value[0]));
+	at73c213_write_reg(DAC_RLOG,(0x1f - ucontrol->value.integer.value[1]));
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ *  Controls
+ *----------------------------------------------------------------------------*/
+static struct snd_kcontrol_new snd_at73c213_controls[] =
+{
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name  = "PCM Playback Volume",
+		.info  = at73c213_info_pcm_volume,
+		.get   = at73c213_get_pcm_volume,
+		.put   = at73c213_put_pcm_volume
+	},
+};
+
+/*-----------------------------------------------------------------------------
+ *  Controls
+ *----------------------------------------------------------------------------*/
+static int __devinit snd_chip_at73c213_mixer_new(snd_card_t *card)
+{
+	int idx, err;
+
+	snd_assert(card != NULL, return -EINVAL);
+
+	if(at73c213_spi_device == NULL) {
+		printk(KERN_WARNING "No at73c231_spi_device found\n");
+		return -EFAULT;
+	}
+
+	/*  Set Mixer IOCTL */
+	for (idx = 0; idx < ARRAY_SIZE(snd_at73c213_controls); idx++) {
+		if ((err = snd_ctl_add(card, snd_ctl_new1(&snd_at73c213_controls[idx], NULL))) < 0)
+			return err;
+	}
+
+	/* Init DAC Hardware */
+	at73c213_hw_init();
+
+	return 0;
+}
+
+/********************************************************************************
+*   DSP
+********************************************************************************/
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_playback_hw
+ *----------------------------------------------------------------------------*/
+static snd_pcm_hardware_t snd_at73c213_playback_hw =
+{
+	.info    = (	SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_BLOCK_TRANSFER  ),
+	.formats = SNDRV_PCM_FMTBIT_S16_LE,
+        .rates =  SNDRV_PCM_RATE_CONTINUOUS,
+        .rate_min =         48000,
+        .rate_max =         48000,
+    	.channels_min   = 2,
+    	.channels_max   = 2,
+    	.buffer_bytes_max = 64 * 1024 - 1,
+    	.period_bytes_min = 1024,
+    	.period_bytes_max = 64 * 1024 - 1,
+    	.periods_min    = 4,
+    	.periods_max    = 1024,
+};
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_pcm_open - open callback
+ *----------------------------------------------------------------------------*/
+static int snd_at73c213_pcm_open(snd_pcm_substream_t *substream)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	runtime->hw = snd_at73c213_playback_hw;
+	chip->substream = substream;
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_pcm_close - close callback
+ *----------------------------------------------------------------------------*/
+static int snd_at73c213_pcm_close(snd_pcm_substream_t *substream)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	chip->substream = NULL;
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_pcm_hw_params - hw_params callback
+ *----------------------------------------------------------------------------*/
+static int snd_at73c213_pcm_hw_params(snd_pcm_substream_t *substream,
+                                      snd_pcm_hw_params_t *hw_params)
+{
+	return snd_pcm_lib_malloc_pages(substream,
+                                    params_buffer_bytes(hw_params));
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_pcm_hw_free - hw_free callback
+ *----------------------------------------------------------------------------*/
+static int snd_at73c213_pcm_hw_free(snd_pcm_substream_t *substream)
+{
+    return snd_pcm_lib_free_pages(substream);
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_pcm_prepare - prepare callback
+ *----------------------------------------------------------------------------*/
+static int snd_at73c213_pcm_prepare(snd_pcm_substream_t *substream)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	struct platform_device *pdev = chip->pdev;
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int block_size;
+
+	block_size = frames_to_bytes(runtime, runtime->period_size);
+
+	chip->period = 0;
+
+	/* Make sure that our data are actually readable by the SSC */
+	dma_sync_single_for_device(&pdev->dev, runtime->dma_addr,
+			block_size, DMA_TO_DEVICE);
+	dma_sync_single_for_device(&pdev->dev, runtime->dma_addr + block_size,
+			block_size, DMA_TO_DEVICE);
+
+	writel(runtime->dma_addr, chip->ssc_regs + PDC_TPR);
+	writel(runtime->period_size * 2, chip->ssc_regs + PDC_TCR);
+	writel(runtime->dma_addr + block_size, chip->ssc_regs + PDC_TNPR);
+	writel(runtime->period_size * 2, chip->ssc_regs + PDC_TNCR);
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_pcm_trigger - trigger callback
+ *----------------------------------------------------------------------------*/
+static int snd_at73c213_pcm_trigger(snd_pcm_substream_t *substream,
+                                    int cmd)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	int retval = 0;
+	unsigned long flags = 0;
+
+	spin_lock_irqsave(&chip->lock, flags);
+
+	switch (cmd)
+	{
+		case SNDRV_PCM_TRIGGER_START:
+			writel(SSC_INT_ENDTX, chip->ssc_regs + SSC_IER);
+			writel(PDC_PTCR_TXTEN, chip->ssc_regs + PDC_PTCR);
+			break;
+		case SNDRV_PCM_TRIGGER_STOP:
+			writel(PDC_PTCR_TXTDIS, chip->ssc_regs + PDC_PTCR);
+			writel(SSC_INT_ENDTX, chip->ssc_regs + SSC_IDR);
+			break;
+		default:
+			printk(KERN_WARNING "at73c213: spurious command %x\n", cmd);
+			retval = -EINVAL;
+			break;
+	}
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	return retval;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_pcm_uframes_t - pointer callback
+ *----------------------------------------------------------------------------*/
+static snd_pcm_uframes_t snd_at73c213_pcm_pointer(snd_pcm_substream_t *substream)
+{
+	struct snd_at73c213 *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_uframes_t pos;
+	unsigned long bytes;
+
+	bytes = readl(chip->ssc_regs + PDC_TPR) - runtime->dma_addr;
+
+	pos = bytes_to_frames(runtime, bytes);
+	if (pos >= runtime->buffer_size)
+		pos -= runtime->buffer_size;
+
+	return pos;
+}
+
+/*-----------------------------------------------------------------------------
+ * operators
+ *----------------------------------------------------------------------------*/
+static snd_pcm_ops_t at73c213_playback_ops =
+{
+	.open       = snd_at73c213_pcm_open,
+	.close      = snd_at73c213_pcm_close,
+	.ioctl      = snd_pcm_lib_ioctl,
+	.hw_params  = snd_at73c213_pcm_hw_params,
+	.hw_free    = snd_at73c213_pcm_hw_free,
+	.prepare    = snd_at73c213_pcm_prepare,
+	.trigger    = snd_at73c213_pcm_trigger,
+	.pointer    = snd_at73c213_pcm_pointer,
+};
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_pcm_free free a pcm device
+ *----------------------------------------------------------------------------*/
+static void snd_at73c213_pcm_free(snd_pcm_t *pcm)
+{
+	struct snd_at73c213 *chip = snd_pcm_chip(pcm);
+
+	if (chip->pcm != 0 )
+	{
+		snd_pcm_lib_preallocate_free_for_all(chip->pcm);
+		chip->pcm = NULL;
+	}
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_new_pcm create a new pcm device
+ *----------------------------------------------------------------------------*/
+static int __devinit snd_at73c213_new_pcm(snd_card_t * card)
+{
+	snd_pcm_t *pcm;
+	struct snd_at73c213 * chip = card->private_data;
+	int err;
+
+	err = snd_pcm_new(chip->card, "AT73C213", 0, 1, 0, &pcm);
+	if (err)
+		return err;
+
+	pcm->private_data = chip;
+	pcm->private_free = snd_at73c213_pcm_free;
+	pcm->info_flags = SNDRV_PCM_INFO_BLOCK_TRANSFER;
+	pcm->private_data = chip;
+	strcpy( pcm->name, "AT73C213" );
+	chip->pcm = pcm;
+
+	/* set operators */
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at73c213_playback_ops);
+
+	/* pre-allocation of buffers */
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, NULL, 64 * 1024, 64 * 1024);
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_interrupt
+ *---------------------------------------------------------------------------*/
+static irqreturn_t snd_at73c213_interrupt(int irq, void *dev_id)
+{
+	struct snd_at73c213 *chip = dev_id;
+	struct platform_device *pdev = chip->pdev;
+	snd_pcm_runtime_t *runtime = chip->substream->runtime;
+	u32 status;
+	int offset, next_period, block_size;
+
+	spin_lock(&chip->lock);
+
+	block_size = frames_to_bytes(runtime, runtime->period_size);
+
+	status = readl(chip->ssc_regs + SSC_IMR);
+
+	if (status & SSC_INT_ENDTX)
+	{
+		chip->period++;
+		if (chip->period == runtime->periods)
+			chip->period = 0;
+		next_period = chip->period + 1;
+		if (next_period == runtime->periods)
+			next_period = 0;
+
+		offset = block_size * next_period;
+
+		/* Make sure that our data are actually readable by the SSC */
+		dma_sync_single_for_device(&pdev->dev, runtime->dma_addr + offset,
+				block_size, DMA_TO_DEVICE);
+		writel(runtime->dma_addr + offset, chip->ssc_regs + PDC_TNPR);
+		writel(runtime->period_size * 2, chip->ssc_regs + PDC_TNCR);
+
+		if (next_period == 0)
+		{
+			(void)readl(chip->ssc_regs + PDC_TPR);
+			(void)readl(chip->ssc_regs + PDC_TCR);
+		}
+	}
+	else
+	{
+		printk(KERN_WARNING
+				"Spurious SSC interrupt, status = 0x%08lx\n",
+				(unsigned long)status);
+		writel(status, chip->ssc_regs + SSC_IDR);
+	}
+
+	(void)readl(chip->ssc_regs + SSC_IMR);
+	spin_unlock(&chip->lock);
+
+	if (status & SSC_INT_ENDTX)
+		snd_pcm_period_elapsed(chip->substream);
+
+	return IRQ_HANDLED;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_chip_init
+ *----------------------------------------------------------------------------*/
+static int snd_at73c213_chip_init(struct snd_at73c213 *chip)
+{
+	/* Reset the SSC */
+	writel(SSC_CR_SWRST, chip->ssc_regs + SSC_CR);
+
+	/* Enable SSC and setup for I2S */
+	writel(chip->ssc_div, chip->ssc_regs + SSC_CMR);
+
+	/* CKO, START, STTDLY, PERIOD */
+	writel((1<<2)|(4<<8)|(1<<16)|(15<<24), chip->ssc_regs + SSC_TCMR);
+
+	/* DATLEN, MSBF, DATNB, FSLEN, FSOS */
+	writel((15<<0)|(1<<7)|(1<<8)|(15<<16)|(1<<20), chip->ssc_regs + SSC_TFMR);
+
+	/* Enable SSC RX */
+	writel(SSC_CR_TXEN, chip->ssc_regs + SSC_CR);
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_probe
+ *----------------------------------------------------------------------------*/
+static int __devinit snd_at73c213_probe(struct platform_device *pdev)
+{
+	struct atmel_at73c213_data *pdata = pdev->dev.platform_data;
+	struct snd_at73c213 *chip;
+	snd_card_t          *card;
+	int irq, ret;
+	struct resource *res;
+
+	/* register the soundcard */
+	card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, sizeof(struct snd_at73c213));
+	if (card == NULL){
+		return -ENOMEM;
+	}
+
+	chip = card->private_data;
+	chip->ssc_div = pdata->ssc_div;
+	chip->at73_mck = pdata->at73_mck;
+	spin_lock_init(&chip->lock);
+	chip->card = card;
+	strcpy( card->driver, "AT73C213" );
+	strcpy( card->shortname, "AT73C213" );
+	strcpy( card->longname, "AT73C213" );
+
+	if (!pdev)
+		return -ENXIO;
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (!res)
+		return -ENXIO;
+
+	irq = platform_get_irq(pdev, 0);
+	if (irq < 0)
+		return irq;
+	chip->irq = irq;
+
+	/* Request mem region */
+	if (!request_mem_region(res->start, res->end - res->start + 1, pdev->name))
+		return -EBUSY;
+
+	/* Remap SSC register */
+	chip->ssc_regs = ioremap(res->start, res->end - res->start + 1);
+	if (!chip->ssc_regs)
+		return -ENOMEM;
+
+	snd_chip_at73c213_mixer_new(card);
+
+	snd_at73c213_new_pcm(card);
+
+	ret = request_irq(chip->irq, snd_at73c213_interrupt, 0, "AT73C213", chip);
+	if (ret)
+		return ret;
+	snd_at73c213_chip_init(chip);
+
+	ret = snd_card_register(card);
+	if(ret)
+		return ret;
+
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_remove
+ *----------------------------------------------------------------------------*/
+static int __devexit snd_at73c213_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+/*-----------------------------------------------------------------------------
+ * snd_at73c213_driver
+ *----------------------------------------------------------------------------*/
+static struct platform_driver snd_at73c213_driver =
+{
+	.probe      = snd_at73c213_probe,
+	.remove     = __devexit_p(snd_at73c213_remove),
+	.driver     =
+	{
+		.name       = "atmel_ssc_at73c213",
+	}
+	,
+};
+
+static int __init snd_at73c213_init(void)
+{
+	int ret;
+
+	ret = spi_register_driver(&at73c213_driver);
+	if(ret)
+		return ret;
+
+	ret = platform_driver_register(&snd_at73c213_driver);
+	if(ret)
+	{
+		spi_unregister_driver(&at73c213_driver);
+		return ret;
+	}
+
+	return 0;
+}
+
+static void __exit snd_at73c213_exit(void)
+{
+	platform_driver_unregister(&snd_at73c213_driver);
+	spi_unregister_driver(&at73c213_driver);
+}
+
+/********************************************************************************
+*   Module
+********************************************************************************/
+MODULE_AUTHOR("Atmel");
+MODULE_DESCRIPTION("at73c213 snd driver");
+MODULE_LICENSE("GPL");
+
+module_init(snd_at73c213_init);
+module_exit(snd_at73c213_exit);
diff -uprN linux-2.6.20/sound/arm/at73c213.h linux-2.6.20-at92_e1.5/sound/arm/at73c213.h
--- linux-2.6.20/sound/arm/at73c213.h	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/sound/arm/at73c213.h	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,182 @@
+/*
+ * Driver for the AT73C213 16-bit stereo DAC
+ *
+ * Copyright (C) 2006 Atmel
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this
+ * distribution in the file called COPYING.
+ */
+
+#ifndef SND_AT73C213_MIXER_H_
+#define SND_AT73C213_MIXER_H_
+
+/* DAC control register */
+#define DAC_CTRL		0x00
+#define DAC_CTRL_ONPADRV	7
+#define DAC_CTRL_ONAUXIN	6
+#define DAC_CTRL_ONDACR		5
+#define DAC_CTRL_ONDACL		4
+#define DAC_CTRL_ONLNOR		3
+#define DAC_CTRL_ONLNOL		2
+#define DAC_CTRL_ONLNIR		1
+#define DAC_CTRL_ONLNIL		0
+
+/* DAC left line in gain register */
+#define DAC_LLIG		0x01
+#define DAC_LLIG_LLIG		0
+
+/* DAC right line in gain register */
+#define DAC_RLIG		0x02
+#define DAC_RLIG_RLIG		0
+
+/* DAC Left Master Playback Gain Register */
+#define DAC_LMPG		0x03
+#define DAC_LMPG_LMPG		0
+
+/* DAC Right Master Playback Gain Register */
+#define DAC_RMPG		0x04
+#define DAC_RMPG_RMPG		0
+
+/* DAC Left Line Out Gain Register */
+#define DAC_LLOG		0x05
+#define DAC_LLOG_LLOG		0
+
+/* DAC Right Line Out Gain Register */
+#define DAC_RLOG		0x06
+#define DAC_RLOG_RLOG		0
+
+/* DAC Output Level Control Register */
+#define DAC_OLC			0x07
+#define DAC_OLC_RSHORT		7
+#define DAC_OLC_ROLC		4
+#define DAC_OLC_LSHORT		3
+#define DAC_OLC_LOLC		0
+
+/* DAC Mixer Control Register */
+#define DAC_MC			0x08
+#define DAC_MC_INVR		5
+#define DAC_MC_INVL		4
+#define DAC_MC_RMSMIN2		3
+#define DAC_MC_RMSMIN1		2
+#define DAC_MC_LMSMIN2		1
+#define DAC_MC_LMSMIN1		0
+
+/* DAC Clock and Sampling Frequency Control Register */
+#define DAC_CSFC		0x09
+#define DAC_CSFC_OVRSEL		4
+
+/* DAC Miscellaneous Register */
+#define DAC_MISC		0x0A
+#define DAC_MISC_VCMCAPSEL	7
+#define DAC_MISC_DINTSEL	4
+#define DAC_MISC_DITHEN		3
+#define DAC_MISC_DEEMPEN	2
+#define DAC_MISC_NBITS		0
+
+/* DAC Precharge Control Register */
+#define DAC_PRECH		0x0C
+#define DAC_PRECH_PRCHGPDRV	7
+#define DAC_PRECH_PRCHGAUX1	6
+#define DAC_PRECH_PRCHGLNOR	5
+#define DAC_PRECH_PRCHGLNOL	4
+#define DAC_PRECH_PRCHGLNIR	3
+#define DAC_PRECH_PRCHGLNIL	2
+#define DAC_PRECH_PRCHG		1
+#define DAC_PRECH_ONMSTR	0
+
+/* DAC Auxiliary Input Gain Control Register */
+#define DAC_AUXG		0x0D
+#define DAC_AUXG_AUXG		0
+
+/* DAC Reset Register */
+#define DAC_RST			0x10
+#define DAC_RST_RESMASK		2
+#define DAC_RST_RESFILZ		1
+#define DAC_RST_RSTZ		0
+
+/* Power Amplifier Control Register */
+#define PA_CTRL			0x11
+#define PA_CTRL_APAON		6
+#define PA_CTRL_APAPRECH	5
+#define PA_CTRL_APALP		4
+#define PA_CTRL_APAGAIN		0
+
+/* PDC */
+#define PDC_RPR		0x100	/* Receive Pointer Register */
+#define PDC_RCR		0x104	/* Receive Counter Register */
+#define PDC_TPR		0x108	/* Transmit Pointer Register */
+#define PDC_TCR		0x10c	/* Transmit Counter Register */
+#define PDC_RNPR		0x110	/* Receive Next Pointer Register */
+#define PDC_RNCR		0x114	/* Receive Next Counter Register */
+#define PDC_TNPR		0x118	/* Transmit Next Pointer Register */
+#define PDC_TNCR		0x11c	/* Transmit Next Counter Register */
+
+#define PDC_PTCR		0x120	/* Transfer Control Register */
+#define		PDC_PTCR_RXTEN		(1 << 0)	/* Receiver Transfer Enable */
+#define		PDC_PTCR_RXTDIS		(1 << 1)	/* Receiver Transfer Disable */
+#define		PDC_PTCR_TXTEN		(1 << 8)	/* Transmitter Transfer Enable */
+#define		PDC_PTCR_TXTDIS		(1 << 9)	/* Transmitter Transfer Disable */
+
+#define PDC_PTSR		0x124	/* Transfer Status Register */
+#define SSC_CMR		0x04
+#define SSC_CR		0x00
+#define SSC_TCMR	0x18
+#define SSC_TFMR	0x1C
+
+/* SSC register definitions */
+#define SSC_CR		0x00
+#define SSC_CMR		0x04
+#define SSC_TCMR	0x18
+#define SSC_TFMR	0x1C
+#define SSC_THR		0x24
+#define SSC_SR		0x40
+#define SSC_IER		0x44
+#define SSC_IDR		0x48
+#define SSC_IMR		0x4C
+
+/* SSC fields definitions */
+#define SSC_CR_TXEN	0x00000100
+#define SSC_CR_TXDIS	0x00000200
+#define SSC_CR_SWRST	0x00008000
+
+/* SSC interrupt definitions */
+#define SSC0_IRQ	10
+#define SSC_INT_ENDTX	0x00000004
+#define SSC_INT_TXBUFE	0x00000008
+
+
+/* chip-specific data */
+struct snd_at73c213 {
+	snd_card_t			*card;
+	snd_pcm_t			*pcm;
+	snd_pcm_substream_t	*substream;
+	struct spi_device	*spi;
+	struct clk			*ssc_clk;
+	struct clk			*at73_mck;
+	spinlock_t			lock;
+	struct platform_device		*pdev;
+	void __iomem		*ssc_regs;
+	int					ext_clk_rate;
+	int 			ssc_div;
+	int					irq;
+	int					period;
+	u8					spi_wbuffer[2];
+	u8					spi_rbuffer[2];
+};
+#endif
+
diff -uprN linux-2.6.20/sound/arm/at91-ac97.c linux-2.6.20-at92_e1.5/sound/arm/at91-ac97.c
--- linux-2.6.20/sound/arm/at91-ac97.c	1969-12-31 19:00:00.000000000 -0500
+++ linux-2.6.20-at92_e1.5/sound/arm/at91-ac97.c	2008-02-07 10:24:59.000000000 -0500
@@ -0,0 +1,654 @@
+/* drivers/sound/arm/at91-ac97c.c
+ *
+ * Driver for the Atmel AC97 Controller
+ *
+ * Copyright (C) 2005 Atmel Norway
+ */
+
+
+#undef DEBUG
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/atmel_pdc.h>
+
+#include <sound/driver.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/ac97_codec.h>
+
+#include <asm/io.h>
+#include <asm/hardware.h>
+#include <asm/cacheflush.h>
+
+#include <asm/arch/gpio.h>
+#include <asm/arch/ac97c.h>
+#include <asm/arch/board.h>
+
+#define platform_num_resources(dev)     ((dev)->num_resources)
+#define platform_resource_start(dev, i) ((dev)->resource[(i)].start)
+#define platform_resource_end(dev, i)   ((dev)->resource[(i)].end)
+#define platform_resource_flags(dev, i) ((dev)->resource[(i)].flags)
+#define platform_resource_len(dev, i)                   \
+        (platform_resource_end((dev), (i)) -            \
+         platform_resource_start((dev), (i)) + 1)
+
+
+/* module parameters */
+static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
+static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
+static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;
+
+module_param_array(index, int, NULL, 0444);
+MODULE_PARM_DESC(index, "Index value for AC97 controller");
+module_param_array(id, charp, NULL, 0444);
+MODULE_PARM_DESC(id, "ID string for AC97 controller");
+module_param_array(enable, bool, NULL, 0444);
+MODULE_PARM_DESC(enable, "Enable AC97 controller");
+
+
+
+typedef struct at91_ac97 {
+	spinlock_t lock;
+	void *regs;
+	int period;
+	struct clk *ac97_clk;
+	snd_pcm_substream_t *playback_substream;
+	snd_card_t *card;
+	snd_pcm_t *pcm;
+	ac97_t *ac97;
+	ac97_bus_t *ac97_bus;
+	int irq;
+	struct platform_device *pdev;
+	u8 reset_pin;
+} at91_ac97_t;
+
+
+
+
+#define get_chip(card) ((at91_ac97_t *)(card)->private_data)
+
+
+
+#define ac97c_writel(chip, reg, val)			\
+	writel((val), (chip)->regs + AC97C_##reg)
+
+#define ac97c_readl(chip, reg)				\
+	readl((chip)->regs + AC97C_##reg)
+
+// PIO management functions
+void at91_ac97c_drive_reset(at91_ac97_t *chip, unsigned int value)
+{
+	at91_set_gpio_value(chip->reset_pin, value);
+}
+
+
+static const char driver_name[] = "at91-ac97";
+
+/* PCM part */
+
+static snd_pcm_hardware_t snd_at91_ac97_hw = {
+	.info			= (SNDRV_PCM_INFO_INTERLEAVED
+				   | SNDRV_PCM_INFO_MMAP
+				   | SNDRV_PCM_INFO_MMAP_VALID
+                                   | SNDRV_PCM_INFO_BLOCK_TRANSFER),
+	.formats		= SNDRV_PCM_FMTBIT_S16_LE,
+	.rates			= SNDRV_PCM_RATE_CONTINUOUS,
+	.rate_min		= 8000,
+	.rate_max		= 48000,
+	.channels_min		= 2,
+	.channels_max		= 2,
+	.buffer_bytes_max	= 256*1024,
+	.period_bytes_min	= 1024,
+	.period_bytes_max	= 4*1024,
+	.periods_min		= 1,
+	.periods_max		= 64,
+};
+
+static int snd_at91_ac97_playback_open(snd_pcm_substream_t *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+
+	runtime->hw = snd_at91_ac97_hw;
+	chip->playback_substream = substream;
+	chip->period = 0;
+
+	snd_printd(KERN_DEBUG "%s : snd_at91_ac97_playback_open\n\r", driver_name);
+
+	return 0;
+}
+
+static int snd_at91_ac97_playback_close(snd_pcm_substream_t *substream)
+{
+        at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+
+        chip->playback_substream = NULL;
+	return 0;
+}
+
+static int snd_at91_ac97_hw_params(snd_pcm_substream_t *substream,
+				    snd_pcm_hw_params_t *hw_params)
+{
+	int err;
+
+	err = snd_pcm_lib_malloc_pages(substream,
+				       params_buffer_bytes(hw_params));
+	return err;
+}
+
+static int snd_at91_ac97_hw_free(snd_pcm_substream_t *substream)
+{
+
+	snd_pcm_lib_free_pages(substream);
+
+	return 0;
+}
+
+static int snd_at91_ac97_playback_prepare(snd_pcm_substream_t *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	int block_size = frames_to_bytes(runtime, runtime->period_size);
+	unsigned long word = 0;
+
+	//clean_dcache_region(runtime->dma_area, block_size * 2);
+	snd_printd(KERN_DEBUG "%s : block_size = %d\n\r", driver_name, block_size);
+
+	/* Assign slots to channels */
+	switch (substream->runtime->channels) {
+          /* TODO: Support more than two channels */
+        case 1:
+          word |= AT91C_AC97C_CHID3_CA;
+          break;
+	case 2:
+        default:
+          /* Assign Left and Right slots (3,4) to Channel A */
+          word |= AT91C_AC97C_CHID3_CA | AT91C_AC97C_CHID4_CA;
+          break;
+	}
+
+	ac97c_writel(chip, OCA, word);
+
+	/*
+	 * Configure sample format and size.
+	 * FIXME: Avoid conflicts with capture channel.
+	 */
+        word = AT91C_AC97C_PDCEN | AT91C_AC97C_SIZE_16_BITS;
+
+        switch (runtime->format){
+        case SNDRV_PCM_FORMAT_S16_BE:
+          word |= AT91C_AC97C_CEM;
+          break;
+        case SNDRV_PCM_FORMAT_S16_LE:
+        default:
+          break;
+        }
+
+	ac97c_writel(chip, CAMR, word);
+
+        /* Set variable rate if needed */
+        if ( runtime->rate != 48000 ){
+          word = ac97c_readl(chip, MR);
+          word |= AT91C_AC97C_VRA;
+          ac97c_writel(chip, MR, word);
+        } else {
+          /* Clear Variable Rate Bit */
+          word = ac97c_readl(chip, MR);
+          word &= ~AT91C_AC97C_VRA;
+          ac97c_writel(chip, MR, word);
+        }
+
+        /* Set rate */
+        snd_ac97_set_rate(chip->ac97, AC97_PCM_FRONT_DAC_RATE, runtime->rate);
+
+	snd_printd(KERN_DEBUG "%s : dma_addr = %x\n\r : dma_area = %x\n\r : dma_bytes = %d\n\r",
+		   driver_name, runtime->dma_addr, runtime->dma_area, runtime->dma_bytes);
+
+	/* Initialize and start the PDC */
+	writel(runtime->dma_addr, chip->regs + ATMEL_PDC_TPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_TCR);
+	writel(runtime->dma_addr + block_size, chip->regs + ATMEL_PDC_TNPR);
+	writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
+
+	/* Enable Channel A interrupts */
+	ac97c_writel(chip, IER, AT91C_AC97C_CAEVT);
+
+	snd_printd(KERN_DEBUG "%s : snd_at91_ac97_playback_prepare\n\r", driver_name);
+
+	return 0;
+}
+
+static int at91_ac97_trigger(snd_pcm_substream_t *substream, int cmd)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	unsigned long camr, ptcr = 0, flags;
+	int err = 0;
+
+	spin_lock_irqsave(&chip->lock, flags);
+	camr = ac97c_readl(chip, CAMR);
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+          camr |= (AT91C_AC97C_CEN | AT91C_AC97C_ENDTX);
+	  ptcr = ATMEL_PDC_TXTEN;
+	  break;
+	case SNDRV_PCM_TRIGGER_STOP:
+          camr &= ~(AT91C_AC97C_CEN | AT91C_AC97C_ENDTX);
+	  ptcr = ATMEL_PDC_TXTDIS;
+          break;
+	default:
+          err = -EINVAL;
+          break;
+	}
+
+	ac97c_writel(chip, CAMR, camr);
+	writel(ptcr, chip->regs + ATMEL_PDC_PTCR);
+
+	spin_unlock_irqrestore(&chip->lock, flags);
+
+	snd_printd(KERN_DEBUG "%s : snd_at91_ac97_trigger\n\r", driver_name);
+
+	return err;
+}
+
+static snd_pcm_uframes_t snd_at91_ac97_pointer(snd_pcm_substream_t *substream)
+{
+	at91_ac97_t *chip = snd_pcm_substream_chip(substream);
+	snd_pcm_runtime_t *runtime = substream->runtime;
+	snd_pcm_uframes_t pos;
+	unsigned long bytes;
+
+	bytes = readl(chip->regs + ATMEL_PDC_TPR) - runtime->dma_addr;
+
+	pos = bytes_to_frames(runtime, bytes);
+	if (pos >= runtime->buffer_size)
+		pos -= runtime->buffer_size;
+
+	snd_printd(KERN_DEBUG "%s : snd_at91_ac97_pointer\n\r", driver_name);
+
+	return pos;
+}
+
+static snd_pcm_ops_t at91_ac97_playback_ops = {
+	.open		= snd_at91_ac97_playback_open,
+	.close		= snd_at91_ac97_playback_close,
+	.ioctl		= snd_pcm_lib_ioctl,
+	.hw_params	= snd_at91_ac97_hw_params,
+	.hw_free	= snd_at91_ac97_hw_free,
+	.prepare	= snd_at91_ac97_playback_prepare,
+	.trigger	= at91_ac97_trigger,
+	.pointer	= snd_at91_ac97_pointer,
+};
+
+
+static struct ac97_pcm at91_ac97_pcm_defs[] __devinitdata = {
+	/* Playback */
+	{
+		.exclusive = 1,
+		.r = { {
+			.slots = ((1 << AC97_SLOT_PCM_LEFT)
+				  | (1 << AC97_SLOT_PCM_RIGHT)),
+		} },
+	},
+};
+
+static int __devinit snd_at91_ac97_pcm_new(at91_ac97_t *chip)
+{
+	snd_pcm_t *pcm;
+	int err;
+
+	err = snd_ac97_pcm_assign(chip->ac97_bus, 1, at91_ac97_pcm_defs);
+	if (err)
+		return err;
+
+	err = snd_pcm_new(chip->card, "Atmel AC97", 0, 1, 0, &pcm);
+	if (err)
+		return err;
+
+	snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
+					      &chip->pdev->dev,
+					      128 * 1024, 256 * 1024);
+
+	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &at91_ac97_playback_ops);
+
+	pcm->private_data = chip;
+	pcm->info_flags = 0;
+	strcpy(pcm->name, "Atmel AC97");
+	chip->pcm = pcm;
+
+	return 0;
+}
+
+/* Mixer part */
+static int snd_at91_ac97_mixer_new(at91_ac97_t *chip)
+{
+	int err;
+	ac97_template_t template;
+
+	memset(&template, 0, sizeof(template));
+	template.private_data = chip;
+	template.num = 0;
+	template.addr = 0;
+	err = snd_ac97_mixer(chip->ac97_bus, &template, &chip->ac97);
+
+	return err;
+}
+
+
+static irqreturn_t snd_at91_ac97_interrupt(int irq, void *dev_id)
+{
+	at91_ac97_t *chip = dev_id;
+	unsigned long status;
+	unsigned long dummy;
+
+	status = ac97c_readl(chip, SR);
+
+	if (status & AT91C_AC97C_CAEVT) {
+		snd_pcm_runtime_t *runtime;
+		int offset, next_period, block_size;
+		unsigned long casr;
+
+		runtime = chip->playback_substream->runtime;
+		block_size = frames_to_bytes(runtime, runtime->period_size);
+
+		casr = ac97c_readl(chip, CASR);
+
+		if (casr & AT91C_AC97C_ENDTX) {
+			chip->period++;
+			if (chip->period == runtime->periods)
+				chip->period = 0;
+			next_period = chip->period + 1;
+			if (next_period == runtime->periods)
+				next_period = 0;
+
+			offset = block_size * next_period;
+
+			writel(runtime->dma_addr + offset, chip->regs + ATMEL_PDC_TNPR);
+			writel(block_size / 2, chip->regs + ATMEL_PDC_TNCR);
+
+			snd_pcm_period_elapsed(chip->playback_substream);
+		} else {
+                  printk(KERN_WARNING
+                         "Spurious AC97A interrupt, status = 0x%08lx\n",
+                         (unsigned long)casr);
+		}
+	} else {
+		printk(KERN_WARNING
+		       "Spurious AC97 interrupt, status = 0x%08lx\n",
+		       status);
+	}
+
+	dummy = ac97c_readl(chip, SR);
+
+	return IRQ_HANDLED;
+}
+
+
+/* CODEC part */
+
+static void snd_at91_ac97_hard_reset(at91_ac97_t *chip)
+{
+       // Enable AC97 Controller.
+       // Perform a cold (hard) reset of the AC97 codec.
+       ac97c_writel(chip, MR, 0);
+       ac97c_writel(chip, MR, AT91C_AC97C_ENA);
+
+       at91_ac97c_drive_reset(chip, 0);
+       udelay(1);
+       at91_ac97c_drive_reset(chip, 1);
+       udelay(1);
+}
+
+
+static void snd_at91_ac97_write(ac97_t *ac97, unsigned short reg,
+				 unsigned short val)
+{
+	at91_ac97_t *chip = ac97->private_data;
+	unsigned long word;
+	int timeout = 0x100;
+
+	snd_printd(KERN_DEBUG "%s : Writing codec register 0x%x = 0x%x\n\r", driver_name, reg, val);
+
+	word = (reg & 0x7f) << 16 | val;
+
+	do {
+		if (ac97c_readl(chip, COSR) & AT91C_AC97C_TXRDY) {
+			ac97c_writel(chip, COTHR, word);
+			return;
+		}
+		udelay(1);
+	} while (--timeout);
+
+	snd_printk(KERN_WARNING "at91-ac97: codec write timeout\n\r");
+}
+
+static unsigned short snd_at91_ac97_read(ac97_t *ac97,
+					  unsigned short reg)
+{
+	at91_ac97_t *chip = ac97->private_data;
+	unsigned long word;
+	int timeout = 0x100;
+
+
+	word = (0x80 | (reg & 0x7f)) << 16;
+
+	do {
+                if (ac97c_readl(chip, COSR) & AT91C_AC97C_TXRDY){
+                     ac97c_writel(chip, COTHR, word);
+                     break;
+                }
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		goto timed_out;
+
+	timeout = 0x100;
+
+	do {
+                if (ac97c_readl(chip, COSR) & AT91C_AC97C_RXRDY){
+                     unsigned short val = (unsigned short) ac97c_readl(chip, CORHR);
+		     return val;
+		}
+		udelay(1);
+	} while (--timeout);
+
+	if (!timeout)
+		goto timed_out;
+
+timed_out:
+	snd_printk(KERN_WARNING "at91-ac97: codec read timeout\n\r");
+	return 0xffff;
+}
+
+static void snd_at91_ac97_warm_reset(ac97_t *ac97)
+{
+        at91_ac97_t *chip = ac97->private_data;
+	volatile unsigned int mr = ac97c_readl(chip, MR);
+
+	mr |= AT91C_AC97C_WRST;
+
+	ac97c_writel(chip, MR, mr);
+	udelay(1);
+
+	mr &= ~AT91C_AC97C_WRST;
+	ac97c_writel(chip, MR, mr);
+}
+
+static void snd_at91_ac97_destroy(snd_card_t *card)
+{
+	at91_ac97_t *chip = get_chip(card);
+
+	if (chip->irq != -1)
+		free_irq(chip->irq, chip);
+
+	if (chip->regs)
+		iounmap(chip->regs);
+}
+
+static int __devinit snd_at91_ac97_create(snd_card_t *card,
+					   struct platform_device *pdev)
+{
+	static ac97_bus_ops_t ops = {
+		.write	= snd_at91_ac97_write,
+		.read	= snd_at91_ac97_read,
+		.reset  = snd_at91_ac97_warm_reset,
+	};
+
+	at91_ac97_t *chip = get_chip(card);
+	int irq, err = 0;
+
+
+
+	card->private_free = snd_at91_ac97_destroy;
+
+	spin_lock_init(&chip->lock);
+	chip->card = card;
+	chip->pdev = pdev;
+	chip->irq = -1;
+
+	if (!(platform_resource_flags(pdev, 0) & IORESOURCE_MEM)
+	    || !(platform_resource_flags(pdev, 1) & IORESOURCE_IRQ))
+		return -ENODEV;
+
+	irq = platform_resource_start(pdev, 1);
+
+	err = request_irq(irq, snd_at91_ac97_interrupt, 0, "ac97", chip);
+	if (err) {
+		snd_printk(KERN_WARNING "unable to request IRQ%d\n", irq);
+		return err;
+	}
+
+	chip->irq = irq;
+    	snd_printk(KERN_INFO "AC97C regs = %08X \n", platform_resource_start(pdev, 0));
+    	snd_printk(KERN_INFO "AC97C irq  = %d \n",irq);
+
+	chip->regs = ioremap(platform_resource_start(pdev, 0),
+			     platform_resource_len(pdev, 0));
+	if (!chip->regs) {
+	        snd_printk(KERN_WARNING "unable to remap AC97C io memory\n");
+		return -ENOMEM;
+	}
+
+	snd_card_set_dev(card, &pdev->dev);
+
+	err = snd_ac97_bus(card, 0, &ops, chip, &chip->ac97_bus);
+
+	return err;
+}
+
+static int __devinit snd_at91_ac97_probe(struct platform_device *pdev)
+{
+	static int dev;
+	struct atmel_ac97_data *pdata = pdev->dev.platform_data;
+	snd_card_t *card;
+	at91_ac97_t *chip;
+	int err;
+
+
+	if (dev >= SNDRV_CARDS)
+		return -ENODEV;
+	if (!enable[dev]) {
+		dev++;
+		return -ENOENT;
+	}
+
+	card = snd_card_new(index[dev], id[dev], THIS_MODULE,
+			    sizeof(at91_ac97_t));
+	if (!card)
+		return -ENOMEM;
+	chip = get_chip(card);
+
+	err = snd_at91_ac97_create(card, pdev);
+	if (err)
+		goto out_free_card;
+
+	// Enable AC97 Controller clock
+	chip->reset_pin = pdata->reset_pin;
+	chip->ac97_clk = clk_get(NULL, "ac97_clk");
+	if(!chip->ac97_clk)
+		goto out_free_card;
+
+	clk_enable(chip->ac97_clk);
+
+	// Perform a codec hard reset.
+	// This also enables the AC97 Controller.
+	snd_at91_ac97_hard_reset(chip);
+
+	err = snd_at91_ac97_mixer_new(chip);
+	if (err)
+		goto out_free_card;
+
+	err = snd_at91_ac97_pcm_new(chip);
+	if (err)
+		goto out_free_card;
+
+	strcpy(card->driver, "ac97c");
+	strcpy(card->shortname, "Atmel AC97");
+	sprintf(card->longname, "Atmel AC97 Controller at %#lx, irq %i",
+		(unsigned long) platform_resource_start(pdev, 0), (int) chip->irq);
+
+	err = snd_card_register(card);
+	if (err)
+		goto out_free_card;
+
+	dev_set_drvdata(&pdev->dev, card);
+	dev++;
+	return 0;
+
+out_free_card:
+	snd_card_free(card);
+	return err;
+}
+
+static int __devexit snd_at91_ac97_remove(struct  platform_device *pdev)
+{
+        snd_card_t *card = dev_get_drvdata(&pdev->dev);
+	at91_ac97_t *chip = get_chip(card);
+
+
+	snd_card_free(card);
+
+	// Disable AC97 Controller
+	ac97c_writel(chip, MR, 0);
+
+	// Disable AC97 Controller clock
+	clk_disable(chip->ac97_clk);
+
+	dev_set_drvdata(&pdev->dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver at91_ac97_driver =
+{
+	.probe      = snd_at91_ac97_probe,
+	.remove     = __devexit_p(snd_at91_ac97_remove),
+	.driver     =
+	{
+		.name       = "ac97c",
+	}
+	,
+};
+
+static int __init at91_ac97_init(void)
+{
+	return platform_driver_register(&at91_ac97_driver);
+}
+
+static void __exit at91_ac97_exit(void)
+{
+	platform_driver_unregister(&at91_ac97_driver);
+}
+
+module_init(at91_ac97_init);
+module_exit(at91_ac97_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Driver for Atmel AC97 Controller");
+MODULE_AUTHOR("Atmel");
