summaryrefslogtreecommitdiffstats
path: root/recipes/linux/linux/acern30
diff options
context:
space:
mode:
Diffstat (limited to 'recipes/linux/linux/acern30')
-rw-r--r--recipes/linux/linux/acern30/defconfig1199
-rw-r--r--recipes/linux/linux/acern30/gcc4-fixes.patch97
-rw-r--r--recipes/linux/linux/acern30/gpio-sysfs.patch252
-rw-r--r--recipes/linux/linux/acern30/mmc-plus.patch17
-rw-r--r--recipes/linux/linux/acern30/n30-apm.patch73
-rw-r--r--recipes/linux/linux/acern30/n30-backlight.patch97
-rw-r--r--recipes/linux/linux/acern30/n30-batt.patch242
-rw-r--r--recipes/linux/linux/acern30/n30-buttons.patch100
-rw-r--r--recipes/linux/linux/acern30/n30-cleanup.patch30
-rw-r--r--recipes/linux/linux/acern30/n30-hardcode.patch158
-rw-r--r--recipes/linux/linux/acern30/n30-lcd.patch66
-rw-r--r--recipes/linux/linux/acern30/n30-mmc-power.patch24
-rw-r--r--recipes/linux/linux/acern30/n30-mmc-wprotect.patch54
-rw-r--r--recipes/linux/linux/acern30/n30-mmc.patch53
-rw-r--r--recipes/linux/linux/acern30/n30-nand-hack.patch32
-rw-r--r--recipes/linux/linux/acern30/n30-nand.patch97
-rw-r--r--recipes/linux/linux/acern30/n30-pm.patch296
-rw-r--r--recipes/linux/linux/acern30/n30-ts.patch43
-rw-r--r--recipes/linux/linux/acern30/n30-usbstart.patch59
-rw-r--r--recipes/linux/linux/acern30/n35.patch80
-rw-r--r--recipes/linux/linux/acern30/regdump.patch279
-rw-r--r--recipes/linux/linux/acern30/s3c2410-nand-pm.patch53
-rw-r--r--recipes/linux/linux/acern30/s3c2410_lcd-pm.c80
-rw-r--r--recipes/linux/linux/acern30/s3c2410_ts-pm.patch73
-rw-r--r--recipes/linux/linux/acern30/s3c2410fb-resume.patch13
-rw-r--r--recipes/linux/linux/acern30/s3c2410mci-pm.patch84
-rw-r--r--recipes/linux/linux/acern30/series27
-rw-r--r--recipes/linux/linux/acern30/spi.patch121
-rw-r--r--recipes/linux/linux/acern30/wingel-hacking.patch1146
29 files changed, 4945 insertions, 0 deletions
diff --git a/recipes/linux/linux/acern30/defconfig b/recipes/linux/linux/acern30/defconfig
new file mode 100644
index 0000000000..860dc9b12c
--- /dev/null
+++ b/recipes/linux/linux/acern30/defconfig
@@ -0,0 +1,1199 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.14-h1940
+# Mon Jan 9 17:37:51 2006
+#
+CONFIG_ARM=y
+CONFIG_MMU=y
+CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+
+#
+# Code maturity level options
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_CLEAN_COMPILE=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_POSIX_MQUEUE is not set
+# CONFIG_BSD_PROCESS_ACCT is not set
+CONFIG_SYSCTL=y
+# CONFIG_AUDIT is not set
+CONFIG_HOTPLUG=y
+CONFIG_KOBJECT_UEVENT=y
+# CONFIG_IKCONFIG is not set
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_EMBEDDED=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+# CONFIG_BASE_FULL is not set
+CONFIG_FUTEX=y
+CONFIG_EPOLL=y
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+# CONFIG_SHMEM is not set
+CONFIG_CC_ALIGN_FUNCTIONS=0
+CONFIG_CC_ALIGN_LABELS=0
+CONFIG_CC_ALIGN_LOOPS=0
+CONFIG_CC_ALIGN_JUMPS=0
+CONFIG_TINY_SHMEM=y
+CONFIG_BASE_SMALL=1
+
+#
+# Loadable module support
+#
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_FORCE_UNLOAD=y
+CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
+# CONFIG_MODULE_SRCVERSION_ALL is not set
+CONFIG_KMOD=y
+
+#
+# System Type
+#
+# 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_CAMELOT is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_IOP3XX is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+# CONFIG_ARCH_SA1100 is not set
+CONFIG_ARCH_S3C2410=y
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_AAEC2000 is not set
+
+#
+# S3C24XX Implementations
+#
+# CONFIG_MACH_ANUBIS is not set
+# CONFIG_ARCH_BAST is not set
+CONFIG_ARCH_H1940=y
+CONFIG_MACH_N30=y
+CONFIG_MACH_N35=y
+# CONFIG_ARCH_SMDK2410 is not set
+# CONFIG_ARCH_S3C2440 is not set
+# CONFIG_MACH_VR1000 is not set
+# CONFIG_MACH_RX3715 is not set
+# CONFIG_MACH_OTOM is not set
+# CONFIG_MACH_NEXCODER_2440 is not set
+CONFIG_CPU_S3C2410=y
+
+#
+# S3C2410 Boot
+#
+
+#
+# S3C2410 Setup
+#
+CONFIG_S3C2410_DMA=y
+# CONFIG_S3C2410_DMA_DEBUG is not set
+CONFIG_S3C2410_PM_DEBUG=y
+CONFIG_S3C2410_PM_CHECK=y
+CONFIG_S3C2410_PM_CHECK_CHUNKSIZE=64
+CONFIG_S3C2410_LOWLEVEL_UART_PORT=0
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_ARM920T=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4T=y
+CONFIG_CPU_CACHE_V4WT=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_COPY_V4WB=y
+CONFIG_CPU_TLB_V4WBI=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
+
+#
+# Bus support
+#
+CONFIG_ISA_DMA_API=y
+
+#
+# PCCARD (PCMCIA/CardBus) support
+#
+# CONFIG_PCCARD is not set
+
+#
+# Kernel Features
+#
+# CONFIG_PREEMPT is not set
+CONFIG_NO_IDLE_HZ=y
+# 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_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="rw root=/dev/ram console=tty0 console=ttySAC2,115200n8 verbose panic=30"
+# 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
+
+#
+# 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=y
+CONFIG_APM=y
+
+#
+# Networking
+#
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+# CONFIG_IP_PNP_RARP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_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_TUNNEL is not set
+# CONFIG_INET_DIAG is not set
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_BIC=y
+# CONFIG_IPV6 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
+# 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_NET_DIVERT is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_NET_CLS_ROUTE is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+CONFIG_IRDA=y
+
+#
+# IrDA protocols
+#
+CONFIG_IRLAN=y
+CONFIG_IRCOMM=y
+# CONFIG_IRDA_ULTRA is not set
+
+#
+# IrDA options
+#
+CONFIG_IRDA_CACHE_LAST_LSAP=y
+CONFIG_IRDA_FAST_RR=y
+CONFIG_IRDA_DEBUG=y
+
+#
+# Infrared-port device drivers
+#
+
+#
+# SIR device drivers
+#
+CONFIG_IRTTY_SIR=y
+
+#
+# Dongle support
+#
+# CONFIG_DONGLE is not set
+
+#
+# Old SIR device drivers
+#
+# CONFIG_IRPORT_SIR is not set
+
+#
+# Old Serial dongle support
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_USB_IRDA is not set
+# CONFIG_SIGMATEL_FIR is not set
+# CONFIG_NSC_FIR is not set
+# CONFIG_WINBOND_FIR is not set
+# CONFIG_SMC_IRCC_FIR is not set
+# CONFIG_ALI_FIR is not set
+# CONFIG_VIA_FIR is not set
+CONFIG_BT=y
+CONFIG_BT_L2CAP=y
+CONFIG_BT_SCO=y
+CONFIG_BT_RFCOMM=y
+CONFIG_BT_RFCOMM_TTY=y
+CONFIG_BT_BNEP=y
+# CONFIG_BT_BNEP_MC_FILTER is not set
+# CONFIG_BT_BNEP_PROTO_FILTER is not set
+CONFIG_BT_HIDP=y
+
+#
+# Bluetooth device drivers
+#
+# CONFIG_BT_HCIUSB is not set
+CONFIG_BT_HCIUART=y
+CONFIG_BT_HCIUART_H4=y
+CONFIG_BT_HCIUART_BCSP=y
+# CONFIG_BT_HCIBCM203X is not set
+# CONFIG_BT_HCIBPA10X is not set
+# CONFIG_BT_HCIBFUSB is not set
+# CONFIG_BT_HCIVHCI 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
+
+#
+# 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 is not set
+# CONFIG_MTD_AFS_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+
+#
+# Mapping drivers for chip access
+#
+# CONFIG_MTD_COMPLEX_MAPPINGS is not set
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLKMTD 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=y
+CONFIG_MTD_NAND_IDS=y
+CONFIG_MTD_NAND_S3C2410=y
+# CONFIG_MTD_NAND_S3C2410_DEBUG is not set
+CONFIG_MTD_NAND_S3C2410_HWECC=y
+# CONFIG_MTD_NAND_DISKONCHIP is not set
+# CONFIG_MTD_NAND_NANDSIM 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 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=4096
+CONFIG_BLK_DEV_INITRD=y
+# CONFIG_CDROM_PKTCDVD is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+# CONFIG_ATA_OVER_ETH is not set
+
+#
+# ATA/ATAPI/MFM/RLL support
+#
+# CONFIG_IDE is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+# CONFIG_SCSI 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=y
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+
+#
+# PHY device support
+#
+
+#
+# Ethernet (10 or 100Mbit)
+#
+# CONFIG_NET_ETHERNET 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
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_TSDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+CONFIG_S3C2410_BUTTONS=y
+CONFIG_INPUT_MOUSE=y
+# CONFIG_MOUSE_PS2 is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+CONFIG_INPUT_TOUCHSCREEN=y
+CONFIG_TOUCHSCREEN_S3C2410=y
+# CONFIG_TOUCHSCREEN_S3C2410_DEBUG is not set
+# 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_INPUT_MISC=y
+CONFIG_INPUT_UINPUT=y
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_SERPORT=y
+# CONFIG_SERIO_LIBPS2 is not set
+# CONFIG_SERIO_RAW is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+# CONFIG_SERIAL_8250 is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_S3C2410=y
+CONFIG_SERIAL_S3C2410_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+CONFIG_UNIX98_PTYS=y
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=10
+
+#
+# IPMI
+#
+# CONFIG_IPMI_HANDLER is not set
+
+#
+# Watchdog Cards
+#
+# CONFIG_WATCHDOG is not set
+# CONFIG_NVRAM is not set
+# CONFIG_RTC is not set
+CONFIG_S3C2410_RTC=y
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# Ftape, the floppy tape device driver
+#
+# CONFIG_RAW_DRIVER is not set
+
+#
+# TPM devices
+#
+
+#
+# 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_PARPORT_LIGHT is not set
+CONFIG_I2C_S3C2410=y
+# CONFIG_I2C_STUB 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_RTC8564 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_RTC_X1205_I2C 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
+
+#
+# Hardware Monitoring support
+#
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ASB100 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_FSCHER is not set
+# CONFIG_SENSORS_FSCPOS is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+
+#
+# Misc devices
+#
+
+#
+# Multimedia Capabilities Port drivers
+#
+
+#
+# Multimedia devices
+#
+# CONFIG_VIDEO_DEV is not set
+
+#
+# Digital Video Broadcasting Devices
+#
+# CONFIG_DVB is not set
+
+#
+# Graphics support
+#
+CONFIG_FB=y
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+CONFIG_FB_SOFT_CURSOR=y
+# CONFIG_FB_MACMODES is not set
+CONFIG_FB_MODE_HELPERS=y
+# CONFIG_FB_TILEBLITTING is not set
+# CONFIG_FB_S1D13XXX is not set
+CONFIG_FB_S3C2410=y
+# CONFIG_FB_S3C2410_DEBUG 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=y
+CONFIG_FONTS=y
+# CONFIG_FONT_8x8 is not set
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_CLEAN_4x6 is not set
+CONFIG_FONT_CLEAN_5x8=y
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+
+#
+# Logo configuration
+#
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+CONFIG_LOGO_LINUX_VGA16=y
+CONFIG_LOGO_LINUX_CLUT224=y
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+CONFIG_BACKLIGHT_DEVICE=y
+CONFIG_LCD_CLASS_DEVICE=y
+CONFIG_LCD_DEVICE=y
+CONFIG_BACKLIGHT_S3C2410=y
+
+#
+# Sound
+#
+CONFIG_SOUND=y
+
+#
+# Advanced Linux Sound Architecture
+#
+CONFIG_SND=y
+CONFIG_SND_TIMER=y
+CONFIG_SND_PCM=y
+CONFIG_SND_SEQUENCER=y
+# CONFIG_SND_SEQ_DUMMY is not set
+CONFIG_SND_OSSEMUL=y
+CONFIG_SND_MIXER_OSS=y
+CONFIG_SND_PCM_OSS=y
+CONFIG_SND_SEQUENCER_OSS=y
+# CONFIG_SND_VERBOSE_PRINTK is not set
+# CONFIG_SND_DEBUG is not set
+
+#
+# Generic devices
+#
+# CONFIG_SND_DUMMY is not set
+# CONFIG_SND_VIRMIDI is not set
+# CONFIG_SND_MTPAV is not set
+# CONFIG_SND_SERIAL_U16550 is not set
+# CONFIG_SND_MPU401 is not set
+
+#
+# ALSA ARM devices
+#
+
+#
+# USB devices
+#
+# CONFIG_SND_USB_AUDIO is not set
+
+#
+# Open Sound System
+#
+# CONFIG_SOUND_PRIME is not set
+
+#
+# USB support
+#
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+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_SUSPEND=y
+# 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_OBSOLETE_OSS_USB_DRIVER is not set
+# 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 is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+CONFIG_USB_HIDINPUT=y
+# CONFIG_HID_FF is not set
+# CONFIG_USB_HIDDEV 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_MTOUCH is not set
+# CONFIG_USB_ITMTOUCH is not set
+# CONFIG_USB_EGALAX is not set
+# CONFIG_USB_YEALINK is not set
+# CONFIG_USB_XPAD is not set
+# CONFIG_USB_ATI_REMOTE 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
+
+#
+# USB Multimedia devices
+#
+# CONFIG_USB_DABUSB is not set
+
+#
+# Video4Linux support is needed for USB Multimedia device support
+#
+
+#
+# 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 is not set
+CONFIG_USB_MON=y
+
+#
+# USB port drivers
+#
+
+#
+# USB Serial Converter support
+#
+CONFIG_USB_SERIAL=y
+# CONFIG_USB_SERIAL_CONSOLE is not set
+CONFIG_USB_SERIAL_GENERIC=y
+# CONFIG_USB_SERIAL_AIRPRIME is not set
+# CONFIG_USB_SERIAL_BELKIN is not set
+# CONFIG_USB_SERIAL_WHITEHEAT is not set
+# CONFIG_USB_SERIAL_DIGI_ACCELEPORT is not set
+# CONFIG_USB_SERIAL_CP2101 is not set
+# CONFIG_USB_SERIAL_CYPRESS_M8 is not set
+# CONFIG_USB_SERIAL_EMPEG is not set
+# CONFIG_USB_SERIAL_FTDI_SIO is not set
+# CONFIG_USB_SERIAL_VISOR is not set
+# CONFIG_USB_SERIAL_IPAQ is not set
+# CONFIG_USB_SERIAL_IR is not set
+# CONFIG_USB_SERIAL_EDGEPORT is not set
+# CONFIG_USB_SERIAL_EDGEPORT_TI is not set
+# CONFIG_USB_SERIAL_GARMIN is not set
+# CONFIG_USB_SERIAL_IPW is not set
+# CONFIG_USB_SERIAL_KEYSPAN_PDA is not set
+# CONFIG_USB_SERIAL_KEYSPAN is not set
+# CONFIG_USB_SERIAL_KLSI is not set
+# CONFIG_USB_SERIAL_KOBIL_SCT is not set
+# CONFIG_USB_SERIAL_MCT_U232 is not set
+# CONFIG_USB_SERIAL_NOKIA_DKU2 is not set
+CONFIG_USB_SERIAL_PL2303=y
+# CONFIG_USB_SERIAL_HP4X is not set
+# CONFIG_USB_SERIAL_SAFE is not set
+# CONFIG_USB_SERIAL_TI is not set
+# CONFIG_USB_SERIAL_CYBERJACK is not set
+# CONFIG_USB_SERIAL_XIRCOM is not set
+# CONFIG_USB_SERIAL_OMNINET is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 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_CYTHERM is not set
+# CONFIG_USB_PHIDGETKIT is not set
+# CONFIG_USB_PHIDGETSERVO is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_LD 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_S3C2410=y
+CONFIG_USB_S3C2410=y
+# CONFIG_USB_S3C2410_DEBUG is not set
+# CONFIG_USB_GADGET_DUMMY_HCD is not set
+# CONFIG_USB_GADGET_DUALSPEED is not set
+# CONFIG_USB_ZERO is not set
+CONFIG_USB_ETH=y
+CONFIG_USB_ETH_RNDIS=y
+# CONFIG_USB_GADGETFS is not set
+# CONFIG_USB_FILE_STORAGE is not set
+# CONFIG_USB_G_SERIAL is not set
+
+#
+# MMC/SD Card support
+#
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_WBSD is not set
+CONFIG_MMC_S3C2410=y
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+# CONFIG_EXT2_FS_POSIX_ACL is not set
+# CONFIG_EXT2_FS_SECURITY is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_FS_MBCACHE=y
+# CONFIG_REISERFS_FS is not set
+# CONFIG_JFS_FS is not set
+# CONFIG_FS_POSIX_ACL is not set
+# CONFIG_XFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=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=y
+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_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_RAMFS=y
+# CONFIG_RELAYFS_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_JFFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_COMPRESSION_OPTIONS is not set
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_RTIME=y
+# CONFIG_JFFS2_RUBIN is not set
+# CONFIG_CRAMFS is not set
+# 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=y
+# CONFIG_NFS_V3_ACL 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_LOCKD_V4=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=y
+# CONFIG_NLS_KOI8_R is not set
+# CONFIG_NLS_KOI8_U is not set
+# CONFIG_NLS_UTF8 is not set
+
+#
+# Profiling support
+#
+# CONFIG_PROFILING is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_DEBUG_KERNEL=y
+CONFIG_MAGIC_SYSRQ=y
+CONFIG_LOG_BUF_SHIFT=16
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_DEBUG_FS is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_DEBUG_USER is not set
+# CONFIG_DEBUG_WAITQ is not set
+# CONFIG_DEBUG_ERRORS is not set
+CONFIG_DEBUG_LL=y
+# CONFIG_DEBUG_ICEDCC is not set
+CONFIG_DEBUG_S3C2410_PORT=y
+CONFIG_DEBUG_S3C2410_UART=0
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+
+#
+# Cryptographic options
+#
+# CONFIG_CRYPTO is not set
+
+#
+# Hardware crypto devices
+#
+
+#
+# Library routines
+#
+CONFIG_CRC_CCITT=y
+# CONFIG_CRC16 is not set
+CONFIG_CRC32=y
+# CONFIG_LIBCRC32C is not set
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
diff --git a/recipes/linux/linux/acern30/gcc4-fixes.patch b/recipes/linux/linux/acern30/gcc4-fixes.patch
new file mode 100644
index 0000000000..722bca7c73
--- /dev/null
+++ b/recipes/linux/linux/acern30/gcc4-fixes.patch
@@ -0,0 +1,97 @@
+--- linux-2.6.14/arch/arm/mm/alignment.c.org 2007-03-06 22:50:23.000000000 +0000
++++ linux-2.6.14/arch/arm/mm/alignment.c 2007-03-06 22:49:21.000000000 +0000
+@@ -110,7 +110,7 @@
+ return len;
+ }
+
+-static int proc_alignment_write(struct file *file, const char __user *buffer,
++static int proc_alignment_write(struct file *file, /*const*/ char __user *buffer,
+ unsigned long count, void *data)
+ {
+ char mode;
+--- linux-2.6.14/lib/bitmap.c.org 2005-10-28 00:02:08.000000000 +0000
++++ linux-2.6.14/lib/bitmap.c 2007-03-07 00:49:39.000000000 +0000
+@@ -345,11 +345,12 @@
+ * characters and for grouping errors such as "1,,5", ",44", "," and "".
+ * Leading and trailing whitespace accepted, but not embedded whitespace.
+ */
+-int bitmap_parse(const char __user *ubuf, unsigned int ubuflen,
++int bitmap_parse(const char __user *_ubuf, unsigned int ubuflen,
+ unsigned long *maskp, int nmaskbits)
+ {
+ int c, old_c, totaldigits, ndigits, nchunks, nbits;
+ u32 chunk;
++ char __user *ubuf = _ubuf;
+
+ bitmap_zero(maskp, nmaskbits);
+
+--- linux-2.6.14/arch/arm/nwfpe/fpa11_cpdt.c.org 2005-10-28 00:02:08.000000000 +0000
++++ linux-2.6.14/arch/arm/nwfpe/fpa11_cpdt.c 2007-03-06 22:52:09.000000000 +0000
+@@ -29,14 +29,14 @@
+
+ #include <asm/uaccess.h>
+
+-static inline void loadSingle(const unsigned int Fn, const unsigned int __user *pMem)
++static inline void loadSingle(const unsigned int Fn, /*const*/ unsigned int __user *pMem)
+ {
+ FPA11 *fpa11 = GET_FPA11();
+ fpa11->fType[Fn] = typeSingle;
+ get_user(fpa11->fpreg[Fn].fSingle, pMem);
+ }
+
+-static inline void loadDouble(const unsigned int Fn, const unsigned int __user *pMem)
++static inline void loadDouble(const unsigned int Fn, /*const*/ unsigned int __user *pMem)
+ {
+ FPA11 *fpa11 = GET_FPA11();
+ unsigned int *p;
+@@ -52,7 +52,7 @@
+ }
+
+ #ifdef CONFIG_FPE_NWFPE_XP
+-static inline void loadExtended(const unsigned int Fn, const unsigned int __user *pMem)
++static inline void loadExtended(const unsigned int Fn, /*const*/ unsigned int __user *pMem)
+ {
+ FPA11 *fpa11 = GET_FPA11();
+ unsigned int *p;
+@@ -64,7 +64,7 @@
+ }
+ #endif
+
+-static inline void loadMultiple(const unsigned int Fn, const unsigned int __user *pMem)
++static inline void loadMultiple(const unsigned int Fn, /*const*/ unsigned int __user *pMem)
+ {
+ FPA11 *fpa11 = GET_FPA11();
+ register unsigned int *p;
+--- linux-2.6.14/fs/proc/proc_misc.c.org 2005-10-28 00:02:08.000000000 +0000
++++ linux-2.6.14/fs/proc/proc_misc.c 2007-03-06 23:17:01.000000000 +0000
+@@ -535,7 +535,7 @@
+ /*
+ * writing 'C' to /proc/sysrq-trigger is like sysrq-C
+ */
+-static ssize_t write_sysrq_trigger(struct file *file, const char __user *buf,
++static ssize_t write_sysrq_trigger(struct file *file, /*const*/ char __user *buf,
+ size_t count, loff_t *ppos)
+ {
+ if (count) {
+--- linux-2.6.14/drivers/char/vc_screen.c.org 2007-03-06 22:43:07.000000000 +0000
++++ linux-2.6.14/drivers/char/vc_screen.c 2007-03-07 00:02:25.000000000 +0000
+@@ -419,7 +419,7 @@
+ while (this_round > 1) {
+ unsigned short w;
+
+- w = get_unaligned(((const unsigned short *)con_buf0));
++ w = get_unaligned(((/*const*/ unsigned short *)con_buf0));
+ vcs_scr_writew(vc, w, org++);
+ con_buf0 += 2;
+ this_round -= 2;
+--- linux-2.6.14/drivers/input/mousedev.c.org 2007-03-07 01:28:18.000000000 +0000
++++ linux-2.6.14/drivers/input/mousedev.c 2007-03-07 01:37:01.000000000 +0000
+@@ -495,7 +495,7 @@
+ }
+
+
+-static ssize_t mousedev_write(struct file * file, const char __user * buffer, size_t count, loff_t *ppos)
++static ssize_t mousedev_write(struct file * file, /*const*/ char __user * buffer, size_t count, loff_t *ppos)
+ {
+ struct mousedev_list *list = file->private_data;
+ unsigned char c;
diff --git a/recipes/linux/linux/acern30/gpio-sysfs.patch b/recipes/linux/linux/acern30/gpio-sysfs.patch
new file mode 100644
index 0000000000..b3fde0f9d6
--- /dev/null
+++ b/recipes/linux/linux/acern30/gpio-sysfs.patch
@@ -0,0 +1,252 @@
+This patch adds a lot of sysfs entries for the different GPIO lines.
+It allows me to poke at different parts of the hardware to see what
+happens. This allowed me to discover the Bluetooth cutoff switch for
+example.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/Makefile
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/Makefile
++++ linux-2.6.14/arch/arm/mach-s3c2410/Makefile
+@@ -42,3 +42,5 @@ obj-$(CONFIG_MACH_VR1000) += mach-vr1000
+ obj-$(CONFIG_MACH_RX3715) += mach-rx3715.o
+ obj-$(CONFIG_MACH_OTOM) += mach-otom.o
+ obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
++
++obj-y += gpio-sysfs.o
+Index: linux-2.6.14/arch/arm/mach-s3c2410/gpio-sysfs.c
+===================================================================
+--- /dev/null
++++ linux-2.6.14/arch/arm/mach-s3c2410/gpio-sysfs.c
+@@ -0,0 +1,232 @@
++#include <linux/version.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/backlight.h>
++#include <linux/notifier.h>
++#include <linux/ctype.h>
++#include <linux/err.h>
++#include <linux/fb.h>
++#include <asm/bug.h>
++
++#include <asm/arch/regs-gpio.h>
++
++#include <asm/arch/regs-clock.h>
++
++static ssize_t s3c2410_gpio_name_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++
++ return snprintf(buf, PAGE_SIZE, "%d\n", pdev->id);
++}
++
++static ssize_t s3c2410_gpio_val_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++
++ return snprintf(buf, PAGE_SIZE, "%d\n",
++ s3c2410_gpio_getpin(pdev->id) ? 1 : 0);
++}
++
++static ssize_t s3c2410_gpio_val_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ int val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (*endp && !isspace(*endp))
++ return -EINVAL;
++
++ s3c2410_gpio_setpin(pdev->id, val ? 1 : 0);
++
++ return count;
++}
++
++static DEVICE_ATTR(name, 0444,
++ s3c2410_gpio_name_show,
++ NULL);
++
++static DEVICE_ATTR(val, 0666,
++ s3c2410_gpio_val_show,
++ s3c2410_gpio_val_store);
++
++
++static int __init s3c2410_gpio_probe(struct device *dev)
++{
++ device_create_file(dev, &dev_attr_name);
++ device_create_file(dev, &dev_attr_val);
++ return 0;
++}
++
++static int s3c2410_gpio_remove(struct device *dev)
++{
++ return 0;
++}
++
++static struct device_driver s3c2410_gpio_driver = {
++ .name = "s3c2410-gpio",
++ .bus = &platform_bus_type,
++ .probe = s3c2410_gpio_probe,
++ .remove = s3c2410_gpio_remove,
++};
++
++static struct platform_device s3c_device_gpio[32 * 8];
++
++static ssize_t s3c2410_clkslow_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ unsigned long clkslow = __raw_readl(S3C2410_CLKSLOW);
++
++ return snprintf(buf, PAGE_SIZE, "0x%08lx\n", clkslow);
++}
++
++static ssize_t s3c2410_clkslow_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ unsigned long val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (*endp && !isspace(*endp))
++ return -EINVAL;
++
++ printk("CLKSLOW <= 0x%lx\n", val);
++
++ __raw_writel(val, S3C2410_CLKSLOW);
++
++ return count;
++}
++
++static DEVICE_ATTR(clkslow, 0666,
++ s3c2410_clkslow_show,
++ s3c2410_clkslow_store);
++
++static ssize_t s3c2410_clkcon_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ unsigned long clkclkcon = __raw_readl(S3C2410_CLKCON);
++
++ return snprintf(buf, PAGE_SIZE, "0x%08lx\n", clkclkcon);
++}
++
++static ssize_t s3c2410_clkcon_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ unsigned long val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (*endp && !isspace(*endp))
++ return -EINVAL;
++
++ printk("CLKCON <= 0x%lx\n", val);
++
++ __raw_writel(val, S3C2410_CLKCON);
++
++ return count;
++}
++
++static DEVICE_ATTR(clkcon, 0666,
++ s3c2410_clkcon_show,
++ s3c2410_clkcon_store);
++
++static ssize_t s3c2410_misccr_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ unsigned long misccr = __raw_readl(S3C2410_MISCCR);
++
++ return snprintf(buf, PAGE_SIZE, "0x%08lx\n", misccr);
++}
++
++static ssize_t s3c2410_misccr_store(struct device *dev,
++ struct device_attribute *attr,
++ const char *buf, size_t count)
++{
++ unsigned long val;
++ char *endp;
++
++ val = simple_strtoul(buf, &endp, 0);
++ if (*endp && !isspace(*endp))
++ return -EINVAL;
++
++ printk("MISCCR <= 0x%lx\n", val);
++
++ __raw_writel(val, S3C2410_MISCCR);
++
++ return count;
++}
++
++static DEVICE_ATTR(misccr, 0666,
++ s3c2410_misccr_show,
++ s3c2410_misccr_store);
++
++static int __init s3c2410_regs_probe(struct device *dev)
++{
++ device_create_file(dev, &dev_attr_clkslow);
++ device_create_file(dev, &dev_attr_clkcon);
++ device_create_file(dev, &dev_attr_misccr);
++ return 0;
++}
++
++static int s3c2410_regs_remove(struct device *dev)
++{
++ return 0;
++}
++
++
++static struct device_driver s3c2410_regs_driver = {
++ .name = "s3c2410-regs",
++ .bus = &platform_bus_type,
++ .probe = s3c2410_regs_probe,
++ .remove = s3c2410_regs_remove,
++};
++
++static struct platform_device s3c_device_regs = {
++ .name = "s3c2410-regs",
++ .id = -1,
++};
++
++static int __init s3c2410_gpio_init(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(s3c_device_gpio); i++) {
++ s3c_device_gpio[i].name = "s3c2410-gpio";
++ s3c_device_gpio[i].id = i;
++ platform_device_register(&s3c_device_gpio[i]);
++ }
++
++ driver_register(&s3c2410_gpio_driver);
++ driver_register(&s3c2410_regs_driver);
++
++ platform_device_register(&s3c_device_regs);
++
++ return 0;
++}
++
++static void __exit s3c2410_gpio_cleanup(void)
++{
++ driver_unregister(&s3c2410_regs_driver);
++ driver_unregister(&s3c2410_gpio_driver);
++}
++
++module_init(s3c2410_gpio_init);
++module_exit(s3c2410_gpio_cleanup);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Christer Weinigel <christer@weinigel.se>");
++MODULE_DESCRIPTION("S3C2410 GPIO Driver");
++
++/*
++ Local variables:
++ compile-command: "make -k -C ../../../.. linux "
++ c-basic-offset: 8
++ End:
++*/
diff --git a/recipes/linux/linux/acern30/mmc-plus.patch b/recipes/linux/linux/acern30/mmc-plus.patch
new file mode 100644
index 0000000000..d88ac531cf
--- /dev/null
+++ b/recipes/linux/linux/acern30/mmc-plus.patch
@@ -0,0 +1,17 @@
+Treat MMCA version 4 cards a version 3 cards. It seem to work for me,
+but it may break things horribly.
+
+So you may not want to use this patch.
+
+Index: linux-2.6.14/drivers/mmc/mmc.c
+===================================================================
+--- linux-2.6.14.orig/drivers/mmc/mmc.c
++++ linux-2.6.14/drivers/mmc/mmc.c
+@@ -495,6 +495,7 @@ static void mmc_decode_cid(struct mmc_ca
+
+ case 2: /* MMC v2.0 - v2.2 */
+ case 3: /* MMC v3.1 - v3.3 */
++ case 4: /* MMC Plus? */
+ card->cid.manfid = UNSTUFF_BITS(resp, 120, 8);
+ card->cid.oemid = UNSTUFF_BITS(resp, 104, 16);
+ card->cid.prod_name[0] = UNSTUFF_BITS(resp, 96, 8);
diff --git a/recipes/linux/linux/acern30/n30-apm.patch b/recipes/linux/linux/acern30/n30-apm.patch
new file mode 100644
index 0000000000..00b34c9a46
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-apm.patch
@@ -0,0 +1,73 @@
+Implement a apm_get_power_status handler for the n30. The handler
+gets the battery charge from the msp430 chip using i2c and sets the ac
+line information based on GPG1 (charger power) and GPC7 (usb power).
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -31,6 +31,7 @@
+ #include <linux/delay.h>
+ #include <linux/device.h>
+ #include <linux/kthread.h>
++#include <linux/i2c.h>
+
+ #include <linux/mmc/protocol.h>
+ #include <linux/mtd/mtd.h>
+@@ -44,6 +45,7 @@
+ #include <asm/hardware/iomd.h>
+ #include <asm/io.h>
+ #include <asm/irq.h>
++#include <asm/apm.h>
+ #include <asm/mach-types.h>
+
+ #include <asm/arch/regs-serial.h>
+@@ -527,6 +529,37 @@ static int n30_usbstart_thread(void *unu
+ return 0;
+ }
+
++#ifdef CONFIG_APM
++static void n30_get_power_status(struct apm_power_info *info)
++{
++#ifdef CONFIG_I2C_S3C2410
++ u8 charge;
++ struct i2c_adapter *adap;
++ struct i2c_msg msg[] = {
++ { .addr = 0x0b, .flags = I2C_M_RD, .buf = &charge, .len = 1 }
++ };
++
++ if ((adap = i2c_get_adapter(0)) != NULL) {
++ if (i2c_transfer(adap, msg, 1) == 1)
++ info->battery_life = charge;
++ i2c_put_adapter(adap);
++ }
++#endif
++
++ if (s3c2410_gpio_getpin(S3C2410_GPC7))
++ info->ac_line_status = 0x01; /* on charger power */
++ else if (s3c2410_gpio_getpin(S3C2410_GPG1))
++ info->ac_line_status = 0x02; /* on USB power */
++ else
++ info->ac_line_status = 0x00; /* on battery power */
++
++ /* TODO I could put some values in these variables based on
++ * the battery life and the ac_line_status. --wingel */
++ info->battery_status = 0xff;
++ info->battery_flag = 0xff;
++}
++#endif
++
+ static void __init n30_init(void)
+ {
+ s3c24xx_fb_set_platdata(&n30_lcdcfg);
+@@ -550,6 +583,10 @@ static void __init n30_init(void)
+ s3c2410_gpio_setpin(S3C2410_GPC5, 1);
+
+ kthread_run(n30_usbstart_thread, NULL, "n30_usbstart");
++
++#ifdef CONFIG_APM
++ apm_get_power_status = n30_get_power_status;
++#endif
+ }
+
+ MACHINE_START(N30, "Acer-N30")
diff --git a/recipes/linux/linux/acern30/n30-backlight.patch b/recipes/linux/linux/acern30/n30-backlight.patch
new file mode 100644
index 0000000000..2b339960f7
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-backlight.patch
@@ -0,0 +1,97 @@
+This patch adds a few functions to control the backlight on the n30.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -45,8 +45,10 @@
+ #include <asm/arch/regs-serial.h>
+ #include <asm/arch/regs-gpio.h>
+ #include <asm/arch/regs-lcd.h>
++#include <asm/arch/regs-timer.h>
+ #include <asm/arch/iic.h>
+ #include <asm/arch/fb.h>
++#include <asm/arch/lcd.h>
+
+ #include <linux/serial_core.h>
+
+@@ -121,9 +123,71 @@ static struct s3c2410fb_mach_info n30_lc
+ .bpp= {16,16,16},
+ };
+
++static void n30_backlight_power(int on)
++{
++ s3c2410_gpio_pullup(S3C2410_GPB1, 1);
++ s3c2410_gpio_cfgpin(S3C2410_GPB1, S3C2410_GPB1_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPB1, on);
++}
++
++static void n30_lcd_power(int on)
++{
++ /* Turning these off will save about 10mA */
++ s3c2410_gpio_setpin(S3C2410_GPB8, on); /* CLOCK driver? */
++ s3c2410_gpio_setpin(S3C2410_GPB9, on); /* VSYNC driver? */
++ s3c2410_gpio_setpin(S3C2410_GPB10, on); /* HSYYNC driver? */
++}
++
++#define BRIGHTNESS_MAX 28
++#define BRIGHTNESS_OFFSET 5
++
++static void n30_set_brightness(int level)
++{
++ unsigned long tcmpb0;
++ unsigned long tcon;
++
++ if (level < 0)
++ level = 0;
++
++ if (level > BRIGHTNESS_MAX)
++ level = BRIGHTNESS_MAX;
++
++ tcmpb0 = level ? level + BRIGHTNESS_OFFSET : 0;
++
++ printk("brightness level %d, tcmpb0 %lu\n", level, tcmpb0);
++
++ /* configure power on/off */
++ n30_backlight_power(level ? 1 : 0);
++
++ writel(34, S3C2410_TCNTB(0));
++
++ tcon = readl(S3C2410_TCON);
++ tcon &= ~0x0F;
++ tcon |= S3C2410_TCON_T0RELOAD;
++ tcon |= S3C2410_TCON_T0MANUALUPD;
++
++ writel(tcon, S3C2410_TCON);
++ writel(0x22, S3C2410_TCNTB(0));
++ writel(tcmpb0, S3C2410_TCMPB(0));
++
++ /* start the timer running */
++ tcon |= S3C2410_TCON_T0START;
++ tcon &= ~S3C2410_TCON_T0MANUALUPD;
++ writel(tcon, S3C2410_TCON);
++}
++
++static struct s3c2410_bl_mach_info n30_blcfg __initdata = {
++ .backlight_max = BRIGHTNESS_MAX,
++ .backlight_default = BRIGHTNESS_MAX / 2,
++ .backlight_power = n30_backlight_power,
++ .set_brightness = n30_set_brightness,
++ .lcd_power = n30_lcd_power
++};
++
+ static struct platform_device *n30_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
++ &s3c_device_bl,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+@@ -160,6 +224,7 @@ static void __init n30_init_irq(void)
+ static void __init n30_init(void)
+ {
+ s3c24xx_fb_set_platdata(&n30_lcdcfg);
++ set_s3c2410bl_info(&n30_blcfg);
+
+ s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
+
diff --git a/recipes/linux/linux/acern30/n30-batt.patch b/recipes/linux/linux/acern30/n30-batt.patch
new file mode 100644
index 0000000000..e5eb9e7812
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-batt.patch
@@ -0,0 +1,242 @@
+A battery controller i2c driver for the n30.
+
+I don't use this driver any more, it was much nicer to use the ARM APM
+emulation to expose this data.
+
+Index: linux-2.6.14/drivers/hwmon/Kconfig
+===================================================================
+--- linux-2.6.14.orig/drivers/hwmon/Kconfig
++++ linux-2.6.14/drivers/hwmon/Kconfig
+@@ -290,6 +290,16 @@
+ This driver can also be built as a module. If so, the module
+ will be called max1619.
+
++config SENSORS_N30_BATT
++ tristate "Acer N30 Battery Controller"
++ depends on HWMON && I2C && MACH_N30
++ help
++ If you say yes here you get support for the battery controller
++ found inside the Acer N30 PDA.
++
++ This driver can also be built as a module. If so, the module
++ will be called n30_batt.
++
+ config SENSORS_PC87360
+ tristate "National Semiconductor PC87360 family"
+ depends on HWMON && I2C && EXPERIMENTAL
+Index: linux-2.6.14/drivers/hwmon/Makefile
+===================================================================
+--- linux-2.6.14.orig/drivers/hwmon/Makefile
++++ linux-2.6.14/drivers/hwmon/Makefile
+@@ -35,6 +35,7 @@
+ obj-$(CONFIG_SENSORS_LM90) += lm90.o
+ obj-$(CONFIG_SENSORS_LM92) += lm92.o
+ obj-$(CONFIG_SENSORS_MAX1619) += max1619.o
++obj-$(CONFIG_SENSORS_N30_BATT) += n30_batt.o
+ obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
+ obj-$(CONFIG_SENSORS_SIS5595) += sis5595.o
+ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
+Index: linux-2.6.14/drivers/hwmon/n30_batt.c
+===================================================================
+--- linux-2.6.14.orig/drivers/hwmon/n30_batt.c
++++ linux-2.6.14/drivers/hwmon/n30_batt.c
+@@ -0,0 +1,199 @@
++/*
++ * n30_batt.c - Support for the Acer N30 Battery Controller
++ * Copyright (c) 2005 Christer Weinigel <christer@weinigel.se>
++ *
++ * 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/config.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++#include <linux/i2c.h>
++#include <linux/hwmon.h>
++#include <asm/mach-types.h>
++#include <asm/apm.h>
++
++static unsigned short normal_i2c[] = { I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short probe[] = { I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short ignore[] = { I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short force[] = { -1, 0x0b, I2C_CLIENT_END, I2C_CLIENT_END };
++static unsigned short *forces[] = { force, NULL };
++
++static struct i2c_client_address_data addr_data = {
++ .normal_i2c = normal_i2c,
++ .probe = probe,
++ .ignore = ignore,
++ .forces = forces,
++};
++
++struct n30_batt_data {
++ struct i2c_client client;
++ struct semaphore update_lock;
++ unsigned long last_updated; /* last update in jiffies */
++ u8 charge;
++};
++
++static struct n30_batt_data *n30_batt_update_device(struct device *dev)
++{
++ struct i2c_client *client = to_i2c_client(dev);
++ struct n30_batt_data *data = i2c_get_clientdata(client);
++
++ down(&data->update_lock);
++
++ if (time_after(jiffies, data->last_updated + 3 * HZ)) {
++ int value;
++
++ value = i2c_smbus_read_byte(client);
++
++ if (value == -1)
++ printk(KERN_WARNING "n30-batt: unable to read charge\n");
++ else
++ data->charge = value;
++ data->last_updated = jiffies;
++ }
++
++ up(&data->update_lock);
++
++ return data;
++}
++
++static ssize_t show_charge(struct device *dev, struct device_attribute *attr, char *buf)
++{
++ struct n30_batt_data *data = n30_batt_update_device(dev);
++ return sprintf(buf, "%d\n", data->charge);
++}
++
++static DEVICE_ATTR(charge, S_IRUGO, show_charge, NULL);
++
++static struct i2c_driver n30_batt_driver;
++
++static struct device *n30_batt_dev;
++
++static int n30_batt_detect(struct i2c_adapter *adapter, int address, int kind)
++{
++ struct i2c_client *new_client;
++ struct n30_batt_data *data;
++ int err = 0;
++ int value;
++
++ printk(KERN_INFO "detect n30 Battery controller\n");
++
++ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
++ goto exit;
++
++ printk(KERN_INFO "kmalloc n30 Battery controller\n");
++
++ if (!(data = kmalloc(sizeof(struct n30_batt_data), GFP_KERNEL))) {
++ err = -ENOMEM;
++ goto exit;
++ }
++ memset(data, 0, sizeof(struct n30_batt_data));
++
++ new_client = &data->client;
++ i2c_set_clientdata(new_client, data);
++ new_client->addr = address;
++ new_client->adapter = adapter;
++ new_client->driver = &n30_batt_driver;
++ new_client->flags = 0;
++ strlcpy(new_client->name, "n30_batt", I2C_NAME_SIZE);
++
++ if ((value = i2c_smbus_read_byte(new_client)) == -1) {
++ printk(KERN_ERR "n30_batt: unable to read charge value\n");
++ err = -ENXIO;
++ goto exit_free;
++ }
++
++ init_MUTEX(&data->update_lock);
++ data->charge = value;
++ data->last_updated = jiffies;
++
++ printk(KERN_DEBUG "n30_batt: battery charge is %d%%\n", data->charge);
++
++ if ((err = i2c_attach_client(new_client)))
++ goto exit_free;
++
++ device_create_file(&new_client->dev, &dev_attr_charge);
++
++ n30_batt_dev = &new_client->dev;
++
++ return 0;
++
++exit_free:
++ kfree(data);
++exit:
++ return err;
++}
++
++static int n30_batt_attach_adapter(struct i2c_adapter *adapter)
++{
++ printk(KERN_INFO "attaching n30 Battery controller\n");
++ return i2c_probe(adapter, &addr_data, n30_batt_detect);
++}
++
++static int n30_batt_detach_client(struct i2c_client *client)
++{
++ n30_batt_dev = NULL;
++ i2c_detach_client(client);
++ kfree(i2c_get_clientdata(client));
++ return 0;
++}
++
++static struct i2c_driver n30_batt_driver = {
++ .owner = THIS_MODULE,
++ .name = "n30_batt",
++ .flags = I2C_DF_NOTIFY,
++ .attach_adapter = n30_batt_attach_adapter,
++ .detach_client = n30_batt_detach_client,
++};
++
++static void n30_get_power_status(struct apm_power_info *info)
++{
++ if (n30_batt_dev) {
++ struct n30_batt_data *data = n30_batt_update_device(n30_batt_dev);
++
++ info->ac_line_status = 0xff;
++ info->battery_status = 0xff;
++ info->battery_flag = 0xff;
++ info->battery_life = data->charge;
++ info->time = -1;
++ info->units = -1;
++ }
++}
++
++static int __init sensors_n30_batt_init(void)
++{
++ printk(KERN_INFO "n30 Battery controller\n");
++
++ if (!machine_is_n30())
++ return -ENODEV;
++ printk(KERN_INFO "adding n30 Battery controller\n");
++
++ apm_get_power_status = n30_get_power_status;
++
++ return i2c_add_driver(&n30_batt_driver);
++}
++
++static void __exit sensors_n30_batt_exit(void)
++{
++ i2c_del_driver(&n30_batt_driver);
++}
++
++MODULE_AUTHOR("Christer Weinigel <christer@weinigel.se>");
++MODULE_DESCRIPTION("Acer n30 Battery Controller");
++MODULE_LICENSE("GPL");
++
++module_init(sensors_n30_batt_init);
++module_exit(sensors_n30_batt_exit);
diff --git a/recipes/linux/linux/acern30/n30-buttons.patch b/recipes/linux/linux/acern30/n30-buttons.patch
new file mode 100644
index 0000000000..ff1214e698
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-buttons.patch
@@ -0,0 +1,100 @@
+Add support for the buttons on the n30.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -46,10 +46,12 @@
+ #include <asm/arch/regs-gpio.h>
+ #include <asm/arch/regs-lcd.h>
+ #include <asm/arch/regs-timer.h>
++#include <asm/arch/irqs.h>
+ #include <asm/arch/iic.h>
+ #include <asm/arch/fb.h>
+ #include <asm/arch/lcd.h>
+ #include <asm/arch/ts.h>
++#include <asm/arch/buttons.h>
+
+ #include <linux/serial_core.h>
+
+@@ -194,11 +196,68 @@ static struct s3c2410_ts_mach_info n30_t
+ .oversampling_shift = 6,
+ };
+
++static struct s3c2410_button n30_buttons[] = {
++ { IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, KEY_POWER,
++ "Power", 0 },
++
++ { IRQ_EINT17, S3C2410_GPG9, S3C2410_GPG9_EINT17, KEY_UP,
++ "Up_arrow", 0 },
++ { IRQ_EINT16, S3C2410_GPG8, S3C2410_GPG8_EINT16, KEY_DOWN,
++ "Down_arrow", 0 },
++ { IRQ_EINT15, S3C2410_GPG7, S3C2410_GPG7_EINT15, KEY_ENTER,
++ "Select", 0 },
++
++ { IRQ_EINT7, S3C2410_GPF7, S3C2410_GPF7_EINT7, KEY_HOMEPAGE,
++ "Home", 0 },
++ { IRQ_EINT6, S3C2410_GPF6, S3C2410_GPF6_EINT6, KEY_CALENDAR,
++ "Calendar", 0 },
++ { IRQ_EINT5, S3C2410_GPF5, S3C2410_GPF5_EINT5, KEY_COFFEE,
++ "Contacts", 0 }, /* TODO: find a better key :P */
++ { IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, KEY_MAIL,
++ "Mail", 0 },
++};
++
++static struct s3c2410_butt_mach_info n30_buttons_cfg __initdata = {
++ .buttons = n30_buttons,
++ .size = ARRAY_SIZE(n30_buttons),
++};
++
++static struct s3c2410_button n35_buttons[] = {
++ { IRQ_EINT0, S3C2410_GPF0, S3C2410_GPF0_EINT0, KEY_POWER,
++ "Power", 0 },
++
++ { IRQ_EINT13, S3C2410_GPG5, S3C2410_GPG5_EINT13, KEY_LEFT,
++ "Left_arrow", 0 },
++ { IRQ_EINT14, S3C2410_GPG6, S3C2410_GPG6_EINT14, KEY_RIGHT,
++ "Right_arrow", 0 },
++ { IRQ_EINT17, S3C2410_GPG9, S3C2410_GPG9_EINT17, KEY_UP,
++ "Up_arrow", 0 },
++ { IRQ_EINT16, S3C2410_GPG8, S3C2410_GPG8_EINT16, KEY_DOWN,
++ "Down_arrow", 0 },
++ { IRQ_EINT15, S3C2410_GPG7, S3C2410_GPG7_EINT15, KEY_ENTER,
++ "Select", 0 },
++
++ { IRQ_EINT7, S3C2410_GPF7, S3C2410_GPF7_EINT7, KEY_HOMEPAGE,
++ "Home", 0 },
++ { IRQ_EINT6, S3C2410_GPF6, S3C2410_GPF6_EINT6, KEY_CALENDAR,
++ "Calendar", 0 },
++ { IRQ_EINT5, S3C2410_GPF5, S3C2410_GPF5_EINT5, KEY_COFFEE,
++ "Contacts", 0 }, /* TODO: find a better key :P */
++ { IRQ_EINT4, S3C2410_GPF4, S3C2410_GPF4_EINT4, KEY_MAIL,
++ "Mail", 0 },
++};
++
++static struct s3c2410_butt_mach_info n35_buttons_cfg __initdata = {
++ .buttons = n35_buttons,
++ .size = ARRAY_SIZE(n35_buttons),
++};
++
+ static struct platform_device *n30_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+ &s3c_device_bl,
+ &s3c_device_ts,
++ &s3c_device_buttons,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+@@ -238,6 +297,11 @@ static void __init n30_init(void)
+ set_s3c2410bl_info(&n30_blcfg);
+ set_s3c2410ts_info(&n30_ts_cfg);
+
++ if (machine_is_n30())
++ s3c24xx_butt_set_platdata(&n30_buttons_cfg);
++ if (machine_is_n35())
++ s3c24xx_butt_set_platdata(&n35_buttons_cfg);
++
+ s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
+
+ /* Turn off suspend on both USB ports, and switch the
diff --git a/recipes/linux/linux/acern30/n30-cleanup.patch b/recipes/linux/linux/acern30/n30-cleanup.patch
new file mode 100644
index 0000000000..ea1c966ae9
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-cleanup.patch
@@ -0,0 +1,30 @@
+Clean up some junk from the official kernel.
+
+The s3c2410.h include isn't needed.
+
+The compile-command is something that's only useful for me personally
+and doesn't belong in the mainstream kernel.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -39,7 +39,6 @@
+
+ #include <linux/serial_core.h>
+
+-#include "s3c2410.h"
+ #include "clock.h"
+ #include "devs.h"
+ #include "cpu.h"
+@@ -137,10 +136,3 @@ MACHINE_START(N30, "Acer-N30")
+ .init_irq = n30_init_irq,
+ .map_io = n30_map_io,
+ MACHINE_END
+-
+-/*
+- Local variables:
+- compile-command: "make ARCH=arm CROSS_COMPILE=/usr/local/arm/3.3.2/bin/arm-linux- -k -C ../../.."
+- c-basic-offset: 8
+- End:
+-*/
diff --git a/recipes/linux/linux/acern30/n30-hardcode.patch b/recipes/linux/linux/acern30/n30-hardcode.patch
new file mode 100644
index 0000000000..735e18ca4c
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-hardcode.patch
@@ -0,0 +1,158 @@
+This patch hardcodes a lot of register settings so that I can boot
+directly from flash on the n30.
+
+Is there a nicer way of doing this?
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -349,9 +349,148 @@ static struct s3c24xx_board n30_board __
+ .devices_count = ARRAY_SIZE(n30_devices)
+ };
+
++/* Lots of hardcoded stuff, but it sets up the hardware in a useful
++ * state so that we can boot Linux directly from flash. */
++static void __init n30_hwinit(void)
++{
++ /* GPA0-11 special functions -- unknown what they do
++ * GPA12 N30 special function -- unknown what it does
++ * N35/PiN output -- unknown what it does
++ *
++ * A12 is nGCS1 on the N30 and an output on the N35/PiN. I
++ * don't think it does anything useful on the N30, so I ought
++ * to make it an output there too since it always driven to 0
++ * as far as I can tell. */
++ if (machine_is_n30())
++ __raw_writel(0x007fffff, S3C2410_GPACON);
++ if (machine_is_n35())
++ __raw_writel(0x007fefff, S3C2410_GPACON);
++ __raw_writel(0x00000000, S3C2410_GPADAT);
++
++ /* GPB0 TOUT0 backlight level
++ * GPB1 output 1=backlight on
++ * GPB2 output IrDA enable 0=transceiver enabled, 1=disabled
++ * GPB3 output USB D+ pull up 0=disabled, 1=enabled
++ * GPB4 N30 output -- unknown function
++ * N30/PiN GPS control 0=GPS enabled, 1=GPS disabled
++ * GPB5 output -- unknown function
++ * GPB6 input -- unknown function
++ * GPB7 output -- unknown function
++ * GPB8 output -- probably LCD driver enable
++ * GPB9 output -- probably LCD VSYNC driver enable
++ * GPB10 output -- probably LCD HSYNC driver enable
++ */
++ __raw_writel(0x00154556, S3C2410_GPBCON);
++ __raw_writel(0x00000750, S3C2410_GPBDAT);
++ __raw_writel(0x0000007d, S3C2410_GPBUP);
++
++ /* GPC0 input RS232 DCD/DSR/RI
++ * GPC1 LCD
++ * GPC2 output RS232 DTR?
++ * GPC3 input RS232 DCD/DSR/RI
++ * GPC4 LCD
++ * GPC5 output 0=NAND write enabled, 1=NAND write protect
++ * GPC6 input -- unknown function
++ * GPC7 input charger status 0=charger connected
++ * this input can be triggered by power on the USB device
++ * port too, but will go back to disconnected soon after.
++ * GPC8 N30/N35 output -- unknown function, always driven to 1
++ * PiN input -- unknown function, always read as 1
++ * Make it an input with a pull up for all models.
++ * GPC9-15 LCD
++ */
++ __raw_writel(0xaaa80618, S3C2410_GPCCON);
++ __raw_writel(0x0000014c, S3C2410_GPCDAT);
++ __raw_writel(0x0000fef2, S3C2410_GPCUP);
++
++ /* GPD0 input -- unknown function
++ * GPD1-D7 LCD
++ * GPD8 N30 output -- unknown function
++ * N35/PiN output 1=GPS LED on
++ * GPD9 output 0=power led blinks red, 1=normal power led function
++ * GPD10 output -- unknown function
++ * GPD11-15 LCD drivers
++ */
++ __raw_writel(0xaa95aaa4, S3C2410_GPDCON);
++ __raw_writel(0x00000601, S3C2410_GPDDAT);
++ __raw_writel(0x0000fbfe, S3C2410_GPDUP);
++
++ /* GPE0-4 I2S audio bus
++ * GPE5-10 SD/MMC bus
++ * E11-13 outputs -- unknown function, probably power management
++ * E14-15 I2C bus connected to the battery controller
++ */
++ __raw_writel(0xa56aaaaa, S3C2410_GPECON);
++ __raw_writel(0x0000efc5, S3C2410_GPEDAT);
++ __raw_writel(0x0000f81f, S3C2410_GPEUP);
++
++ /* GPF0 input 0=power button pressed
++ * GPF1 input SD/MMC switch 0=card present
++ * GPF2 N30 1=reset button pressed (inverted compared to the rest)
++ * N35/PiN 0=reset button pressed
++ * GPF3 N30/PiN input -- unknown function
++ * N35 input GPS antenna position, 0=antenna closed, 1=open
++ * GPF4 input 0=button 4 pressed
++ * GPF5 input 0=button 3 pressed
++ * GPF6 input 0=button 2 pressed
++ * GPF7 input 0=button 1 pressed
++ */
++ __raw_writel(0x0000aaaa, S3C2410_GPFCON);
++ __raw_writel(0x00000000, S3C2410_GPFDAT);
++ __raw_writel(0x000000ff, S3C2410_GPFUP);
++
++ /* GPG0 input RS232 DCD/DSR/RI
++ * GPG1 input 1=USB gadget port has power from a host
++ * GPG2 N30 input -- unknown function
++ * N35/PiN input 0=headphones plugged in, 1=not plugged in
++ * GPG3 N30 output -- unknown function
++ * N35/PiN input with unknown function
++ * GPG4 N30 output 0=MMC enabled, 1=MMC disabled
++ * GPG5 N30 output 0=BlueTooth chip disabled, 1=enabled
++ * N35/PiN input joystick right
++ * GPG6 N30 output 0=blue led on, 1=off
++ * N35/PiN input joystick left
++ * GPG7 input 0=thumbwheel pressed
++ * GPG8 input 0=thumbwheel down
++ * GPG9 input 0=thumbwheel up
++ * GPG10 input SD/MMC write protect switch
++ * GPG11 N30 input -- unknown function
++ * N35 output 0=GPS antenna powered, 1=not powered
++ * PiN output -- unknown function
++ * GPG12-15 touch screen functions
++ *
++ * The pullups differ between the models, so enable all
++ * pullups that are enabled on any of the models.
++ */
++ if (machine_is_n30())
++ __raw_writel(0xff0a956a, S3C2410_GPGCON);
++ if (machine_is_n35())
++ __raw_writel(0xff4aa92a, S3C2410_GPGCON);
++ __raw_writel(0x0000e800, S3C2410_GPGDAT);
++ __raw_writel(0x0000f86f, S3C2410_GPGUP);
++
++ /* GPH0/1/2/3 RS232 serial port
++ * GPH4/5 IrDA serial port
++ * GPH6/7 N30 BlueTooth serial port
++ * N35/PiN GPS receiver
++ * GPH8 input -- unknown function
++ * GPH9 CLKOUT0 HCLK -- unknown use
++ * GPH10 CLKOUT1 FCLK -- unknown use
++ *
++ * The pull ups for H6/H7 are enabled on N30 but not on the
++ * N35/PiN. I suppose is useful for a budget model of the N30
++ * with no bluetooh. It doesn't hurt to have the pull ups
++ * enable, so leave them enabled for all models.
++ */
++ __raw_writel(0x0028aaaa, S3C2410_GPHCON);
++ __raw_writel(0x000005ef, S3C2410_GPHDAT);
++ __raw_writel(0x0000063f, S3C2410_GPHUP);
++}
++
+ static void __init n30_map_io(void)
+ {
+ s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
++ n30_hwinit();
+ s3c24xx_init_clocks(0);
+ s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
+ s3c24xx_set_board(&n30_board);
diff --git a/recipes/linux/linux/acern30/n30-lcd.patch b/recipes/linux/linux/acern30/n30-lcd.patch
new file mode 100644
index 0000000000..c56ad5aadc
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-lcd.patch
@@ -0,0 +1,66 @@
+This patch adds the configuration needed for the LCD display on the n30.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -44,7 +44,9 @@
+
+ #include <asm/arch/regs-serial.h>
+ #include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-lcd.h>
+ #include <asm/arch/iic.h>
++#include <asm/arch/fb.h>
+
+ #include <linux/serial_core.h>
+
+@@ -85,6 +87,40 @@ static struct s3c2410_uartcfg n30_uartcf
+ },
+ };
+
++static struct s3c2410fb_mach_info n30_lcdcfg __initdata = {
++ .fixed_syncs= 1,
++ .regs={
++ .lcdcon1= S3C2410_LCDCON1_TFT16BPP |
++ S3C2410_LCDCON1_TFT |
++ S3C2410_LCDCON1_CLKVAL(0x0A),
++
++ .lcdcon2= S3C2410_LCDCON2_VBPD(1) |
++ S3C2410_LCDCON2_LINEVAL(319) |
++ S3C2410_LCDCON2_VFPD(2) |
++ S3C2410_LCDCON2_VSPW(1),
++
++ .lcdcon3= S3C2410_LCDCON3_HBPD(39) |
++ S3C2410_LCDCON3_HOZVAL(239) |
++ S3C2410_LCDCON3_HFPD(2),
++
++ .lcdcon4= S3C2410_LCDCON4_MVAL(13) |
++ S3C2410_LCDCON4_HSPW(39),
++
++ .lcdcon5= S3C2410_LCDCON5_FRM565 |
++ S3C2410_LCDCON5_INVVLINE |
++ S3C2410_LCDCON5_INVVFRAME |
++ S3C2410_LCDCON5_PWREN |
++ S3C2410_LCDCON5_HWSWP,
++ },
++ .lpcsel= 0x06,
++
++ .width= 240,
++ .height= 320,
++ .xres= {240,240,240},
++ .yres= {320,320,320},
++ .bpp= {16,16,16},
++};
++
+ static struct platform_device *n30_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+@@ -123,6 +159,8 @@ static void __init n30_init_irq(void)
+
+ static void __init n30_init(void)
+ {
++ s3c24xx_fb_set_platdata(&n30_lcdcfg);
++
+ s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
+
+ /* Turn off suspend on both USB ports, and switch the
diff --git a/recipes/linux/linux/acern30/n30-mmc-power.patch b/recipes/linux/linux/acern30/n30-mmc-power.patch
new file mode 100644
index 0000000000..cacb2fafd6
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-mmc-power.patch
@@ -0,0 +1,24 @@
+This patch adds power management for the mmc port on the n30.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -261,9 +261,16 @@ static struct s3c2410_butt_mach_info n35
+ .size = ARRAY_SIZE(n35_buttons),
+ };
+
++static void n30_mmc_set_power(unsigned int to)
++{
++ /* TODO This may not be correct. This needs testing. */
++ if (machine_is_n30())
++ s3c2410_gpio_setpin(S3C2410_GPG4, !to);
++}
++
+ static struct s3c24xx_mmc_platdata n30_mmc_cfg = {
+ .gpio_detect = S3C2410_GPF1,
+- .set_power = NULL,
++ .set_power = n30_mmc_set_power,
+ .f_max = 3000000,
+ .ocr_avail = MMC_VDD_32_33,
+ };
diff --git a/recipes/linux/linux/acern30/n30-mmc-wprotect.patch b/recipes/linux/linux/acern30/n30-mmc-wprotect.patch
new file mode 100644
index 0000000000..e319432c6c
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-mmc-wprotect.patch
@@ -0,0 +1,54 @@
+This adds support for the write protect switch on the n30.
+
+It also adds some code to the generic s3c2410sdi driver so that the
+write protect switch actually does something.
+
+But I'm not sure if I want to add support for the write protect switch
+since it really protect against anything. Using the switch is
+entirely up to software, and saying that the card is write protected
+when it really isn't sounds like a bad idea. "Secure" Digital indeed.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -270,6 +270,7 @@ static void n30_mmc_set_power(unsigned i
+
+ static struct s3c24xx_mmc_platdata n30_mmc_cfg = {
+ .gpio_detect = S3C2410_GPF1,
++ .gpio_wprotect = S3C2410_GPG10,
+ .set_power = n30_mmc_set_power,
+ .f_max = 3000000,
+ .ocr_avail = MMC_VDD_32_33,
+Index: linux-2.6.14/drivers/mmc/s3c2410mci.c
+===================================================================
+--- linux-2.6.14.orig/drivers/mmc/s3c2410mci.c
++++ linux-2.6.14/drivers/mmc/s3c2410mci.c
+@@ -515,6 +515,17 @@ static void s3c2410sdi_set_ios(struct mm
+
+ }
+
++static int s3c2410sdi_get_ro(struct mmc_host* mmc)
++{
++ struct s3c2410sdi_host *host = mmc_priv(mmc);
++ int r;
++
++ r = s3c2410_gpio_getpin(host->pdata->gpio_wprotect);
++ if (host->pdata->wprotect_polarity)
++ r = !r;
++ return r;
++}
++
+ static struct mmc_host_ops s3c2410sdi_ops = {
+ .request = s3c2410sdi_request,
+ .set_ios = s3c2410sdi_set_ios,
+@@ -643,6 +654,9 @@ static int s3c2410sdi_probe(struct devic
+ mmc->f_max = clk_get_rate(host->clk) / 2;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
+
++ if (host->pdata->gpio_wprotect)
++ mmc->ops->get_ro = s3c2410sdi_get_ro;
++
+ /* HACK: There seems to be a hardware bug in TomTom GO. */
+ /*if(mmc->f_max>3000000) mmc->f_max=3000000;*/
+
diff --git a/recipes/linux/linux/acern30/n30-mmc.patch b/recipes/linux/linux/acern30/n30-mmc.patch
new file mode 100644
index 0000000000..6fb58f142b
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-mmc.patch
@@ -0,0 +1,53 @@
+This patch adds configuration for the SD/MMC port on the n30.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -32,6 +32,8 @@
+ #include <linux/device.h>
+ #include <linux/kthread.h>
+
++#include <linux/mmc/protocol.h>
++
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+ #include <asm/mach/irq.h>
+@@ -52,6 +54,7 @@
+ #include <asm/arch/lcd.h>
+ #include <asm/arch/ts.h>
+ #include <asm/arch/buttons.h>
++#include <asm/arch/mmc.h>
+
+ #include <linux/serial_core.h>
+
+@@ -258,6 +261,13 @@ static struct s3c2410_butt_mach_info n35
+ .size = ARRAY_SIZE(n35_buttons),
+ };
+
++static struct s3c24xx_mmc_platdata n30_mmc_cfg = {
++ .gpio_detect = S3C2410_GPF1,
++ .set_power = NULL,
++ .f_max = 3000000,
++ .ocr_avail = MMC_VDD_32_33,
++};
++
+ static struct platform_device *n30_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+@@ -268,6 +278,7 @@ static struct platform_device *n30_devic
+ &s3c_device_i2c,
+ &s3c_device_iis,
+ &s3c_device_usbgadget,
++ &s3c_device_sdi,
+ };
+
+ static struct s3c2410_platform_i2c n30_i2ccfg = {
+@@ -309,6 +320,7 @@ static void __init n30_init(void)
+ s3c24xx_butt_set_platdata(&n35_buttons_cfg);
+
+ s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
++ s3c_device_sdi.dev.platform_data = &n30_mmc_cfg;
+
+ /* Turn off suspend on both USB ports, and switch the
+ * selectable USB port to USB device mode. */
diff --git a/recipes/linux/linux/acern30/n30-nand-hack.patch b/recipes/linux/linux/acern30/n30-nand-hack.patch
new file mode 100644
index 0000000000..d606f2b47c
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-nand-hack.patch
@@ -0,0 +1,32 @@
+The flash is locked on the n30 and needs to be unlocked before every
+write. It should be possible to do one big unlock operation outside
+of the erase and write functions but for some strange reason that
+doesn't seem to work any more, so do this ugly workaround for now.
+
+Index: linux-2.6.14/drivers/mtd/nand/nand_base.c
+===================================================================
+--- linux-2.6.14.orig/drivers/mtd/nand/nand_base.c
++++ linux-2.6.14/drivers/mtd/nand/nand_base.c
+@@ -866,6 +866,10 @@ static int nand_write_page (struct mtd_i
+ /* FIXME: Enable cached programming */
+ cached = 0;
+
++ /* unlock the page */
++ this->cmdfunc (mtd, 0x23, -1, page);
++ this->cmdfunc (mtd, 0x24, -1, page);
++
+ /* Send command to begin auto page programming */
+ this->cmdfunc (mtd, NAND_CMD_SEQIN, 0x00, page);
+
+@@ -2037,6 +2041,11 @@ out:
+ static void single_erase_cmd (struct mtd_info *mtd, int page)
+ {
+ struct nand_chip *this = mtd->priv;
++
++ /* unlock the page */
++ this->cmdfunc (mtd, 0x23, -1, page);
++ this->cmdfunc (mtd, 0x24, -1, page);
++
+ /* Send commands to erase a block */
+ this->cmdfunc (mtd, NAND_CMD_ERASE1, -1, page);
+ this->cmdfunc (mtd, NAND_CMD_ERASE2, -1, -1);
diff --git a/recipes/linux/linux/acern30/n30-nand.patch b/recipes/linux/linux/acern30/n30-nand.patch
new file mode 100644
index 0000000000..d3ac8c557a
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-nand.patch
@@ -0,0 +1,97 @@
+This patch adds a nand flash configuration for the n30.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -33,6 +33,8 @@
+ #include <linux/kthread.h>
+
+ #include <linux/mmc/protocol.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/partitions.h>
+
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+@@ -55,6 +57,7 @@
+ #include <asm/arch/ts.h>
+ #include <asm/arch/buttons.h>
+ #include <asm/arch/mmc.h>
++#include <asm/arch/nand.h>
+
+ #include <linux/serial_core.h>
+
+@@ -276,6 +279,50 @@ static struct s3c24xx_mmc_platdata n30_m
+ .ocr_avail = MMC_VDD_32_33,
+ };
+
++static int chip0_map[] = { 0 };
++
++struct mtd_partition n30_default_nand_part[] = {
++ {
++ .name = "Whole flash",
++ .offset = 0,
++ .size = MTDPART_SIZ_FULL,
++ .mask_flags = MTD_WRITEABLE,
++ },
++ {
++ .name = "Partition Table",
++ .offset = 0x28000,
++ .size = 0x8000,
++ },
++ {
++ .name = "Kernel",
++ .offset = 0x30000,
++ .size = 0x4d0000,
++ },
++ {
++ .name = "Root",
++ .offset = 0x500000,
++ .size = MTDPART_SIZ_FULL,
++ },
++};
++
++static struct s3c2410_nand_set n30_nand_sets[] = {
++ {
++ .name = "chip0",
++ .nr_chips = 1,
++ .nr_map = chip0_map,
++ .nr_partitions = ARRAY_SIZE(n30_default_nand_part),
++ .partitions = n30_default_nand_part
++ },
++};
++
++static struct s3c2410_platform_nand n30_nand_info = {
++ .tacls = 80,
++ .twrph0 = 80,
++ .twrph1 = 80,
++ .nr_sets = ARRAY_SIZE(n30_nand_sets),
++ .sets = n30_nand_sets,
++};
++
+ static struct platform_device *n30_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+@@ -287,6 +334,7 @@ static struct platform_device *n30_devic
+ &s3c_device_iis,
+ &s3c_device_usbgadget,
+ &s3c_device_sdi,
++ &s3c_device_nand,
+ };
+
+ static struct s3c2410_platform_i2c n30_i2ccfg = {
+@@ -329,6 +377,14 @@ static void __init n30_init(void)
+
+ s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
+ s3c_device_sdi.dev.platform_data = &n30_mmc_cfg;
++ s3c_device_nand.dev.platform_data = &n30_nand_info;
++
++ /* Clear any locks and write protects on the flash. */
++ s3c2410_gpio_setpin(S3C2410_GPC5, 1);
++ msleep(1);
++ s3c2410_gpio_setpin(S3C2410_GPC5, 0);
++ msleep(1);
++ s3c2410_gpio_setpin(S3C2410_GPC5, 1);
+
+ /* Turn off suspend on both USB ports, and switch the
+ * selectable USB port to USB device mode. */
diff --git a/recipes/linux/linux/acern30/n30-pm.patch b/recipes/linux/linux/acern30/n30-pm.patch
new file mode 100644
index 0000000000..014043b55b
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-pm.patch
@@ -0,0 +1,296 @@
+Add suspend/resume support for the Acer N30.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -66,11 +66,46 @@
+ #include "clock.h"
+ #include "devs.h"
+ #include "cpu.h"
++#include "pm.h"
+
+ static struct map_desc n30_iodesc[] __initdata = {
+ /* nothing here yet */
+ };
+
++/* This code is copied to physical address SDRAM_PA + 0x201000. The
++ * bootloader will jump there on a watchdog reset or when resuming
++ * from suspend to ram. */
++
++#define N30_RESUME_VA __va(S3C2410_SDRAM_PA + 0x201000)
++
++static void __init n30_resume(void) __attribute__((naked));
++static void __init n30_resume(void)
++{
++ asm(
++ "mov r1, #0x56000000 \n\t"
++
++ /* load GSTATUS2 and check for a wake from suspend */
++ "ldr r0, [r1, #0xb4] \n\t" /* GSTATUS2 */
++ "ands r0, r0, #2 \n\t" /* OFFRST */
++ "beq 1f \n\t"
++
++ /* it is a wake reset, so jump to the resume function
++ * pointed to by GSTATUS3 */
++ "ldr pc, [r1, #0xb8] \n\t" /* GSTATUS3 */
++
++ /* Probably a watchdog reset, so fake a power on reset
++ * by writing PWRST to GSTATUS2 and then jump back to
++ * the bootloader. */
++ "1: \n\t"
++ "mov r0, #1 \n\t" /* PWRST */
++ "str r0, [r1, #0xb4] \n\t" /* GSTATUS2 */
++ "mov pc, #0 \n\t"
++
++ "n30_resume_end: \n\t"
++ );
++}
++extern void n30_resume_end;
++
+ static struct s3c2410_uartcfg n30_uartcfgs[] = {
+ /* Normal serial port */
+ [0] = {
+@@ -483,6 +518,154 @@ static void __init n30_hwinit(void)
+ __raw_writel(0x0000063f, S3C2410_GPHUP);
+ }
+
++void n30_pm_gpio(void)
++{
++ if (machine_is_n35()) {
++ /* Prepare for suspend to ram. This is what WinCE
++ * apparently does. I know where some of these pins
++ * are connected and ought to be moved to code related
++ * that hardware, but some stuff is magic so far. */
++
++ /* All this is magic. WinCE does this and it brings
++ * the power consumption in sleep mode down. */
++
++ /* Drive ADDR0, ADDR16..ADDR23, and ADDR26 low.
++ * ADDR24 and ADDR 25 are still working.
++ * nGCS1..nGCS5 are driven low.
++ * CLE, ALE, nFWE, nFRE, nRSTOUT and nFCW are working. */
++ __raw_writel(0x007e0600, S3C2410_GPACON);
++ __raw_writel(0x00000000, S3C2410_GPADAT);
++ __raw_writel(0x00015556, S3C2410_GPBCON);
++ __raw_writel(0x00000011, S3C2410_GPBDAT);
++ __raw_writel(0x000007ff, S3C2410_GPBUP);
++ __raw_writel(0xaa950618, S3C2410_GPCCON);
++ __raw_writel(0x0000024c, S3C2410_GPCDAT);
++ __raw_writel(0x0000ffb6, S3C2410_GPCUP);
++ __raw_writel(0xaa95aaa5, S3C2410_GPDCON);
++ __raw_writel(0x00000202, S3C2410_GPDDAT);
++ __raw_writel(0x0000fffd, S3C2410_GPDUP);
++ __raw_writel(0xa56aaaaa, S3C2410_GPECON);
++ __raw_writel(0x0000c7c1, S3C2410_GPEDAT);
++ __raw_writel(0x0000ffff, S3C2410_GPEUP);
++ __raw_writel(0x0000aa22, S3C2410_GPFCON);
++ __raw_writel(0x000000f5, S3C2410_GPFDAT);
++ __raw_writel(0x000000fd, S3C2410_GPFUP);
++ __raw_writel(0xff40010a, S3C2410_GPGCON);
++ __raw_writel(0x0000abf5, S3C2410_GPGDAT);
++ __raw_writel(0x0000fcef, S3C2410_GPGUP);
++ __raw_writel(0x0014aaaa, S3C2410_GPHCON);
++ __raw_writel(0x0000062f, S3C2410_GPHDAT);
++ __raw_writel(0x000007ff, S3C2410_GPHUP);
++
++ /* Turn GPB6 into an output and drive it low. */
++ s3c2410_gpio_cfgpin(S3C2410_GPB6, S3C2410_GPB6_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPB6, 0);
++
++ /* Turn off the pull up on GPB7. */
++ s3c2410_gpio_pullup(S3C2410_GPB7, 1);
++
++ /* Drive GPC8 low */
++ s3c2410_gpio_cfgpin(S3C2410_GPC8, S3C2410_GPC8_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPC8, 0);
++ s3c2410_gpio_pullup(S3C2410_GPC8, 1);
++
++ /* Drive GPC9/VD[1] high. */
++ s3c2410_gpio_cfgpin(S3C2410_GPC9, S3C2410_GPC9_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPC9, 1);
++
++ /* Drive GPC10/VD[2] low. */
++ s3c2410_gpio_cfgpin(S3C2410_GPC10, S3C2410_GPC10_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPC10, 0);
++
++ /* Disable pull up on RS232 DTR? */
++ s3c2410_gpio_pullup(S3C2410_GPC2, 1);
++
++ /* Enable pull up on GPC6. */
++ s3c2410_gpio_pullup(S3C2410_GPC6, 0);
++
++ /* Turn GPD0 into an output and drive it low. */
++ s3c2410_gpio_cfgpin(S3C2410_GPD0, S3C2410_GPD0_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPD0, 0);
++ s3c2410_gpio_pullup(S3C2410_GPD0, 1);
++
++ /* Drive VD[9] high and enable the pull up. */
++ s3c2410_gpio_cfgpin(S3C2410_GPD1, S3C2410_GPD1_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPD1, 1);
++ s3c2410_gpio_pullup(S3C2410_GPD1, 0);
++
++ /* Drive DPD10 low. */
++ s3c2410_gpio_setpin(S3C2410_GPD10, 0);
++ s3c2410_gpio_pullup(S3C2410_GPD10, 1);
++
++ /* This may do something about the power planes. */
++ s3c2410_gpio_setpin(S3C2410_GPE11, 0);
++ s3c2410_gpio_setpin(S3C2410_GPE12, 0);
++ s3c2410_gpio_setpin(S3C2410_GPE13, 0);
++
++ /* Disable pull ups on H8. Don't know why. */
++ s3c2410_gpio_pullup(S3C2410_GPH8, 1);
++
++ /* LCD stuff, ought to be moved to n30_lcd_power.
++ * GPB8 is still an output and drives 0.
++ * GPB9 and GPB10 are turned into inputs.
++ * All pull ups are disabled. */
++ s3c2410_gpio_setpin(S3C2410_GPB8, 0);
++ s3c2410_gpio_pullup(S3C2410_GPB8, 1);
++ s3c2410_gpio_cfgpin(S3C2410_GPB9, S3C2410_GPB9_INP);
++ s3c2410_gpio_pullup(S3C2410_GPB9, 1);
++ s3c2410_gpio_cfgpin(S3C2410_GPB10, S3C2410_GPB10_INP);
++ s3c2410_gpio_pullup(S3C2410_GPB10, 1);
++
++ /* Disable IrDA (not done by WinCE). */
++ s3c2410_gpio_setpin(S3C2410_GPB2, 1);
++
++ /* Disable the GPS. */
++ s3c2410_gpio_setpin(S3C2410_GPB4, 1);
++ s3c2410_gpio_setpin(S3C2410_GPG11, 1);
++
++ /* Turn on flash write protect. */
++ s3c2410_gpio_setpin(S3C2410_GPC5, 0);
++
++ /* Disable pull ups on the SD/MMC port. This should
++ * maybe be done after power has been removed from the
++ * SD/MMC port. */
++ s3c2410_gpio_pullup(S3C2410_GPE5, 1);
++ s3c2410_gpio_pullup(S3C2410_GPE6, 1);
++ s3c2410_gpio_pullup(S3C2410_GPE7, 1);
++ s3c2410_gpio_pullup(S3C2410_GPE8, 1);
++ s3c2410_gpio_pullup(S3C2410_GPE9, 1);
++ s3c2410_gpio_pullup(S3C2410_GPE10, 1);
++
++ /* Disable MMC? On the N30 this makes a difference,
++ * on the N35, maybe not. */
++ s3c2410_gpio_setpin(S3C2410_GPG4, 1);
++
++ /* Enable pull up on SD/MMC switch. */
++ s3c2410_gpio_pullup(S3C2410_GPF1, 0);
++
++ /* Disable pull up on thumbwheel. Why not on the
++ * other inputs too? */
++ s3c2410_gpio_pullup(S3C2410_GPG7, 1);
++
++ /* Disable pull up on SD write protect switch. */
++ s3c2410_gpio_pullup(S3C2410_GPG10, 1);
++
++ /* Disable pull ups on the bluetooth/gps port. */
++ s3c2410_gpio_pullup(S3C2410_GPH6, 1);
++ s3c2410_gpio_pullup(S3C2410_GPH7, 1);
++
++ /* Drive CLKOUT0 high while sleeping. */
++ s3c2410_gpio_cfgpin(S3C2410_GPH9, S3C2410_GPH9_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPH9, 1);
++
++ /* Drive CLKOUT1 high while sleeping. */
++ s3c2410_gpio_cfgpin(S3C2410_GPH10, S3C2410_GPH10_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPH10, 1);
++
++ s3c2410_capture_regs();
++ }
++}
++
+ static void __init n30_map_io(void)
+ {
+ s3c24xx_init_io(n30_iodesc, ARRAY_SIZE(n30_iodesc));
+@@ -569,6 +752,12 @@ static void __init n30_init(void)
+ s3c_device_sdi.dev.platform_data = &n30_mmc_cfg;
+ s3c_device_nand.dev.platform_data = &n30_nand_info;
+
++ s3c2410_pm_init();
++ enable_irq_wake(IRQ_EINT0);
++
++ memcpy_toio(N30_RESUME_VA, (void *)n30_resume,
++ &n30_resume_end - (void *)n30_resume);
++
+ /* Clear any locks and write protects on the flash. */
+ s3c2410_gpio_setpin(S3C2410_GPC5, 1);
+ msleep(1);
+Index: linux-2.6.14/arch/arm/mach-s3c2410/pm.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/pm.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/pm.c
+@@ -565,6 +565,8 @@ static int s3c2410_pm_enter(suspend_stat
+ s3c2410_pm_do_save(core_save, ARRAY_SIZE(core_save));
+ s3c2410_pm_do_save(uart_save, ARRAY_SIZE(uart_save));
+
++ n30_pm_gpio();
++
+ /* set the irq configuration for wake */
+
+ s3c2410_pm_configure_extint();
+@@ -601,6 +603,8 @@ static int s3c2410_pm_enter(suspend_stat
+ tmp &= S3C2410_GSTATUS2_OFFRESET;
+ __raw_writel(tmp, S3C2410_GSTATUS2);
+
++ s3c2410_capture_regs();
++
+ /* restore the system state */
+
+ s3c2410_pm_do_restore_core(core_save, ARRAY_SIZE(core_save));
+Index: linux-2.6.14/arch/arm/mach-s3c2410/sleep.S
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/sleep.S
++++ linux-2.6.14/arch/arm/mach-s3c2410/sleep.S
+@@ -80,6 +80,7 @@ ENTRY(s3c2410_cpu_suspend)
+
+ orr r7, r7, #S3C2410_REFRESH_SELF @ SDRAM sleep command
+ orr r8, r8, #S3C2410_MISCCR_SDSLEEP @ SDRAM power-down signals
++ orr r8, r8, #3 @ turn on data pull ups
+ orr r9, r9, #S3C2410_CLKCON_POWER @ power down command
+
+ teq pc, #0 @ first as a trial-run to load cache
+Index: linux-2.6.14/arch/arm/Makefile
+===================================================================
+--- linux-2.6.14.orig/arch/arm/Makefile
++++ linux-2.6.14/arch/arm/Makefile
+@@ -99,6 +99,10 @@ textaddr-$(CONFIG_ARCH_FORTUNET) := 0x
+ machine-$(CONFIG_ARCH_IMX) := imx
+ machine-$(CONFIG_ARCH_H720X) := h720x
+ machine-$(CONFIG_ARCH_AAEC2000) := aaec2000
++# The Acer N30/N35 needs to put some code at 0xc0201000 to handle
++# the watchdog interrupt and resume from suspend.
++textaddr-$(CONFIG_MACH_N30) := 0xc0208000
++textaddr-$(CONFIG_MACH_N35) := 0xc0208000
+
+ ifeq ($(CONFIG_ARCH_EBSA110),y)
+ # This is what happens if you forget the IOCS16 line.
+Index: linux-2.6.14/arch/arm/mm/init.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mm/init.c
++++ linux-2.6.14/arch/arm/mm/init.c
+@@ -230,6 +230,9 @@ static __init void reserve_node_zero(pg_
+ #endif
+ if (res_size)
+ reserve_bootmem_node(pgdat, PHYS_OFFSET, res_size);
++
++ if (machine_is_n30() || machine_is_n35())
++ reserve_bootmem_node(pgdat, 0x30201000, PAGE_SIZE);
+ }
+
+ void __init build_mem_type_table(void);
+Index: linux-2.6.14/arch/arm/mach-s3c2410/Makefile.boot
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/Makefile.boot
++++ linux-2.6.14/arch/arm/mach-s3c2410/Makefile.boot
+@@ -1,3 +1,7 @@
+ zreladdr-y := 0x30008000
+ params_phys-y := 0x30000100
+
++# The N30/N35 needs 0x30201000 for the bootloader interface. So place
++# the kernel after that.
++zreladdr-$(CONFIG_MACH_N30) := 0x30208000
++zreladdr-$(CONFIG_MACH_N35) := 0x30208000
diff --git a/recipes/linux/linux/acern30/n30-ts.patch b/recipes/linux/linux/acern30/n30-ts.patch
new file mode 100644
index 0000000000..bc619ed2f3
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-ts.patch
@@ -0,0 +1,43 @@
+This patch adds the touch screen configuration for the n30.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -49,6 +49,7 @@
+ #include <asm/arch/iic.h>
+ #include <asm/arch/fb.h>
+ #include <asm/arch/lcd.h>
++#include <asm/arch/ts.h>
+
+ #include <linux/serial_core.h>
+
+@@ -184,10 +185,20 @@ static struct s3c2410_bl_mach_info n30_b
+ .lcd_power = n30_lcd_power
+ };
+
++/* The touch is very noisy on the n30 so sample often and average many
++ * samples before passing them on to userspace. */
++
++static struct s3c2410_ts_mach_info n30_ts_cfg __initdata = {
++ .delay = 1800,
++ .presc = 49,
++ .oversampling_shift = 6,
++};
++
+ static struct platform_device *n30_devices[] __initdata = {
+ &s3c_device_usb,
+ &s3c_device_lcd,
+ &s3c_device_bl,
++ &s3c_device_ts,
+ &s3c_device_wdt,
+ &s3c_device_i2c,
+ &s3c_device_iis,
+@@ -225,6 +236,7 @@ static void __init n30_init(void)
+ {
+ s3c24xx_fb_set_platdata(&n30_lcdcfg);
+ set_s3c2410bl_info(&n30_blcfg);
++ set_s3c2410ts_info(&n30_ts_cfg);
+
+ s3c_device_i2c.dev.platform_data = &n30_i2ccfg;
+
diff --git a/recipes/linux/linux/acern30/n30-usbstart.patch b/recipes/linux/linux/acern30/n30-usbstart.patch
new file mode 100644
index 0000000000..b7479b50e4
--- /dev/null
+++ b/recipes/linux/linux/acern30/n30-usbstart.patch
@@ -0,0 +1,59 @@
+This patch tries to start the USB gadget in a nice way by
+disconnecting and then reconnecting the pull up.
+
+I ought to use the same callback and configuration as RTP does in
+mach-h1940.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -356,7 +356,33 @@ static void __init n30_init_irq(void)
+ s3c24xx_init_irq();
+ }
+
+-/* GPB3 is the line that controls the pull-up for the USB D+ line */
++static int n30_usbstart_thread(void *unused)
++{
++ /* Disable both USB ports */
++ s3c2410_modify_misccr(S3C2410_MISCCR_USBSUSPND0 |
++ S3C2410_MISCCR_USBSUSPND1,
++ S3C2410_MISCCR_USBSUSPND0 |
++ S3C2410_MISCCR_USBSUSPND1);
++
++ /* Turn off the D+ pull up for a few second so that the USB
++ * host at the other end will do a rescan of the USB bus. */
++ s3c2410_gpio_setpin(S3C2410_GPB3, 0);
++
++ msleep_interruptible(1 * 1000);
++
++ /* Enable the USB host port if this is a n30 */
++ if (machine_is_n30())
++ s3c2410_modify_misccr(S3C2410_MISCCR_USBSUSPND0, 0);
++
++ /* Turn off suspend on USB device port and switch it to device
++ * mode. */
++ s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
++ S3C2410_MISCCR_USBSUSPND1, 0x0);
++
++ s3c2410_gpio_setpin(S3C2410_GPB3, 1);
++
++ return 0;
++}
+
+ static void __init n30_init(void)
+ {
+@@ -380,12 +406,7 @@ static void __init n30_init(void)
+ msleep(1);
+ s3c2410_gpio_setpin(S3C2410_GPC5, 1);
+
+- /* Turn off suspend on both USB ports, and switch the
+- * selectable USB port to USB device mode. */
+-
+- s3c2410_modify_misccr(S3C2410_MISCCR_USBHOST |
+- S3C2410_MISCCR_USBSUSPND0 |
+- S3C2410_MISCCR_USBSUSPND1, 0x0);
++ kthread_run(n30_usbstart_thread, NULL, "n30_usbstart");
+ }
+
+ MACHINE_START(N30, "Acer-N30")
diff --git a/recipes/linux/linux/acern30/n35.patch b/recipes/linux/linux/acern30/n35.patch
new file mode 100644
index 0000000000..75f1818eee
--- /dev/null
+++ b/recipes/linux/linux/acern30/n35.patch
@@ -0,0 +1,80 @@
+Index: linux-2.6.14/arch/arm/tools/mach-types
+===================================================================
+--- linux-2.6.14.orig/arch/arm/tools/mach-types
++++ linux-2.6.14/arch/arm/tools/mach-types
+@@ -869,3 +869,4 @@ davinci_dvdp MACH_DAVINCI_DVDP DAVINCI_
+ htcuniversal MACH_HTCUNIVERSAL HTCUNIVERSAL 855
+ tpad MACH_TPAD TPAD 856
+ roverp3 MACH_ROVERP3 ROVERP3 857
++n35 MACH_N35 N35 927
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -1,5 +1,14 @@
+ /* linux/arch/arm/mach-s3c2410/mach-n30.c
+ *
++ * Machine specific code for the following PDAs:
++ *
++ * Acer N30
++ *
++ * Acer N35
++ * Navman PiN 570
++ * Yakumo AlphaX (untested)
++ * Airis NC05 (untested)
++ *
+ * Copyright (c) 2003-2005 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+@@ -65,7 +74,8 @@ static struct s3c2410_uartcfg n30_uartcf
+ .ulcon = 0x43,
+ .ufcon = 0x51,
+ },
+- /* The BlueTooth controller is connected to port 2 */
++ /* On the N30 the bluetooth controller is connected here.
++ * On the N35 and variants the GPS receiver is connected here. */
+ [2] = {
+ .hwport = 2,
+ .flags = 0,
+@@ -136,3 +146,16 @@ MACHINE_START(N30, "Acer-N30")
+ .init_irq = n30_init_irq,
+ .map_io = n30_map_io,
+ MACHINE_END
++
++MACHINE_START(N35, "Acer-N35")
++ /* Maintainer: Christer Weinigel <christer@weinigel.se>
++ */
++ .phys_ram = S3C2410_SDRAM_PA,
++ .phys_io = S3C2410_PA_UART,
++ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
++ .boot_params = S3C2410_SDRAM_PA + 0x100,
++ .timer = &s3c24xx_timer,
++ .init_machine = n30_init,
++ .init_irq = n30_init_irq,
++ .map_io = n30_map_io,
++MACHINE_END
+Index: linux-2.6.14/arch/arm/mach-s3c2410/Kconfig
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/Kconfig
++++ linux-2.6.14/arch/arm/mach-s3c2410/Kconfig
+@@ -39,9 +39,18 @@ config MACH_N30
+ bool "Acer N30"
+ select CPU_S3C2410
+ help
+- Say Y here if you are using the Acer N30
++ Say Y here if you want support for the Acer N30 PDA.
+
+- <http://zoo.weinigel.se/n30>.
++ <http://www.handhelds.org/moin/moin.cgi/AcerN30>.
++
++config MACH_N35
++ bool "Acer N35/Navman PiN 570"
++ select CPU_S3C2410
++ help
++ Say Y here if you want support for the Acer N35 or
++ Navman PiN 570 PDAs.
++
++ <http://www.handhelds.org/moin/moin.cgi/AcerN30>.
+
+ config ARCH_SMDK2410
+ bool "SMDK2410/A9M2410"
diff --git a/recipes/linux/linux/acern30/regdump.patch b/recipes/linux/linux/acern30/regdump.patch
new file mode 100644
index 0000000000..9e5ffe370d
--- /dev/null
+++ b/recipes/linux/linux/acern30/regdump.patch
@@ -0,0 +1,279 @@
+Add some code to dump most registers. It's a good way to find in what
+state the bootloader or Windows has left the device.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/regdump.c
+===================================================================
+--- /dev/null
++++ linux-2.6.14/arch/arm/mach-s3c2410/regdump.c
+@@ -0,0 +1,261 @@
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/module.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++
++#include <asm/hardware.h>
++#include <asm/irq.h>
++#include <asm/io.h>
++
++#include <asm/arch/map.h>
++#include <asm/arch/regs-adc.h>
++#include <asm/arch/regs-clock.h>
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-iic.h>
++#include <asm/arch/regs-iis.h>
++#include <asm/arch/regs-irq.h>
++#include <asm/arch/regs-lcd.h>
++#include <asm/arch/regs-mem.h>
++#include <asm/arch/regs-nand.h>
++#include <asm/arch/regs-rtc.h>
++#include <asm/arch/regs-timer.h>
++#include <asm/arch/regs-udc.h>
++#include <asm/arch/regs-watchdog.h>
++
++#define REGV(reg) { #reg, (reg) }
++#define REGI(va, reg) { #reg, (va) + (reg) }
++
++static struct reginfo {
++ const char *name;
++ void *va;
++} reginfo[] = {
++ /* ADC */
++ REGI(S3C24XX_VA_ADC, S3C2410_ADCCON),
++ REGI(S3C24XX_VA_ADC, S3C2410_ADCTSC),
++ REGI(S3C24XX_VA_ADC, S3C2410_ADCDLY),
++ REGI(S3C24XX_VA_ADC, S3C2410_ADCDAT0),
++ REGI(S3C24XX_VA_ADC, S3C2410_ADCDAT1),
++
++ /* Clocks */
++ REGV(S3C2410_LOCKTIME),
++ REGV(S3C2410_MPLLCON),
++ REGV(S3C2410_UPLLCON),
++ REGV(S3C2410_CLKCON),
++ REGV(S3C2410_CLKSLOW),
++ REGV(S3C2410_CLKDIVN),
++
++ /* GPIO */
++ REGV(S3C2410_GPACON),
++ REGV(S3C2410_GPADAT),
++ REGV(S3C2410_GPBCON),
++ REGV(S3C2410_GPBDAT),
++ REGV(S3C2410_GPBUP),
++ REGV(S3C2410_GPCCON),
++ REGV(S3C2410_GPCDAT),
++ REGV(S3C2410_GPCUP),
++ REGV(S3C2410_GPDCON),
++ REGV(S3C2410_GPDDAT),
++ REGV(S3C2410_GPDUP),
++ REGV(S3C2410_GPECON),
++ REGV(S3C2410_GPEDAT),
++ REGV(S3C2410_GPEUP),
++ REGV(S3C2410_GPFCON),
++ REGV(S3C2410_GPFDAT),
++ REGV(S3C2410_GPFUP),
++ REGV(S3C2410_GPGCON),
++ REGV(S3C2410_GPGDAT),
++ REGV(S3C2410_GPGUP),
++ REGV(S3C2410_GPHCON),
++ REGV(S3C2410_GPHDAT),
++ REGV(S3C2410_GPHUP),
++ REGV(S3C2410_MISCCR),
++ REGV(S3C2410_DCLKCON),
++ REGV(S3C2410_EXTINT0),
++ REGV(S3C2410_EXTINT1),
++ REGV(S3C2410_EXTINT2),
++ REGV(S3C2410_EINFLT0),
++ REGV(S3C2410_EINFLT1),
++ REGV(S3C2410_EINFLT2),
++ REGV(S3C2410_EINFLT3),
++ REGV(S3C2410_GSTATUS0),
++ REGV(S3C2410_GSTATUS1),
++ REGV(S3C2410_GSTATUS2),
++ REGV(S3C2410_GSTATUS3),
++ REGV(S3C2410_GSTATUS4),
++
++#if 0
++ /* IIC */
++ REGI(S3C24XX_VA_IIC, S3C2410_IICCON),
++ REGI(S3C24XX_VA_IIC, S3C2410_IICSTAT),
++ REGI(S3C24XX_VA_IIC, S3C2410_IICADD),
++ REGI(S3C24XX_VA_IIC, S3C2410_IICDS),
++
++ /* IIS */
++ REGI(S3C24XX_VA_IIS, S3C2410_IISCON),
++ REGI(S3C24XX_VA_IIS, S3C2410_IISMOD),
++ REGI(S3C24XX_VA_IIS, S3C2410_IISPSR),
++ REGI(S3C24XX_VA_IIS, S3C2410_IISFCON),
++ REGI(S3C24XX_VA_IIS, S3C2410_IISFIFO),
++#endif
++
++ /* IRQ */
++ REGV(S3C2410_SRCPND),
++ REGV(S3C2410_INTMOD),
++ REGV(S3C2410_INTMSK),
++ REGV(S3C2410_PRIORITY),
++ REGV(S3C2410_INTPND),
++ REGV(S3C2410_INTOFFSET),
++ REGV(S3C2410_SUBSRCPND),
++ REGV(S3C2410_INTSUBMSK),
++ REGV(S3C2410_EINTMASK),
++ REGV(S3C2410_EINTPEND),
++
++ /* LCD */
++ REGV(S3C2410_LCDCON1),
++ REGV(S3C2410_LCDCON2),
++ REGV(S3C2410_LCDCON3),
++ REGV(S3C2410_LCDCON4),
++ REGV(S3C2410_LCDCON5),
++ REGV(S3C2410_LCDSADDR1),
++ REGV(S3C2410_LCDSADDR2),
++ REGV(S3C2410_LCDSADDR3),
++ REGV(S3C2410_REDLUT),
++ REGV(S3C2410_GREENLUT),
++ REGV(S3C2410_BLUELUT),
++ REGV(S3C2410_DITHMODE),
++ REGV(S3C2410_TPAL),
++ REGV(S3C2410_LCDINTPND),
++ REGV(S3C2410_LCDSRCPND),
++ REGV(S3C2410_LCDINTMSK),
++ REGV(S3C2410_LPCSEL),
++
++ // REGV(S3C2410_TFTPAL(x)),
++
++#if 0
++ /* Memory controller */
++ REGV(S3C2410_BWSCON),
++ REGV(S3C2410_BANKCON0),
++ REGV(S3C2410_BANKCON1),
++ REGV(S3C2410_BANKCON2),
++ REGV(S3C2410_BANKCON3),
++ REGV(S3C2410_BANKCON4),
++ REGV(S3C2410_BANKCON5),
++ REGV(S3C2410_BANKCON6),
++ REGV(S3C2410_BANKCON7),
++ REGV(S3C2410_REFRESH),
++ REGV(S3C2410_BANKSIZE),
++ REGV(S3C2410_MRSRB6),
++ REGV(S3C2410_MRSRB7),
++
++ /* Nand flash */
++ REGI(S3C24XX_VA_NAND, S3C2410_NFCONF),
++ REGI(S3C24XX_VA_NAND, S3C2410_NFCMD),
++ REGI(S3C24XX_VA_NAND, S3C2410_NFADDR),
++ REGI(S3C24XX_VA_NAND, S3C2410_NFDATA),
++ REGI(S3C24XX_VA_NAND, S3C2410_NFSTAT),
++ REGI(S3C24XX_VA_NAND, S3C2410_NFECC),
++
++ /* RTC */
++ REGV(S3C2410_RTCCON),
++ REGV(S3C2410_TICNT),
++ REGV(S3C2410_RTCALM),
++ REGV(S3C2410_ALMSEC),
++ REGV(S3C2410_ALMMIN),
++ REGV(S3C2410_ALMHOUR),
++ REGV(S3C2410_ALMDATE),
++ REGV(S3C2410_ALMMON),
++ REGV(S3C2410_ALMYEAR),
++ REGV(S3C2410_RTCRST),
++ REGV(S3C2410_RTCSEC),
++ REGV(S3C2410_RTCMIN),
++ REGV(S3C2410_RTCHOUR),
++ REGV(S3C2410_RTCDATE),
++ REGV(S3C2410_RTCDAY),
++ REGV(S3C2410_RTCMON),
++ REGV(S3C2410_RTCYEAR),
++#endif
++
++ /* Timer */
++ REGV(S3C2410_TCFG0),
++ REGV(S3C2410_TCFG1),
++ REGV(S3C2410_TCON),
++
++ /* USB Device */
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_FUNC_ADDR_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_PWR_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP_INT_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_USB_INT_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP_INT_EN_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_USB_INT_EN_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_FRAME_NUM1_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_FRAME_NUM2_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP0_FIFO_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP1_FIFO_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP2_FIFO_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP3_FIFO_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP4_FIFO_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP1_DMA_CON),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP1_DMA_UNIT),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP1_DMA_FIFO),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP1_DMA_TTC_L),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP1_DMA_TTC_M),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP1_DMA_TTC_H),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP2_DMA_CON),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP2_DMA_UNIT),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP2_DMA_FIFO),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP2_DMA_TTC_L),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP2_DMA_TTC_M),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP2_DMA_TTC_H),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP3_DMA_CON),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP3_DMA_UNIT),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP3_DMA_FIFO),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP3_DMA_TTC_L),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP3_DMA_TTC_M),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP3_DMA_TTC_H),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP4_DMA_CON),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP4_DMA_UNIT),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP4_DMA_FIFO),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP4_DMA_TTC_L),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP4_DMA_TTC_M),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP4_DMA_TTC_H),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_INDEX_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_MAXP_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_EP0_CSR_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_IN_CSR1_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_IN_CSR2_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_OUT_CSR1_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_OUT_CSR2_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_OUT_FIFO_CNT1_REG),
++ REGI(S3C24XX_VA_USBDEV, S3C2410_UDC_OUT_FIFO_CNT2_REG),
++
++ /* Watchdog */
++ REGV(S3C2410_WTCON),
++ REGV(S3C2410_WTDAT),
++ REGV(S3C2410_WTCNT),
++};
++
++static u32 regval[ARRAY_SIZE(reginfo)];
++
++void s3c2410_capture_regs(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(reginfo); i++)
++ regval[i] = readl(reginfo[i].va);
++}
++
++void s3c2410_dump_regs(void)
++{
++ int i;
++
++ for (i = 0; i < ARRAY_SIZE(reginfo); i++)
++ printk("%-20s = 0x%08x\n", reginfo[i].name, regval[i]);
++}
++
++/*
++ Local variables:
++ compile-command: "make -k -C ../../../.. linux "
++ c-basic-offset: 8
++ End:
++*/
+Index: linux-2.6.14/arch/arm/mach-s3c2410/Makefile
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/Makefile
++++ linux-2.6.14/arch/arm/mach-s3c2410/Makefile
+@@ -44,3 +44,5 @@ obj-$(CONFIG_MACH_OTOM) += mach-otom.o
+ obj-$(CONFIG_MACH_NEXCODER_2440) += mach-nexcoder.o
+
+ obj-y += gpio-sysfs.o
++obj-y += regdump.o
++
diff --git a/recipes/linux/linux/acern30/s3c2410-nand-pm.patch b/recipes/linux/linux/acern30/s3c2410-nand-pm.patch
new file mode 100644
index 0000000000..b53a2f2760
--- /dev/null
+++ b/recipes/linux/linux/acern30/s3c2410-nand-pm.patch
@@ -0,0 +1,53 @@
+Index: linux-2.6.14/drivers/mtd/nand/s3c2410.c
+===================================================================
+--- linux-2.6.14.orig/drivers/mtd/nand/s3c2410.c
++++ linux-2.6.14/drivers/mtd/nand/s3c2410.c
+@@ -692,11 +692,39 @@ static int s3c2440_nand_probe(struct dev
+ return s3c24xx_nand_probe(dev, 1);
+ }
+
++#ifdef CONFIG_PM
++
++static int s3c2410_nand_suspend(struct device *dev, pm_message_t state)
++{
++ struct s3c2410_nand_info *info = to_nand_info(dev);
++
++ clk_disable(info->clk);
++
++ return 0;
++}
++
++static int s3c2410_nand_resume(struct device *dev)
++{
++ struct s3c2410_nand_info *info = to_nand_info(dev);
++
++ clk_enable(info->clk);
++ msleep(1);
++
++ return s3c2410_nand_inithw(info, dev);
++}
++
++#else
++#define s3c2410_nand_suspend NULL
++#define s3c2410_nand_resume NULL
++#endif
++
+ static struct device_driver s3c2410_nand_driver = {
+ .name = "s3c2410-nand",
+ .bus = &platform_bus_type,
+ .probe = s3c2410_nand_probe,
+ .remove = s3c2410_nand_remove,
++ .suspend = s3c2410_nand_suspend,
++ .resume = s3c2410_nand_resume,
+ };
+
+ static struct device_driver s3c2440_nand_driver = {
+@@ -704,6 +732,8 @@ static struct device_driver s3c2440_nand
+ .bus = &platform_bus_type,
+ .probe = s3c2440_nand_probe,
+ .remove = s3c2410_nand_remove,
++ .suspend = s3c2410_nand_suspend,
++ .resume = s3c2410_nand_resume,
+ };
+
+ static int __init s3c2410_nand_init(void)
diff --git a/recipes/linux/linux/acern30/s3c2410_lcd-pm.c b/recipes/linux/linux/acern30/s3c2410_lcd-pm.c
new file mode 100644
index 0000000000..304baf385c
--- /dev/null
+++ b/recipes/linux/linux/acern30/s3c2410_lcd-pm.c
@@ -0,0 +1,80 @@
+Index: linux-2.6.14/drivers/video/backlight/s3c2410_lcd.c
+===================================================================
+--- linux-2.6.14.orig/drivers/video/backlight/s3c2410_lcd.c
++++ linux-2.6.14/drivers/video/backlight/s3c2410_lcd.c
+@@ -248,10 +248,75 @@ static int s3c2410bl_remove(struct devic
+
+ }
+
++#ifdef CONFIG_PM
++
++static int s3c2410bl_suspend(struct device *dev, pm_message_t state)
++{
++ struct s3c2410_bl_mach_info *info =
++ (struct s3c2410_bl_mach_info *)dev->platform_data;
++
++ if (info) {
++ if (info->backlight_power)
++ info->backlight_power(0);
++ if (info->lcd_power)
++ info->lcd_power(0);
++ }
++
++ return 0;
++}
++
++static int s3c2410bl_resume(struct device *dev)
++{
++ struct s3c2410_bl_mach_info *info =
++ (struct s3c2410_bl_mach_info *)dev->platform_data;
++
++ if (info) {
++ if (info->lcd_power) {
++ switch(info->lcd_power_value) {
++ case FB_BLANK_NORMAL:
++ case FB_BLANK_POWERDOWN:
++ info->lcd_power(0);
++ break;
++ default:
++ case FB_BLANK_VSYNC_SUSPEND:
++ case FB_BLANK_HSYNC_SUSPEND:
++ case FB_BLANK_UNBLANK:
++ info->lcd_power(1);
++ break;
++ }
++ }
++ if (info->backlight_power) {
++ switch(info->backlight_power_value) {
++ case FB_BLANK_NORMAL:
++ case FB_BLANK_VSYNC_SUSPEND:
++ case FB_BLANK_HSYNC_SUSPEND:
++ case FB_BLANK_POWERDOWN:
++ info->backlight_power(0);
++ break;
++ default:
++ case FB_BLANK_UNBLANK:
++ info->backlight_power(1);
++ break;
++ }
++ }
++ if (info->set_brightness)
++ info->set_brightness(info->brightness_value);
++ }
++
++ return 0;
++}
++
++#else
++#define s3c2410bl_suspend NULL
++#define s3c2410bl_resume NULL
++#endif
++
+ static struct device_driver s3c2410bl_driver = {
+ .name = "s3c2410-bl",
+ .bus = &platform_bus_type,
+ .probe = s3c2410bl_probe,
++ .suspend = s3c2410bl_suspend,
++ .resume = s3c2410bl_resume,
+ .remove = s3c2410bl_remove,
+ };
+
diff --git a/recipes/linux/linux/acern30/s3c2410_ts-pm.patch b/recipes/linux/linux/acern30/s3c2410_ts-pm.patch
new file mode 100644
index 0000000000..ef89f7042f
--- /dev/null
+++ b/recipes/linux/linux/acern30/s3c2410_ts-pm.patch
@@ -0,0 +1,73 @@
+Index: linux-2.6.14/drivers/input/touchscreen/s3c2410_ts.c
+===================================================================
+--- linux-2.6.14.orig/drivers/input/touchscreen/s3c2410_ts.c
++++ linux-2.6.14/drivers/input/touchscreen/s3c2410_ts.c
+@@ -56,6 +56,8 @@
+ /* For ts.dev.id.version */
+ #define S3C2410TSVERSION 0x0101
+
++#define TSC_SLEEP (S3C2410_ADCTSC_PULL_UP_DISABLE | S3C2410_ADCTSC_XY_PST(0))
++
+ #define WAIT4INT(x) (((x)<<8) | \
+ S3C2410_ADCTSC_YM_SEN | S3C2410_ADCTSC_YP_SEN | S3C2410_ADCTSC_XP_SEN | \
+ S3C2410_ADCTSC_XY_PST(3))
+@@ -321,10 +323,59 @@ static int s3c2410ts_remove(struct devic
+ return 0;
+ }
+
++#ifdef CONFIG_PM
++
++static int s3c2410ts_suspend(struct device *dev, pm_message_t state)
++{
++ writel(TSC_SLEEP, base_addr+S3C2410_ADCTSC);
++ writel(readl(base_addr+S3C2410_ADCCON) | S3C2410_ADCCON_STDBM,
++ base_addr+S3C2410_ADCCON);
++
++ disable_irq(IRQ_ADC);
++ disable_irq(IRQ_TC);
++
++ clk_disable(adc_clock);
++
++ return 0;
++}
++
++static int s3c2410ts_resume(struct device *dev)
++{
++ struct s3c2410_ts_mach_info *info =
++ (struct s3c2410_ts_mach_info *)dev->platform_data;
++
++ clk_enable(adc_clock);
++ msleep(1);
++
++ enable_irq(IRQ_ADC);
++ enable_irq(IRQ_TC);
++
++ if ((info->presc&0xff) > 0)
++ writel(S3C2410_ADCCON_PRSCEN | S3C2410_ADCCON_PRSCVL(info->presc&0xFF),\
++ base_addr+S3C2410_ADCCON);
++ else
++ writel(0,base_addr+S3C2410_ADCCON);
++
++ /* Initialise registers */
++ if ((info->delay&0xffff) > 0)
++ writel(info->delay & 0xffff, base_addr+S3C2410_ADCDLY);
++
++ writel(WAIT4INT(0), base_addr+S3C2410_ADCTSC);
++
++ return 0;
++}
++
++#else
++#define s3c2410ts_suspend NULL
++#define s3c2410ts_resume NULL
++#endif
++
+ static struct device_driver s3c2410ts_driver = {
+ .name = "s3c2410-ts",
+ .bus = &platform_bus_type,
+ .probe = s3c2410ts_probe,
++ .suspend = s3c2410ts_suspend,
++ .resume = s3c2410ts_resume,
+ .remove = s3c2410ts_remove,
+ };
+
diff --git a/recipes/linux/linux/acern30/s3c2410fb-resume.patch b/recipes/linux/linux/acern30/s3c2410fb-resume.patch
new file mode 100644
index 0000000000..b4727454cf
--- /dev/null
+++ b/recipes/linux/linux/acern30/s3c2410fb-resume.patch
@@ -0,0 +1,13 @@
+Index: linux-2.6.14/drivers/video/s3c2410fb.c
+===================================================================
+--- linux-2.6.14.orig/drivers/video/s3c2410fb.c
++++ linux-2.6.14/drivers/video/s3c2410fb.c
+@@ -569,7 +569,7 @@ int s3c2410fb_init_registers(struct s3c2
+
+ local_irq_restore(flags);
+
+- writel(fbi->regs.lcdcon1, S3C2410_LCDCON1);
++ writel(fbi->regs.lcdcon1 & ~S3C2410_LCDCON1_ENVID, S3C2410_LCDCON1);
+ writel(fbi->regs.lcdcon2, S3C2410_LCDCON2);
+ writel(fbi->regs.lcdcon3, S3C2410_LCDCON3);
+ writel(fbi->regs.lcdcon4, S3C2410_LCDCON4);
diff --git a/recipes/linux/linux/acern30/s3c2410mci-pm.patch b/recipes/linux/linux/acern30/s3c2410mci-pm.patch
new file mode 100644
index 0000000000..33a88713cb
--- /dev/null
+++ b/recipes/linux/linux/acern30/s3c2410mci-pm.patch
@@ -0,0 +1,84 @@
+Index: linux-2.6.14/drivers/mmc/s3c2410mci.c
+===================================================================
+--- linux-2.6.14.orig/drivers/mmc/s3c2410mci.c
++++ linux-2.6.14/drivers/mmc/s3c2410mci.c
+@@ -614,7 +614,8 @@ static int s3c2410sdi_probe(struct devic
+ goto probe_iounmap;
+ }
+
+- s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_EINT5);
++ // This should be parametrised
++ // s3c2410_gpio_cfgpin(S3C2410_GPF5, S3C2410_GPF5_EINT5);
+ set_irq_type(host->irq_cd, IRQT_BOTHEDGE);
+
+ if(request_irq(host->irq_cd, s3c2410sdi_irq_cd, 0, DRIVER_NAME, host)) {
+@@ -732,12 +733,57 @@ static int s3c2410sdi_remove(struct devi
+ return 0;
+ }
+
++#ifdef CONFIG_PM
++static int s3c2410mci_suspend(struct device *dev, pm_message_t state)
++{
++ struct mmc_host *mmc = dev_get_drvdata(dev);
++ int ret = 0;
++
++ if (mmc) {
++ struct s3c2410sdi_host *host = mmc_priv(mmc);
++
++ ret = mmc_suspend_host(mmc, state);
++
++ clk_disable(host->clk);
++
++ disable_irq(host->irq_cd);
++ disable_irq(host->irq);
++ }
++
++ return ret;
++}
++
++static int s3c2410mci_resume(struct device *dev)
++{
++ struct mmc_host *mmc = dev_get_drvdata(dev);
++ int ret = 0;
++
++ if (mmc) {
++ struct s3c2410sdi_host *host = mmc_priv(mmc);
++
++ enable_irq(host->irq_cd);
++ enable_irq(host->irq);
++
++ clk_enable(host->clk);
++
++ ret = mmc_resume_host(mmc);
++ }
++
++ return ret;
++}
++#else
++#define s3c2410mci_suspend NULL
++#define s3c2410mci_resume NULL
++#endif
++
+ static struct device_driver s3c2410sdi_driver =
+ {
+ .name = "s3c2410-sdi",
+ .bus = &platform_bus_type,
+ .probe = s3c2410sdi_probe,
+ .remove = s3c2410sdi_remove,
++ .suspend = s3c2410mci_suspend,
++ .resume = s3c2410mci_resume,
+ };
+
+ static int __init s3c2410sdi_init(void)
+Index: linux-2.6.14/drivers/mmc/mmc.c
+===================================================================
+--- linux-2.6.14.orig/drivers/mmc/mmc.c
++++ linux-2.6.14/drivers/mmc/mmc.c
+@@ -1263,6 +1263,7 @@ EXPORT_SYMBOL(mmc_suspend_host);
+ */
+ int mmc_resume_host(struct mmc_host *host)
+ {
++ mmc_power_up(host);
+ mmc_detect_change(host, 0);
+
+ return 0;
diff --git a/recipes/linux/linux/acern30/series b/recipes/linux/linux/acern30/series
new file mode 100644
index 0000000000..16b58a1144
--- /dev/null
+++ b/recipes/linux/linux/acern30/series
@@ -0,0 +1,27 @@
+v2.6.14-gitcurrent.patch
+v2.6.14-full.patch
+n30-cleanup.patch
+n35.patch
+n30-lcd.patch
+n30-backlight.patch
+n30-ts.patch
+n30-buttons.patch
+n30-mmc.patch
+n30-mmc-power.patch
+n30-mmc-wprotect.patch
+n30-nand.patch
+n30-usbstart.patch
+n30-hardcode.patch
+n30-apm.patch
+s3c2410fb-resume.patch
+s3c2410_ts-pm.patch
+s3c2410_lcd-pm.c
+s3c2410mci-pm.patch
+s3c2410-nand-pm.patch
+n30-nand-hack.patch
+mmc-plus.patch
+gpio-sysfs.patch
+regdump.patch
+n30-pm.patch
+spi.patch
+wingel-hacking.patch
diff --git a/recipes/linux/linux/acern30/spi.patch b/recipes/linux/linux/acern30/spi.patch
new file mode 100644
index 0000000000..f835f82d32
--- /dev/null
+++ b/recipes/linux/linux/acern30/spi.patch
@@ -0,0 +1,121 @@
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -52,6 +52,7 @@
+ #include <asm/arch/regs-gpio.h>
+ #include <asm/arch/regs-lcd.h>
+ #include <asm/arch/regs-timer.h>
++#include <asm/arch/regs-spi.h>
+ #include <asm/arch/irqs.h>
+ #include <asm/arch/iic.h>
+ #include <asm/arch/fb.h>
+@@ -372,6 +373,7 @@ static struct platform_device *n30_devic
+ &s3c_device_usbgadget,
+ &s3c_device_sdi,
+ &s3c_device_nand,
++ &s3c_device_spi1,
+ };
+
+ static struct s3c2410_platform_i2c n30_i2ccfg = {
+@@ -712,6 +714,90 @@ static int n30_usbstart_thread(void *unu
+ return 0;
+ }
+
++static int spi_thread(void *regs)
++{
++ unsigned sptdat1 = ~0, sprdat1 = ~0, spsta1 = ~0;
++ unsigned value;
++
++ writel(0x01, regs + S3C2410_SPCON);
++ writel(0x02, regs + S3C2410_SPPIN);
++
++ s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
++ s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
++
++ s3c2410_gpio_cfgpin(S3C2410_GPG3, 0x3 << 6);
++
++ printk("GPGCON=0x%x\n", readl(S3C2410_GPGCON));
++
++ msleep(10);
++
++ while (1) {
++ value = readl(regs + S3C2410_SPTDAT);
++ if (sptdat1 != value) {
++ printk(KERN_INFO "SPTDAT1=0x%x\n", value);
++ sptdat1 = value;
++ }
++ value = readl(regs + S3C2410_SPRDAT);
++ if (sprdat1 != value) {
++ printk(KERN_INFO "SPRDAT1=0x%x\n", value);
++ sprdat1 = value;
++ }
++ value = readl(regs + S3C2410_SPSTA);
++ if (spsta1 != value) {
++ printk(KERN_INFO "SPSTA1=0x%x\n", value);
++ spsta1 = value;
++ }
++
++ msleep(10);
++ }
++}
++
++static int s3c24xx_spi_probe(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct resource *res;
++ int ret;
++ void *regs;
++ struct resource *ioarea;
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (res == NULL) {
++ dev_err(dev, "cannot find IO resource\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ ioarea = request_mem_region(res->start, (res->end-res->start)+1,
++ pdev->name);
++ if (ioarea == NULL) {
++ dev_err(dev, "cannot request IO\n");
++ ret = -ENXIO;
++ goto out;
++ }
++
++ regs = ioremap(res->start, (res->end-res->start)+1);
++ if (regs == NULL) {
++ dev_err(dev, "cannot map IO\n");
++ ret = -ENXIO;
++ goto out;
++ }
++
++ dev_info(dev, "registers %p (%p, %p)\n", regs, ioarea, res);
++
++ kthread_run(spi_thread, regs, "spi_debug");
++
++ ret = 0;
++
++ out:
++ return ret;
++}
++
++static struct device_driver s3c24xx_spi_driver = {
++ .name = "s3c2410-spi",
++ .bus = &platform_bus_type,
++ .probe = s3c24xx_spi_probe,
++};
++
+ #ifdef CONFIG_APM
+ static void n30_get_power_status(struct apm_power_info *info)
+ {
+@@ -764,6 +850,9 @@ static void __init n30_init(void)
+ memcpy_toio(N30_RESUME_VA, (void *)n30_resume,
+ &n30_resume_end - (void *)n30_resume);
+
++ if (driver_register(&s3c24xx_spi_driver) < 0)
++ printk(KERN_ERR "failed to register spi driver\n");
++
+ /* Clear any locks and write protects on the flash. */
+ s3c2410_gpio_setpin(S3C2410_GPC5, 1);
+ msleep(1);
diff --git a/recipes/linux/linux/acern30/wingel-hacking.patch b/recipes/linux/linux/acern30/wingel-hacking.patch
new file mode 100644
index 0000000000..e87de5a460
--- /dev/null
+++ b/recipes/linux/linux/acern30/wingel-hacking.patch
@@ -0,0 +1,1146 @@
+This patch contains some hacks that I'm playing around with right now.
+
+This isn't anything that should be merged into the official kernel.
+
+Index: linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/mach-n30.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/mach-n30.c
+@@ -22,6 +22,12 @@
+ * published by the Free Software Foundation.
+ */
+
++// #define USBHACK 1
++#define SPIHACK 1
++
++void s3c2410_capture_regs(void);
++void s3c2410_dump_regs(void);
++
+ #include <linux/kernel.h>
+ #include <linux/types.h>
+ #include <linux/interrupt.h>
+@@ -272,14 +278,18 @@ static struct s3c2410_button n35_buttons
+
+ { IRQ_EINT13, S3C2410_GPG5, S3C2410_GPG5_EINT13, KEY_LEFT,
+ "Left_arrow", 0 },
++#ifndef SPIHACK
+ { IRQ_EINT14, S3C2410_GPG6, S3C2410_GPG6_EINT14, KEY_RIGHT,
+ "Right_arrow", 0 },
++#endif
+ { IRQ_EINT17, S3C2410_GPG9, S3C2410_GPG9_EINT17, KEY_UP,
+ "Up_arrow", 0 },
+ { IRQ_EINT16, S3C2410_GPG8, S3C2410_GPG8_EINT16, KEY_DOWN,
+ "Down_arrow", 0 },
++#ifndef SPIHACK
+ { IRQ_EINT15, S3C2410_GPG7, S3C2410_GPG7_EINT15, KEY_ENTER,
+ "Select", 0 },
++#endif
+
+ { IRQ_EINT7, S3C2410_GPF7, S3C2410_GPF7_EINT7, KEY_HOMEPAGE,
+ "Home", 0 },
+@@ -367,7 +377,6 @@ static struct platform_device *n30_devic
+ &s3c_device_usbgadget,
+ &s3c_device_sdi,
+ &s3c_device_nand,
+- &s3c_device_spi1,
+ };
+
+ static struct s3c2410_platform_i2c n30_i2ccfg = {
+@@ -382,6 +391,27 @@ static struct s3c24xx_board n30_board __
+ .devices_count = ARRAY_SIZE(n30_devices)
+ };
+
++static struct platform_device *n35_devices[] __initdata = {
++ &s3c_device_lcd,
++ &s3c_device_bl,
++ &s3c_device_ts,
++ &s3c_device_buttons,
++ &s3c_device_wdt,
++ &s3c_device_i2c,
++ &s3c_device_iis,
++ &s3c_device_usbgadget,
++ &s3c_device_sdi,
++ &s3c_device_nand,
++#ifdef SPIHACK
++ &s3c_device_spi1,
++#endif
++};
++
++static struct s3c24xx_board n35_board __initdata = {
++ .devices = n35_devices,
++ .devices_count = ARRAY_SIZE(n35_devices)
++};
++
+ /* Lots of hardcoded stuff, but it sets up the hardware in a useful
+ * state so that we can boot Linux directly from flash. */
+ static void __init n30_hwinit(void)
+@@ -674,7 +704,10 @@ static void __init n30_map_io(void)
+ n30_hwinit();
+ s3c24xx_init_clocks(0);
+ s3c24xx_init_uarts(n30_uartcfgs, ARRAY_SIZE(n30_uartcfgs));
+- s3c24xx_set_board(&n30_board);
++ if (machine_is_n30())
++ s3c24xx_set_board(&n30_board);
++ if (machine_is_n35())
++ s3c24xx_set_board(&n35_board);
+ }
+
+ static void __init n30_init_irq(void)
+@@ -710,90 +743,6 @@ static int n30_usbstart_thread(void *unu
+ return 0;
+ }
+
+-static int spi_thread(void *regs)
+-{
+- unsigned sptdat1 = ~0, sprdat1 = ~0, spsta1 = ~0;
+- unsigned value;
+-
+- writel(0x01, regs + S3C2410_SPCON);
+- writel(0x02, regs + S3C2410_SPPIN);
+-
+- s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
+- s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
+-
+- s3c2410_gpio_cfgpin(S3C2410_GPG3, 0x3 << 6);
+-
+- printk("GPGCON=0x%x\n", readl(S3C2410_GPGCON));
+-
+- msleep(10);
+-
+- while (1) {
+- value = readl(regs + S3C2410_SPTDAT);
+- if (sptdat1 != value) {
+- printk(KERN_INFO "SPTDAT1=0x%x\n", value);
+- sptdat1 = value;
+- }
+- value = readl(regs + S3C2410_SPRDAT);
+- if (sprdat1 != value) {
+- printk(KERN_INFO "SPRDAT1=0x%x\n", value);
+- sprdat1 = value;
+- }
+- value = readl(regs + S3C2410_SPSTA);
+- if (spsta1 != value) {
+- printk(KERN_INFO "SPSTA1=0x%x\n", value);
+- spsta1 = value;
+- }
+-
+- msleep(10);
+- }
+-}
+-
+-static int s3c24xx_spi_probe(struct device *dev)
+-{
+- struct platform_device *pdev = to_platform_device(dev);
+- struct resource *res;
+- int ret;
+- void *regs;
+- struct resource *ioarea;
+-
+- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+- if (res == NULL) {
+- dev_err(dev, "cannot find IO resource\n");
+- ret = -ENOENT;
+- goto out;
+- }
+-
+- ioarea = request_mem_region(res->start, (res->end-res->start)+1,
+- pdev->name);
+- if (ioarea == NULL) {
+- dev_err(dev, "cannot request IO\n");
+- ret = -ENXIO;
+- goto out;
+- }
+-
+- regs = ioremap(res->start, (res->end-res->start)+1);
+- if (regs == NULL) {
+- dev_err(dev, "cannot map IO\n");
+- ret = -ENXIO;
+- goto out;
+- }
+-
+- dev_info(dev, "registers %p (%p, %p)\n", regs, ioarea, res);
+-
+- kthread_run(spi_thread, regs, "spi_debug");
+-
+- ret = 0;
+-
+- out:
+- return ret;
+-}
+-
+-static struct device_driver s3c24xx_spi_driver = {
+- .name = "s3c2410-spi",
+- .bus = &platform_bus_type,
+- .probe = s3c24xx_spi_probe,
+-};
+-
+ #ifdef CONFIG_APM
+ static void n30_get_power_status(struct apm_power_info *info)
+ {
+@@ -825,6 +774,128 @@ static void n30_get_power_status(struct
+ }
+ #endif
+
++#define DEBUG_GPIO 1
++
++#ifdef DEBUG_GPIO
++static int n30_debug_thread(void *unused)
++{
++ int i;
++#define PIN(x) { x, #x }
++ static struct pin {
++ unsigned int pin;
++ const char *name;
++ } pins[] = {
++ PIN(S3C2410_GPA12),
++ PIN(S3C2410_GPB2),
++ PIN(S3C2410_GPB4),
++ PIN(S3C2410_GPB5),
++ PIN(S3C2410_GPB6),
++ PIN(S3C2410_GPB7),
++ PIN(S3C2410_GPC0),
++ PIN(S3C2410_GPC3),
++ PIN(S3C2410_GPC6),
++ PIN(S3C2410_GPC7),
++ PIN(S3C2410_GPC8),
++ PIN(S3C2410_GPD0),
++ PIN(S3C2410_GPD8),
++ PIN(S3C2410_GPD9),
++ PIN(S3C2410_GPD10),
++ PIN(S3C2410_GPE11),
++ PIN(S3C2410_GPE12),
++ PIN(S3C2410_GPE13),
++ PIN(S3C2410_GPF0),
++ PIN(S3C2410_GPF1),
++ PIN(S3C2410_GPF2),
++ PIN(S3C2410_GPF3),
++ PIN(S3C2410_GPG0),
++ PIN(S3C2410_GPG1),
++ PIN(S3C2410_GPG2),
++ PIN(S3C2410_GPG3),
++ PIN(S3C2410_GPG4),
++ PIN(S3C2410_GPH8),
++ };
++#undef PIN
++ enum { PIN_CNT = (sizeof(pins) / sizeof(struct pin)) };
++ static int values[PIN_CNT];
++ static int changes[PIN_CNT];
++
++ set_current_state(TASK_INTERRUPTIBLE);
++ schedule_timeout(1 * HZ);
++
++// s3c2410_dump_regs();
++
++ printk("AFTER\n");
++
++ s3c2410_capture_regs();
++
++// s3c2410_dump_regs();
++
++ for (i = 0; i < PIN_CNT; i++)
++ values[i] = s3c2410_gpio_getpin(pins[i].pin) ? 1 : 0;
++
++ printk("MISCCR=0x%08x\n", readl(S3C2410_MISCCR));
++
++ while (!kthread_should_stop()) {
++ for (i = 0; i < PIN_CNT; i++) {
++ int value = s3c2410_gpio_getpin(pins[i].pin) ? 1 : 0;
++
++ if (values[i] != value && changes[i] < 100) {
++ changes[i]++;
++ values[i] = value;
++ printk(KERN_CRIT "%s: %d (%d)\n", pins[i].name, value, changes[i]);
++ }
++ }
++
++ if (0) {
++ s3c2410_gpio_pullup(S3C2410_GPE15, 1);
++ s3c2410_gpio_cfgpin(S3C2410_GPE15, S3C2410_GPE15_OUTP);
++ s3c2410_gpio_setpin(S3C2410_GPE15, !s3c2410_gpio_getpin(S3C2410_GPE15));
++ }
++
++ if (0)
++ s3c2410_gpio_setpin(S3C2410_GPB3, !s3c2410_gpio_getpin(S3C2410_GPB3));
++
++ if (1) {
++ static int last_f0;
++ int f0 = s3c2410_gpio_getpin(S3C2410_GPF0);
++
++ if (last_f0 != f0) {
++ last_f0 = f0;
++ if (!f0) {
++ int r;
++ printk("entering suspend\n");
++ r = pm_suspend(PM_SUSPEND_MEM);
++ printk("after suspend %d\n", r);
++ }
++ }
++ }
++
++
++ if (0) {
++ static int last_f6;
++ int f6 = s3c2410_gpio_getpin(S3C2410_GPF6);
++
++ if (last_f6 != f6) {
++ last_f6 = f6;
++ if (!f6) {
++ if (s3c2410_gpio_getcfg(S3C2410_GPB6) != S3C2410_GPB6_OUTP) {
++ printk("B6 configured as output");
++ s3c2410_gpio_cfgpin(S3C2410_GPB6, S3C2410_GPB6_OUTP);
++ } else {
++ printk("B6 configured as input");
++ s3c2410_gpio_cfgpin(S3C2410_GPB6, S3C2410_GPB6_INP);
++ }
++ }
++ }
++ }
++
++ msleep(10);
++ }
++
++ return 0;
++}
++#endif
++
+ static void __init n30_init(void)
+ {
+ s3c24xx_fb_set_platdata(&n30_lcdcfg);
+@@ -846,9 +917,6 @@ static void __init n30_init(void)
+ memcpy_toio(N30_RESUME_VA, (void *)n30_resume,
+ &n30_resume_end - (void *)n30_resume);
+
+- if (driver_register(&s3c24xx_spi_driver) < 0)
+- printk(KERN_ERR "failed to register spi driver\n");
+-
+ /* Clear any locks and write protects on the flash. */
+ s3c2410_gpio_setpin(S3C2410_GPC5, 1);
+ msleep(1);
+@@ -861,6 +929,8 @@ static void __init n30_init(void)
+ #ifdef CONFIG_APM
+ apm_get_power_status = n30_get_power_status;
+ #endif
++
++ kthread_run(n30_debug_thread, NULL, "n30_debug");
+ }
+
+ MACHINE_START(N30, "Acer-N30")
+Index: linux-2.6.14/arch/arm/mach-s3c2410/Makefile
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/Makefile
++++ linux-2.6.14/arch/arm/mach-s3c2410/Makefile
+@@ -46,3 +46,5 @@ obj-$(CONFIG_MACH_NEXCODER_2440) += mach
+ obj-y += gpio-sysfs.o
+ obj-y += regdump.o
+
++obj-m += spi-int.o
++obj-m += spi-dma.o
+Index: linux-2.6.14/arch/arm/mach-s3c2410/spi-int.c
+===================================================================
+--- /dev/null
++++ linux-2.6.14/arch/arm/mach-s3c2410/spi-int.c
+@@ -0,0 +1,261 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/kthread.h>
++#include <linux/delay.h>
++
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <asm/hardware/clock.h>
++
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-spi.h>
++#include <asm/arch/regs-irq.h>
++
++struct spi_info {
++ void *regs;
++ struct device *dev;
++ struct clk *clk;
++ struct resource *ioarea;
++ struct resource *irq;
++ struct task_struct *debug_thread;
++};
++
++static int spi_debug_thread(void *data)
++{
++ struct spi_info *info = data;
++ unsigned sptdat1 = ~0, sprdat1 = ~0, spsta1 = ~0;
++ unsigned value;
++
++ while (!kthread_should_stop()) {
++ if (1) {
++ value = readl(info->regs + S3C2410_SPTDAT);
++ if (sptdat1 != value) {
++ printk(KERN_INFO "SPTDAT1=0x%x\n", value);
++ sptdat1 = value;
++ }
++ value = readl(info->regs + S3C2410_SPRDAT);
++ if (sprdat1 != value) {
++ printk(KERN_INFO "SPRDAT1=0x%x\n", value);
++ sprdat1 = value;
++ }
++ value = readl(info->regs + S3C2410_SPSTA);
++ if (spsta1 != value) {
++ printk("SRCPND=0x%08x\n", readl(S3C2410_SRCPND));
++ printk("INTMOD=0x%08x\n", readl(S3C2410_INTMOD));
++ printk("INTMSK=0x%08x\n", readl(S3C2410_INTMSK));
++ printk("INTPND=0x%08x\n", readl(S3C2410_INTPND));
++
++ printk(KERN_INFO "SPSTA1=0x%x\n", value);
++ spsta1 = value;
++ }
++ }
++ if (1) {
++ if (readl(info->regs + S3C2410_SPSTA) & S3C2410_SPSTA_READY) {
++ value = readl(info->regs + S3C2410_SPRDAT);
++ printk("DAT=0x%02x\n", value);
++ writel(1, info->regs + S3C2410_SPTDAT);
++ }
++ }
++
++ msleep(1);
++ }
++
++ return 0;
++}
++
++static irqreturn_t spi_int_irq(int irq, void *dev_id, struct pt_regs *regs)
++{
++ struct spi_info *info = dev_id;
++ unsigned long status;
++
++ status = readl(info->regs + S3C2410_SPSTA);
++
++ if (status & S3C2410_SPSTA_READY) {
++ printk("INT %02x\n", readb(info->regs + S3C2410_SPRDAT));
++ writeb(0xff, info->regs + S3C2410_SPTDAT);
++ }
++
++ return IRQ_HANDLED;
++}
++
++static void spi_int_free(struct spi_info *info)
++{
++ if (!info)
++ return;
++
++ if (info->debug_thread)
++ kthread_stop(info->debug_thread);
++ if (info->irq)
++ free_irq(info->irq->start, info);
++ if (info->regs)
++ iounmap(info->regs);
++ if (info->ioarea) {
++ release_resource(info->ioarea);
++ kfree(info->ioarea);
++ }
++ if (info->clk) {
++ clk_unuse(info->clk);
++ clk_disable(info->clk);
++ }
++ kfree(info);
++}
++
++static int spi_int_probe(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ int ret;
++ struct spi_info *info;
++ struct resource *res;
++
++ printk("spi_int_probe\n");
++
++ info = kmalloc(sizeof(struct spi_info), GFP_KERNEL);
++ if (!info) {
++ dev_err(dev, "failed to allocate info structure\n");
++ ret = -ENOMEM;
++ goto out;
++ }
++ memset(info, 0, sizeof(*info));
++ info->dev = dev;
++
++ dev_info(dev, "got info %p\n", info);
++
++ info->clk = clk_get(dev, "spi");
++ if (IS_ERR(info->clk)) {
++ dev_err(dev, "clk_get failed\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ dev_dbg(dev, "clk %p\n", info->clk);
++
++ clk_use(info->clk);
++ clk_enable(info->clk);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(dev, "unable to find registers\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ dev_info(dev, "got res %p\n", res);
++
++ info->ioarea = request_mem_region(res->start,
++ (res->end-res->start)+1,
++ pdev->name);
++ if (!info->ioarea) {
++ dev_err(dev, "request_mem_region failed\n");
++ ret = -ENXIO;
++ goto out;
++ }
++
++ dev_info(dev, "got ioarea %p\n", info->ioarea);
++
++ info->regs = ioremap(res->start, (res->end-res->start)+1);
++ if (!info->regs) {
++ dev_err(dev, "ioremap failed\n");
++ ret = -ENXIO;
++ goto out;
++ }
++
++ dev_info(dev, "got regs %p\n", info->regs);
++
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res) {
++ dev_err(dev, "unable to find irq\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ writel(S3C2410_SPCON_SMOD_INT /* | S3C2410_SPCON_TAGD */,
++ info->regs + S3C2410_SPCON);
++ writel(S3C2410_SPPIN_RESERVED, info->regs + S3C2410_SPPIN);
++
++ s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
++ s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
++ s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
++
++ s3c2410_gpio_cfgpin(S3C2410_GPG3, 0x3 << 6);
++
++ ret = request_irq(res->start, spi_int_irq, 0, pdev->name, info);
++ if (ret) {
++ dev_err(dev, "request_irq failed\n");
++ goto out;
++ }
++ info->irq = res;
++
++ dev_info(dev, "got irq %ld\n", info->irq->start);
++
++ dev_info(dev, "SPI driver active\n");
++
++ dev_set_drvdata(dev, info);
++ ret = 0;
++
++ writeb(0x00, info->regs + S3C2410_SPTDAT);
++
++ if (0) {
++ info->debug_thread = kthread_run(spi_debug_thread, info,
++ "spi_debug_thread");
++ }
++
++ printk("SRCPND=0x%08x\n", readl(S3C2410_SRCPND));
++ printk("INTMOD=0x%08x\n", readl(S3C2410_INTMOD));
++ printk("INTMSK=0x%08x\n", readl(S3C2410_INTMSK));
++ printk("INTPND=0x%08x\n", readl(S3C2410_INTPND));
++ printk("EINTMASK=0x%08x\n", readl(S3C2410_EINTMASK));
++
++ printk("SPCON=0x%08x\n", readl(info->regs + S3C2410_SPCON));
++ __raw_writel(S3C2410_SPCON_SMOD_INT | S3C2410_SPCON_TAGD,
++ info->regs + S3C2410_SPCON);
++ printk("SPCON=0x%08x\n", readl(info->regs + S3C2410_SPCON));
++ printk("FOO=0x%08x\n", S3C2410_SPCON_SMOD_INT);
++
++ out:
++ if (ret)
++ spi_int_free(info);
++
++ return ret;
++}
++
++static int spi_int_remove(struct device *dev)
++{
++ struct spi_info *info = dev_get_drvdata(dev);
++
++ dev_set_drvdata(dev, NULL);
++
++ spi_int_free(info);
++
++ return 0;
++}
++
++static struct device_driver spi_int_driver = {
++ .name = "s3c2410-spi",
++ .bus = &platform_bus_type,
++ .probe = spi_int_probe,
++ .remove = spi_int_remove,
++};
++
++static int __init spi_int_init(void)
++{
++ printk("SPI interrput driver loaded\n");
++
++ return driver_register(&spi_int_driver);
++}
++
++static void __exit spi_int_exit(void)
++{
++ driver_unregister(&spi_int_driver);
++}
++
++module_init(spi_int_init);
++module_exit(spi_int_exit);
++
++MODULE_DESCRIPTION("S3C2410 interrupt driven SPI driver");
++MODULE_AUTHOR("Christer Weinigel <christer@weinigel.se>");
++MODULE_LICENSE("GPL");
+Index: linux-2.6.14/arch/arm/mach-s3c2410/devs.c
+===================================================================
+--- linux-2.6.14.orig/arch/arm/mach-s3c2410/devs.c
++++ linux-2.6.14/arch/arm/mach-s3c2410/devs.c
+@@ -400,11 +400,17 @@ static struct resource s3c_spi0_resource
+
+ };
+
++static u64 s3c_device_spi0_dmamask = 0xffffffffUL;
++
+ struct platform_device s3c_device_spi0 = {
+ .name = "s3c2410-spi",
+ .id = 0,
+ .num_resources = ARRAY_SIZE(s3c_spi0_resource),
+ .resource = s3c_spi0_resource,
++ .dev = {
++ .dma_mask = &s3c_device_spi0_dmamask,
++ .coherent_dma_mask = 0xffffffffUL
++ }
+ };
+
+ EXPORT_SYMBOL(s3c_device_spi0);
+@@ -425,11 +431,17 @@ static struct resource s3c_spi1_resource
+
+ };
+
++static u64 s3c_device_spi1_dmamask = 0xffffffffUL;
++
+ struct platform_device s3c_device_spi1 = {
+ .name = "s3c2410-spi",
+ .id = 1,
+ .num_resources = ARRAY_SIZE(s3c_spi1_resource),
+ .resource = s3c_spi1_resource,
++ .dev = {
++ .dma_mask = &s3c_device_spi1_dmamask,
++ .coherent_dma_mask = 0xffffffffUL
++ }
+ };
+
+ EXPORT_SYMBOL(s3c_device_spi1);
+Index: linux-2.6.14/arch/arm/mach-s3c2410/spi-dma.c
+===================================================================
+--- /dev/null
++++ linux-2.6.14/arch/arm/mach-s3c2410/spi-dma.c
+@@ -0,0 +1,498 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/interrupt.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/kthread.h>
++#include <linux/delay.h>
++#include <linux/dma-mapping.h>
++#include <linux/spinlock.h>
++
++#include <asm/uaccess.h>
++#include <asm/dma.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++
++#include <asm/hardware/clock.h>
++
++#include <asm/arch/dma.h>
++#include <asm/arch/regs-gpio.h>
++#include <asm/arch/regs-spi.h>
++
++#define BUFFER_SIZE (1024*1024)
++#define CHUNK_SIZE (64*1024)
++#define NUM_CHUNKS (BUFFER_SIZE / CHUNK_SIZE)
++
++static char spi_dma_name[] = "s3c2410-spi-dma-reader";
++
++static struct s3c2410_dma_client spi_dma_client = {
++ .name = spi_dma_name,
++};
++
++struct spi_dma_state {
++ struct spi_dma_info *info;
++ int status; /* 0=inactive, 1=running, <0 = -errno */
++ unsigned tail;
++};
++
++struct spi_chunk {
++ int index;
++ dma_addr_t handle;
++ struct spi_dma_info *info;
++};
++
++struct spi_dma_info {
++ void *cpu_addr;
++ dma_addr_t handle;
++ size_t size;
++
++ spinlock_t head_lock;
++ unsigned head;
++ wait_queue_head_t wait_q;
++
++ void *regs;
++
++ struct device *dev;
++ struct clk *clk;
++ struct resource *iomem;
++ int major;
++ dmach_t dmach;
++ int dcon;
++ int flushing;
++ char have_dma;
++ struct spi_chunk chunks[NUM_CHUNKS];
++};
++
++static void spi_queue_dma(struct spi_chunk *chunk)
++{
++ s3c2410_dma_enqueue(chunk->info->dmach,
++ chunk, chunk->handle, CHUNK_SIZE);
++}
++
++static void spi_dma_done_callback(s3c2410_dma_chan_t *dma_ch, void *buf_id,
++ int size, s3c2410_dma_buffresult_t result)
++{
++ struct spi_chunk *chunk = buf_id;
++ struct spi_dma_info *info = chunk->info;
++
++ if (info->flushing)
++ return;
++
++ spin_lock(&info->head_lock);
++ if ((info->head / CHUNK_SIZE) % NUM_CHUNKS != chunk->index)
++ dev_warn(info->dev, "out of sync, head=0x%x, index=0x%x\n",
++ info->head, chunk->index);
++
++ info->head += size;
++ spin_unlock(&info->head_lock);
++
++ wake_up_interruptible(&info->wait_q);
++
++ spi_queue_dma(chunk);
++}
++
++static struct spi_dma_info *global_info;
++
++static ssize_t spi_dma_read(struct file *file, char __user *buf,
++ size_t len, loff_t *ppos)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ struct spi_dma_state *state = file->private_data;
++ struct spi_dma_info *info = state->info;
++ unsigned head;
++ ssize_t start, end;
++ ssize_t n;
++
++ if (state->status <= 0) {
++ if (state->status) {
++ state->status = 0;
++ return state->status;
++ }
++ state->tail = info->head;
++ state->status = 1;
++ }
++
++ add_wait_queue(&info->wait_q, &wait);
++ while (1) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ if ((head = info->head) != state->tail)
++ break;
++ if (signal_pending(current))
++ break;
++ schedule();
++ }
++ remove_wait_queue(&info->wait_q, &wait);
++ set_current_state(TASK_RUNNING);
++
++ if (signal_pending(current))
++ return -EINTR;
++
++ if ((head - state->tail) > BUFFER_SIZE)
++ return -ENOBUFS;
++
++ start = state->tail % BUFFER_SIZE;
++ end = head % BUFFER_SIZE;
++
++ if (end > start)
++ n = end - start;
++ else
++ n = BUFFER_SIZE - start;
++
++ if (n > len)
++ n = len;
++
++ if (copy_to_user(buf, info->cpu_addr + start, n))
++ return -EFAULT;
++
++ state->tail += n;
++
++ return n;
++}
++
++static int spi_dma_mmap(struct file *file, struct vm_area_struct *vma)
++{
++ struct spi_dma_state *state = file->private_data;
++ struct spi_dma_info *info = state->info;
++
++ return dma_mmap_coherent(info->dev, vma,
++ info->cpu_addr, info->handle, info->size);
++}
++
++static int spi_dma_get_pos(struct spi_dma_info *info, unsigned *arg)
++{
++ if (put_user(info->head, arg))
++ return -EFAULT;
++
++ return 0;
++}
++
++static int spi_dma_wait_pos(struct spi_dma_info *info, unsigned *arg)
++{
++ DECLARE_WAITQUEUE(wait, current);
++ unsigned pos;
++ int diff;
++
++ if (get_user(pos, arg))
++ return -EFAULT;
++
++ add_wait_queue(&info->wait_q, &wait);
++ while (1) {
++ set_current_state(TASK_INTERRUPTIBLE);
++ if ((diff = info->head - pos) > 0)
++ break;
++ if (signal_pending(current))
++ break;
++ schedule();
++ }
++ remove_wait_queue(&info->wait_q, &wait);
++ set_current_state(TASK_RUNNING);
++
++ if (signal_pending(current))
++ return -EINTR;
++
++ if (diff > BUFFER_SIZE)
++ return -ENOBUFS;
++
++ if (put_user(info->head, arg))
++ return -EFAULT;
++
++ return 0;
++}
++
++#define SPI_DMA_IOCTL_BASE ('N' ^ 'M')
++#define SPI_DMA_GET_BUFFER_SIZE _IOR(SPI_DMA_IOCTL_BASE, 0, unsigned)
++#define SPI_DMA_GET_POS _IOR(SPI_DMA_IOCTL_BASE, 1, unsigned)
++#define SPI_DMA_WAIT_POS _IOWR(SPI_DMA_IOCTL_BASE, 2, unsigned)
++
++static int spi_dma_ioctl(struct inode *inode, struct file *file,
++ unsigned int cmd, unsigned long arg)
++{
++ struct spi_dma_state *state = file->private_data;
++ struct spi_dma_info *info = state->info;
++
++ switch (cmd) {
++ case SPI_DMA_GET_BUFFER_SIZE:
++ if (put_user((unsigned)BUFFER_SIZE, (unsigned *)arg))
++ return -EFAULT;
++ return 0;
++
++ case SPI_DMA_GET_POS:
++ return spi_dma_get_pos(info, (unsigned *)arg);
++
++ case SPI_DMA_WAIT_POS:
++ return spi_dma_wait_pos(info, (unsigned *)arg);
++
++ default:
++ return -EINVAL;
++ }
++}
++
++static int spi_dma_open(struct inode *inode, struct file *file)
++{
++ struct spi_dma_info *info = global_info;
++ struct spi_dma_state *state;
++ int ret;
++
++ state = kmalloc(sizeof(struct spi_dma_state), GFP_KERNEL);
++ if (!state)
++ return -ENOMEM;
++ state->info = info;
++ state->status = 0;
++ file->private_data = state;
++
++ ret = nonseekable_open(inode, file);
++
++ if (ret)
++ kfree(state);
++
++ return ret;
++}
++
++static int spi_dma_release(struct inode *inode, struct file *file)
++{
++ kfree(file->private_data);
++ return 0;
++}
++
++static struct file_operations spi_dma_fops = {
++ .owner = THIS_MODULE,
++ .read = spi_dma_read,
++ .open = spi_dma_open,
++ .release = spi_dma_release,
++ .mmap = spi_dma_mmap,
++ .ioctl = spi_dma_ioctl,
++};
++
++static void spi_dma_free(struct spi_dma_info *info)
++{
++ if (!info)
++ return;
++
++ if (info->major)
++ unregister_chrdev(info->major, "s3c2410-spi");
++ if (info->have_dma) {
++ int value;
++
++ printk("flush\n");
++ info->flushing = 1;
++ s3c2410_dma_ctrl(info->dmach, S3C2410_DMAOP_FLUSH);
++ msleep(100);
++ printk("stop\n");
++ s3c2410_dma_ctrl(info->dmach, S3C2410_DMAOP_STOP);
++ msleep(100);
++
++ printk("poll\n");
++ writel(S3C2410_SPCON_SMOD_POLL, info->regs + S3C2410_SPCON);
++ value = readb(info->regs + S3C2410_SPRDAT);
++ printk("%02x\n", value);
++
++ s3c2410_dma_free(info->dmach, &spi_dma_client);
++ }
++ if (info->regs)
++ iounmap(info->regs);
++ if (info->iomem) {
++ release_resource(info->iomem);
++ kfree(info->iomem);
++ }
++ if (info->clk) {
++ clk_unuse(info->clk);
++ clk_disable(info->clk);
++ }
++ if (info->cpu_addr) {
++ dma_free_coherent(info->dev,
++ info->size, info->cpu_addr,
++ info->handle);
++
++ }
++ kfree(info);
++}
++
++static int spi_dma_probe(struct device *dev)
++{
++ struct platform_device *pdev = to_platform_device(dev);
++ struct spi_dma_info *info;
++ struct resource *res;
++ int ret;
++ int i;
++
++ printk("spi_dma_probe\n");
++
++ info = kmalloc(sizeof(struct spi_dma_info), GFP_KERNEL);
++ if (!info) {
++ dev_err(dev, "failed to allocate info structure\n");
++ ret = -ENOMEM;
++ goto out;
++ }
++ memset(info, 0, sizeof(*info));
++ info->dev = dev;
++
++ dev_info(dev, "got info %p\n", info);
++
++ // TODO figure this out in a better way
++ info->dmach = 3;
++ info->dcon = S3C2410_DCON_CH3_SPI;
++ info->size = BUFFER_SIZE;
++
++ spin_lock_init(&info->head_lock);
++ init_waitqueue_head(&info->wait_q);
++
++ info->cpu_addr = dma_alloc_coherent(dev, info->size, &info->handle, GFP_KERNEL);
++ if (!info->cpu_addr) {
++ dev_err(dev, "failed to allocate DMA buffer\n");
++ ret = -ENOMEM;
++ goto out;
++ }
++
++ dev_info(dev, "got DMA buffer at %p, handle 0x%08lx, size %d\n",
++ info->cpu_addr, (long)info->handle,
++ info->size);
++
++ info->clk = clk_get(dev, "spi");
++ if (IS_ERR(info->clk)) {
++ dev_err(dev, "clk_get failed\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ dev_dbg(dev, "clk %p\n", info->clk);
++
++ clk_use(info->clk);
++ clk_enable(info->clk);
++
++ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
++ if (!res) {
++ dev_err(dev, "unable to find registers\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ dev_info(dev, "got iomem %p\n", res);
++
++ info->iomem = request_mem_region(res->start,
++ (res->end-res->start)+1,
++ pdev->name);
++ if (!info->iomem) {
++ dev_err(dev, "request_mem_region failed\n");
++ ret = -ENXIO;
++ goto out;
++ }
++
++ dev_info(dev, "got iomem %p\n", info->iomem);
++
++ dev_info(dev, "res->start=0x%lx, res->end=0x%lx\n", res->start, res->end);
++ dev_info(dev, "iomem->start=0x%lx, iomem->end=0x%lx\n", info->iomem->start, info->iomem->end);
++
++ info->regs = ioremap(res->start, (res->end-res->start)+1);
++ if (!info->regs) {
++ dev_err(dev, "ioremap failed\n");
++ ret = -ENXIO;
++ goto out;
++ }
++
++ dev_info(dev, "got regs %p\n", info->regs);
++
++ if (s3c2410_dma_request(info->dmach, &spi_dma_client, NULL)) {
++ dev_err(dev, "unable to allocate dma channel\n");
++ ret = -ENOENT;
++ goto out;
++ }
++ info->have_dma = 1;
++
++ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
++ if (!res) {
++ dev_err(dev, "unable to find irq\n");
++ ret = -ENOENT;
++ goto out;
++ }
++
++ ret = register_chrdev(0, "s3c2410-spi", &spi_dma_fops);
++ if (ret < 0) {
++ dev_err(dev, "unable to register character device\n");
++ goto out;
++ }
++ info->major = ret;
++ global_info = info;
++
++ dev_info(dev, "SPI driver active\n");
++
++ dev_set_drvdata(dev, info);
++
++ writel(S3C2410_SPCON_SMOD_DMA | S3C2410_SPCON_TAGD,
++ info->regs + S3C2410_SPCON);
++ writel(S3C2410_SPPIN_RESERVED, info->regs + S3C2410_SPPIN);
++
++ // s3c2410_gpio_cfgpin(S3C2410_GPG5, S3C2410_GPG5_SPIMISO1);
++ s3c2410_gpio_cfgpin(S3C2410_GPG6, S3C2410_GPG6_SPIMOSI1);
++ s3c2410_gpio_cfgpin(S3C2410_GPG7, S3C2410_GPG7_SPICLK1);
++
++ s3c2410_gpio_cfgpin(S3C2410_GPG3, 0x3 << 6);
++
++ s3c2410_dma_devconfig(info->dmach, S3C2410_DMASRC_HW,
++ S3C2410_DISRCC_INC | S3C2410_DISRCC_APB,
++ info->iomem->start + S3C2410_SPRDAT);
++
++ s3c2410_dma_config(info->dmach, 1, info->dcon);
++
++ s3c2410_dma_set_buffdone_fn(info->dmach, spi_dma_done_callback);
++ s3c2410_dma_setflags(info->dmach, S3C2410_DMAF_AUTOSTART);
++
++ writeb(0, info->regs + S3C2410_SPTDAT);
++ msleep(10);
++
++ for (i = 0; i < NUM_CHUNKS; i++) {
++ int offset = i * CHUNK_SIZE;
++ info->chunks[i].index = i;
++ info->chunks[i].handle = info->handle + offset;
++ info->chunks[i].info = info;
++ }
++
++ for (i = 0; i < NUM_CHUNKS; i++) {
++ spi_queue_dma(&info->chunks[i]);
++ }
++
++ ret = 0;
++
++ out:
++ if (ret)
++ spi_dma_free(info);
++
++ return ret;
++}
++
++static int spi_dma_remove(struct device *dev)
++{
++ struct spi_dma_info *info = dev_get_drvdata(dev);
++
++ dev_set_drvdata(dev, NULL);
++
++ spi_dma_free(info);
++
++ return 0;
++}
++
++static struct device_driver spi_dma_driver = {
++ .name = "s3c2410-spi",
++ .bus = &platform_bus_type,
++ .probe = spi_dma_probe,
++ .remove = spi_dma_remove,
++};
++
++static int __init spi_dma_init(void)
++{
++ printk("SPI dma driver loaded\n");
++
++ return driver_register(&spi_dma_driver);
++}
++
++static void __exit spi_dma_exit(void)
++{
++ driver_unregister(&spi_dma_driver);
++}
++
++module_init(spi_dma_init);
++module_exit(spi_dma_exit);
++
++MODULE_DESCRIPTION("S3C2410 DMA driven SPI driver");
++MODULE_AUTHOR("Christer Weinigel <christer@weinigel.se>");
++MODULE_LICENSE("GPL");