diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/Documentation/Configure.help linux-2.4.21-rmk1-lh7a400/Documentation/Configure.help --- linux-2.4.21-rmk1/Documentation/Configure.help Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/Documentation/Configure.help Sun Feb 8 20:06:00 2004 @@ -26801,6 +26801,33 @@ CONFIG_IPMI_WATCHDOG This enables the IPMI watchdog timer. +Sharp LH7A400 based bords +CONFIG_ARCH_LH7A400 + Say Y here to support the Sharp LH7A400 System on Chip. + +Sharp LH7A400 Evaluation Board (Aruba) +CONFIG_MACH_KEV7A400 + Say Y here to support the Sharp LH7A400 SoC Evaluation Board. + +Sharp LH7A400 UART +CONFIG_SERIAL_LH7A400 + Say Y here to include support for the UART on the Sharp + LH7A400 SoC. + + If unsure, say N. + +Console on a Sharp LH7A400 Serial port +CONFIG_SERIAL_LH7A400_CONSOLE + Say Y here to support a serial console on the + Sharp LH7A400 SoC Serial port. + + If unsure, say N. + +PCMCIA support for Sharp LH7A400 +CONFIG_PCMCIA_LH7A400 + Say Y here to support PCMCIA no the Sharp LH7A400 + + if unsure, say N. # # A couple of things I keep forgetting: # capitalize: AppleTalk, Ethernet, DOS, DMA, FAT, FTP, Internet, diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/Makefile linux-2.4.21-rmk1-lh7a400/Makefile --- linux-2.4.21-rmk1/Makefile Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/Makefile Thu Oct 16 13:43:25 2003 @@ -1,11 +1,12 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 21 -EXTRAVERSION =-rmk1 +EXTRAVERSION =-rmk1-lh7a400 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) -ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) +#ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) +ARCH := arm KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g") CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ @@ -19,7 +20,7 @@ HOSTCC = gcc HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -CROSS_COMPILE = +CROSS_COMPILE = /opt/hardhat/devkit/arm/920t_le/bin/arm_920t_le- # # Include the make variables (CC, etc...) @@ -195,6 +196,7 @@ DRIVERS-$(CONFIG_ISDN_BOOL) += drivers/isdn/vmlinux-obj.o DRIVERS-$(CONFIG_PLD) += drivers/pld/pld.o DRIVERS-$(CONFIG_ARCH_AT91RM9200) += drivers/at91/at91drv.o +DRIVERS-$(CONFIG_MMC) += drivers/mmc/mmc.o DRIVERS := $(DRIVERS-y) diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/Makefile linux-2.4.21-rmk1-lh7a400/arch/arm/Makefile --- linux-2.4.21-rmk1/arch/arm/Makefile Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/Makefile Thu Oct 16 13:44:16 2003 @@ -164,6 +164,10 @@ MACHINE = omaha endif +ifeq ($(CONFIG_ARCH_LH7A400),y) +MACHINE = lh7a400 +endif + export MACHINE PROCESSOR TEXTADDR GZFLAGS CFLAGS_BOOT OBJCOPYFLAGS # Only set INCDIR if its not already defined above diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/boot/Makefile linux-2.4.21-rmk1-lh7a400/arch/arm/boot/Makefile --- linux-2.4.21-rmk1/arch/arm/boot/Makefile Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/boot/Makefile Thu Oct 16 13:45:25 2003 @@ -101,6 +101,15 @@ INITRD_VIRT = 0x0C800000 endif +ifeq ($(CONFIG_ARCH_LH7A400),y) +ZTEXTADDR = 0xC0008000 +ZBSSADDR = 0xC0200000 +ZRELADDR = 0xC0008000 +INITRD_PHYS = 0xC4000000 +INITRD_VIRT = 0xC4000000 +PARAMS_PHYS = 0xC0000100 +endif + ifeq ($(CONFIG_ARCH_SA1100),y) ZRELADDR = 0xc0008000 # No defconfig file to move this into... diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/boot/compressed/head.S linux-2.4.21-rmk1-lh7a400/arch/arm/boot/compressed/head.S --- linux-2.4.21-rmk1/arch/arm/boot/compressed/head.S Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/boot/compressed/head.S Thu Oct 16 13:46:44 2003 @@ -73,6 +73,13 @@ */ str \rb, [r3, #0x14] @ UTDR .endm +#elif defined(CONFIG_ARCH_LH7A400) + .macro loadsp, rb + ldr \rb, =0x80000700 @ UART1 base + .endm + .macro writeb, rb + strb \rb, [r3, #0] + .endm #else #error no serial architecture defined #endif diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/config.in linux-2.4.21-rmk1-lh7a400/arch/arm/config.in --- linux-2.4.21-rmk1/arch/arm/config.in Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/config.in Sat Oct 18 07:56:34 2003 @@ -43,6 +43,7 @@ FootBridge CONFIG_ARCH_FOOTBRIDGE \ Integrator CONFIG_ARCH_INTEGRATOR \ Omaha CONFIG_ARCH_OMAHA \ + LH7A400-based CONFIG_ARCH_LH7A400 \ LinkUp-L7200 CONFIG_ARCH_L7200 \ Motorola-MX1ADS CONFIG_ARCH_MX1ADS \ RiscPC CONFIG_ARCH_RPC \ @@ -181,7 +182,14 @@ endmenu +mainmenu_option next_comment +comment 'Sharp LH7A400 Implementations' +dep_bool ' KEV7A400 EVB' CONFIG_MACH_KEV7A400 $CONFIG_ARCH_LH7A400 +dep_bool ' Heeltoe eframe board' CONFIG_MACH_EFRAME $CONFIG_ARCH_LH7A400 +endmenu + # Definitions to make life easier +comment 'Acorn' if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then define_bool CONFIG_ARCH_ACORN y @@ -190,6 +198,7 @@ fi ##################################################################### +comment 'Footbridge support' # Footbridge support if [ "$CONFIG_ARCH_CO285" = "y" -o \ "$CONFIG_ARCH_FOOTBRIDGE" = "y" ]; then @@ -313,11 +322,15 @@ # ARM922T -if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then +if [ "$CONFIG_ARCH_CAMELOT" = "y" -o "$CONFIG_ARCH_LH7A400" = "y" ]; then define_bool CONFIG_CPU_ARM922T y - define_bool CONFIG_PLD y else define_bool CONFIG_CPU_ARM922T n +fi + +if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then + define_bool CONFIG_PLD y +else define_bool CONFIG_PLD n fi @@ -378,7 +391,8 @@ "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_ARCH_L7200" = "y" -o "$CONFIG_ARCH_ANAKIN" = "y" -o \ "$CONFIG_ARCH_CAMELOT" = "y" -o "$CONFIG_ARCH_MX1ADS" = "y" -o \ - "$CONFIG_ARCH_OMAHA" = "y" -o "$CONFIG_ARCH_AT91RM9200" = "y" ]; then + "$CONFIG_ARCH_OMAHA" = "y" -o "$CONFIG_ARCH_AT91RM9200" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" ]; then define_bool CONFIG_CPU_32v4 y else define_bool CONFIG_CPU_32v4 n @@ -414,7 +428,8 @@ # Select various configuration options depending on the machine type if [ "$CONFIG_ARCH_EDB7211" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_RISCSTATION" = "y" ]; then + "$CONFIG_ARCH_RISCSTATION" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" ]; then define_bool CONFIG_DISCONTIGMEM y else define_bool CONFIG_DISCONTIGMEM n @@ -446,7 +461,8 @@ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_CDB89712" = "y" -o \ "$CONFIG_ARCH_EDB7211" = "y" -o \ - "$CONFIG_ARCH_SA1100" = "y" ]; then + "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" ]; then define_bool CONFIG_ISA y else define_bool CONFIG_ISA n @@ -466,7 +482,8 @@ hex 'Compressed ROM boot loader BSS address' CONFIG_ZBOOT_ROM_BSS 0 if [ "$CONFIG_ARCH_SA1100" = "y" -o \ - "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then + "$CONFIG_ARCH_INTEGRATOR" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" ]; then dep_bool 'Support CPU clock change (EXPERIMENTAL)' CONFIG_CPU_FREQ $CONFIG_EXPERIMENTAL fi @@ -663,7 +680,8 @@ "$CONFIG_ARCH_CLPS7500" = "y" -o \ "$CONFIG_ARCH_P720T" = "y" -o \ "$CONFIG_ARCH_ANAKIN" = "y" -o \ - "$CONFIG_ARCH_MX1ADS" = "y" ]; then + "$CONFIG_ARCH_MX1ADS" = "y" -o \ + "$CONFIG_MACH_KEV7A400" = "y" ]; then define_bool CONFIG_PC_KEYMAP y fi if [ "$CONFIG_ARCH_ACORN" != "y" -a "$CONFIG_ARCH_EBSA110" != "y" -a "$CONFIG_ARCH_RISCSTATION" != "y" ]; then @@ -679,6 +697,7 @@ "$CONFIG_ARCH_TBOX" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" -o \ "$CONFIG_PCI" = "y" ]; then mainmenu_option next_comment comment 'Sound' @@ -694,6 +713,8 @@ source drivers/usb/Config.in +source drivers/mmc/Config.in + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then source net/bluetooth/Config.in fi diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/def-configs/kev7a400 linux-2.4.21-rmk1-lh7a400/arch/arm/def-configs/kev7a400 --- linux-2.4.21-rmk1/arch/arm/def-configs/kev7a400 Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/def-configs/kev7a400 Sat Oct 18 15:52:32 2003 @@ -0,0 +1,1008 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# 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_OMAHA is not set +CONFIG_ARCH_LH7A400=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# Sharp LH7A400 Implementations +# +CONFIG_MACH_KEV7A400=y +# CONFIG_MACH_EFRAME is not set + +# +# Acorn +# +# CONFIG_ARCH_ACORN is not set + +# +# Footbridge support +# +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +CONFIG_CPU_ARM922T=y +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_CPU_FREQ is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_PCMCIA_PROBE=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_LH7A400=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_TOS is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_ROUTE_LARGE_TABLES is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +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=y +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +CONFIG_ARM_CIRRUS=y +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=y + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=y +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=y + +# +# IrDA protocols +# +# CONFIG_IRLAN is not set +# CONFIG_IRNET is not set +CONFIG_IRCOMM=y +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=y +CONFIG_IRPORT_SIR=y + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_OLD is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_LH7X_KEYBOARD_DRIVER is not set +CONFIG_LH7X_BUTTON_DRIVER=y + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_LH7A400=y +CONFIG_SERIAL_LH7A400_CONSOLE=y +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=16 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +CONFIG_LH7A400_DC2DC=y +# CONFIG_RTC is not set +# CONFIG_LH7A400_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_UMSDOS_FS=y +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# 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_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_DBMX1 is not set +CONFIG_FB_PL110=y +CONFIG_PL110_LQ39=y +# CONFIG_PL110_LM57 is not set +# CONFIG_PL110_LQ57 is not set +# CONFIG_PL110_LQ121 is not set +# CONFIG_PL110_LQ104 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_LH7A400=y +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# Misc devices +# +CONFIG_TOUCHSCREEN_LH7X=y +# CONFIG_EEPROM_LH7X is not set +# CONFIG_7SEGMENT_LH7X is not set +# CONFIG_LH7A400_SCI is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/kernel/Makefile linux-2.4.21-rmk1-lh7a400/arch/arm/kernel/Makefile --- linux-2.4.21-rmk1/arch/arm/kernel/Makefile Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/kernel/Makefile Fri Nov 28 09:44:33 2003 @@ -45,7 +45,8 @@ $(CONFIG_FOOTBRIDGE) $(CONFIG_ARCH_EBSA110) \ $(CONFIG_ARCH_SA1100) $(CONFIG_ARCH_CAMELOT) \ $(CONFIG_ARCH_MX1ADS) $(CONFIG_ARCH_OMAHA) \ - $(CONFIG_ARCH_AT91RM9200) + $(CONFIG_ARCH_AT91RM9200) $(CONFIG_MACH_KEV7A400) \ + $(CONFIG_MACH_EFRAME) ifneq ($(findstring y,$(no-irq-arch)),y) obj-y += irq-arch.o @@ -54,6 +55,7 @@ obj-$(CONFIG_ARCH_ACORN) += ecard.o fiq.o time-acorn.o obj-$(CONFIG_ARCH_CLPS7500) += time-acorn.o obj-$(CONFIG_ARCH_RISCSTATION) += time-acorn.o +obj-$(CONFIG_ARCH_LH7A400) += fiq.o obj-$(CONFIG_DEBUG_LL) += debug-$(PROCESSOR).o obj-$(CONFIG_MODULES) += armksyms.o obj-$(CONFIG_ARTHUR) += arthur.o diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/kernel/debug-armv.S linux-2.4.21-rmk1-lh7a400/arch/arm/kernel/debug-armv.S --- linux-2.4.21-rmk1/arch/arm/kernel/debug-armv.S Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/kernel/debug-armv.S Thu Oct 16 14:05:47 2003 @@ -468,7 +468,30 @@ beq 1002b @ wait until transmit done .endm +#elif defined(CONFIG_ARCH_LH7A400) + .macro addruart,rx + mrc p15, 0, \rx, c1, c0 + tst \rx, #1 @ MMU enabled? + ldr \rx, =UART2_PHYS @ physical base address + orrne \rx, \rx, #0xf8000000 @ virtual base + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] @ UART3_DR + .endm + + .macro busyuart,rd,rx @ spin while busy +1001: ldr \rd, [\rx, #0x10] @ UART3_FR + tst \rd, #1 << 3 @ BUSY ? + bne 1001b @ yes, spin + .endm + + .macro waituart,rd,rx @ wait for Tx FIFO room +1001: ldrb \rd, [\rx, #0x10] @ UART3_FR + tst \rd, #1 << 5 @ TXFF full? + bne 1001b @ yes, spin + .endm #else #error Unknown architecture diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/kernel/entry-armv.S linux-2.4.21-rmk1-lh7a400/arch/arm/kernel/entry-armv.S --- linux-2.4.21-rmk1/arch/arm/kernel/entry-armv.S Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/kernel/entry-armv.S Thu Oct 16 14:08:07 2003 @@ -615,6 +615,28 @@ .text .endm +#elif defined(CONFIG_ARCH_LH7A400) +#include + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqstat, =IO_ADDRESS(INTC_PHYS) @ Virt addr IRQ regs + ldr \irqstat, [\irqstat, #0] @ get masked int status + mov \irqnr, #0 @ start count at 0 +1001: tst \irqstat, #1 @ this the interrupt? + bne 1002f @ yup, outta here + add \irqnr, \irqnr, #1 @ no, increment count + mov \irqstat, \irqstat, lsr #1 @ look at next bit + cmp \irqnr, #28 @ at end? + bcc 1001b @ not yet, keep looking +1002: /* EQ will be set if we reach 28 */ + .endm + + .macro irq_prio_table + .endm + #else #error Unknown architecture #endif diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/kernel/head-armv.S linux-2.4.21-rmk1-lh7a400/arch/arm/kernel/head-armv.S --- linux-2.4.21-rmk1/arch/arm/kernel/head-armv.S Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/kernel/head-armv.S Fri Oct 17 11:24:10 2003 @@ -130,6 +130,10 @@ */ mov r1, #MACH_TYPE_L7200 #endif +#if defined(CONFIG_MACH_KEV7A400) + mov r1, #(MACH_TYPE_KEV7A400&0xff) + orr r1, r1, #(MACH_TYPE_KEV7A400&0xff00) +#endif mov r0, #F_BIT | I_BIT | MODE_SVC @ make sure svc mode msr cpsr_c, r0 @ and all irqs disabled diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/Makefile linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/Makefile --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/Makefile Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/Makefile Wed Nov 19 21:42:56 2003 @@ -0,0 +1,31 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). + +USE_STANDARD_AS_RULE := true + +O_TARGET := lh7a400.o + +export-objs := generic.o dma.o hclkfreq.o + +# Object file lists. +obj-y := arch.o generic.o dma.o apm.o fiqhandler.o +obj-m := +obj-n := +obj- := + +mmc-$(CONFIG_MMC) := mmc.o +obj-y += $(mmc-y) +obj-m += $(mmc-m) + +obj-$(CONFIG_CPU_FREQ) += hclkfreq.o cpu_lh7a400.o + +# Specific board support +obj-$(CONFIG_MACH_KEV7A400) += kev7a400.o apm_kev7a400.o lcd_kev7a400.o \ + irq_kev7a400.o +obj-$(CONFIG_MACH_EFRAME) += eframe.o lcd_eframe.o irq_eframe.o + +include $(TOPDIR)/Rules.make diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/apm.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/apm.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/apm.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/apm.c Fri Oct 17 11:26:25 2003 @@ -0,0 +1,535 @@ +/* + * linux/arch/arm/mach-lh7a400/apm.c + * Jim Gleason + * Adapted from: (See below) + * + * bios-less APM driver for ARM Linux + * Jamey Hicks + * adapted from the APM BIOS driver for Linux by Stephen Rothwell (sfr@linuxcare.com) + * + * APM 1.2 Reference: + * Intel Corporation, Microsoft Corporation. Advanced Power Management + * (APM) BIOS Interface Specification, Revision 1.2, February 1996. + * + * [This document is available from Microsoft at: + * http://www.microsoft.com/hwdev/busbios/amp_12.htm] + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +//#include + +// JMG extern int pm_suggest_suspend(void); + +#if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) +extern int (*console_blank_hook)(int); +#endif + +struct apm_bios_info apm_bios_info = { + /* this driver simulates APM version 1.2 */ + version: 0x102, + flags: APM_32_BIT_SUPPORT +}; + +/* + * The apm_bios device is one of the misc char devices. + * This is its minor number. + */ +#define APM_MINOR_DEV 134 + +/* + * See Documentation/Config.help for the configuration options. + * + * Various options can be changed at boot time as follows: + * (We allow underscores for compatibility with the modules code) + * apm=on/off enable/disable APM + * [no-]debug log some debugging messages + * [no-]power[-_]off power off on shutdown + */ + +/* + * Need to poll the APM BIOS every second + */ +#define APM_CHECK_TIMEOUT (HZ) + +/* + * Ignore suspend events for this amount of time after a resume + */ +#define DEFAULT_BOUNCE_INTERVAL (3 * HZ) + +/* + * Maximum number of events stored + */ +#define APM_MAX_EVENTS 20 + +/* + * The per-file APM data + */ +struct apm_user { + int magic; + struct apm_user * next; + int suser: 1; + int suspend_wait: 1; + int suspend_result; + int suspends_pending; + int standbys_pending; + int suspends_read; + int standbys_read; + int event_head; + int event_tail; + apm_event_t events[APM_MAX_EVENTS]; +}; + +/* + * The magic number in apm_user + */ +#define APM_BIOS_MAGIC 0x4101 + +/* + * Local variables + */ +//static int suspends_pending; +//static int standbys_pending; +//static int ignore_normal_resume; + +#ifdef CONFIG_APM_RTC_IS_GMT +# define clock_cmos_diff 0 +# define got_clock_diff 1 +#else +//static long clock_cmos_diff; +//static int got_clock_diff; +#endif +static int debug; +static int apm_disabled; +#ifdef CONFIG_SMP +static int power_off; +#else +static int power_off = 1; +#endif +static int exit_kapmd; +static int kapmd_running; + +static DECLARE_WAIT_QUEUE_HEAD(apm_waitqueue); +static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); +static struct apm_user * user_list = NULL; + +static char driver_version[] = "1.13"; /* no spaces */ + +typedef struct lookup_t { + int key; + char * msg; +} lookup_t; + +static const lookup_t error_table[] = { +/* N/A { APM_SUCCESS, "Operation succeeded" }, */ + { APM_DISABLED, "Power management disabled" }, + { APM_CONNECTED, "Real mode interface already connected" }, + { APM_NOT_CONNECTED, "Interface not connected" }, + { APM_16_CONNECTED, "16 bit interface already connected" }, +/* N/A { APM_16_UNSUPPORTED, "16 bit interface not supported" }, */ + { APM_32_CONNECTED, "32 bit interface already connected" }, + { APM_32_UNSUPPORTED, "32 bit interface not supported" }, + { APM_BAD_DEVICE, "Unrecognized device ID" }, + { APM_BAD_PARAM, "Parameter out of range" }, + { APM_NOT_ENGAGED, "Interface not engaged" }, + { APM_BAD_FUNCTION, "Function not supported" }, + { APM_RESUME_DISABLED, "Resume timer disabled" }, + { APM_BAD_STATE, "Unable to enter requested state" }, +/* N/A { APM_NO_EVENTS, "No events pending" }, */ + { APM_NO_ERROR, "BIOS did not set a return code" }, + { APM_NOT_PRESENT, "No APM present" } +}; +#define ERROR_COUNT (sizeof(error_table)/sizeof(lookup_t)) + +#ifdef CONFIG_MACH_KEV7A400 +extern void kev7a400_apm_get_power_status(u_char *ac_line_status, + u_char *battery_status, + u_char *battery_flag, + u_char *battery_percentage, + u_short *battery_life); +void kev7a400_apm_init(void); +void kev7a400_apm_exit(void); +#endif + +static int apm_get_power_status(u_char *ac_line_status, + u_char *battery_status, + u_char *battery_flag, + u_char *battery_percentage, + u_short *battery_life) +{ +#ifdef CONFIG_MACH_KEV7A400 + kev7a400_apm_get_power_status(ac_line_status, + battery_status, + battery_flag, + battery_percentage, + battery_life); +#endif + return APM_SUCCESS; +} + +static int queue_empty(struct apm_user *as) +{ + return as->event_head == as->event_tail; +} + +static apm_event_t get_queued_event(struct apm_user *as) +{ + as->event_tail = (as->event_tail + 1) % APM_MAX_EVENTS; + return as->events[as->event_tail]; +} + +static int check_apm_user(struct apm_user *as, const char *func) +{ + if ((as == NULL) || (as->magic != APM_BIOS_MAGIC)) { + printk(KERN_ERR "apm: %s passed bad filp\n", func); + return 1; + } + return 0; +} + +static ssize_t do_read(struct file *fp, char *buf, size_t count, loff_t *ppos) +{ + struct apm_user * as; + int i; + apm_event_t event; + DECLARE_WAITQUEUE(wait, current); + + as = fp->private_data; + if (check_apm_user(as, "read")) + return -EIO; + if (count < sizeof(apm_event_t)) + return -EINVAL; + if (queue_empty(as)) { + if (fp->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&apm_waitqueue, &wait); + printk("do_read: waiting\n"); +repeat: + set_current_state(TASK_INTERRUPTIBLE); + if (queue_empty(as) && !signal_pending(current)) { + schedule(); + goto repeat; + } + set_current_state(TASK_RUNNING); + remove_wait_queue(&apm_waitqueue, &wait); + } + i = count; + while ((i >= sizeof(event)) && !queue_empty(as)) { + event = get_queued_event(as); + printk(" do_read: event=%d\n", event); + if (copy_to_user(buf, &event, sizeof(event))) { + if (i < count) + break; + return -EFAULT; + } + switch (event) { + case APM_SYS_SUSPEND: + case APM_USER_SUSPEND: + as->suspends_read++; + break; + + case APM_SYS_STANDBY: + case APM_USER_STANDBY: + as->standbys_read++; + break; + } + buf += sizeof(event); + i -= sizeof(event); + } + if (i < count) + return count - i; + if (signal_pending(current)) + return -ERESTARTSYS; + return 0; +} + +static unsigned int do_poll(struct file *fp, poll_table * wait) +{ + struct apm_user * as; + + as = fp->private_data; + if (check_apm_user(as, "poll")) + return 0; + poll_wait(fp, &apm_waitqueue, wait); + if (!queue_empty(as)) + return POLLIN | POLLRDNORM; + return 0; +} + +static int do_ioctl(struct inode * inode, struct file *filp, + u_int cmd, u_long arg) +{ + struct apm_user * as; + + as = filp->private_data; + if (check_apm_user(as, "ioctl")) + return -EIO; + if (!as->suser) + return -EPERM; + switch (cmd) { + case APM_IOC_SUSPEND: + // JMG if (pm_suggest_suspend()) { + // JMG return -EBUSY; + // JMG } + break; + default: + return -EINVAL; + } + return 0; +} + +static int do_release(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = filp->private_data; + if (check_apm_user(as, "release")) + return 0; + filp->private_data = NULL; + lock_kernel(); + unlock_kernel(); + kfree(as); + return 0; +} + +static int do_open(struct inode * inode, struct file * filp) +{ + struct apm_user * as; + + as = (struct apm_user *)kmalloc(sizeof(*as), GFP_KERNEL); + if (as == NULL) { + printk(KERN_ERR "apm: cannot allocate struct of size %d bytes\n", + sizeof(*as)); + return -ENOMEM; + } + as->magic = APM_BIOS_MAGIC; + as->event_tail = as->event_head = 0; + as->suspends_pending = as->standbys_pending = 0; + as->suspends_read = as->standbys_read = 0; + /* + * XXX - this is a tiny bit broken, when we consider BSD + * process accounting. If the device is opened by root, we + * instantly flag that we used superuser privs. Who knows, + * we might close the device immediately without doing a + * privileged operation -- cevans + */ + as->suser = capable(CAP_SYS_ADMIN); + as->next = user_list; + user_list = as; + filp->private_data = as; + return 0; +} + +static int apm_get_info(char *buf, char **start, off_t fpos, int length) +{ + char * p; + unsigned short dx; + unsigned short error; + unsigned char ac_line_status = 0xff; + unsigned char battery_status = 0xff; + unsigned char battery_flag = 0xff; + unsigned char percentage = 0xff; + int time_units = -1; + char *units = "?"; + + p = buf; + + if ((smp_num_cpus == 1) && + !(error = apm_get_power_status(&ac_line_status, + &battery_status, &battery_flag, &percentage, &dx))) { + if (apm_bios_info.version > 0x100) { + if (dx != 0xffff) { + units = (dx & 0x8000) ? "min" : "sec"; + time_units = dx & 0x7fff; + } + } + } + /* Arguments, with symbols from linux/apm_bios.h. Information is + from the Get Power Status (0x0a) call unless otherwise noted. + + 0) Linux driver version (this will change if format changes) + 1) APM BIOS Version. Usually 1.0, 1.1 or 1.2. + 2) APM flags from APM Installation Check (0x00): + bit 0: APM_16_BIT_SUPPORT + bit 1: APM_32_BIT_SUPPORT + bit 2: APM_IDLE_SLOWS_CLOCK + bit 3: APM_BIOS_DISABLED + bit 4: APM_BIOS_DISENGAGED + 3) AC line status + 0x00: Off-line + 0x01: On-line + 0x02: On backup power (BIOS >= 1.1 only) + 0xff: Unknown + 4) Battery status + 0x00: High + 0x01: Low + 0x02: Critical + 0x03: Charging + 0x04: Selected battery not present (BIOS >= 1.2 only) + 0xff: Unknown + 5) Battery flag + bit 0: High + bit 1: Low + bit 2: Critical + bit 3: Charging + bit 7: No system battery + 0xff: Unknown + 6) Remaining battery life (percentage of charge): + 0-100: valid + -1: Unknown + 7) Remaining battery life (time units): + Number of remaining minutes or seconds + -1: Unknown + 8) min = minutes; sec = seconds */ + + p += sprintf(p, "%s %d.%d 0x%02x 0x%02x 0x%02x 0x%02x %d%% %d %s\n", + driver_version, + (apm_bios_info.version >> 8) & 0xff, + apm_bios_info.version & 0xff, + apm_bios_info.flags, + ac_line_status, + battery_status, + battery_flag, + (signed char)percentage, + time_units, + units); + + return p - buf; +} + +#ifndef MODULE +static int __init apm_setup(char *str) +{ + int invert; + + while ((str != NULL) && (*str != '\0')) { + if (strncmp(str, "off", 3) == 0) + apm_disabled = 1; + if (strncmp(str, "on", 2) == 0) + apm_disabled = 0; + invert = (strncmp(str, "no-", 3) == 0); + if (invert) + str += 3; + if (strncmp(str, "debug", 5) == 0) + debug = !invert; + if ((strncmp(str, "power-off", 9) == 0) || + (strncmp(str, "power_off", 9) == 0)) + power_off = !invert; + str = strchr(str, ','); + if (str != NULL) + str += strspn(str, ", \t"); + } + return 1; +} + +__setup("apm=", apm_setup); +#endif + +static struct file_operations apm_bios_fops = { + owner: THIS_MODULE, + read: do_read, + poll: do_poll, + ioctl: do_ioctl, + open: do_open, + release: do_release, +}; + +static struct miscdevice apm_device = { + APM_MINOR_DEV, + "apm_bios", + &apm_bios_fops +}; + +#define APM_INIT_ERROR_RETURN return -1 + +/* + * Just start the APM thread. We do NOT want to do APM BIOS + * calls from anything but the APM thread, if for no other reason + * than the fact that we don't trust the APM BIOS. This way, + * most common APM BIOS problems that lead to protection errors + * etc will have at least some level of being contained... + * + * In short, if something bad happens, at least we have a choice + * of just killing the apm thread.. + */ +static int __init apm_init(void) +{ + if (apm_bios_info.version == 0) { + printk(KERN_INFO "apm: BIOS not found.\n"); + APM_INIT_ERROR_RETURN; + } + printk(KERN_INFO + "apm: BIOS version %d.%d Flags 0x%02x (Driver version %s)\n", + ((apm_bios_info.version >> 8) & 0xff), + (apm_bios_info.version & 0xff), + apm_bios_info.flags, + driver_version); + + if (apm_disabled) { + printk(KERN_NOTICE "apm: disabled on user request.\n"); + APM_INIT_ERROR_RETURN; + } + + if (PM_IS_ACTIVE()) { + printk(KERN_NOTICE "apm: overridden by ACPI.\n"); + APM_INIT_ERROR_RETURN; + } + // JMG pm_active = 1; + +#ifdef CONFIG_MACH_KEV7A400 + kev7a400_apm_init(); +#endif + + create_proc_info_entry("apm", 0, NULL, apm_get_info); + + misc_register(&apm_device); + + return 0; +} + +static void __exit apm_exit(void) +{ +#ifdef CONFIG_MACH_KEV7A400 + kev7a400_apm_exit(); +#endif + + misc_deregister(&apm_device); + remove_proc_entry("apm", NULL); + if (power_off) + pm_power_off = NULL; + exit_kapmd = 1; + while (kapmd_running) + schedule(); + // JMG pm_active = 0; +} + +module_init(apm_init); +module_exit(apm_exit); + +MODULE_AUTHOR("Jamey Hicks, pulling bits from original by Stephen Rothwell"); +MODULE_DESCRIPTION("A minimal emulation of APM"); +MODULE_PARM(debug, "i"); +MODULE_PARM_DESC(debug, "Enable debug mode"); +MODULE_PARM(power_off, "i"); +MODULE_PARM_DESC(power_off, "Enable power off"); + +EXPORT_NO_SYMBOLS; diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/apm_kev7a400.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/apm_kev7a400.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/apm_kev7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/apm_kev7a400.c Mon Oct 20 16:07:04 2003 @@ -0,0 +1,1068 @@ +/* + * linux/arch/arm/mach-lh7a400/apm-kev7a400.c + * + * Author: Jim Gleason + * + * Copyright (c) 2002, Embedix, Inc. + * + * This file contains the LH7A400 Battery Monitor Interface driver + * ((( Single Wire interface ))) + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Based on Sharp MicroElectronics LH7A400 Battery Monitor interface. + * Author: MaysR + * Date: 16 Apr 2002 + * + * COPYRIGHT (C) 2001, SHARP MICROELECTRONICS OF THE AMERICAS, INC. + * CAMAS, WA + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +/* The number of times a transmit/receive command are retried on failure */ +#define NTXRXATTEMPTS 3 + +/* +* I found it easier to control without the TX and RX interrupts +* ALSO - If using the interrupts, a watchdog interrupt will be needed!!! +*/ +#undef USE_TX_INTERRUPT +#undef USE_RX_INTERRUPT + +/* A loop count controlling logic overriding stuck processes */ +#define TX_WATCHDOGCOUNT 1000 +#define RX_WATCHDOGCOUNT 3000 + +/* +* Delays associated with the respective action +* (See BQ2050H datasheet timing info +* (I found it hangs periodically with less delay - JimG) +*/ +#undef USE_BREAK_UDELAY +#define USE_TX_UDELAY +#define USE_RX_UDELAY + +#define BREAK_UDELAY_COUNT 1000 +#define TX_UDELAY_COUNT 1000 +#define RX_UDELAY_COUNT 1000 + +/* Use a group of flags to "try" and determine if it is ok to proceed */ +#define USE_TX_WAITUNTILREADY +#define USE_RX_WAITUNTILREADY + +#undef DEBUG +#undef VERBOSE +#define DRVNAME "LH7A400 BMI" + +static gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); +static clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + +/* BMI Single Wire Interface (SWI) Register Structure */ +typedef struct { + volatile uint32_t dr; /* Data Register */ + volatile uint32_t cr; /* Control Register */ + volatile uint32_t sr; /* Status Register */ + volatile union { + volatile uint32_t risr; /* Raw Interrupt Status Register */ + volatile uint32_t eoi; /* RISR End-Of-Interrupt Register */ + } u; + volatile uint32_t isr; /* Interrupt Status Register */ + volatile uint32_t ie; /* Interrupt Enable Register */ + volatile uint32_t tr; /* Timing Register */ + volatile uint32_t br; /* Break Register */ +} bmiSwiRegs_t; + +/* SWI CR (Control Register) defines */ +#define SWICR_SWIEN _BIT(0) +#define SWICR_GBS _BIT(1) +#define SWICR_SWIDINV _BIT(2) +#define SWICR_WDCS(n) ((n & 0x3F) << 3) +#define SWICR_RDSS(n) ((n & 0x3F) << 9) +#define SWICR_T_RST _BIT(15) +#define SWICR_SP_INVERT _BIT(16) + +/* SWI SR (Status Register) defines */ +#define SWISR_TXB _BIT(0) +#define SWISR_SBS _BIT(1) +#define SWISR_DBS _BIT(2) +#define SWISR_PBS _BIT(3) +#define SWISR_WTF _BIT(4) +#define SWISR_WRF _BIT(5) +#define SWISR_BKS _BIT(6) +#define SWISR_BRS _BIT(7) +#define SWISR_BRF _BIT(8) +#define SWISR_RXB _BIT(9) +#define SWISR_TEF _BIT(10) +#define SWISR_COL _BIT(11) + +/* SWI RISR (Raw Interrupt Status Register) defines */ +#define SWIRISR_RWTIS _BIT(0) +#define SWIRISR_RWRIS _BIT(1) +#define SWIRISR_RBRIS _BIT(2) + +/* SWI EOI (RISR End-Of-Interrupt Register) defines */ +#define SWIEOI_RWTIS SWIRISR_RWTIS +#define SWIEOI_RWRIS SWIRISR_RWRIS +#define SWIEOI_RBRIS SWIRISR_RBRIS + +/* SWI ISR (Interrupt Status Register) defines */ +#define SWIISR_WTIS _BIT(0) +#define SWIISR_WRIS _BIT(1) +#define SWIISR_BRIS _BIT(2) + +/* SWI IE (Interrupt Enable Register) defines */ +#define SWIIE_WTIE _BIT(0) +#define SWIIE_WRIE _BIT(1) +#define SWIIE_BRIE _BIT(2) + +/* SWI TR (Timing Register) defines */ +#define SWITR_BTG(n) ((n & 0xFFFF) << 0) + +/* SWI BR (Break Register) defines */ +#define SWIBR_BR(n) (n & 0x0FFF) +#define SWIBR_B(n) ((n & 0x0FFF) << 12) + +/* BMI Smart Battery Interface (SBI) Register Structure */ +typedef struct { + volatile uint32_t dr; /* Data Register */ + volatile uint32_t cr; /* Control Register */ + volatile uint32_t count; /* Count Register */ + volatile uint32_t sr; /* Status Register */ + volatile union { + volatile uint32_t risr; /* Raw Interrupt Status Register */ + volatile uint32_t eoi; /* RISR End-Of-Interrupt Register */ + } u; + volatile uint32_t isr; /* Interrupt Status Register */ + volatile uint32_t ie; /* Interrupt Enable Register */ +} bmiSbiRegs_t; + +/* SBI CR (Control Register) defines */ +#define SBICR_SBI_EN _BIT(0) +#define SBICR_FFLUSH _BIT(1) +#define SBICR_DIVFACT(n) ((n & 0xFF) << 2) +#define SBICR_TX_FDIS _BIT(10) +#define SBICR_RX_FDIS _BIT(11) +#define SBICR_TOC(n) ((n & 0x0FFF) << 12) +#define SBICR_BRF _BIT(24) +#define SBICR_PEF _BIT(25) + +/* SBI COUNT (Count Register) defines */ +#define SBICOUNT_PRE(n) ((n & 0x1F) << 0) +#define SBICOUNT_REP(n) ((n & 0x1F) << 5) +#define SBICOUNT_READ(n) ((n & 0x1F) << 10) + +/* SBI SR (Status Register) defines */ +#define SBISR_RXFE _BIT(0) +#define SBISR_TXFE _BIT(1) +#define SBISR_RXFF _BIT(2) +#define SBISR_TXFF _BIT(3) +#define SBISR_TXBUSY _BIT(4) +#define SBISR_MASTER _BIT(5) +#define SBISR_SLAVE _BIT(6) +#define SBISR_READnWRITE _BIT(7) +#define SBISR_ACKFAIL _BIT(8) +#define SBISR_RXOE _BIT(9) +#define SBISR_TXUE _BIT(10) +#define SBISR_CLT _BIT(11) +#define SBISR_SBH _BIT(12) + +/* SBI RISR (Raw Interrupt Status Register) defines */ +#define SBIRISR_RMTCIS _BIT(0) +#define SBIRISR_RRTIS _BIT(1) +#define SBIRISR_RTIS _BIT(2) +#define SBIRISR_RRIS _BIT(3) +#define SBIRISR_RAFIS _BIT(4) +#define SBIRISR_RALIS _BIT(5) +#define SBIRISR_RSTCIS _BIT(6) +#define SBIRISR_RCLTIS _BIT(7) + +/* SBI EOI (RISR End-Of-Interrupt Register) defines */ +#define SBIEOI_RMTCIS SBIRISR_RMTCIS +#define SBIEOI_RRTIS SBIRISR_RRTIS +#define SBIEOI_RTIS SBIRISR_RTIS +#define SBIEOI_RRIS SBIRISR_RRIS +#define SBIEOI_RAFIS SBIRISR_RAFIS +#define SBIEOI_RALIS SBIRISR_RALIS +#define SBIEOI_RSTCIS SBIRISR_RSTCIS +#define SBIEOI_RCLTIS SBIRISR_RCLTIS + +/* SBI ISR (Interrupt Status Register) defines */ +#define SBIISR_MTCIS _BIT(0) +#define SBIISR_RTIS _BIT(1) +#define SBIISR_TIS _BIT(2) +#define SBIISR_RIS _BIT(3) +#define SBIISR_AFIS _BIT(4) +#define SBIISR_ALIS _BIT(5) +#define SBIISR_STCIS _BIT(6) +#define SBIISR_CLTIS _BIT(7) + +/* SBI IE (Interrupt Enable Register) defines */ +#define SBIIE_TCIE _BIT(0) +#define SBIIE_RTIE _BIT(1) +#define SBIIE_TIE _BIT(2) +#define SBIIE_RIE _BIT(3) +#define SBIIE_AFE _BIT(4) +#define SBIIE_ALE _BIT(5) +#define SBIIE_STCIE _BIT(6) +#define SBIIE_CLTIE _BIT(7) + +/* Battery monitor Interface (BMI) Register Structure */ +typedef struct { + bmiSwiRegs_t swi; + uint32_t res[36]; + bmiSbiRegs_t sbi; +} bmiRegs_t; + +static bmiRegs_t *bmi = (bmiRegs_t *)IO_ADDRESS(BMI_PHYS); +static bmiSwiRegs_t *bmiswi = NULL; /* Set in kev7a400_apm_init() */ +static bmiSbiRegs_t *bmisbi = NULL; /* Set in kev7a400_apm_init() */ + +typedef enum { + BQ2050H, + BQ2014H, + MAX_BMI_SWI +} swi_types_t; + +typedef struct { + uint32_t break_time; + uint32_t break_recovery; + uint16_t bit_time_gen; + uint16_t read_size; + uint16_t write_size; + uint8_t ss_invert; + uint8_t data_invert; +} swi_settings_t; + +#if !defined (YES) +#define YES (1) +#endif + +#if !defined (NO) +#define NO (0) +#endif + +static int bmi_irq_enabled = 0; +static swi_types_t bmi_device = BQ2050H; + +#define vdprintk if (0) printk +#define dprintk if (0) printk + +/********************************************************************* + * Interface communication parameters for each battery monitor device. + * Add additional device parameters here. + *********************************************************************/ +#define BQ2050H_BREAK_TIME (1481) +#define BQ2050H_BREAK_RECOVERY_TIME (370) +//#define BQ2050H_BIT_TIME_GENERATION (37) +#define BQ2050H_BIT_TIME_GENERATION (494) +#define BQ2050H_READ_DATA_SIZE (8) +#define BQ2050H_WRITE_DATA_SIZE (8) +#define BQ2050H_START_STOP_INVERT NO +#define BQ2050H_DATA_INVERT NO + +#define BQ2014H_BREAK_TIME (1481) +#define BQ2014H_BREAK_RECOVERY_TIME (370) +//#define BQ2014H_BIT_TIME_GENERATION (37) +#define BQ2014H_BIT_TIME_GENERATION (494) +#define BQ2014H_READ_DATA_SIZE (8) +#define BQ2014H_WRITE_DATA_SIZE (8) +#define BQ2014H_START_STOP_INVERT NO +#define BQ2014H_DATA_INVERT NO + +/********************************************************************* + * Structure to provide interface communications parameters to driver. + * Add new device entries here in the same order as the typedef list + * above. + *********************************************************************/ +static swi_settings_t swi_settings[] = +{ + { + BQ2050H_BREAK_TIME, + BQ2050H_BREAK_RECOVERY_TIME, + BQ2050H_BIT_TIME_GENERATION, + BQ2050H_READ_DATA_SIZE, + BQ2050H_WRITE_DATA_SIZE, + BQ2050H_START_STOP_INVERT, + BQ2050H_DATA_INVERT + }, + { + BQ2014H_BREAK_TIME, + BQ2014H_BREAK_RECOVERY_TIME, + BQ2014H_BIT_TIME_GENERATION, + BQ2014H_READ_DATA_SIZE, + BQ2014H_WRITE_DATA_SIZE, + BQ2014H_START_STOP_INVERT, + BQ2014H_DATA_INVERT + } +}; + +typedef struct { + uint8_t flgs1; /* Primary Status Flags */ + uint8_t tmp; /* Temperature */ + uint8_t nach; /* Nominal Available Capacity High Byte */ + uint8_t batid; /* Battery ID */ + uint8_t lmd; /* Last Measured Discharge */ + uint8_t flgs2; /* Secondary Status Flags */ + uint8_t ppd; /* Program Pin Pull-Down */ + uint8_t ppu; /* Program Pin Pull-Up */ + uint8_t cpi; /* Capacity Inaccurate Count */ + uint8_t reserved_0x0A; + uint8_t vsb; /* Battery Voltage */ + uint8_t vts; /* End-of-Discharge Threshld Select */ + uint8_t cact; /* Temp & Discharge Rate Compensated Avail Capacity */ + uint8_t cacd; /* Discharge Rate Compensated Avail Capacity */ + uint8_t saeh; /* Scaled Available Energy High Byte */ + uint8_t sael; /* Scaled Available Energy Low Byte */ + uint8_t rcac; /* Relative CAC */ + uint8_t vsrh; /* Current Scale High */ + uint8_t vsrl; /* Current Scale Low */ + uint8_t reserved_0x14; + uint8_t nmcv; /* Maximum Cell Voltage */ + uint8_t reserved_0x16; + uint8_t nacl; /* Nominal Available Capacity Low Byte */ + uint8_t dcr; /* Discharge */ + uint8_t reserved_0x19_to_0x1d[5]; + uint8_t ppfc; /* Program Pin Data */ + uint8_t reserved_0x1F_to_0x37[25]; + uint8_t intss; /* Vos interrupt */ + uint8_t rst; /* Reset */ + uint8_t reserved_0x3A_to_0x3E[5]; + uint8_t hexff; /* Check */ +} BQ2050HREGS_t; +static BQ2050HREGS_t BQ2050HREGS; + +wait_queue_head_t bmi_wait_q; + +#ifdef DEBUG +static void +dump_bmi_swi_regs(void) +{ + uint32_t dr, cr, sr, risr, isr, ie, tr, br; + + dr = bmiswi->dr; + cr = bmiswi->cr; + sr = bmiswi->sr; + risr = bmiswi->u.risr; + isr = bmiswi->isr; + ie = bmiswi->ie; + tr = bmiswi->tr; + br = bmiswi->br; + + dprintk("* bmiswi->dr : 0x%08X\n", dr); + + dprintk("* bmiswi->cr : 0x%08X\n", cr); + if (cr & SWICR_SWIEN) { + vdprintk(" SWI enabled\n"); + } else { + vdprintk(" SWI disabled\n"); + } + if (cr & SWICR_GBS) + vdprintk(" Generate a break\n"); + if (cr & SWICR_SWIDINV) + vdprintk(" Data inverted\n"); + vdprintk(" %d bits to be written\n", (cr & SWICR_WDCS(-1)) >> 3); + vdprintk(" %d bits to be read\n", (cr & SWICR_RDSS(-1)) >> 9); + if (cr & SWICR_T_RST) + vdprintk(" Reset data transfer\n"); + if (cr & SWICR_SP_INVERT) + vdprintk(" Protocol bits inverted\n"); + + dprintk("* bmiswi->sr : 0x%08X\n", sr); + if (sr & SWISR_TXB) + vdprintk(" Transmit process busy\n"); + if (sr & SWISR_SBS) + vdprintk(" Reading/writing a start bit\n"); + if (sr & SWISR_DBS) + vdprintk(" Reading/writing a data bit\n"); + if (sr & SWISR_PBS) + vdprintk(" Read/writing a stop bit\n"); + if (sr & SWISR_WTF) + vdprintk(" Write finished\n"); + if (sr & SWISR_WRF) + vdprintk(" Read finished\n"); + if (sr & SWISR_BKS) + vdprintk(" In break process\n"); + if (sr & SWISR_BRS) + vdprintk(" Generating a break recovery\n"); + if (sr & SWISR_BRF) + vdprintk(" Break recovery finished\n"); + if (sr & SWISR_RXB) + vdprintk(" Receive process is busy\n"); + if (sr & SWISR_TEF) + vdprintk(" Cannot transmit - Process busy\n"); + if (sr & SWISR_COL) + vdprintk(" Cannot receive - Process busy\n"); + + dprintk("* bmiswi->u.risr: 0x%08X\n", risr); + if (risr & SWIRISR_RWTIS) + vdprintk(" Transfer complete\n"); + if (risr & SWIRISR_RWRIS) + vdprintk(" Receive complete\n"); + if (risr & SWIRISR_RBRIS) + vdprintk(" Break complete\n"); + + dprintk("* bmiswi->isr : 0x%08X\n", isr); + if (isr & SWIISR_WTIS) + vdprintk(" Transfer complete\n"); + if (isr & SWIISR_WRIS) + vdprintk(" Receive complete\n"); + if (isr & SWIISR_BRIS) + vdprintk(" Break complete\n"); + + dprintk("* bmiswi->ie : 0x%08X\n", ie); + if (ie & SWIIE_WTIE) + vdprintk(" Transfer interrupt enabled\n"); + if (ie & SWIIE_WRIE) + vdprintk(" Receive interrupt enabled\n"); + if (ie & SWIIE_BRIE) + vdprintk(" Break interrupt enabled\n"); + + dprintk("* bmiswi->tr : 0x%08X\n", tr); + vdprintk(" BTG is %d\n", (tr & SWITR_BTG(-1)) >> 0); + + dprintk("* bmiswi->br : 0x%08X\n", br); + vdprintk(" SWIBR is %d\n", (tr & SWIBR_BR(-1)) >> 0); + vdprintk(" SWIB is %d\n", (tr & SWIBR_B(-1)) >> 12); +} +#else +#define dump_bmi_swi_regs() +#endif /* DEBUG */ + +/* Enable the Single Wire Interface (SWI) */ +static void +bmi_swi_enable(void) +{ + vdprintk("ENTER: bmi_swi_enable()\n"); + bmiswi->cr |= SWICR_SWIEN; + vdprintk("LEAVE: bmi_swi_enable()\n"); +} + +#ifdef NOT_CURRENTLY_USED +/* Disable the Single Wire Interface (SWI) */ +static void +bmi_swi_disable(void) +{ + vdprintk("ENTER: bmi_swi_disable()\n"); + bmiswi->cr &= ~(SWICR_SWIEN); + vdprintk("LEAVE: bmi_swi_disable()\n"); +} +#endif /* NOT_CURRENTLY_USED */ + +void bmi_swi_break(u_char device) +{ + DECLARE_WAITQUEUE(bmi_swi_break_wait, current); + + vdprintk("ENTER: bmi_swi_break()\n"); + add_wait_queue(&bmi_wait_q, &bmi_swi_break_wait); + /* + * SWIBR_B: + * Specifies the number of 7.3278 MHZ clock cycles in which SWI + * must be driven LOW to generate a break. i.e. + * 0xFFF generates a 555 micro-second break. + * 0x000 generates a 135 nano-second break. + * SWIBR_BR + * Specifies the number of 7.3278 MHZ clocks in which HDQ must be + * returned HIGH to generate a break recovery. i.e. + * 0xFFF generates a 555 micro-second recovery period. + * 0x000 generates a 135 nano-second recovery period. + */ + bmiswi->br = (SWIBR_B(swi_settings[device].break_time) | + SWIBR_BR(swi_settings[device].break_recovery)); + /* + * Specifies the 7.3278 MHZ clock cycles required to generate + * a bit time * for the start, stop, and data bits required in + * a data packet. The clock * period generated is 3 x (the + * data rate). + */ + bmiswi->tr = 0; + /* Generate a break followed by a recovery period */ + set_current_state(TASK_INTERRUPTIBLE); + bmiswi->cr |= SWICR_GBS; + /* Wait for the break and recovery period to finish */ + while (bmiswi->sr & SWISR_BKS) { + schedule(); /* Give the system time to do other work */ + } + remove_wait_queue(&bmi_wait_q, &bmi_swi_break_wait); + current->state = TASK_RUNNING; + /* Clean up from the break and recovery period */ + bmiswi->br = 0; + bmiswi->tr = SWITR_BTG(swi_settings[device].bit_time_gen); + bmiswi->cr &= ~(SWICR_GBS); +#ifdef USE_BREAK_UDELAY + schedule(); /* Give the system time to do other work */ + udelay(BREAK_UDELAY_COUNT); + schedule(); /* Give the system time to do other work */ +#endif /* USE_BREAK_UDELAY */ + + vdprintk("LEAVE: bmi_swi_break()\n"); +} + +#ifdef NOT_CURRENTLY_USED +static void +bmi_swi_data_invert(void) +{ + vdprintk("ENTER: bmi_swi_data_invert()\n"); + bmiswi->cr |= SWICR_SWIDINV; + vdprintk("LEAVE: bmi_swi_data_invert()\n"); + + return; +} +#endif /* NOT_CURRENTLY_USED */ + +#ifdef NOT_CURRENTLY_USED +static void +bmi_swi_data_normal(void) +{ + vdprintk("ENTER: bmi_swi_data_normal()\n"); + bmiswi->cr &= ~(SWICR_SWIDINV); + vdprintk("LEAVE: bmi_swi_data_normal()\n"); + + return; +} +#endif /* NOT_CURRENTLY_USED */ + +#ifdef NOT_CURRENTLY_USED +static void +bmi_swi_read_size(uint32_t size) +{ + vdprintk("ENTER: bmi_swi_read_size()\n"); + bmiswi->cr |= SWICR_RDSS(size); + vdprintk("LEAVE: bmi_swi_read_size()\n"); + + return; +} +#endif /* NOT_CURRENTLY_USED */ + +#ifdef NOT_CURRENTLY_USED +static void +bmi_swi_write_size(uint32_t size) +{ + vdprintk("ENTER: bmi_swi_write_size()\n"); + bmiswi->cr |= SWICR_WDCS(size); + vdprintk("LEAVE: bmi_swi_write_size()\n"); + + return; +} +#endif /* NOT_CURRENTLY_USED */ + +#ifdef NOT_CURRENTLY_USED +static void +bmi_swi_transfer_reset(void) +{ + vdprintk("ENTER: bmi_swi_transfer_reset()\n"); + bmiswi->cr |= SWICR_T_RST; + vdprintk("LEAVE: bmi_swi_transfer_reset()\n"); + + return; +} +#endif /* NOT_CURRENTLY_USED */ + +#ifdef NOT_CURRENTLY_USED +static void +bmi_swi_stop_start_invert(void) +{ + vdprintk("ENTER: bmi_swi_stop_start_invert()\n"); + bmiswi->cr |= SWICR_SP_INVERT; + vdprintk("LEAVE: bmi_swi_stop_start_invert()\n"); + + return; +} +#endif /* NOT_CURRENTLY_USED */ + +#ifdef NOT_CURRENTLY_USED +static void +bmi_swi_stop_start_normal(void) +{ + vdprintk("ENTER: bmi_swi_stop_start_normal()\n"); + bmiswi->cr &= ~(SWICR_SP_INVERT); + vdprintk("LEAVE: bmi_swi_stop_start_normal()\n"); + + return; +} +#endif /* NOT_CURRENTLY_USED */ + +static uint32_t +bmi_swi_send_data(uint32_t data) +{ + uint32_t retval = 0; +#ifdef USE_TX_INTERRUPT + DECLARE_WAITQUEUE(bmi_swi_send_data_wait, current); +#endif /* USE_TX_INTERRUPT */ + int watchdogCount; + + vdprintk("ENTER: bmi_swi_send_data()\n"); +#ifdef USE_TX_INTERRUPT + add_wait_queue(&bmi_wait_q, &bmi_swi_send_data_wait); + set_current_state(TASK_INTERRUPTIBLE); +#endif /* USE_TX_INTERRUPT */ + +#ifdef USE_TX_WAITUNTILREADY + /* Wait until it is ok to transmit/receive */ + watchdogCount = 0; + while ((bmiswi->sr & (SWISR_RXB | SWISR_TXB | SWISR_BRS | + SWISR_BKS | SWISR_PBS | SWISR_DBS | SWISR_SBS)) + && watchdogCount < TX_WATCHDOGCOUNT) + { + /* Give the system time to do other work */ + schedule(); + watchdogCount++; + } + /***** WHAT IF WATCHDOG FAILS - JMG *****/ +#ifdef DEBUG + if (watchdogCount >= TX_WATCHDOGCOUNT) { + dprintk("SEND WATCHDOG FAILURE(1)\n"); + } +#endif /* DEBUG */ +#endif /* USE_TX_WAITUNTILREADY */ + + /* Send the data */ + bmiswi->dr = data; + + /* Wait for the data to be sent */ +#ifdef USE_TX_UDELAY + /* Give the system time to do other work */ + schedule(); + udelay(TX_UDELAY_COUNT); + + /* Give the system time to do other work */ + schedule(); +#endif /* USE_TX_UDELAY */ + watchdogCount = 0; + while ((bmiswi->sr & SWISR_TXB) && watchdogCount < TX_WATCHDOGCOUNT) + { + /* Give the system time to do other work */ + schedule(); + watchdogCount++; + } + +#ifdef USE_TX_INTERRUPT + remove_wait_queue(&bmi_wait_q, &bmi_swi_send_data_wait); + current->state = TASK_RUNNING; +#endif /* USE_TX_INTERRUPT */ + + if (watchdogCount >= TX_WATCHDOGCOUNT) { + dprintk("SEND WATCHDOG FAILURE(2)\n"); +// retval = -1; + } + vdprintk("LEAVE: bmi_swi_send_data()\n"); + + return(retval); +} + +#if 0 +static uint32_t +bmi_swi_status(void) +{ + uint32_t retval; + vdprintk("ENTER: bmi_swi_status()\n"); + retval = bmiswi->sr; + vdprintk("LEAVE: bmi_swi_status()\n"); + + return(retval); +} +#endif + +static uint32_t +bmi_swi_recv_data(void) +{ +#ifdef USE_RX_INTERRUPT + DECLARE_WAITQUEUE(bmi_swi_recv_data_wait, current); +#endif /* USE_RX_INTERRUPT */ + int watchdogCount; + uint32_t retval; + + vdprintk("ENTER: bmi_swi_recv_data()\n"); + +#ifdef USE_RX_INTERRUPT + add_wait_queue(&bmi_wait_q, &bmi_swi_recv_data_wait); + set_current_state(TASK_INTERRUPTIBLE); +#endif /* USE_RX_INTERRUPT */ + +#ifdef USE_RX_WAITUNTILREADY + /* Wait until it is ok to transmit/receive */ + watchdogCount = 0; + while ((bmiswi->sr & (SWISR_RXB | SWISR_TXB | SWISR_BRS | + SWISR_BKS | SWISR_PBS | SWISR_DBS | SWISR_SBS)) + && watchdogCount < RX_WATCHDOGCOUNT) + { + /* Give the system time to do other work */ + schedule(); + watchdogCount++; + } + /***** WHAT IF WATCHDOG FAILS - JMG *****/ +#ifdef DEBUG + if (watchdogCount >= RX_WATCHDOGCOUNT) { + dprintk("RECV WATCHDOG FAILURE(1)\n"); + } +#endif /* DEBUG */ +#endif /* USE_RX_WAITUNTILREADY */ + + /* Wait for the data to be received */ + watchdogCount = 0; + while (((bmiswi->sr & SWISR_WRF) == 0) && + watchdogCount < RX_WATCHDOGCOUNT) + { + /* Give the system time to do other work */ + schedule(); + watchdogCount++; + } + if (watchdogCount < RX_WATCHDOGCOUNT) { + retval = bmiswi->dr; /* read data & clear interupt */ + } else { + dprintk("RECV WATCHDOG FAILURE(2)\n"); + retval = -1; + } + +#ifdef USE_RX_INTERRUPT + remove_wait_queue(&bmi_wait_q, &bmi_swi_recv_data_wait); + current->state = TASK_RUNNING; +#endif /* USE_RX_INTERRUPT */ + +#ifdef USE_RX_UDELAY + schedule(); /* Give the system time to do other work */ + udelay(RX_UDELAY_COUNT); + schedule(); /* Give the system time to do other work */ +#endif /* USE_RX_UDELAY */ + vdprintk("LEAVE: bmi_swi_recv_data(0x%X)\n", retval); + + return(retval); +} + +#ifdef DEBUG +static void +bmi_swi_dumpstruct(void) +{ + vdprintk("ENTER: bmi_swi_dumpstruct()\n"); + printk("\n" + "0x%02X = flgs1 = Primary Status Flags\n" + "0x%02X = tmp = Temperature\n" + "0x%02X = nach = Nominal Available Capacity High Byte\n" + "0x%02X = batid = Battery ID\n" + "0x%02X = lmd = Last Measured Discharge\n" + "0x%02X = flgs2 = Secondary Status Flags\n" + "0x%02X = ppd = Program Pin Pull-Down\n" + "0x%02X = ppu = Program Pin Pull-Up\n" + "0x%02X = cpi = Capacity Inaccurate Count\n" + "0x%02X = vsb = Battery Voltage\n" + "0x%02X = vts = End-of-Discharge Threshld Select\n" + "0x%02X = cact = Temp & Discharge Rate Compensated Avail Capacity\n" + "0x%02X = cacd = Discharge Rate Compensated Avail Capacity\n" + "0x%02X = saeh = Scaled Available Energy High Byte\n" + "0x%02X = sael = Scaled Available Energy Low Byte\n" + "0x%02X = rcac = Relative CAC\n" + "0x%02X = vsrh = Current Scale High\n" + "0x%02X = vsrl = Current Scale Low\n" + "0x%02X = nmcv = Maximum Cell Voltage\n" + "0x%02X = nacl = Nominal Available Capacity Low Byte\n" + "0x%02X = dcr = Discharge\n" + "0x%02X = ppfc = Program Pin Data\n" + "0x%02X = intss = Vos interrupt\n" + "0x%02X = rst = Reset\n" + "0x%02X = hexff = Check\n" + "\n" + , + BQ2050HREGS.flgs1, + BQ2050HREGS.tmp, + BQ2050HREGS.nach, + BQ2050HREGS.batid, + BQ2050HREGS.lmd, + BQ2050HREGS.flgs2, + BQ2050HREGS.ppd, + BQ2050HREGS.ppu, + BQ2050HREGS.cpi, + BQ2050HREGS.vsb, + BQ2050HREGS.vts, + BQ2050HREGS.cact, + BQ2050HREGS.cacd, + BQ2050HREGS.saeh, + BQ2050HREGS.sael, + BQ2050HREGS.rcac, + BQ2050HREGS.vsrh, + BQ2050HREGS.vsrl, + BQ2050HREGS.nmcv, + BQ2050HREGS.nacl, + BQ2050HREGS.dcr, + BQ2050HREGS.ppfc, + BQ2050HREGS.intss, + BQ2050HREGS.rst, + BQ2050HREGS.hexff + ); + vdprintk("LEAVE: bmi_swi_dumpstruct()\n"); +} +#endif /* DEBUG */ + +static void +bmi_swi_fillstruct(void) +{ + u_char *member; + u_char i; + uint32_t data; + int nAttempts; + int sts; + + vdprintk("ENTER: bmi_swi_fillstruct()\n"); + + member = (u_char *)&BQ2050HREGS; + for (i = 1; i < sizeof(BQ2050HREGS); i++) { + /* Skip the BQ2050HREGS reserved registers */ + if (i == 0xa || i == 0x14 || i == 0x16) + i++; + else if (i == 0x19 || i == 0x3a) + i += 5; + else if (i == 0x1f) + i += 25; + + /* Read the BQ2050HREGS registers */ + for (nAttempts = 0; nAttempts < NTXRXATTEMPTS; nAttempts++) { + /* Preset in case send fails on last retry */ + data = -1; + /* Send the READ command */ + sts = bmi_swi_send_data(i); + if (sts == -1) { + bmi_swi_break(bmi_device); + continue; /* Retry if invalid send */ + } + /* Read the return data */ + data = bmi_swi_recv_data(); + if (sts == -1) { + bmi_swi_break(bmi_device); + continue; /* Retry if invalid read */ + } + break; + } + /* JMG ??? If data is still == -1 should we do a reset ??? */ + member[i - 1] = (u_char)data; /* Store the data */ + } +#ifdef DEBUG + bmi_swi_dumpstruct(); +#endif /* DEBUG */ + + vdprintk("LEAVE: bmi_swi_fillstruct()\n"); +} + +static void +bmi_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + vdprintk("ENTER: bmi_interrupt()\n"); + + /* See if the break sequence has completed */ + if ((bmiswi->isr & SWIISR_BRIS) || (bmiswi->u.risr & SWIRISR_RBRIS)) { + bmiswi->u.eoi |= SWIEOI_RBRIS; /* clear interupt */ + vdprintk("LH7A400 BMI: bmi_interrupt(): BREAK RECOVERED\n"); + } +#ifdef USE_RX_INTERRUPT + /* See if the data word has been read from the SWI peripheral */ + if ((bmiswi->isr & SWIISR_WRIS) || (bmiswi->u.risr & SWIRISR_RWRIS)) { + vdprintk("LH7A400 BMI: bmi_interrupt(): WORD RECEIVED\n"); + bmiswi_dr = bmiswi->dr; /* clear interupt */ + vdprintk("", bmiswi_dr); + } +#endif /* USE_RX_INTERRUPT */ +#ifdef USE_TX_INTERRUPT + /* See if the data word has been written to the SWI peripheral */ + if ((bmiswi->isr & SWIISR_WTIS) || (bmiswi->u.risr & SWIRISR_RWTIS)) { + vdprintk("LH7A400 BMI: bmi_interrupt(): WORD TRANSMITTED\n"); + bmiswi->u.eoi |= SWIEOI_RWTIS; /* clear interupt */ + } +#endif /* USE_TX_INTERRUPT */ + wake_up_interruptible(&bmi_wait_q); /* Wake up our waiting processes */ + + vdprintk("LEAVE: bmi_interrupt()\n"); +} + +static void +initialize_swi(u_char device) +{ + vdprintk("ENTER: initialize_swi()\n"); + + bmiswi->cr = (SWICR_RDSS(swi_settings[device].read_size) | + SWICR_WDCS(swi_settings[device].write_size) | + ((swi_settings[device].ss_invert) ? + SWICR_SP_INVERT : 0) | + ((swi_settings[device].data_invert) ? + SWICR_SWIDINV : 0)); + + bmi_swi_enable(); + bmi_swi_break(device); + /* + * Force bmi_swi_fillstruct() to be manually called each time... + * bmi_swi_fillstruct(); + */ + vdprintk("LEAVE: initialize_swi()\n"); + + return; +} + +void +kev7a400_apm_get_power_status(u_char *ac_line_status, + u_char *battery_status, + u_char *battery_flag, + u_char *battery_percentage, + u_short *battery_life) +{ + int on_battery; + + vdprintk("ENTER: kev7a400_apm_get_power_status()\n"); + + /* See if we are on AC/DC */ + dprintk("clksc->pwrsr = 0x%08X\n", clksc->pwrsr); + if (clksc->pwrsr & (PWRSR_NBFLG | PWRSR_RSTFLG | + PWRSR_PFFLG | PWRSR_CLDFLG)) + { + vdprintk("Clearing (PWRSR_NBFLG | PWRSR_RSTFLG | PWRSR_PFFLG | PWRSR_CLDFLG)\n"); + clksc->stfclr = clksc->pwrsr; + dprintk("clksc->pwrsr = 0x%08X\n", clksc->pwrsr); + } + on_battery = clksc->pwrsr & PWRSR_DCDET; + + /* Talk to the battery and tell us what it thinks */ + bmi_swi_fillstruct(); + + /* + * Get the AC LINE STATUS + * 0x00: Off-line + * 0x01: On-line + * 0x02: On backup power (BIOS >= 1.1 only) + * 0xff: Unknown + * + * NOTE: See line in BATTERY STATUS section that adjust (a little) for + * the fact that the DCDET line doesn't work. + */ + if (on_battery) { + *ac_line_status = 0x00; + } else { + *ac_line_status = 0x01; + } + + /* + * Get the BATTERY STATUS + * 0x00: High + * 0x01: Low + * 0x02: Critical + * 0x03: Charging + * 0x04: Selected battery not present (BIOS >= 1.2 only) + * 0xff: Unknown + */ + if (BQ2050HREGS.flgs1 == 0xFF) { + *battery_status = 0xFF; /* Unknown */ + } else { + *battery_status = 0x00; /* High ( > 50% ) */ + if (BQ2050HREGS.flgs1 & 0x80) { + *battery_status |= 0x03; /* Charging */ + /* Account for the fact that the DCDET bit doesn't work */ + *ac_line_status = 0x01; /* AC ON-LINE */ + } else if (BQ2050HREGS.flgs1 & 0x03) { + *battery_status |= 0x02; /* Critical */ + } else if (BQ2050HREGS.rcac != 0xFF) { + if (BQ2050HREGS.rcac <= 50 ) { + *battery_status |= 0x01; /* Low ( <= 50% ) */ + } + } else { + *battery_status = 0xFF; /* Unknown */ + } + } + + /* + * Get the BATTERY FLAG + * bit 0: High + * bit 1: Low + * bit 2: Critical + * bit 3: Charging + * bit 7: No system battery + * 0xff: Unknown + */ + *battery_flag = *battery_status; + + /* + * Get the BATTERY PERCENTAGE + * 0-100: valid + * 0xFF == -1: Unknown + */ + *battery_percentage = BQ2050HREGS.rcac; + + /* + * Get the BATTERY LIFE + * Number of remaining minutes or seconds (size == 0x7FFF) + * bit 0x8000: + * 0 == sec = seconds + * 1 == min = minutes + * 0xFFFF == -1: Unknown + */ +/* I'm not sure what to do here and my batteries won't hold up to find out */ + *battery_life = 0xFFFF; + + vdprintk("LEAVE: kev7a400_apm_get_power_status()\n"); +} + +void kev7a400_apm_init(void) +{ + int sts; + + vdprintk("ENTER: kev7a400_apm_init()\n"); + + printk("Sharp KEV7A400 BMI Driver Copyright 2002 Embedix\n"); + bmiswi = &bmi->swi; + bmisbi = &bmi->sbi; + init_waitqueue_head(&bmi_wait_q); + sts = request_irq(IRQ_BMI, bmi_interrupt, + SA_INTERRUPT | SA_SAMPLE_RANDOM, "bmi", NULL); + if (sts == 0) { + /* Enable Ints for Break Recovered/Word Received/Transmitted */ + bmiswi->ie = SWIIE_BRIE; +#ifdef USE_RX_INTERRUPT + bmiswi->ie |= SWIIE_WRIE; +#endif /* USE_RX_INTERRUPT */ +#ifdef USE_TX_INTERRUPT + bmiswi->ie |= SWIIE_WTIE; +#endif /* USE_TX_INTERRUPT */ + bmi_irq_enabled++; + printk("KEV7A400 BMI: IRQ %d Enabled.\n", IRQ_BMI); + } else { + printk(KERN_ERR "KEV7A400 BMI: IRQ %d already in use.\n", + IRQ_BMI); + } + + /* turn off leds D18 and D19 */ + gpio->pbdr = _BIT(1) | _BIT(2); + gpio->pcdr |= _BIT(0); + + /* Initialize the BMI SWI */ + initialize_swi(bmi_device); + + vdprintk("LEAVE: kev7a400_apm_init()\n"); +} + +void kev7a400_apm_exit(void) +{ + vdprintk("ENTER: kev7a400_apm_exit()\n"); + + bmiswi->ie = 0; /* Disable interrupts */ + free_irq (IRQ_BMI, NULL); + bmi_irq_enabled = 0; + printk("KEV7A400 BMI: IRQ %d Disabled.\n", IRQ_BMI); + + vdprintk("LEAVE: kev7a400_apm_exit()\n"); +} + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/arch.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/arch.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/arch.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/arch.c Sat Oct 18 10:38:17 2003 @@ -0,0 +1,57 @@ +/* + * linux/arch/arm/mach-lh7a400/arch.c + * + * Architecture specific fixups. + * + * Copyright (C) 2001 Lineo, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern u32 cpufreq_get( int); +extern u32 hclkfreq_get( void); +extern u32 pclkfreq_get( void); + +int lh7a400_stepping; + +void +lh7a400_show_freq_and_stepping(void) +{ + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + +#ifndef CONFIG_CPU_FREQ + printk( "FCLK=%d.%d MHz, HCLK=%d.%d MHz, PCLK=%d.%d MHz\n", + cpufreq_get(0) / 1000, cpufreq_get(0) % 1000, + hclkfreq_get() / 1000, hclkfreq_get() % 1000, + pclkfreq_get() / 1000, pclkfreq_get() % 1000); +#endif + + lh7a400_stepping = (clksc->pwrsr & PWRSR_CHIPI) >> 16; + printk( "Stepping = %d\n", lh7a400_stepping); +} + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/cpu_lh7a400.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/cpu_lh7a400.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/cpu_lh7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/cpu_lh7a400.c Thu Oct 16 16:33:58 2003 @@ -0,0 +1,83 @@ +/* + * cpu-lh7a400.c: SDRAM support for clock scaling for the Sharp LH7A400 + * Copyright (C) Embedix, Inc. + * + * based on cpu-sa1100.c, which is + * + * Copyright (C) 2000 2001, The Delft University of Technology + * + * 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 +#include +#include +#include +#include +#include + +#define DEBUG 0 + +#if DEBUG +# define DPRINTK( args...) printk( args) +#else +# define DPRINTK( args...) +#endif + + +static int hclk_clkchg_notifier(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct hclkfreq_info *hi = data; + sdramRegs_t *sdram = (sdramRegs_t *)IO_ADDRESS(SDRAM_REGS_PHYS); + + switch(val) { + case HCLKFREQ_PRECHANGE: + if(hi->new_freq < hi->old_freq) { + DPRINTK( __FUNCTION__ ": going slower, do it before\n"); + DPRINTK( __FUNCTION__ ": reftimer = %d\n", sdram->refreshTimer); + DPRINTK( __FUNCTION__ ": setting reftimer to %d\n", + SDRAM_REFTMR_REFCNT((hi->new_freq / 64) + 1)); + sdram->refreshTimer = SDRAM_REFTMR_REFCNT((hi->new_freq / 64) + 1); + } + break; + + case HCLKFREQ_POSTCHANGE: + if(hi->new_freq > hi->old_freq) { + DPRINTK( __FUNCTION__ ": going faster, do it after\n"); + DPRINTK( __FUNCTION__ ": reftimer = %d\n", sdram->refreshTimer); + DPRINTK( __FUNCTION__ ": setting reftimer to %d\n", + SDRAM_REFTMR_REFCNT((hi->new_freq / 64) + 1)); + sdram->refreshTimer = SDRAM_REFTMR_REFCNT((hi->new_freq / 64) + 1); + } + break; + } + + return 0; +} + + +static struct notifier_block hclk_block = { + notifier_call: hclk_clkchg_notifier, +}; + + +static int __init lh7a400_sdram_init(void) +{ + return hclkfreq_register_notifier( &hclk_block); +} + +__initcall(lh7a400_sdram_init); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/dma.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/dma.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/dma.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/dma.c Mon Oct 20 16:21:50 2003 @@ -0,0 +1,1255 @@ +/* + * arch/arm/mach-lh7a400/dma.c + * + * Support functions for the Sharp LH7A400 internal DMA channels. + * + * Copyright (C) 2002 Embedix, Inc. + * + * Based on arch/arm/mach-lh79520/dma.c + * Copyright (C) 2002 Embedix, Inc. + * Based on arch/arm/mach-sa1100/dma-sa1100.c, which is + * Copyright (C) 2000 Nicolas Pitre + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + */ + +/* +* To the best of my understanding, the LH7A400 DMA operates as follows: +* Jim Gleason - Embedix, Inc. +* +* +---------------+ +* | + +* | "IDLE" STATE | +* | +<----+ +* +-------+-------+ | +* | | +* a) IDLE -> STALL (a) | (x) | x) STALL -> IDLE +* The control register | | The control register +* has had the ENABLE | | has had the enable +* bit set. \|/ | bit cleared. +* +---------------+ | +* | +->>>-+ +* | "STALL" STATE | +* | +<----+ +* +-------+-------+ | +* | | +* b) STALL -> ON (b) | (y) | y) ON -> STALL +* The control register | | The DMA has no more +* has had its first | | buffers to work with. +* base[nextbuffer] \|/ | (zero buffers full) +* value set. +---------------+ | !!! This can generate +* (one buffer full) | +->>>-+ !!! a "STALL" interrupt. +* | "ON" STATE | +* | +<----+ +* +-------+-------+ | +* | | +* c) ON -> NEXT (c) | (z) | z) NEXT -> ON +* The control register | | The DMA finished its +* has had its second | | current buffer and has +* base[nextbuffer] \|/ | switched to its alternate +* value set. +---------------+ | buffer. +* (two buffers full) | +->>>-+ (one buffer full) +* | "NEXT" STATE | !!! This can generate +* | + !!! a "NFB" interrupt. +* +---------------+ +* +* !!! A "CHERROR" interrupt can also be generated on transmission errors. +*/ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "dma.h" + +#if 0 +#define DEBUG +#define VERBOSE +#else +#undef DEBUG +#undef VERBOSE +#endif + +#define DRVNAME "LH7X DMA" + +#ifdef DEBUG +#define DPRINTK( s, arg... ) \ + dprintk( "dma<%s>: " s, channel_context->channel_name , ##arg ) +#else /* DEBUG */ +#define DPRINTK( s, arg... ) +#endif /* DEBUG */ + +dma_regs_t *dma_regs = (dma_regs_t *)IO_ADDRESS(DMAC_PHYS); +//cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + +lh7a400_dma_context_t *lh7a400_dma_context = NULL; + +#define vdprintk if (0) printk +#define dprintk if (0) printk + +#ifdef DEBUG +/********************************************************************** +* Function: lh7a400_dump_dma_queue() +**********************************************************************/ +static inline void +lh7a400_dump_dma_queue(lh7a400_dma_channel_context_t *channel_context) +{ + dma_buf_list_t *p = channel_context->tail; + + dprintk("Q: curr=0x%p, tail=0x%p, head=0x%p, bid: ", + channel_context->curr, channel_context->tail, + channel_context->head); + + while (p) { + printk( "(0x%p 0x%p), ", p, p->id); + p = p->next; + } + printk("\n"); + + return; +} /* lh7a400_dump_dma_queue() */ +#else /* DEBUG */ +#define lh7a400_dump_dma_queue(d) +#endif /* DEBUG */ + +/* +* DMA processing... +*/ + +/********************************************************************** +* Function: lh7a400_start_dma() +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +static inline int +lh7a400_start_dma(lh7a400_dma_channel_context_t *channel_context, + dma_addr_t dma_ptr, int size) +{ + dma_channel_regs_t *channel_regs = channel_context->channel_regs; + uint32_t status; + int state; + + vdprintk("ENTER: %s()\n", __FUNCTION__); + + status = channel_regs->status; + state = status & DMAC_STATE_MASK; + + /* If both DMA buffers are started, there's nothing else we can do. */ + if (state == DMAC_STATE_NEXT) { + vdprintk("%s() - BUSY\n", __FUNCTION__); + return(-EBUSY); + } + +#if 0 // DDD + /* If there is an interrupt pending, let it happen first. */ + if (channel_regs->interrupt) { + vdprintk("%s() - IRQ Pending\n", __FUNCTION__); + return(-EAGAIN); + } +#endif + + /* + * We have an available buffer, + * Update the base[01] and maxcnt[01] register pair + * and Start the DMA for this channel and buffer + * + * NOTE: DMAC_ENABLE must be set FIRST + * and the base[01] register must be set LAST + */ + + vdprintk("%s(dma_ptr=%#x, size=%d) - buff(%d)\n", + __FUNCTION__, dma_ptr, size, status & DMAC_NEXTBUFFER ? 1:0); + + if( state == DMAC_STATE_IDLE) { + channel_regs->control = + DMAC_STALL /* Enable STALL interrupt gen */ + | DMAC_CHERROR /* Enable CHERROR interrupt gen */ + | DMAC_ENABLE /* Enable the Channel */ + /* | DMAC_ABORT *//* ??? */ + | DMAC_ICE; /* ??? */ + } + + if ((status & DMAC_NEXTBUFFER) == 0 ) { + /* Update the base0 and maxcnt0 register pair */ + channel_regs->maxcnt0 = size; + channel_regs->base0 = dma_ptr; + } else { + channel_regs->maxcnt1 = size; + channel_regs->base1 = dma_ptr; + } + + /* want to get NFB ints. */ + channel_regs->control |= DMAC_NFB; + + vdprintk("LEAVE: %s()\n", __FUNCTION__); + + return(0); +} /* lh7a400_start_dma() */ + +/********************************************************************** +* Function: lh7a400_process_dma() +* +* NOTE: This must be called with IRQ disabled +* +**********************************************************************/ +static void +lh7a400_process_dma(lh7a400_dma_channel_context_t *channel_context) +{ + dma_buf_list_t *buf; + int chunksize; + + vdprintk("ENTER: %s( channel_context=0x%p)\n", + __FUNCTION__, channel_context); + + lh7a400_dump_dma_queue(channel_context); + + for ( ; ; ) { + buf = channel_context->tail; + + if (!buf || channel_context->stopped) { + /* no more data available */ + DPRINTK("process: no more buf (dma %s), " + "buf=0x%p, stopped=%d, spin_size=%d, " + "spin_ref=%d\n", + channel_context->curr ? "active" : "inactive", + buf, channel_context->stopped, + channel_context->spin_size, + channel_context->spin_ref); + /* + * Some devices may require DMA still sending data + * at any time for clock reference, etc. + * Note: if there is still a data buffer being + * processed then the ref count is negative. This + * allows for the DMA termination to be accounted in + * the proper order. + */ + if (channel_context->spin_size && + channel_context->spin_ref >= 0) + { + chunksize = channel_context->spin_size; + if (chunksize > MAX_DMA_SIZE) + chunksize = (1 << MAX_DMA_ORDER); + while (lh7a400_start_dma( + channel_context, + channel_context->spin_addr, + chunksize) == 0) + { + channel_context->spin_ref++; + } + if (channel_context->curr != NULL) { + channel_context->spin_ref = + -channel_context->spin_ref; + } + } + break; + } + + /* + * Let's try to start DMA on the current buffer. + * If DMA is busy then we break here. + */ + chunksize = buf->size; + if (chunksize > MAX_DMA_SIZE) + chunksize = (1 << MAX_DMA_ORDER); + + DPRINTK("process: bid=%#x s=%d\n", (int) buf->id, buf->size); + + if (lh7a400_start_dma(channel_context, buf->dma_ptr, + chunksize) != 0) + break; + + if (!channel_context->curr) { + channel_context->curr = buf; + DPRINTK("process: set curr to %p\n", + channel_context->curr); + } + + buf->ref++; + buf->dma_ptr += chunksize; + buf->size -= chunksize; + if (buf->size == 0) { + /* current buffer is done: move tail to the next one */ + channel_context->tail = buf->next; + DPRINTK("process: set tail b=%#x\n", + (int) channel_context->tail); + } + } + + lh7a400_dump_dma_queue(channel_context); + + vdprintk("LEAVE: %s()\n", __FUNCTION__); +} /* lh7a400_process_dma() */ + +/********************************************************************** +* Function: lh7a400_dma_done() +* +* NOTE: This must be called with IRQ disabled +**********************************************************************/ +void +lh7a400_dma_done(lh7a400_dma_channel_context_t *channel_context) +{ + dma_buf_list_t *buf = channel_context->curr; + + vdprintk("ENTER: %s()\n", __FUNCTION__); + vdprintk( "spin_ref=%d buf=%p\n", channel_context->spin_ref, buf); + + if (channel_context->spin_ref > 0) { + channel_context->spin_ref--; + } else if (buf) { + buf->ref--; + if (buf->ref == 0 && buf->size == 0) { + /* + * Current buffer is done. + * Move current reference to the next one and send + * the processed buffer to the callback function, + * then discard it. + */ + DPRINTK("IRQ: buf done: set curr to %p\n", buf->next); + channel_context->curr = buf->next; + if (channel_context->curr == NULL) + channel_context->spin_ref = + -channel_context->spin_ref; + + if (channel_context->head == buf) + channel_context->head = NULL; + + if (channel_context->callback) { + int size = buf->dma_ptr - buf->dma_start; + channel_context->callback(buf->id, size); + } + + kfree(buf); + } + } + + lh7a400_process_dma(channel_context); + + vdprintk("LEAVE: %s()\n", __FUNCTION__); + + return; +} /* lh7a400_dma_done() */ + +/********************************************************************** +* Function: lh7a400_dma_channel_stall_irq_handler() +* +* This interrupt handler handles the "stall" interrupt +* for the IRQ for the channel specified +* by lh7a400_dma_channel_irq_handler(). +* +* NOTE: The DMA doesn't have any buffers to work with (both are empty). +* +**********************************************************************/ +static inline void +lh7a400_dma_channel_stall_irq_handler(lh7a400_dma_context_t *dma_context, + lh7a400_dma_channel_context_t *channel_context) +{ + vdprintk( "channel_context=0x%p channel_regs=0x%p\n", + channel_context, channel_context->channel_regs); + lh7a400_dma_done(channel_context); + + /* + * Turn off the controller to prevent aflood of + * these stall interrupts. + */ + channel_context->channel_regs->control &= ~DMAC_ENABLE; + /* JMG - Further action TBD */ +} /* lh7a400_dma_channel_stall_irq_handler() */ + +/********************************************************************** +* Function: lh7a400_dma_channel_nfb_irq_handler() +* +* This interrupt handler handles the "nfb" interrupt +* for the IRQ for the channel specified +* by lh7a400_dma_channel_irq_handler(). +* +* NOTE: The DMA has finished a buffer and is now working on the alternate. +* +**********************************************************************/ +static inline void +lh7a400_dma_channel_nfb_irq_handler(lh7a400_dma_context_t *dma_context, + lh7a400_dma_channel_context_t *channel_context) +{ + lh7a400_dma_done(channel_context); + /* JMG - Further action TBD */ +} /* lh7a400_dma_channel_nfb_irq_handler() */ + +/********************************************************************** +* Function: lh7a400_dma_channel_cherror_irq_handler() +* +* This interrupt handler handles the "cherror" interrupt +* for the IRQ for the channel specified +* by lh7a400_dma_channel_irq_handler(). +* +* NOTE: The last buffer transfer terminated with an error. +* +**********************************************************************/ +static inline void +lh7a400_dma_channel_cherror_irq_handler(lh7a400_dma_context_t *dma_context, + lh7a400_dma_channel_context_t *channel_context) +{ + /* Clear the error by writing "anything" to the interrupt register */ + channel_context->channel_regs->interrupt = DMAC_CHERROR; + dprintk("DMAC_CHERROR on %s\n", channel_context->channel_name); + /* JMG - Further action TBD */ +} /* lh7a400_dma_channel_cherror_irq_handler() */ + +/********************************************************************** +* Function: lh7a400_dma_channel_irq_handler() +* +* This interrupt handler handles the IRQ for the channel specified +* by lh7a400_dma_irq_handler(). +* +**********************************************************************/ +static inline void +lh7a400_dma_channel_irq_handler(lh7a400_dma_context_t *dma_context, + lh7a400_dma_channel_context_t *channel_context) +{ + uint32_t interrupt = channel_context->channel_regs->interrupt; + + vdprintk("%s regs=%p, chan_interrupt=0x%x\n", + __FUNCTION__, channel_context->channel_regs, interrupt); + + if (interrupt & DMAC_CHERROR) { + /* The last buffer transfer terminated with an error */ + lh7a400_dma_channel_cherror_irq_handler(dma_context, + channel_context); + } + if (interrupt & DMAC_STALL) { + /* DMA has no buffers to work with (both empty) */ + lh7a400_dma_channel_stall_irq_handler(dma_context, + channel_context); + } + if (interrupt & DMAC_NFB) { + dma_channel_regs_t *channel_regs = + channel_context->channel_regs; + + channel_regs->control &= ~DMAC_NFB; // only need one + /* DMA has finished a buffer and is working on the alternate */ + lh7a400_dma_channel_nfb_irq_handler(dma_context, + channel_context); + } + + return; +} /* lh7a400_dma_channel_irq_handler() */ + +/********************************************************************** +* Function: lh7a400_dma_irq_handler() +* +* This interrupt handler only directs traffic for the interrupts +* by forwarding on the call to the appropriate interrupt handler. +* +**********************************************************************/ +static void +lh7a400_dma_irq_handler(int irq, void *context, struct pt_regs *regs) +{ + lh7a400_dma_context_t *dma_context = (lh7a400_dma_context_t *)context; + lh7a400_dma_channel_context_t *channel_context = NULL; + uint32_t global_int; + int bit; + int channel_num; + + dma_regs_t *dma_regs = dma_context->dma_regs; + + /* Find out all who are interrupting, and act accordingly */ + global_int = dma_regs->dma_global_int & DMAC_INTMASK; + + vdprintk("\nENTER: %s() global_int=0x%x\n", __FUNCTION__, global_int); + + channel_num = 0; + for (bit = 1; bit & DMAC_INTMASK; bit <<= 1) { + if (bit & global_int) { + channel_context = + &dma_context->channel_context[channel_num]; + + vdprintk( "channel_num=%d\n", channel_num); + + lh7a400_dma_channel_irq_handler(dma_context, + channel_context); + } + channel_num++; + } + + vdprintk("LEAVE: %s()\n", __FUNCTION__); + + return; +} /* lh7a400_dma_irq_handler() */ + +/* +* DMA interface functions +*/ + +static spinlock_t lh7a400_dma_list_lock; + +/********************************************************************** +* Function: lh7a400_request_dma() +* +* NOTE: This function is exported! +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_request_dma(dmach_t *channel, const char *device_name, + dma_channel_t channel_requested) +{ + lh7a400_dma_channel_context_t *channel_context = NULL; + int err = 0; + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + + dprintk("ENTER: %s(device_name=%s, channel_requested=%d)\n", + __FUNCTION__, device_name, (int)channel_requested); + + /* be sure we catch the freeing of misregistered channels */ + *channel = -1; + + if ((unsigned)channel_requested >= n_LH7A400_DMA_CHANNELS) + return(-ECHRNG); /* Channel number out of range */ + + if (lh7a400_dma_context->channel_context[channel_requested].in_use) + return(-EBUSY); + + spin_lock(&lh7a400_dma_list_lock); + + /* + * Allocate a channel on the LH7A400. + * On the lh7a400 channels are as follows (see dma_channel_t): + * 0 == Universal Serial bus (USB) Rx + * 1 == Universal Serial bus (USB) Tx + * 2 == Multi-Media Card (MMC) Rx + * 3 == Multi-Media Card (MMC) Tx + * 4 == Advanced Audio Controller (AAC) 0 Rx + * 5 == Advanced Audio Controller (AAC) 0 Tx + * 6 == Advanced Audio Controller (AAC) 1 Rx + * 7 == Advanced Audio Controller (AAC) 1 Tx + * 8 == Advanced Audio Controller (AAC) 2 Rx + * 9 == Advanced Audio Controller (AAC) 2 Tx + */ + + switch( channel_requested) { + case DMA_USB_Rx: + case DMA_USB_Tx: + case DMA_MMC_Rx: + case DMA_MMC_Tx: + case DMA_AAC_0_Rx: + case DMA_AAC_0_Tx: + case DMA_AAC_1_Rx: + case DMA_AAC_1_Tx: + case DMA_AAC_2_Rx: + case DMA_AAC_2_Tx: + break; + + default: + err = -ENOSR; + break; + } + + if ( ! err) { + *channel = channel_requested; + channel_context = + &lh7a400_dma_context->channel_context[*channel]; + channel_context->in_use = 1; + } + + spin_unlock(&lh7a400_dma_list_lock); + + if (err) + return(err); + + channel_context->callback = NULL; + channel_context->spin_size = 0; + + dprintk("ENTER: %s(channel=%d,device_name=%s,channel_requested=%d)\n", + __FUNCTION__, *channel, device_name, (int)channel_requested); + + /* turn on the clock to this DMA channel */ + clksc->pwrcnt |= 1 << (channel_requested + 16); + + return(0); +} /* lh7a400_request_dma() */ + +/********************************************************************** +* Function: lh7a400_dma_set_callback() +* +* NOTE: This function is exported! +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_set_callback(dmach_t channel, dma_callback_t cb) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + + vdprintk("ENTER: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || !channel_context->in_use) + return(-EINVAL); + + channel_context->callback = cb; + + vdprintk("LEAVE: %s(channel=%d, cb=%p)\n", + __FUNCTION__, (int)channel, cb); + + return(0); +} /* lh7a400_dma_set_callback() */ + +/********************************************************************** +* Function: lh7a400_dma_set_spin() +* +* NOTE: This function is exported! +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_set_spin(dmach_t channel, dma_addr_t addr, int size) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + int flags; + + vdprintk("ENTER: %s(channel=%d,size=%d,addr=%#x,channel_context=%p)\n", + __FUNCTION__, (int)channel, size, addr, channel_context); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || + !channel_context->in_use) + return(-EINVAL); + + local_irq_save(flags); + + channel_context->spin_addr = addr; + channel_context->spin_size = size; + + if (size) + lh7a400_process_dma(channel_context); + + local_irq_restore(flags); + + vdprintk("LEAVE: %s(channel=%d, size=%d, addr=%#x)\n", + __FUNCTION__, (int)channel, size, addr); + + return(0); +} /* lh7a400_dma_set_spin() */ + +/********************************************************************** +* Function: lh7a400_dma_queue_buffer() +* +* NOTE: This function is exported! +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_queue_buffer(dmach_t channel, void *buf_id, + dma_addr_t data, int size) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + dma_buf_list_t *buf; + int flags; + + vdprintk("ENTER: %s(channel=%d, buf_id=%#x, data=%#x, size=%d)\n", + __FUNCTION__, (int)channel, (int)buf_id, data, size); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || + !channel_context->in_use) + return(-EINVAL); + + buf = kmalloc(sizeof(*buf), GFP_KERNEL | GFP_DMA | GFP_ATOMIC); + if (!buf) + return(-ENOMEM); + + buf->next = NULL; + buf->ref = 0; + buf->dma_ptr = buf->dma_start = data; + buf->size = size; + buf->id = buf_id; + + local_irq_save(flags); + + if (channel_context->head) + channel_context->head->next = buf; + + channel_context->head = buf; + if (!channel_context->tail) + channel_context->tail = buf; + + lh7a400_process_dma(channel_context); + + local_irq_restore(flags); + + vdprintk("LEAVE: %s(channel=%d, buf_id=%#x, data=%#x, size=%d)\n", + __FUNCTION__, (int)channel, (int)buf_id, data, size); + + return(0); +} /* lh7a400_dma_queue_buffer() */ + +/********************************************************************** +* Function: lh7a400_dma_get_current() +* +* NOTE: This function is exported! +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + int flags, ret; + dma_channel_regs_t *channel_regs; + + vdprintk("ENTER: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || + !channel_context->in_use) + return(-EINVAL); + + channel_regs = channel_context->channel_regs; + local_irq_save(flags); + if (channel_context->curr && channel_context->spin_ref <= 0) { + dma_buf_list_t *buf = channel_context->curr; + + /* + * If we got here, that's because there is, or recently was, a + * buffer being processed. Two possibilities: either we are + * in the middle of a buffer, or the DMA controller just + * switched to the next toggle but the interrupt hasn't been + * serviced yet. The former case is straight forward. In + * the later case, we'll do like if DMA is just at the end + * of the previous toggle since all registers haven't been + * reset yet. This goes around the edge case and since we're + * always a little behind anyways it shouldn't make a big + * difference. If DMA has been stopped prior calling this + * then the position is always exact. + */ + if (buf_id) + *buf_id = buf->id; + + /* JMG - These current[01] registers may need swapped ??? */ + if ((channel_regs->status & DMAC_NEXTBUFFER) == 0) { + *addr = channel_regs->current0; + } else { + *addr = channel_regs->current1; + } + + vdprintk("%s(c0=%x c1=%x *addr=%x)\n", __FUNCTION__, + channel_regs->current0, channel_regs->current1, + *addr); + + /* + * Clamp funky pointers sometimes returned by the hardware + * on completed DMA transfers + */ + if (*addr < buf->dma_start || *addr > buf->dma_ptr) + *addr = buf->dma_ptr; + DPRINTK("curr_pos: b=%#x a=%#x\n", + (int)channel_context->curr->id, *addr); + ret = 0; + } else if (channel_context->tail && channel_context->stopped) { + dma_buf_list_t *buf = channel_context->tail; + if (buf_id) + *buf_id = buf->id; + *addr = buf->dma_ptr; + vdprintk("%s 1 ( *addr=%x)\n", __FUNCTION__, *addr); + ret = 0; + } else { + if (buf_id) + *buf_id = NULL; +#if 0 // DDD + *addr = 0; + ret = -ENXIO; +#else + if ((channel_regs->status & DMAC_NEXTBUFFER) == 0) { + *addr = channel_regs->current1; + } else { + *addr = channel_regs->current0; + } + + vdprintk("%s 2 (c0=%x c1=%x *addr=%x)\n", __FUNCTION__, + channel_regs->current0, channel_regs->current1, + *addr); + + ret = 0; +#endif + } + local_irq_restore(flags); + + vdprintk("LEAVE: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + return(ret); +} /* lh7a400_dma_get_current() */ + +/********************************************************************** +* Function: lh7a400_dma_stop() +* +* NOTE: This function is exported! +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_stop(dmach_t channel) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + int flags; + + vdprintk("ENTER: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || + !channel_context->in_use) + return(-EINVAL); + + if (channel_context->stopped) + return(0); + + local_irq_save(flags); + + channel_context->stopped = 1; + + /* + * Stop DMA and tweak state variables so everything could restart + * from there when resume/wakeup occurs. + */ + channel_context->channel_regs->control &= ~DMAC_ENABLE; + channel_context->channel_regs->control &= + ~(DMAC_STALL | DMAC_NFB | DMAC_CHERROR); + /* JMG - TBD if any additional tweaking needs done */ + + if (channel_context->curr) { + dma_buf_list_t *buf = channel_context->curr; + if (channel_context->spin_ref <= 0) { + dma_addr_t curpos; + lh7a400_dma_get_current(channel, NULL, &curpos); + buf->size += buf->dma_ptr - curpos; + buf->dma_ptr = curpos; + } + buf->ref = 0; + channel_context->tail = buf; + channel_context->curr = NULL; + } + channel_context->spin_ref = 0; + + lh7a400_process_dma(channel_context); + + local_irq_restore(flags); + + vdprintk("LEAVE: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + return(0); +} /* lh7a400_dma_stop() */ + +/********************************************************************** +* Function: lh7a400_dma_resume() +* +* NOTE: This function is exported! +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_resume(dmach_t channel) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + int flags; + + vdprintk("ENTER: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || + !channel_context->in_use) + return(-EINVAL); + + if (channel_context->stopped) { + save_flags_cli(flags); + channel_context->stopped = 0; + channel_context->spin_ref = 0; + lh7a400_process_dma(channel_context); + restore_flags(flags); + } + + vdprintk("LEAVE: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + return(0); +} /* lh7a400_dma_resume() */ + +/********************************************************************** +* Function: lh7a400_dma_flush_all() +* +* NOTE: This function is exported! +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_flush_all(dmach_t channel) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + dma_buf_list_t *buf, *next_buf; + int flags; + + vdprintk("ENTER: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + lh7a400_dump_dma_queue(channel_context); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || + !channel_context->in_use) + return(-EINVAL); + + local_irq_save(flags); + + /* + * Disable the channel, and mask off its interrupts + */ + channel_context->channel_regs->control &= ~DMAC_ENABLE; + channel_context->channel_regs->control &= + ~(DMAC_STALL | DMAC_NFB | DMAC_CHERROR); + /* JMG - TBD if any additional "tweaking needs done */ + + buf = channel_context->curr; + if (!buf) + buf = channel_context->tail; + + channel_context->curr = NULL; + channel_context->head = NULL; + channel_context->tail = NULL; + channel_context->stopped = 0; + channel_context->spin_ref = 0; + + lh7a400_process_dma(channel_context); + + local_irq_restore(flags); + + while (buf) { + next_buf = buf->next; + kfree(buf); + buf = next_buf; + } + + vdprintk("LEAVE: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + return(0); +} /* lh7a400_dma_flush_all() */ + +/********************************************************************** +* Function: lh7a400_free_dma() +* +* NOTE: This function is exported! +* +**********************************************************************/ +void +lh7a400_free_dma(dmach_t channel) +{ + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + + vdprintk("ENTER: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS) { + printk(KERN_ERR "Freeing invalid DMA channel (%d)\n", + (int)channel); + return; + } + if (!channel_context->in_use) { + printk(KERN_ERR "Freeing unallocated DMA channel (%d)\n", + (int)channel); + return; + } + + lh7a400_dma_set_spin(channel, 0, 0); + lh7a400_dma_flush_all(channel); + + channel_context->in_use = 0; + + /* turn off the clock to this DMA channel */ + clksc->pwrcnt &= ~(1 << (channel_context->channel_num + 16) ); + + vdprintk("LEAVE: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + return; +} /* lh7a400_free_dma() */ + +#if 1 || defined(CONFIG_SYMTAB) +EXPORT_SYMBOL(lh7a400_request_dma); +EXPORT_SYMBOL(lh7a400_dma_set_callback); +EXPORT_SYMBOL(lh7a400_dma_set_spin); +EXPORT_SYMBOL(lh7a400_dma_queue_buffer); +EXPORT_SYMBOL(lh7a400_dma_get_current); +EXPORT_SYMBOL(lh7a400_dma_stop); +EXPORT_SYMBOL(lh7a400_dma_resume); +EXPORT_SYMBOL(lh7a400_dma_flush_all); +EXPORT_SYMBOL(lh7a400_free_dma); +#endif /* CONFIG_SYMTAB */ + +#ifdef CONFIG_PM +/********************************************************************** +* Function: lh7a400_dma_sleep() +* +* NOTE: This function is exported! +* +* NOTE: Drivers should call this from their PM callback function. +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_sleep(dmach_t channel) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + int orig_state; + + vdprintk("ENTER: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || + !channel_context->in_use) + return(-EINVAL); + + orig_state = channel_context->stopped; + lh7a400_dma_stop(channel); + channel_context->channel_regs->control &= ~DMAC_ENABLE; + channel_context->channel_regs->control &= + ~(DMAC_STALL | DMAC_NFB | DMAC_CHERROR); + /* JMG - TBD if any additional "tweaking needs done */ + + channel_context->stopped = orig_state; + channel_context->spin_ref = 0; + + vdprintk("LEAVE: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + return(0); +} /* lh7a400_dma_sleep() */ + +/********************************************************************** +* Function: lh7a400_dma_wakeup() +* +* NOTE: This function is exported! +* +* NOTE: Drivers should call this from their PM callback function. +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +int +lh7a400_dma_wakeup(dmach_t channel) +{ + lh7a400_dma_channel_context_t *channel_context = + &lh7a400_dma_context->channel_context[channel]; + int flags; + + vdprintk("ENTER: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + if ((unsigned)channel >= n_LH7A400_DMA_CHANNELS || + !channel_context->in_use) + return(-EINVAL); + + channel_context->channel_regs->control &= ~DMAC_ENABLE; + channel_context->channel_regs->control &= + ~(DMAC_STALL | DMAC_NFB | DMAC_CHERROR); + /* JMG - TBD if any additional "tweaking needs done */ + + local_irq_save(flags); + + lh7a400_process_dma(channel_context); + + local_irq_restore(flags); + + vdprintk("LEAVE: %s(channel=%d)\n", __FUNCTION__, (int)channel); + + return(0); +} /* lh7a400_dma_wakeup */ + +#if 1 || defined(CONFIG_SYMTAB) +EXPORT_SYMBOL(lh7a400_dma_sleep); +EXPORT_SYMBOL(lh7a400_dma_wakeup); +#endif /* CONFIG_SYMTAB */ + +#endif /* CONFIG_PM */ + +/********************************************************************** +* Function: lh7a400_init_dma_channel() +* +* NOTE: Prior to this being called, everything was zeroed... +* +**********************************************************************/ +static void +lh7a400_init_dma_channel(lh7a400_dma_channel_context_t *channel_context, + const char *channel_name, dma_channel_t channel_num, + dma_channel_regs_t *channel_regs, dma_direction_t direction) +{ + vdprintk("ENTER: %s()\n", __FUNCTION__); + + /* Context variables */ + channel_context->channel_name = channel_name; + channel_context->channel_num = channel_num; + channel_context->channel_regs = channel_regs; + channel_context->direction = direction; + + /* Control variable(s) */ + channel_regs->control = 0; + + /* Buffer 0 variables */ + channel_regs->maxcnt0 = 0; + channel_regs->base0 = 0; + channel_regs->current0 = 0; + + /* Buffer 1 variables */ + channel_regs->maxcnt1 = 0; + channel_regs->base1 = 0; + channel_regs->current1 = 0; + + vdprintk("LEAVE: %s()\n", __FUNCTION__); + + return; +} + +/********************************************************************** +* Function: lh7a400_init_dma() +* +* Returns: +* SUCCESS == 0 +* FAILURE != 0 +* +**********************************************************************/ +static int __init +lh7a400_init_dma(void) +{ + int channel_num; + lh7a400_dma_channel_context_t *channel_context; + char *channel_name = NULL; + dma_channel_regs_t *channel_regs = NULL; + dma_direction_t direction = DMA_RX; /* Init to quiet gcc */ + int sts; + + vdprintk("ENTER: %s()\n", __FUNCTION__); + + /* + * Initialize the context structure(s) + */ + lh7a400_dma_context = &static_lh7a400_dma_context; + + /* Zero out everything */ + memset(lh7a400_dma_context, 0, sizeof(lh7a400_dma_context_t)); + + /* Point to the actual DMA registers */ + lh7a400_dma_context->dma_regs = (dma_regs_t *)IO_ADDRESS(DMAC_PHYS); + + /* Initialize the individual stream and channel context structures */ + for (channel_num = 0; channel_num < n_LH7A400_DMA_CHANNELS; channel_num++) { + channel_context = &lh7a400_dma_context->channel_context[channel_num]; + switch (channel_num) { + case DMA_USB_Rx: + channel_name = "USB_RX"; + channel_regs = &lh7a400_dma_context->dma_regs->usb_rx; + direction = DMA_RX; + break; + case DMA_USB_Tx: + channel_name = "USB_TX"; + channel_regs = &lh7a400_dma_context->dma_regs->usb_tx; + direction = DMA_TX; + break; + case DMA_MMC_Rx: + channel_name = "MMC_RX"; + channel_regs = &lh7a400_dma_context->dma_regs->mmc_rx; + direction = DMA_RX; + break; + case DMA_MMC_Tx: + channel_name = "MMC_TX"; + channel_regs = &lh7a400_dma_context->dma_regs->mmc_tx; + direction = DMA_TX; + break; + case DMA_AAC_0_Rx: + channel_name = "AAC_0_RX"; + channel_regs = &lh7a400_dma_context->dma_regs->aac_0_rx; + direction = DMA_RX; + break; + case DMA_AAC_0_Tx: + channel_name = "AAC_0_TX"; + channel_regs = &lh7a400_dma_context->dma_regs->aac_0_tx; + direction = DMA_TX; + break; + case DMA_AAC_1_Rx: + channel_name = "AAC_1_RX"; + channel_regs = &lh7a400_dma_context->dma_regs->aac_1_rx; + direction = DMA_RX; + break; + case DMA_AAC_1_Tx: + channel_name = "AAC_1_TX"; + channel_regs = &lh7a400_dma_context->dma_regs->aac_1_tx; + direction = DMA_TX; + break; + case DMA_AAC_2_Rx: + channel_name = "AAC_2_RX"; + channel_regs = &lh7a400_dma_context->dma_regs->aac_2_rx; + direction = DMA_RX; + break; + case DMA_AAC_2_Tx: + channel_name = "AAC_2_TX"; + channel_regs = &lh7a400_dma_context->dma_regs->aac_2_tx; + direction = DMA_TX; + break; + } + + lh7a400_init_dma_channel(channel_context, channel_name, + channel_num, channel_regs, direction); + } + + lh7a400_dma_context->irq = IRQ_DMA; + sts = request_irq(lh7a400_dma_context->irq, lh7a400_dma_irq_handler, + SA_INTERRUPT, DRVNAME, (void *)lh7a400_dma_context); + if (sts) { + printk(KERN_ERR "unable to request IRQ %d for DMA.\n", + lh7a400_dma_context->irq); + return(sts); + } + + vdprintk("LEAVE: %s()\n", __FUNCTION__); + + return(0); +} /* lh7a400_init_dma() */ + +__initcall(lh7a400_init_dma); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/dma.h linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/dma.h --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/dma.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/dma.h Sun Feb 8 20:39:36 2004 @@ -0,0 +1,224 @@ +/* + * linux/arch/arm/mach-lh7a400/dma.h + * + * Based on arch/arm/mach-lh79520/dma.h + * Copyright (C) 2002 Embedix, Inc. + * Based on arch/arm/mach-sa1100/dma.h which is + * (C) 2000 Nicolas Pitre + * + * Copyright (C) 2002 Embedix, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * References: + * Sharp LH7A400 Programming Manual + */ + +#ifndef _ARCH_ARM_MACH_LH7A400_DMA_H +#define _ARCH_ARM_MACH_LH7A400_DMA_H + +#include +#include +//#include + +#include + +/* +* DMA buffer list structure +*/ + +typedef struct dma_buf_list_t dma_buf_list_t; +struct dma_buf_list_t { + int size; /* buffer size */ + dma_addr_t dma_start; /* starting DMA address */ + dma_addr_t dma_ptr; /* next DMA pointer to use */ + int ref; /* number of DMA references */ + void *id; /* to identify buffer from outside */ + dma_buf_list_t *next; /* next buffer to process */ +}; + +typedef enum { + DMA_OUT, + DMA_IN +} dma_direction_t; +#define DMA_RX DMA_IN +#define DMA_TX DMA_OUT + +/* +* DMA channel registers structure +* +* The following structure declaration allows referencing the status +* register either by bit field or by 32-bit register. +* This allows any of the following constructs to be used, to retrieve +* the currentstate bit field for example, once DMAC is defined properly, +* e.g., #define DMAC ((DMACREGS *)(DMAC_REGS_BASE)): +* +* tmp = DMAC->usbrx.status.bf.currentstate; +* or +* tmp = DMAC_CURRENTSTATE(DMAC->usbrx.status.r); +* or +* tmp = (DMAC->usbrx.status.r & 0x30) >> 4; +*/ +typedef struct dma_status_bits_t dma_status_bits_t; +struct dma_status_bits_t { + volatile uint32_t stall : 1; + volatile uint32_t nfb : 1; + const uint32_t: 1; + volatile uint32_t cherror : 1; + volatile uint32_t currentstate : 2; + volatile uint32_t nextbuffer : 1; + volatile uint32_t bytes : 5; + const uint32_t: 0; +}; + +typedef struct dma_channel_regs_t dma_channel_regs_t; +struct dma_channel_regs_t { + volatile uint32_t control; /* Control */ + volatile uint32_t interrupt; /* Interrupt */ + volatile uint32_t reserved1; + volatile uint32_t status; /* Status */ + volatile uint32_t reserved2; + volatile uint32_t remain; /* Bytes Remaining */ + volatile uint32_t reserved3[2]; + volatile uint32_t maxcnt0; /* Maximum byte count */ + volatile uint32_t base0; /* Base Address */ + volatile uint32_t current0; /* Current Address */ + volatile uint32_t reserved4; + volatile uint32_t maxcnt1; /* Maximum byte count */ + volatile uint32_t base1; /* Base Address */ + volatile uint32_t current1; /* Current Address */ + volatile uint32_t reserved5; +}; + +/* +* DMA channel registers structure +*/ +typedef struct dma_regs_t dma_regs_t; +struct dma_regs_t { + dma_channel_regs_t usb_rx; + dma_channel_regs_t usb_tx; + dma_channel_regs_t mmc_rx; + dma_channel_regs_t mmc_tx; + dma_channel_regs_t reserved0[4]; + dma_channel_regs_t aac_0_rx; + dma_channel_regs_t aac_0_tx; + dma_channel_regs_t aac_1_rx; + dma_channel_regs_t aac_1_tx; + dma_channel_regs_t aac_2_rx; + dma_channel_regs_t aac_2_tx; + dma_channel_regs_t reserved1; + volatile uint32_t dma_global_int; + volatile uint32_t reserved2[15]; +}; + +/*********************************************************************** +* DMA Channel Control Register Bit Fields +* DMA Channel Interrupt Register Bit Fields +* DMA Channel Status Register Bit Fields +**********************************************************************/ +#define DMAC_STALL _BIT(0) +#define DMAC_NFB _BIT(1) +#define DMAC_CHERROR _BIT(3) +#define DMAC_ENABLE _BIT(4) +#define DMAC_ABORT _BIT(5) +#define DMAC_ICE _BIT(6) +#define DMAC_NEXTBUFFER _BIT(6) +#define DMAC_CURRENTSTATE(n) (((n)&0x30) >> 4) +#define DMAC_STATUS_BYTES(n) (((n)&0xF80) >> 7) + +/* +* Note: The following STATE values have NOT been shifted +* and would need shifted with/if using the DMAC_CURRENTSTATE(n) macro. +*/ +#define DMAC_STATE_IDLE 0x0000 +#define DMAC_STATE_STALL 0x0010 +#define DMAC_STATE_ON 0x0020 +#define DMAC_STATE_NEXT 0x0030 +#define DMAC_STATE_MASK 0x0030 + +/*********************************************************************** +* DMA Global Interrupt Register Bit Fields +**********************************************************************/ +#define DMAC_USBTXINT _BIT(0) +#define DMAC_USBRXINT _BIT(1) +#define DMAC_MMCTXINT _BIT(2) +#define DMAC_MMCRXINT _BIT(3) +#define DMAC_AACRX0INT _BIT(4) +#define DMAC_AACTX0INT _BIT(5) +#define DMAC_AACRX1INT _BIT(6) +#define DMAC_AACTX1INT _BIT(7) +#define DMAC_AACRX2INT _BIT(8) +#define DMAC_AACTX2INT _BIT(9) + +#define DMAC_INTMASK \ + ( \ + DMAC_USBTXINT | \ + DMAC_USBRXINT | \ + DMAC_MMCTXINT | \ + DMAC_MMCRXINT | \ + DMAC_AACRX0INT | \ + DMAC_AACTX0INT | \ + DMAC_AACRX1INT | \ + DMAC_AACTX1INT | \ + DMAC_AACRX2INT | \ + DMAC_AACTX2INT \ + ) + +#define n_LH7A400_DMA_CHANNELS (5 * 2) + +/* +* DMA context structures. +*/ + +typedef struct lh7a400_dma_channel_context_t lh7a400_dma_channel_context_t; +struct lh7a400_dma_channel_context_t { + const char *channel_name; /* Channel name */ + dma_channel_t channel_num; /* Channel number */ + dma_channel_regs_t *channel_regs;/* Adrress of actual DMA Registers */ + + dma_direction_t direction; /* DMA direction: 0=Out / 1=In */ + + dma_buf_list_t *head; /* where to insert buffers */ + dma_buf_list_t *tail; /* where to remove buffers */ + dma_buf_list_t *curr; /* buffer currently DMA'ed */ + + unsigned int in_use; /* Stream is allocated */ + int stopped; /* 1 if DMA is stalled */ + + dma_callback_t callback; /* What to call when buffers are done */ + + int spin_size; /* > 0 when DMA should spin when no more buffer */ + dma_addr_t spin_addr; /* DMA address to spin onto */ + int spin_ref; /* number of spinning references */ +}; + +typedef struct lh7a400_dma_context_t lh7a400_dma_context_t; + +struct lh7a400_dma_context_t { + int irq; /* All channels share a common IRQ */ + dma_regs_t *dma_regs; + lh7a400_dma_channel_context_t channel_context[n_LH7A400_DMA_CHANNELS]; +}; + +lh7a400_dma_context_t static_lh7a400_dma_context; + +/* +* Maximum physical DMA buffer size +*/ +#define MAX_DMA_SIZE 0xffff +#define MAX_DMA_ORDER 15 + +#endif /* _ARCH_ARM_MACH_LH7A400_DMA_H */ + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/eframe.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/eframe.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/eframe.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/eframe.c Wed Nov 19 22:04:09 2003 @@ -0,0 +1,138 @@ +/* + * linux/arch/arm/mach-lh7a400/eframe.c + * + * Machine (board) specific fixups. + * + * Copyright (C) 2003 Brad Parker + * + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern void genarch_init_irq( void); +extern void lh7a400_show_freq_and_stepping(void); + +#define USE_BLOB_PARAMS + +#define IO_RW DOMAIN_IO, 0, 1, 0, 0 + +static struct map_desc lh7a400_io_desc[] __initdata = { +/* virt phys size r w c b */ +{ FLASH_BASE, FLASH_START, FLASH_SIZE, IO_RW }, +{ INT_SRAM_BASE, INT_SRAM_START, INT_SRAM_SIZE, IO_RW }, +{ CPLD_BASE, CPLD_START, CPLD_SIZE, IO_RW }, +{ CS8900_BASE, CS8900_START, CS8900_SIZE, IO_RW }, +{ IDE_BASE, IDE_START, IDE_SIZE, IO_RW }, +{ IDE2_BASE, IDE2_START, IDE2_SIZE, IO_RW }, +{ EXPBRD_BASE, EXPBRD_START, EXPBRD_SIZE, IO_RW }, +{ APB_BASE, APB_START, APB_SIZE, IO_RW }, +{ AHB_BASE, AHB_START, AHB_SIZE, IO_RW }, +{ PCMCIA_IO_0_BASE, PCMCIA_IO_0_START, PCMCIA_IO_0_SIZE, IO_RW }, +{ PCMCIA_IO_1_BASE, PCMCIA_IO_1_START, PCMCIA_IO_1_SIZE, IO_RW }, +{ PCMCIA_STATUS_BASE, PCMCIA_STATUS_START, PCMCIA_STATUS_SIZE, IO_RW }, +LAST_DESC +}; + +void __init lh7a400_map_io(void) +{ + iotable_init(lh7a400_io_desc); +} + +static void __init +fixup_lh7a400(struct machine_desc *desc, struct param_struct *unused, + char **cmdline, struct meminfo *mi) +{ +#ifndef USE_BLOB_PARAMS + /* 16 banks: 64 MB SDRAM 8 nodes */ + mi->nr_banks = 16; + + for (i = 0; i < 16; i++) { + mi->bank[i].start = 0; + mi->bank[i].size = (4*1024*1024); + mi->bank[i].node = i/2; + } + + mi->bank[0].start = 0xc0000000; + mi->bank[1].start = 0xc1000000; + mi->bank[2].start = 0xc4000000; + mi->bank[3].start = 0xc5000000; + mi->bank[4].start = 0xc8000000; + mi->bank[5].start = 0xc9000000; + mi->bank[6].start = 0xcc000000; + mi->bank[7].start = 0xcd000000; + + mi->bank[8].start = 0xd0000000; + mi->bank[9].start = 0xd1000000; + mi->bank[10].start = 0xd4000000; + mi->bank[11].start = 0xd5000000; + mi->bank[12].start = 0xd8000000; + mi->bank[13].start = 0xd9000000; + mi->bank[14].start = 0xdc000000; + mi->bank[15].start = 0xdd000000; + +#if 0 /* use ramdisk root */ + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); + setup_initrd( __phys_to_virt(0xc4000000), 3 * 1024 * 1024); + + /* Serial Console on UART 1, root on ramdisk */ + strcpy( *cmdline, "console=ttyAM1,115200 root=/dev/ram0 ip=bootp"); +#else /* use nfs root */ + /* Serial Console on UART 1 root over NFS */ + strcpy( *cmdline, "console=ttyAM1,115200 noinitrd root=/dev/nfs ip=bootp"); +#endif /* ramdisk or nfs root */ + +#endif /* USE_BLOB_PARAMS */ + + lh7a400_show_freq_and_stepping(); +} + +void +lh7a400_apm_get_power_status(u_char *ac_line_status, + u_char *battery_status, + u_char *battery_flag, + u_char *battery_percentage, + u_short *battery_life) +{ + *ac_line_status = 0x01; + *battery_status = 0xFF; /* Unknown */ + *battery_flag = *battery_status; + *battery_percentage = 0xff; + *battery_life = 0xFFFF; +} + +MACHINE_START(LH7A400EVB, "Heeltoe eframe board") + MAINTAINER("brad@heeltoe.com") + BOOT_MEM(0xC0000000, 0x80000000, 0xF8000000) // pio, vio must be 8MB +#ifdef USE_BLOB_PARAMS + BOOT_PARAMS(0xC0000100) +#endif /* USE_BLOB_PARAMS */ + FIXUP(fixup_lh7a400) + MAPIO(lh7a400_map_io) + INITIRQ(genarch_init_irq) +MACHINE_END + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/fiqhandler.S linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/fiqhandler.S --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/fiqhandler.S Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/fiqhandler.S Thu Oct 16 14:12:30 2003 @@ -0,0 +1,39 @@ +/* + * linux/arch/arm/lib/lh7a400-fiqhandler.S + * Copyright (C) 2002, Lineo, Inc. + * based on linux/arch/arm/lib/floppydma.S, which is + * Copyright (C) 1995, 1996 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + */ +#include +#include + .text + + .global SYMBOL_NAME(fiqhandler_end) + + @ register usage: + @ r8 &interrupt controller registers + @ r9 &gpio registers + @ r11 work + @ r12 work + +ENTRY(fiqhandler) + + @ read the status register to find out which FIQ this is + + ldr r12, [r8] @ intc->status + and r12, r12, #0xf @ only interested in low-order 4 bits + + @ translate FIQ 0:3 to IRQ 23:26 + @ disable this FIQ and enable the corresponding IRQ + + str r12, [r8, #0xc] @ disable this FIQ + mov r12, r12, lsl #23 @ get the corresopnding IRQ bit + str r12, [r8, #0x8] @ enable that IRQ + + subs pc, lr, #4 +SYMBOL_NAME(fiqhandler_end): + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/generic.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/generic.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/generic.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/generic.c Fri Oct 17 11:24:28 2003 @@ -0,0 +1,339 @@ +/* + * linux/arch/arm/mach-lhlh7a400/generic.c + * + * Common code for all LH7A400 based machines. + * + * Copyright (C) 2001 Lineo, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include + +#ifdef CONFIG_MACH_KEV7A400 +u16 g_ioBrdCtl = 0; /* shadow copy of CPLD->ioBrdCtl */ +EXPORT_SYMBOL(g_ioBrdCtl); +#endif /* CONFIG_MACH_KEV7A400*/ + +void hclkfreq_notify(unsigned long event, unsigned int old_freq, + unsigned int new_freq); + +#define DEBUG 0 +#if DEBUG +# define DPRINTK( args...) printk( args) +#else +# define DPRINTK( args...) +#endif + +/* + * return FCLK in Hz. + */ +static inline unsigned int +fclkfreq_get(void) +{ + u32 mainDiv1, mainDiv2, preDiv, ps, clkset; + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + + clkset = clksc->clkset; + + mainDiv1 = (clkset >> 7) & 0x0f; + mainDiv2 = (clkset >> 11) & 0x1f; + preDiv = (clkset >> 2) & 0x1f; + ps = (clkset >> 18) & 0x03; + + return XTAL_IN / ((preDiv + 2) * (1 << ps)) * + (mainDiv1 +2) * (mainDiv2 + 2); +} + +#ifdef CONFIG_CPU_FREQ +unsigned int hclkfreq_get(void); + +/* Do: + * clksc->clkset = value; + * so that it fits in one cache line. + */ +static inline void +set_clkset(u32 value) +{ + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + + __asm__ __volatile__ (" + b 1f + .align 5 +1: str %1, [%0,#0] + nop + nop + nop + nop + nop + nop + nop" + : /* no outputs */ + : "r" (&clksc->clkset), "r" (value) ); + + mdelay(20); /* allow clocks to settle */ +} + + + +typedef struct { + u32 fclk_khz; /* FCLK (CPU) clock rate, in kHz. */ + u32 clkset; /* corresponding CLKSET register settings */ +} clksetParams_t; + +clksetParams_t clksetParams[] = { + { 199987, CLKSET_MAINDIV1(12) | CLKSET_MAINDIV2(29) | CLKSET_PREDIV(14) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 190464, CLKSET_MAINDIV1(13) | CLKSET_MAINDIV2(29) | CLKSET_PREDIV(16) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 184320, CLKSET_MAINDIV1(13) | CLKSET_MAINDIV2(28) | CLKSET_PREDIV(16) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 174618, CLKSET_MAINDIV1(13) | CLKSET_MAINDIV2(28) | CLKSET_PREDIV(17) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 165888, CLKSET_MAINDIV1(13) | CLKSET_MAINDIV2(28) | CLKSET_PREDIV(18) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 150088, CLKSET_MAINDIV1(13) | CLKSET_MAINDIV2(17) | CLKSET_PREDIV(12) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 133120, CLKSET_MAINDIV1(11) | CLKSET_MAINDIV2(23) | CLKSET_PREDIV(16) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 99993, CLKSET_MAINDIV1( 5) | CLKSET_MAINDIV2(29) | CLKSET_PREDIV(14) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 75010, CLKSET_MAINDIV1(11) | CLKSET_MAINDIV2(16) | CLKSET_PREDIV(21) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 65967, CLKSET_MAINDIV1(15) | CLKSET_MAINDIV2( 8) | CLKSET_PREDIV(17) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 50006, CLKSET_MAINDIV1(11) | CLKSET_MAINDIV2(10) | CLKSET_PREDIV(21) | CLKSET_PS1 | CLKSET_PCLKDIV2}, + { 32983, CLKSET_MAINDIV1(15) | CLKSET_MAINDIV2( 8) | CLKSET_PREDIV(17) | CLKSET_PS2 | CLKSET_PCLKDIV2}, + { 0, 0 } /* mark the end */ +}; + + +/* + * validate the desired CPU speed. + * return the CPU speed that is closest to the desired + * speed, without going over. + */ +static unsigned int +lh7a400_validateCPUspeed(unsigned int want_khz) +{ + clksetParams_t *cp = clksetParams; + + /* find the closest available CPU speed */ + while (cp->fclk_khz) { + if (cp->fclk_khz <= want_khz) + break; + cp++; + } + + if (cp->fclk_khz == 0) /* fell off the end */ + cp--; /* set to slowest speed */ + + DPRINTK(__FUNCTION__ ": want_khz=%d got %d\n", + want_khz, cp->fclk_khz); + + return cp->fclk_khz; +} + + + +static void +lh7a400_setCPUspeed(unsigned int new_khz) +{ + u32 curr_khz = fclkfreq_get() / 1000; + clksetParams_t *cp = clksetParams; + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + u32 hclkDiv; + u32 new_hclk_khz = 0; + u32 curr_hclk_khz; + + /* find clkset parameters for the new speed */ + while (cp->fclk_khz) { + if (cp->fclk_khz <= new_khz) + break; + cp++; + } + + /* + * find a new HCLK divisor such that the new HCLK + * is as close as possible to the current HCLK without + * going over. + */ + hclkDiv = (clksc->clkset & 0x3) + 1; + + curr_hclk_khz = curr_khz / hclkDiv; + + for (hclkDiv = 1; hclkDiv < 5; hclkDiv++) { + if ((new_hclk_khz = new_khz / hclkDiv) <= curr_hclk_khz) + break; + } + + if (hclkDiv > 4) + hclkDiv = 4; + + DPRINTK(__FUNCTION__ ": curr_hclk_khz=%d new_hclk_khz=%d new hclkDiv=%d\n", + curr_hclk_khz, new_hclk_khz, hclkDiv); + + /* + * if the new HCLK is different from the current HCLK, + * notify the drivers interested in HCLK changes before + * HCLK changes. + */ + if (new_hclk_khz != curr_hclk_khz) { + hclkfreq_notify(HCLKFREQ_PRECHANGE, curr_hclk_khz, + new_hclk_khz); + } + + /* set HCLK */ + set_clkset(cp->clkset | (hclkDiv - 1)); + + DPRINTK(__FUNCTION__ ": clkset = 0x%x\n", clksc->clkset); + + /* + * if the new HCLK is different from the current HCLK, + * notify the drivers interested in HCLK changes after + * HCLK has changed. + * + */ + if (new_hclk_khz != curr_hclk_khz) { + hclkfreq_notify(HCLKFREQ_POSTCHANGE, curr_hclk_khz, + new_hclk_khz); + } + + /* + * recompute minimum and maxmum HCLK values for + * this CPU clock speed. + */ + hclkfreq_set_minmax(cp->fclk_khz, new_hclk_khz); +} + + +/* + * validate the desired HCLK speed. + * return the HCLK speed that is closest to the desired + * speed, without going over. + */ +static unsigned int +lh7a400_validateHCLKspeed(unsigned int want_khz) +{ + int div; + u32 new_khz=0; + u32 fclk_khz = fclkfreq_get() / 1000; + + /* + * find the closest bus speed without going over. + */ + for (div = 1; div < 5; div++) { + if ((new_khz = fclk_khz / div) <= want_khz) + break; + } + + DPRINTK(__FUNCTION__ ": wanted %d got %d fclk=%d\n", + want_khz, new_khz, fclk_khz); + + return new_khz; +} + + +static void +lh7a400_setHCLKspeed(unsigned int want_khz) +{ + u32 fclk_khz = fclkfreq_get() / 1000; + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + u32 hclkDiv; + + DPRINTK(__FUNCTION__ ": want %d khz\n", want_khz); + + /* + * find the closest bus speed without going over. + */ + for (hclkDiv = 1; hclkDiv < 5; hclkDiv++) { + if ((fclk_khz / hclkDiv) <= want_khz) + break; + } + + /* set new HCLK */ + set_clkset((clksc->clkset & ~0x03) | (hclkDiv - 1)); + + DPRINTK(__FUNCTION__ ": clkset = 0x%x\n", clksc->clkset); +} + + +static int __init lh7a400_init_cpufreq(void) +{ + cpufreq_init(fclkfreq_get() / 1000 ); + cpufreq_setfunctions(lh7a400_validateCPUspeed, lh7a400_setCPUspeed); + + hclkfreq_init(hclkfreq_get()); + hclkfreq_setfunctions(lh7a400_validateHCLKspeed, lh7a400_setHCLKspeed); + + return 0; +} + +__initcall(lh7a400_init_cpufreq); + +#else +/* + * return the CPU clock frequency (FCLK) in kHz. + */ +unsigned int +cpufreq_get(int cpu) +{ + return fclkfreq_get() / 1000; +} + +EXPORT_SYMBOL(cpufreq_get); +#endif + + +/* + * return the AHB bus clock frequency (HCLK) in kHz. + */ +unsigned int +hclkfreq_get(void) +{ + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + u32 hclkDiv; + + hclkDiv = (clksc->clkset & 0x3) + 1; + DPRINTK("fclk=%d hclkDiv = %d\n", fclkfreq_get() / 1000, hclkDiv); + + return fclkfreq_get() / 1000 / hclkDiv; +} + +EXPORT_SYMBOL(hclkfreq_get); + + +/* + * return the APB bus clock frequency (PCLK) in kHz. + */ +unsigned int +pclkfreq_get(void) +{ + clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + u32 pclkDiv; + + pclkDiv = 2 ^ ((clksc->clkset >> 16) & 0x3); + DPRINTK("pclkDiv = %d\n", pclkDiv); + + return hclkfreq_get() / pclkDiv; +} + +EXPORT_SYMBOL(pclkfreq_get); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/hclkfreq.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/hclkfreq.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/hclkfreq.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/hclkfreq.c Thu Oct 16 16:33:58 2003 @@ -0,0 +1,431 @@ +/* + * arch/arm/mach-lh7a400/hclkfreq.c + * Copyright (C) 2002 Embedix, Inc. + * + * Based on + * linux/kernel/cpufreq.c + * which is + * Copyright (C) 2001 Russell King + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * HCLK bus speed changing core functionality. We provide the following + * services to the system: + * - notifier lists to inform other code of the freq change both + * before and after the freq change. + * - the ability to change the freq speed + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include /* requires system.h */ + +#define DEBUG 0 +#if DEBUG +# define DPRINTK( args...) printk( args) +#else +# define DPRINTK( args...) +#endif + +/* + * This list is for kernel code that needs to handle + * changes to devices when the HCLK bus clock speed changes. + */ +static struct notifier_block *hclkfreq_notifier_list; +static DECLARE_MUTEX_LOCKED(hclkfreq_sem); +static int hclkfreq_initialised; +static unsigned int (*hclkfreq_validatespeed)(unsigned int); +static void (*hclkfreq_setspeed)(unsigned int); + +#ifndef CONFIG_SMP +static unsigned int __hclkfreq_max; +static unsigned int __hclkfreq_min; +static unsigned int __hclkfreq_cur; +#endif + +extern unsigned int hclkfreq_get( void); + + + +/** + * hclkfreq_register_notifier - register a driver with hclkfreq + * @nb: notifier function to register + * + * Add a driver to the list of drivers that which to be notified about + * HCLK clock rate changes. The driver will be called three times on + * clock change. + * + * This function may sleep, and has the same return conditions as + * notifier_chain_register. + */ +int hclkfreq_register_notifier(struct notifier_block *nb) +{ + int ret; + + down(&hclkfreq_sem); + ret = notifier_chain_register(&hclkfreq_notifier_list, nb); + up(&hclkfreq_sem); + + return ret; +} + +EXPORT_SYMBOL(hclkfreq_register_notifier); + +/** + * hclkfreq_unregister_notifier - unregister a driver with hclkfreq + * @nb: notifier block to be unregistered + * + * Remove a driver from the HCLK frequency notifier lists. + * + * This function may sleep, and has the same return conditions as + * notifier_chain_unregister. + */ +int hclkfreq_unregister_notifier(struct notifier_block *nb) +{ + int ret; + + down(&hclkfreq_sem); + ret = notifier_chain_unregister(&hclkfreq_notifier_list, nb); + up(&hclkfreq_sem); + + return ret; +} + +EXPORT_SYMBOL(hclkfreq_unregister_notifier); + + + +void +hclkfreq_notify( unsigned long event, unsigned int old_freq, unsigned int new_freq) +{ + struct hclkfreq_info clkinfo; + + clkinfo.old_freq = old_freq; + clkinfo.new_freq = new_freq; + + notifier_call_chain( &hclkfreq_notifier_list, event, &clkinfo); +} + + +/** + * hclk_setfreq - change the HCLK clock frequency. + * @freq: frequency (in kHz) at which we should run. + * + * Set the HCLK clock frequency, informing all registered users of + * the change. We bound the frequency according to the hclkfreq_max + * command line parameter, and the parameters the registered users + * will allow. + * + * This function must be called from process context, and on the + * cpu that we wish to change the frequency of. + * + * We return 0 if successful. (we are currently always successful). + */ +int hclkfreq_set(unsigned int freq) +{ + unsigned long old_cpus; + // DDD struct hclkfreq_info clkinfo; + struct hclkfreq_minmax minmax; + int cpu = smp_processor_id(); + int ret; + unsigned int old_freq; + + if (!hclkfreq_initialised) + panic("hclkfreq_set() called before initialisation!"); + if (in_interrupt()) + panic("hclkfreq_set() called from interrupt context!"); + + /* + * Bind to the current CPU. + */ + old_cpus = current->cpus_allowed; + current->cpus_allowed = 1UL << cpu_logical_map(cpu); + + down(&hclkfreq_sem); + ret = -ENXIO; + if (!hclkfreq_setspeed || !hclkfreq_validatespeed) + goto out; + + /* + * Don't allow the CPU to be clocked over the limit. + */ + minmax.min_freq = hclkfreq_min(cpu); + minmax.max_freq = hclkfreq_max(cpu); + minmax.cur_freq = hclkfreq_current(cpu); + minmax.new_freq = freq; + + /* + * Find out what the registered devices will currently tolerate, + * and limit the requested clock rate to these values. Drivers + * must not rely on the 'new_freq' value - it is only a guide. + */ + notifier_call_chain(&hclkfreq_notifier_list, HCLKFREQ_MINMAX, &minmax); + if (freq < minmax.min_freq) + freq = minmax.min_freq; + if (freq > minmax.max_freq) + freq = minmax.max_freq; + + /* + * Ask the CPU specific code to validate the speed. If the speed + * is not acceptable, make it acceptable. Current policy is to + * round the frequency down to the value the processor actually + * supports. + */ + freq = hclkfreq_validatespeed(freq); + + if (hclkfreq_current(cpu) != freq) { + old_freq = hclkfreq_current(cpu); + hclkfreq_notify( HCLKFREQ_PRECHANGE, old_freq, freq); + + /* + * Actually set the HCLK frequency. + */ + hclkfreq_setspeed(freq); + hclkfreq_current(cpu) = freq; + + hclkfreq_notify( HCLKFREQ_POSTCHANGE, old_freq, freq); + } + + ret = 0; + + out: + up(&hclkfreq_sem); + + current->cpus_allowed = old_cpus; + + return ret; +} + +EXPORT_SYMBOL(hclkfreq_set); + + + +#ifdef CONFIG_SYSCTL + +static int +hclkfreq_procctl(ctl_table *ctl, int write, struct file *filp, + void *buffer, size_t *lenp) +{ + char buf[16], *p; + int len, left = *lenp; + + if (!left || (filp->f_pos && !write)) { + *lenp = 0; + return 0; + } + + if (write) { + unsigned int freq; + + len = left; + if (left > sizeof(buf)) + left = sizeof(buf); + if (copy_from_user(buf, buffer, left)) + return -EFAULT; + buf[sizeof(buf) - 1] = '\0'; + + freq = simple_strtoul(buf, &p, 0); + hclkfreq_set(freq); + } else { + len = sprintf(buf, "%d\n", hclkfreq_get()); + if (len > left) + len = left; + if (copy_to_user(buffer, buf, len)) + return -EFAULT; + } + + *lenp = len; + filp->f_pos += len; + return 0; +} + +static int +hclkfreq_sysctl(ctl_table *table, int *name, int nlen, + void *oldval, size_t *oldlenp, + void *newval, size_t newlen, void **context) +{ + if (oldval && oldlenp) { + size_t oldlen; + + if (get_user(oldlen, oldlenp)) + return -EFAULT; + + if (oldlen != sizeof(unsigned int)) + return -EINVAL; + + if (put_user(hclkfreq_get(), (unsigned int *)oldval) || + put_user(sizeof(unsigned int), oldlenp)) + return -EFAULT; + } + if (newval && newlen) { + unsigned int freq; + + if (newlen != sizeof(unsigned int)) + return -EINVAL; + + if (get_user(freq, (unsigned int *)newval)) + return -EFAULT; + + hclkfreq_set(freq); + } + return 1; +} + +enum { + HCLK_FREQ_MAX = 1, + HCLK_FREQ_MIN = 2, + HCLK_FREQ = 3 +}; + +static ctl_table ctl_hclk_vars[4] = { + { + ctl_name: HCLK_FREQ_MAX, + procname: "hclk-max", + data: &hclkfreq_max(0), + maxlen: sizeof(hclkfreq_max(0)), + mode: 0444, + proc_handler: proc_dointvec, + }, + { + ctl_name: HCLK_FREQ_MIN, + procname: "hclk-min", + data: &hclkfreq_min(0), + maxlen: sizeof(hclkfreq_min(0)), + mode: 0444, + proc_handler: proc_dointvec, + }, + { + ctl_name: HCLK_FREQ, + procname: "hclk", + mode: 0644, + proc_handler: hclkfreq_procctl, + strategy: hclkfreq_sysctl, + }, + { + ctl_name: 0, + } +}; + +enum { + CPU_NR = 1, +}; + +static ctl_table ctl_cpu_nr[2] = { + { + ctl_name: CPU_NR, + procname: "0", + mode: 0555, + child: ctl_hclk_vars, + }, + { + ctl_name: 0, + } +}; + +static ctl_table ctl_cpu[2] = { + { + ctl_name: CTL_CPU, + procname: "cpu", + mode: 0555, + child: ctl_cpu_nr, + }, + { + ctl_name: 0, + } +}; + +static inline void hclkfreq_sysctl_init(void) +{ + register_sysctl_table(ctl_cpu, 0); +} + +#else +#define hclkfreq_sysctl_init() +#endif + +/** + * hclkfreq_setfunctions - Set HCLK clock functions + * @validate: pointer to validation function + * @setspeed: pointer to setspeed function + */ +void __init +hclkfreq_setfunctions(unsigned int (*validate)(unsigned int), + void (*setspeed)(unsigned int)) +{ + down(&hclkfreq_sem); + hclkfreq_validatespeed = validate; + hclkfreq_setspeed = setspeed; + up(&hclkfreq_sem); +} + +EXPORT_SYMBOL(hclkfreq_setfunctions); + +/** + * hclkfreq_set_minmax - Compute min and max HCLK values + * based on the current FCLK. + * + * @freq: current HCLK clock speed in kHz. + */ +void hclkfreq_set_minmax( unsigned int fclk_khz, unsigned int hclk_khz) +{ + /* + * Compute min and max HCLK values based on current + * CPU clock. + * + * Limit the max HCLK speed to ~ 100 MHZ. + * The min speed is FCLK/4 (the largest hclk divisor) + */ + hclkfreq_max(0) = fclk_khz; + + if(hclkfreq_max(0) > MAX_HCLK_KHZ) + hclkfreq_max(0) = fclk_khz / 2; + + hclkfreq_min(0) = fclk_khz / 4; + + hclkfreq_current(smp_processor_id()) = hclk_khz; + + DPRINTK( __FUNCTION__ ": hclk_khz=%d fclk_khz=%d current=%d min=%d max=%d\n", + hclk_khz, fclk_khz, hclkfreq_current(smp_processor_id()), + hclkfreq_min(0), hclkfreq_max(0)); +} + + +EXPORT_SYMBOL(hclkfreq_set_minmax); + +/** + * hclkfreq_init - Initialise the hclkfreq core + * @freq: current HCLK clock speed in kHz. + * + * Initialise the hclkfreq core. + */ +void hclkfreq_init(unsigned int freq) +{ + hclkfreq_set_minmax( cpufreq_get(0), freq); + + printk(KERN_INFO "HCLK bus clock: %d.%03d MHz (%d.%03d-%d.%03d MHz)\n", + freq / 1000, freq % 1000, + hclkfreq_min(0) / 1000, hclkfreq_min(0) % 1000, + hclkfreq_max(0) / 1000, hclkfreq_max(0) % 1000); + + hclkfreq_initialised = 1; + up(&hclkfreq_sem); + + hclkfreq_sysctl_init(); +} + +EXPORT_SYMBOL(hclkfreq_init); diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/irq_eframe.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/irq_eframe.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/irq_eframe.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/irq_eframe.c Fri Feb 6 15:58:04 2004 @@ -0,0 +1,234 @@ +/* + * arch/arm/mach-lh7a400/irq_eframe.c + * + * interrupts through the eframe cpld + * + * Copyright (C) 2003 Brad Parker + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +extern unsigned int do_IRQ(int irq, struct pt_regs *regs); +extern void genarch_init_irq(void); + +inline void cpld_enable_irq(unsigned int irq_nr) +{ + volatile u32 *cpld = (volatile u32 *)CPLD_BASE; + + /* map the intr # to a cpld enable bit */ + irq_nr -= FIRST_EFRAME_IRQ; + cpld[CPLD_INT_SET] = 1 << irq_nr; +} + + +inline void cpld_disable_irq(unsigned int irq_nr) +{ + volatile u32 *cpld = (volatile u32 *)CPLD_BASE; + + /* map the intr # to a cpld enable bit */ + irq_nr -= FIRST_EFRAME_IRQ; + cpld[CPLD_INT_RESET] &= ~(1 << irq_nr); +} + +inline void cpld_ack_irq(unsigned int irq_nr) +{ + volatile u32 *cpld = (volatile u32 *)CPLD_BASE; + + /* map the intr # to a cpld enable bit */ + irq_nr -= FIRST_EFRAME_IRQ; + cpld[CPLD_ACK_RESET] = 1 << irq_nr; +} + +static inline void mask_and_ack_irq(unsigned int irq_nr) +{ + cpld_disable_irq(irq_nr); + cpld_ack_irq(irq_nr); +} + +static inline void mask_irq(unsigned int irq_nr) +{ + cpld_disable_irq(irq_nr); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + cpld_enable_irq(irq_nr); +} + +/* actual cpld interrupt */ +static void +cpld_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + volatile u32 *cpld = (volatile u32 *)CPLD_BASE; + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + unsigned int latched, i; + + gpio->eoi = GPIOF_INT(1); /* clear interrupt in GPIO */ + + latched = cpld[CPLD_ACK_READ] & 0x00ff; + if (0) printk("cpld_intr() latched %x\n", latched); + + /* map cpld interrupts into our the high range */ + for (i = 0; i < 7; i++) { + if (latched & (1 << i)) { + do_IRQ(FIRST_EFRAME_IRQ + i, regs); + } + } +} + +/* wire in the psuedo interrupts we generate from the cpld interrupt */ +void __init +eframe_cpld_irq_init(void) +{ + int irq; + volatile u32 *cpld = (volatile u32 *)CPLD_BASE; + + /* initialize the functions */ + for (irq = FIRST_EFRAME_IRQ; irq <= LAST_EFRAME_IRQ; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 0; + irq_desc[irq].mask_ack = mask_and_ack_irq; + irq_desc[irq].mask = mask_irq; + irq_desc[irq].unmask = unmask_irq; + } + + /* clear int enables */ + cpld[CPLD_INT_RESET] = 0xff; + + /* clear pending ints */ + cpld[CPLD_ACK_RESET] = 0xff; +} + +void +eframe_cpld_irq_install(void) +{ + /* install the GPIO interrupt to call us */ + if (request_irq(IRQ_CPLD, cpld_intr, 0, "CPLD intr", NULL)) { + panic("eframe: can't get CPLD interrupt\n"); + } +} + +module_init(eframe_cpld_irq_install) + +static void mask_ack_pcmcia_slot1(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + intc->clear = (1 << irq); + gpio->eoi = GPIOF_INT_PC_SLOT1; /* ACK IRQ */ +} + + +static void mask_ack_pcmcia_cd1(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + intc->clear = (1 << irq); + gpio->eoi = GPIOF_INT_PC_CD1; /* ACK IRQ */ +} + + +static void lh7a400_mask_irq(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + + intc->clear = (1 << irq); +} + +static void lh7a400_unmask_irq(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + + intc->enable = (1 << irq); +} + + +void __init eframe_init_irq(void) +{ + int irq; + int rc; + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + /* clear all interrupt enables */ + intc->clear = 0xffffffff; + + for (irq = 0; irq < LH7A400_MAX_INTR; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = lh7a400_mask_irq; + irq_desc[irq].mask = lh7a400_mask_irq; + irq_desc[irq].unmask = lh7a400_unmask_irq; + } + + /* pcmcia interrupts */ + irq_desc[IRQ_EFRAME_PCMCIA_CD1].mask_ack = mask_ack_pcmcia_cd1; + irq_desc[IRQ_EFRAME_PCMCIA1].mask_ack = mask_ack_pcmcia_slot1; + + /* + * deal with GPIO interrupts + */ + + /* disallow all interrupts thru GPIO */ + gpio->intEnable = 0; + barrier(); + + /* specify which Port F ints are edge triggered */ + gpio->intType1 = GPIOF_EDGE_TRIGGER; + + /* specify which Port F ints are active high */ + gpio->intType2 = GPIOF_ACTIVE_HIGH; + + /* clear all interrupts in GPIO */ + gpio->eoi = GPIOF_ALL_INT; + + /* enable GPIO Port F interrupts */ + gpio->intEnable = GPIOF_ALL_INT; + + /* add cpld interrupts */ + eframe_cpld_irq_init(); +} + +void +eframe_remove_irq(void) +{ + free_irq(IRQ_EFRAME_CPLD, NULL); +} + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/irq_kev7a400.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/irq_kev7a400.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/irq_kev7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/irq_kev7a400.c Sat Feb 7 16:38:25 2004 @@ -0,0 +1,314 @@ +/* + * arch/arm/mach-lh7a400/cpld_irq_kev7a400.c + * + * interrupts through the kev7a400 cpld + * + * Copyright (C) 2003 Brad Parker + * Copyright (C) 2001 Lineo, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + + +extern unsigned int do_IRQ(int irq, struct pt_regs *regs); +extern void genarch_init_irq(void); + +inline void cpld_enable_irq(unsigned int irq_nr) +{ + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + + /* map the intr # to a cpld enable bit */ + irq_nr -= FIRST_KEV7A400_IRQ; + cpld->u3.latchedIntMask |= 1 << irq_nr; +} + + +inline void cpld_disable_irq(unsigned int irq_nr) +{ + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + + /* map the intr # to a cpld enable bit */ + irq_nr -= FIRST_KEV7A400_IRQ; + cpld->u3.latchedIntMask &= ~(1 << irq_nr); +} + +inline void cpld_ack_irq(unsigned int irq_nr) +{ + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + + /* map the intr # to a cpld enable bit */ + irq_nr -= FIRST_KEV7A400_IRQ; + cpld->latchedInts = 1 << irq_nr; +} + +static inline void mask_and_ack_irq(unsigned int irq_nr) +{ +// cpld_disable_irq(irq_nr); + cpld_ack_irq(irq_nr); +} + +static inline void mask_irq(unsigned int irq_nr) +{ + cpld_disable_irq(irq_nr); +} + +static inline void unmask_irq(unsigned int irq_nr) +{ + cpld_enable_irq(irq_nr); +} + +void +cpld_check(void) +{ + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + printk("cpld_check() latchedInts %08x, lastIntMask %08x\n", + cpld->latchedInts, + cpld->u3.latchedIntMask); + printk(" intEnable %08x, intStatus %08x, rawIntStatus %08x\n", + gpio->intEnable, gpio->intStatus, gpio->rawIntStatus); +} + +/* actual cpld interrupt */ +static void +cpld_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + unsigned int latched, i; + + latched = cpld->latchedInts & CPLD_INT_MASK; + if (0) printk("cpld_intr() latched %x\n", latched); + + /* map cpld interrupts into our the high range */ + for (i = 0; i < 5; i++) { + if (latched & (1 << i)) { + do_IRQ(FIRST_KEV7A400_IRQ + i, regs); + } + } +} + +/* wire in the psuedo interrupts we generate from the cpld interrupt */ +void __init kev7a400_cpld_irq_init(void) +{ + int irq; + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + + /* initialize cpld */ + + /* initialize the functions */ + for (irq = FIRST_KEV7A400_IRQ; irq <= LAST_KEV7A400_IRQ; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 0; + irq_desc[irq].mask_ack = mask_and_ack_irq; + irq_desc[irq].mask = mask_irq; + irq_desc[irq].unmask = unmask_irq; + } + + /* allow Ethernet and MMC detect external interrupts */ + cpld->u3.latchedIntMask = CPLD_INT_ENET | CPLD_INT_MMC; +} + +void __init +kev7a400_cpld_irq_install(void) +{ + /* install the GPIO interrupt to call us */ + if (request_irq(IRQ_KEV7A400_CPLD, cpld_intr, + SA_INTERRUPT/*0*/, "CPLD intr", NULL)) { + panic("kev7a400: can't get CPLD interrupt\n"); + } +} + +static void mask_ack_pcmcia_slot1(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + intc->clear = (1 << irq); + gpio->eoi = GPIOF_INT_PC_SLOT1; /* ACK IRQ */ +} + + +static void mask_ack_pcmcia_slot2(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + intc->clear = (1 << irq); + gpio->eoi = GPIOF_INT_PC_SLOT2; /* ACK IRQ */ +} + + +static void mask_ack_pcmcia_cd1(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + intc->clear = (1 << irq); + gpio->eoi = GPIOF_INT_PC_CD1; /* ACK IRQ */ +} + + +static void mask_ack_pcmcia_cd2(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + intc->clear = (1 << irq); + gpio->eoi = GPIOF_INT_PC_CD2; /* ACK IRQ */ +} + +/* + * Called by do_IRQ with an FIQ number. Mask the corresponding IRQ, + * and ACK the corresponding IRQ. + */ +static void mask_ack_fiq( u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + intc->clear = (1 << (irq + IRQ_GPIO_F4)); /* mask IRQ */ + gpio->eoi = (GPIOF_INT_F4 << irq); /* ACK IRQ */ +} + + +static struct fiq_handler fh = { + name: "tsfiq" +}; + +extern unsigned char fiqhandler, fiqhandler_end; + + +static void __init kev7a400_init_fiq(void) +{ + struct pt_regs regs; + int rc; + + init_FIQ(); + + /* + * set up our FIQ handler + */ + regs.ARM_r8 = IO_ADDRESS(INTC_PHYS); + regs.ARM_r9 = IO_ADDRESS(GPIO_PHYS); + + if( (rc = claim_fiq(&fh)) != 0) { + printk("%s couldn't get ts fiq. rc=%d\n", __FUNCTION__, rc); + return; + } + + set_fiq_handler(&fiqhandler, &fiqhandler_end - &fiqhandler); + set_fiq_regs(®s); + + irq_desc[IRQ_KEV7A400_TS].mask_ack = mask_ack_fiq; +} + +static void lh7a400_mask_irq(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + + intc->clear = (1 << irq); +} + +static void lh7a400_unmask_irq(u32 irq) +{ + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + + intc->enable = (1 << irq); +} + + +void __init kev7a400_init_irq(void) +{ + int irq; + intcRegs_t *intc = (intcRegs_t *)IO_ADDRESS(INTC_PHYS); + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + /* clear all interrupt enables */ + intc->clear = 0xffffffff; + + for (irq = 0; irq < LH7A400_MAX_INTR; irq++) { + irq_desc[irq].valid = 1; + irq_desc[irq].probe_ok = 1; + irq_desc[irq].mask_ack = lh7a400_mask_irq; + irq_desc[irq].mask = lh7a400_mask_irq; + irq_desc[irq].unmask = lh7a400_unmask_irq; + } + + /* pcmcia interrupts */ + irq_desc[IRQ_KEV7A400_PCMCIA_CD1].mask_ack = mask_ack_pcmcia_cd1; + irq_desc[IRQ_KEV7A400_PCMCIA_CD2].mask_ack = mask_ack_pcmcia_cd2; + irq_desc[IRQ_KEV7A400_PCMCIA1].mask_ack = mask_ack_pcmcia_slot1; + irq_desc[IRQ_KEV7A400_PCMCIA2].mask_ack = mask_ack_pcmcia_slot2; + + /* + * deal with GPIO interrupts + */ + + /* disallow all interrupts thru GPIO */ + gpio->intEnable = 0; + barrier(); + + /* add cpld interrupts */ + kev7a400_cpld_irq_init(); + + /* specify which Port F ints are edge triggered */ + gpio->intType1 = GPIOF_EDGE_TRIGGER; + + /* specify which Port F ints are active high */ + gpio->intType2 = GPIOF_ACTIVE_HIGH; + + /* clear all interrupts in GPIO */ + gpio->eoi = GPIOF_ALL_INT; + + /* enable GPIO Port F interrupts */ + gpio->intEnable = GPIOF_ALL_INT; + + /* add fiq interrupts */ + kev7a400_init_fiq(); +} + +void +kev7a400_remove_irq(void) +{ + free_irq(IRQ_KEV7A400_CPLD, NULL); +} + + +module_init(kev7a400_cpld_irq_install); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/kev7a400.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/kev7a400.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/kev7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/kev7a400.c Fri Feb 6 15:19:10 2004 @@ -0,0 +1,173 @@ +/* + * linux/arch/arm/mach-lh7a400/kev7a400.c + * + * Machine (board) specific fixups. + * + * Copyright (C) 2001 Lineo, Inc + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +extern void genarch_init_irq( void); +extern void lh7a400_show_freq_and_stepping(void); +extern void kev7a400_init_irq(void); + +extern int lh7a400_stepping; + +//#define USE_BLOB_PARAMS +//#define SDRAM_64MB /* 16 banks: 64 MB SDRAM 8 nodes */ +#define SDRAM_32MB /* 8 banks: 32 MB SDRAM 4 nodes */ +//#define USE_RAMDISK_ROOT +#define USE_NFS_ROOT + + +#include + +#define IO_RW DOMAIN_IO, 0, 1, 0, 0 + +static struct map_desc lh7a400_io_desc[] __initdata = { +/* virt phys size r w c b */ +{ FLASH_BASE, FLASH_START, FLASH_SIZE, IO_RW }, +{ INT_SRAM_BASE, INT_SRAM_START, INT_SRAM_SIZE, IO_RW }, +{ EXT_SRAM_BASE, EXT_SRAM_START, EXT_SRAM_SIZE, IO_RW }, +{ CPLD_BASE, CPLD_START, CPLD_SIZE, IO_RW }, +{ CS8900_BASE, CS8900_START, CS8900_SIZE, IO_RW }, +{ IDE_BASE, IDE_START, IDE_SIZE, IO_RW }, +{ IDE2_BASE, IDE2_START, IDE2_SIZE, IO_RW }, +{ APB_BASE, APB_START, APB_SIZE, IO_RW }, +{ AHB_BASE, AHB_START, AHB_SIZE, IO_RW }, +#ifdef CONFIG_MTD_LH7A400_SYNCFLASH +{ SYNCFLASH_B0_BASE, SYNCFLASH_B0_START, SYNCFLASH_BANK_SIZE, IO_RW }, +{ SYNCFLASH_B1_BASE, SYNCFLASH_B1_START, SYNCFLASH_BANK_SIZE, IO_RW }, +{ SYNCFLASH_B2_BASE, SYNCFLASH_B2_START, SYNCFLASH_BANK_SIZE, IO_RW }, +{ SYNCFLASH_B3_BASE, SYNCFLASH_B3_START, SYNCFLASH_BANK_SIZE, IO_RW }, +#endif +#if defined(CONFIG_PCMCIA_LH7A400) || defined(CONFIG_PCMCIA_LH7A400_MODULE) +{ PCMCIA_IO_0_BASE, PCMCIA_IO_0_START, PCMCIA_IO_0_SIZE, IO_RW }, +{ PCMCIA_IO_1_BASE, PCMCIA_IO_1_START, PCMCIA_IO_1_SIZE, IO_RW }, +{ PCMCIA_STATUS_BASE, PCMCIA_STATUS_START, PCMCIA_STATUS_SIZE, IO_RW }, +#endif +LAST_DESC +}; + +void __init lh7a400_map_io(void) +{ + iotable_init( lh7a400_io_desc); +} + +static void __init +fixup_lh7a400(struct machine_desc *desc, struct param_struct *unused, + char **cmdline, struct meminfo *mi) +{ +#ifndef USE_BLOB_PARAMS +#ifdef SDRAM_64MB + int i; + + mi->nr_banks = 16; + + for (i = 0; i < 16; i++) { + mi->bank[i].start = 0; + mi->bank[i].size = (4*1024*1024); + mi->bank[i].node = i/2; + } + + mi->bank[0].start = 0xc0000000; + mi->bank[1].start = 0xc1000000; + mi->bank[2].start = 0xc4000000; + mi->bank[3].start = 0xc5000000; + mi->bank[4].start = 0xc8000000; + mi->bank[5].start = 0xc9000000; + mi->bank[6].start = 0xcc000000; + mi->bank[7].start = 0xcd000000; + + mi->bank[8].start = 0xd0000000; + mi->bank[9].start = 0xd1000000; + mi->bank[10].start = 0xd4000000; + mi->bank[11].start = 0xd5000000; + mi->bank[12].start = 0xd8000000; + mi->bank[13].start = 0xd9000000; + mi->bank[14].start = 0xdc000000; + mi->bank[15].start = 0xdd000000; + +#elif defined(SDRAM_32MB) + int i; + + mi->nr_banks = 8; + + for (i = 0; i < 8; i++) { + mi->bank[i].start = 0; + mi->bank[i].size = (4*1024*1024); + mi->bank[i].node = i/2; + } + + mi->bank[0].start = 0xc0000000; + mi->bank[1].start = 0xc1000000; + mi->bank[2].start = 0xc4000000; + mi->bank[3].start = 0xc5000000; + mi->bank[4].start = 0xc8000000; + mi->bank[5].start = 0xc9000000; + mi->bank[6].start = 0xcc000000; + mi->bank[7].start = 0xcd000000; + +#endif /* 32 or 64 Mb testing */ + + +#ifdef USE_RAMDISK_ROOT + /* use ramdisk root */ + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk(1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); + setup_initrd(__phys_to_virt(0xc4000000), 3 * 1024 * 1024); + + /* Serial Console on UART 1, root on ramdisk */ + strcpy(*cmdline, + "console=ttyAM1,115200 root=/dev/ram0 ip=bootp"); +#elif defined(USE_NFS_ROOT) + /* use nfs root */ + /* Serial Console on UART 1 root over NFS */ + strcpy(*cmdline, + "console=ttyAM1,115200 noinitrd root=/dev/nfs ip=bootp"); +#endif + +#endif /* USE_BLOB_PARAMS */ + + lh7a400_show_freq_and_stepping(); + +} + +MACHINE_START(KEV7A400, "Sharp LH7A400 Evaluation Board") + MAINTAINER("brad@heeltoe.com") + /* pio, vio must be 8MB */ + BOOT_MEM(0xC0000000, 0x80000000, 0xF8000000) +#ifdef USE_BLOB_PARAMS + BOOT_PARAMS(0xC0000100) +#endif + FIXUP(fixup_lh7a400) + MAPIO(lh7a400_map_io) + INITIRQ(kev7a400_init_irq) +MACHINE_END + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/lcd_eframe.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/lcd_eframe.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/lcd_eframe.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/lcd_eframe.c Wed Nov 19 22:03:43 2003 @@ -0,0 +1,64 @@ +/* + * arch/arm/mach-lh7a400/lcd-eframe.c + * + * lcd hardware "helper" routines + * + * Copyright (C) 2003 Brad Parker + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include + +#include +#include + +#include + +void +lh7a400_backlight_power(int on) +{ + volatile u32 *cpld = (volatile u32 *)CPLD_BASE; + + if (on) { + /* backlight on */ + cpld[CPLD_CTRL_SET] = CPLD_CTRL_BACKLIGHT; + } else { + /* backlight off */ + cpld[CPLD_CTRL_RESET] = CPLD_CTRL_BACKLIGHT; + } +} + +void +lh7a400_lcd_power(int on) +{ + if (on) { + /* power up lcd */ + cpld[CPLD_CTRL_SET] = CPLD_CTRL_LCDPWR; + } else { + /* power down lcd */ + cpld[CPLD_CTRL_RESET] = CPLD_CTRL_LCDPWR; + } +} + +void +eframe_lcd_enable(int on) +{ + if (on) { + /* enable lcd drive */ + cpld[CPLD_CTRL_SET] = CPLD_CTRL_LCDOE; + } else { + /* disable lcd drive */ + cpld[CPLD_CTRL_RESET] = CPLD_CTRL_LCDOE; + } +} + +int +eframe_get_bpp(void) +{ + return 16; +} diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/lcd_kev7a400.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/lcd_kev7a400.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/lcd_kev7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/lcd_kev7a400.c Sat Oct 18 16:10:47 2003 @@ -0,0 +1,142 @@ +/* + * arch/arm/mach-lh7a400/lcd-kev7a400.c + * + * lcd hardware "helper" routines + * + * Copyright (C) 2002 Lineo, Inc. + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include + +#include +#include + +#ifdef CONFIG_ARCH_LH79520 +#include +#include +#include +#endif + +#ifdef CONFIG_ARCH_LH7A400 +#include +#include +#endif + +void +lh7a400_backlight_power(int on) +{ + if (on) { + /* backlight on */ +#ifdef CONFIG_ARCH_LH79520 + if( machine_is_lh79520evb()) { + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + cpld->lcd_pwr_cntl |= CPLD_BACKLIGHT_ON; + } +#endif +#ifdef CONFIG_ARCH_LH7A400 + if( machine_is_kev7a400()) { + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + cpld->lcd_pwr_cntl |= CPLD_BACKLIGHT_ON; + } +#endif + } else { + /* backlight off */ +#ifdef CONFIG_ARCH_LH79520 + if( machine_is_kev79520()) { + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + cpld->lcd_pwr_cntl &= ~CPLD_BACKLIGHT_ON; + } +#endif +#ifdef CONFIG_ARCH_LH7A400 + if( machine_is_kev7a400()) { + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + cpld->lcd_pwr_cntl &= ~CPLD_BACKLIGHT_ON; + } +#endif + } +} + +void +lh7a400_lcd_power(int on) +{ + if (on) { + /* power up lcd */ +#ifdef CONFIG_ARCH_LH79520 + if( machine_is_kev79520()) { + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + cpld->lcd_pwr_cntl |= CPLD_LCDP_EN; + } +#endif +#ifdef CONFIG_ARCH_LH7A400 + if( machine_is_kev7a400()) { + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + cpld->lcd_pwr_cntl |= (CPLD_LCDP_EN | CPLD_DISP_EN); + if( b0_stepping) + cpld->lcd_pwr_cntl |= CPLD_LCD_LOWVOLT_EN; + } +#endif + } else { + /* power down lcd */ +#ifdef CONFIG_ARCH_LH79520 + if( machine_is_kev79520()) { + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + cpld->lcd_pwr_cntl &= ~CPLD_LCDP_EN; + if( b0_stepping) + cpld->lcd_pwr_cntl &|= ~CPLD_LCD_LOWVOLT_EN; + } +#endif +#ifdef CONFIG_ARCH_LH7A400 + if( machine_is_kev7a400()) { + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + cpld->lcd_pwr_cntl &= ~(CPLD_LCDP_EN | CPLD_DISP_EN); + } +#endif + } + +} + +void +lh7a400_lcd_enable(int on) +{ +#if defined(CONFIG_MACH_KEV7A400) + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + + if (on) { + /* enable lcd drive */ + cpld->lcd_pwr_cntl |= CPLD_LCD_OE; + } else { + /* disable lcd drive */ + cpld->lcd_pwr_cntl &= ~CPLD_LCD_OE; + } +#endif +} + +int +lh7a400_get_bpp(void) +{ +#if defined(CONFIG_ARCH_KEV79520) + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + u8 dipSw = (u8)~(cpld->display_dip_sw & 0xff); + + if( machine_is_kev79520()) { + /* set bpp based on LCD board dip switch 0 */ + return (dipSw & 1 ? 8 : 16); + } +#endif +#if defined(CONFIG_MACH_KEV7A400) + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + u8 dipSw = (u8)~(cpld->u3.dispDipSw & 0xff); + + if( machine_is_kev7a400()) { + /* set bpp based on LCD board dip switch 0 */ + return (dipSw & 1 ? 8 : 16); + } +#endif + return 8; +} diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/mmc.c linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/mmc.c --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/mmc.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/mmc.c Sun Oct 19 07:39:02 2003 @@ -0,0 +1,1020 @@ +/* + * Low-level MMC functions for the Sharp LH7A400 EVB. + * + * Portions Copyright (C) 2002 Embedix, Inc + * Strongly based on code for the iPAQ H3800, see below. + * + * 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 + */ + +/* + * Low-level MMC functions for the iPAQ H3800 + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Author: Andrew Christian + * 6 May 2002 + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include /* LH7A400 specific interrupts */ +#include + +#include +#include + +#ifdef CONFIG_MACH_KEV7A400 +#include +#endif + +#ifdef CONFIG_CPU_FREQ +#include +#endif + +#include + +#include "mmc.h" + +/* gives 312500 Hz (divisor 6) to 20 MHz (d=0) at 100MHz HCLK */ +#define HCLK_DIVISOR 5 + +#undef LH7A400_EVB_01 /* define for older (-01) EVBs */ + +#ifdef LH7A400_EVB_01 +#define ROTATE_RESP_FIFO 1 +#else +#define ROTATE_RESP_FIFO 0 +#endif + +struct response_info { + int length; + u16 cdc_flags; +}; + +static struct response_info rinfo[] = { +{ 0, MMC_CMD_DATA_CONT_FORMAT_NO_RESPONSE }, /* R0 */ +{ 6, MMC_CMD_DATA_CONT_FORMAT_R1 }, /* R1 */ +{ 6, MMC_CMD_DATA_CONT_FORMAT_R1 | MMC_CMD_DATA_CONT_BUSY_BIT }, /* R1b */ +{ 17, MMC_CMD_DATA_CONT_FORMAT_R2 }, /* R2 CID */ +{ 17, MMC_CMD_DATA_CONT_FORMAT_R2 }, /* R2 CSD */ +{ 6, MMC_CMD_DATA_CONT_FORMAT_R3 }, /* R3 */ +{ 6, 0 }, /* R4 */ +{ 6, 0 }, /* R5 */ +}; + +enum lh7a400_request_type { + RT_NO_RESPONSE, + RT_RESPONSE_ONLY, + RT_READ, + RT_WRITE +}; + +struct lh7a400_mmc_data { + struct timer_list sd_detect_timer; + struct timer_list reset_timer; + struct timer_list irq_timer; /* Panic timer */ + u32 rate; /* Desired clock frequency */ + u32 clock; /* Current clock frequency */ + struct mmc_request *request; + enum lh7a400_request_type type; +}; + +static struct lh7a400_mmc_data g_lh7a400_data = {{{0}}}; +struct mmc_statistics g_lh7a400_mmc_statistics; + +#define MMC_IRQ_TIMEOUT (3 * HZ) + + +static __inline__ void mmc_delay( void ) { udelay(1); } +static int lh7a400_slot_is_empty( int slot ); + +extern unsigned int hclkfreq_get( void); + +/************************************************************************** + * Utility routines for debuging + **************************************************************************/ + +struct cmd_to_name { + int id; + char *name; +}; + +static struct cmd_to_name cmd_names[] = { + { MMC_CIM_RESET, "CIM_RESET" }, + { MMC_GO_IDLE_STATE, "GO_IDLE_STATE" }, + { MMC_SEND_OP_COND, "SEND_OP_COND" }, + { MMC_ALL_SEND_CID, "ALL_SEND_CID" }, + { MMC_SET_RELATIVE_ADDR, "SET_RELATIVE_ADDR" }, + { MMC_SET_DSR, "SET_DSR" }, + { MMC_SELECT_CARD, "SELECT_CARD" }, + { MMC_SEND_CSD, "SEND_CSD" }, + { MMC_SEND_CID, "SEND_CID" }, + { MMC_READ_DAT_UNTIL_STOP, "READ_DAT_UNTIL_STOP" }, + { MMC_STOP_TRANSMISSION, "STOP_TRANSMISSION" }, + { MMC_SEND_STATUS , "SEND_STATUS " }, + { MMC_GO_INACTIVE_STATE, "GO_INACTIVE_STATE" }, + { MMC_SET_BLOCKLEN, "SET_BLOCKLEN" }, + { MMC_READ_SINGLE_BLOCK, "READ_SINGLE_BLOCK" }, + { MMC_READ_MULTIPLE_BLOCK, "READ_MULTIPLE_BLOCK" }, + { MMC_WRITE_DAT_UNTIL_STOP, "WRITE_DAT_UNTIL_STOP" }, + { MMC_SET_BLOCK_COUNT, "SET_BLOCK_COUNT" }, + { MMC_WRITE_BLOCK, "WRITE_BLOCK" }, + { MMC_WRITE_MULTIPLE_BLOCK, "WRITE_MULTIPLE_BLOCK" }, + { MMC_PROGRAM_CID, "PROGRAM_CID" }, + { MMC_PROGRAM_CSD, "PROGRAM_CSD" }, + { MMC_SET_WRITE_PROT, "SET_WRITE_PROT" }, + { MMC_CLR_WRITE_PROT, "CLR_WRITE_PROT" }, + { MMC_SEND_WRITE_PROT, "SEND_WRITE_PROT" }, + { MMC_ERASE_GROUP_START, "ERASE_GROUP_START" }, + { MMC_ERASE_GROUP_END, "ERASE_GROUP_END" }, + { MMC_ERASE, "ERASE" }, + { MMC_FAST_IO, "FAST_IO" }, + { MMC_GO_IRQ_STATE, "GO_IRQ_STATE" }, + { MMC_LOCK_UNLOCK, "LOCK_UNLOCK" }, + { MMC_APP_CMD, "APP_CMD" }, + { MMC_GEN_CMD, "GEN_CMD" }, +}; + +static char * get_cmd_name( int cmd ) +{ + int i; + int len = sizeof(cmd_names) / sizeof(struct cmd_to_name); + for ( i = 0 ; i < len ; i++ ) + if ( cmd == cmd_names[i].id ) + return cmd_names[i].name; + + return "UNKNOWN"; +} + +struct status_bit_to_name { + u16 mask; + int shift; + char *name; +}; + +struct status_bit_to_name status_bit_names[] = { + { MMC_STATUS_READ_TIMEOUT, -1, "READ_TIMEOUT" }, + { MMC_STATUS_RESPONSE_TIMEOUT, -1, "RESPONSE_TIMEOUT" }, + { MMC_STATUS_CRC_WRITE_ERROR, -1, "CRC_WRITE_ERROR" }, + { MMC_STATUS_CRC_READ_ERROR, -1, "CRC_READ_ERROR" }, + { MMC_STATUS_SPI_READ_ERROR, -1, "SPI_READ_ERROR" }, + { MMC_STATUS_CRC_RESPONSE_ERROR, -1, "CRC_RESPONSE_ERROR" }, + { MMC_STATUS_FIFO_EMPTY, -1, "FIFO_EMPTY" }, + { MMC_STATUS_FIFO_FULL, -1, "FIFO_FULL" }, + { MMC_STATUS_CLOCK_STOPPED, -1, "CLOCK_STOPPED" }, +#ifndef CONFIG_ARCH_LH7A400 + { MMC_STATUS_WR_CRC_ERROR_CODE, 9, "WR_CRC_ERROR_CODE" }, +#endif + { MMC_STATUS_DATA_TRANSFER_DONE, -1, "DATA_TRANSFER_DONE" }, + { MMC_STATUS_END_PROGRAM, -1, "END_PROGRAM" }, + { MMC_STATUS_END_COMMAND_RESPONSE, -1, "END_COMMAND_RESPONSE" } +}; + +static void decode_status( u16 status ) +{ + int i; + int len = sizeof(status_bit_names)/sizeof(struct status_bit_to_name); + struct status_bit_to_name *b = status_bit_names; + for ( i = 0 ; i < len ; i++, b++ ) { + if ( status & b->mask ) { + if ( b->shift >= 0 ) + printk("%s[%d] ", b->name, ((status & b->mask) >> b->shift)); + else + printk("%s ", b->name); + } + } +} + +static void printk_request( struct mmc_request *request, char *header ) +{ + printk("%sindex %d\n", header, request->index ); + printk("%scmd %d\n", header, request->cmd ); + printk("%sarg 0x%08x\n", header, request->arg ); + printk("%srtype %d\n", header, request->rtype ); + printk("%snob %d\n", header, request->nob ); + printk("%sbl_len %d\n", header, request->block_len ); + printk("%sbuffer %p\n", header, request->buffer ); + printk("%sresult %d\n", header, request->result); +} + + +static void printk_mmc_state( char *header ) +{ + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + u16 status = mmc->Status; + + printk("%sStatus 0x%04x ", header, status ); + decode_status(status); + printk("\n%sClockRate 0x%02x\n", header, mmc->ClockRate ); + printk("%sPrediv 0x%02x\n", header, mmc->PreDivider ); + printk("%sCmdDataCont 0x%02x\n", header, mmc->CmdDataControl ); + printk("%sResponseTimeout 0x%02x\n", header, mmc->ResponseTimeout ); + printk("%sReadTimeout 0x%04x\n", header, mmc->ReadTimeout ); + printk("%sBlock Length 0x%04x\n", header, mmc->BlockLength ); + printk("%sNum of Blocks 0x%04x\n", header, mmc->NumOfBLocks ); + printk("%sInterruptMask 0x%02x\n", header, mmc->InterruptMask ); + printk("%sInterruptStatus 0x%02x\n", header, mmc->InterruptStatus ); + printk("%sCommandNumber 0x%02x %s\n", header, mmc->CommandNumber, get_cmd_name(mmc->CommandNumber) ); + printk("%sArgument 0x%04x\n", header, mmc->CommandArg ); + printk("%sBufferPartFull 0x%02x\n", header, mmc->BufferPartFull ); +} + +/************************************************************************** + * Clock routines + * + * We have to poll the status register until we're sure that the clock has stopped. + * This may be called in interrupt context, so we can't go to sleep! + **************************************************************************/ + +static int lh7a400_stop_clock( void ) +{ + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + DEBUG( 1, "\n"); + + mmc->ClockControl = MMC_STOP_CLOCK; + mmc_delay(); + + while( !(mmc->Status & MMC_STATUS_CLOCK_STOPPED) ) /* wait for clock to stop */ + ; + + return 0; +} + +static void lh7a400_start_clock( void ) +{ + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + DEBUG( 1,"\n"); + + mmc->ClockControl = MMC_START_CLOCK; /* Start the clock */ + mmc_delay(); + + /* Wait for MMC clock to start */ + while( mmc->Status & MMC_STATUS_CLOCK_STOPPED) + ; +} + +static int lh7a400_set_clock( u32 rate ) +{ + int retval; + + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + u32 master = hclkfreq_get() * 1000 / HCLK_DIVISOR; + u8 divisor = 1; /* No divisor */ + + DEBUG( 1, ": rate = %d master=%d\n", rate, master); + + while ( master > rate ) { + divisor++; + master /= 2; + } + if ( divisor > 8 ) divisor = 8; + + DEBUG(1,": setting divisor to %d (request=%d result=%d)\n", + divisor, rate, master ); + + retval = lh7a400_stop_clock(); + if ( retval ) + return retval; + + mmc->ClockRate = divisor; + mmc_delay(); + + mmc->ResponseTimeout = 0x0040; + mmc_delay(); + + mmc->ReadTimeout = 0xffff; + mmc_delay(); + + lh7a400_start_clock(); + g_lh7a400_data.clock = master; + g_lh7a400_data.rate = rate; + + return MMC_NO_ERROR; +} + +static int reset_mmc_controller( u32 clock_rate ) +{ + int retval; + DEBUG( 1, ": clock_rate=%d\n", clock_rate); + + retval = lh7a400_set_clock( clock_rate ); + lh7a400_start_clock(); + return retval; +} + +/* + The reset function clears _everything_ in the ASIC, + so it needs be completely reset +*/ + +static void lh7a400_reset_timeout( unsigned long nr ) +{ +// struct lh7a400_mmc_data *sd = (struct lh7a400_mmc_data *) nr; + + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + DEBUG( 1, ": nr=%ul\n", (unsigned int)nr); + + /* Send 80 clocks to get things started */ + mmc->CmdDataControl = MMC_CMD_DATA_CONT_INITIALIZE; + mmc_delay(); + + mmc->InterruptMask = MMC_INT_MASK_END_COMMAND_RESPONSE; + mmc_delay(); + + START_DEBUG(2) { + u16 status = mmc->Status; + printk("%s: enabling irq mask=%04x status=0x%04x (", + __FUNCTION__, mmc->InterruptMask, status); + decode_status(status); + printk(")\n"); + } END_DEBUG; + + mod_timer( &g_lh7a400_data.irq_timer, jiffies + MMC_IRQ_TIMEOUT); + enable_irq( IRQ_MMC ); +} + +static int lh7a400_reset( struct lh7a400_mmc_data *sd ) +{ + int retval = reset_mmc_controller( MMC_CLOCK_SLOW ); + g_lh7a400_data.type = RT_NO_RESPONSE; + mod_timer( &sd->reset_timer, jiffies + (100 * HZ) / 1000 ); + g_lh7a400_mmc_statistics.mmc_reset++; + + return retval; +} + + +static void lh7a400_set_command( u16 cmd, u32 arg ) +{ + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + DEBUG(2,": cmd=%d arg=0x%08x\n", cmd, arg); + + mmc->CommandArg = arg; + mmc_delay(); + + mmc->CommandNumber = cmd; + mmc_delay(); +} + +static void lh7a400_set_transfer( u16 block_len, u16 nob ) +{ + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + DEBUG(2,": block_len=%d nob=%d\n", block_len, nob); + + mmc->BlockLength = block_len; + mmc_delay(); + + mmc->NumOfBLocks = nob; + mmc_delay(); +} + +static void lh7a400_transmit_data( struct mmc_request *request ) +{ + u8 *buf = request->buffer; + u16 data; + int i; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + DEBUG(2,": nob=%d block_len=%d\n", request->nob, request->block_len); + + if ( request->nob <= 0 ) { + DEBUG(1,": *** nob already at 0 ***\n"); + return; + } + + for ( i = 0 ; i < request->block_len ; i+=2, buf+=2 ) { + data = *(buf+1) | (((u16) *buf) << 8); + mmc->DataFifo = data; + mmc_delay(); + } + + START_DEBUG(2) { + u16 status = mmc->Status; + printk("%s: irq_mask=%04x status=0x%04x (", + __FUNCTION__, mmc->InterruptMask, status); + decode_status(status); + printk(")\n"); + } END_DEBUG; + + START_DEBUG(3) { + u8 *b = request->buffer; + for ( i = 0 ; i < request->block_len ; i++ ) { + printk(" %02x", *b++); + if ( ((i + 1) % 16) == 0 ) + printk("\n"); + } + } END_DEBUG; + + /* Updated the request buffer to reflect the current state */ + request->buffer = (u8 *) buf; + request->nob--; + g_lh7a400_mmc_statistics.mmc_written++; +} + +static void lh7a400_receive_data( struct mmc_request *request ) +{ + u8 *buf = request->buffer; + u16 data; + int i; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + DEBUG(2,": nob=%d block_len=%d buf=%p\n", + request->nob, request->block_len, buf); + + if ( request->nob <= 0 ) { + DEBUG(1,": *** nob already at 0 ***\n"); + return; + } + + for ( i = 0 ; i < request->block_len ; i+=2 ) { + data = mmc->DataFifo; + mmc_delay(); + *buf++ = data >> 8; + *buf++ = data & 0xff; + } + + START_DEBUG(3) { + u8 *b = request->buffer; + for ( i = 0 ; i < request->block_len ; i++ ) { + printk(" %02x", *b++); + if ( ((i + 1) % 16) == 0 ) + printk("\n"); + } + } END_DEBUG; + + /* Updated the request buffer to reflect the current state */ + request->buffer = (u8 *) buf; + request->nob--; + g_lh7a400_mmc_statistics.mmc_read++; +} + +#ifdef CONFIG_MMC_DEBUG +#define STATBUG(_x) \ + { u16 status = mmc->Status; \ + if ( status & ~(MMC_STATUS_FIFO_EMPTY | MMC_STATUS_CLOCK_STOPPED)) { \ + printk("..." _x " status=0x%04x ( ", status); \ + decode_status(status); \ + printk(")\n"); \ + printk_mmc_state( "... "); \ + } \ + } +#else +#define STATBUG(_x) +#endif + +static int lh7a400_exec_command( struct mmc_request *request ) +{ + int retval; + int cdc = 0; + int irq = 0; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + DEBUG(2,": request=%p status=%04x\n", request, mmc->Status ); + + /* Start the actual transfer */ + retval = lh7a400_stop_clock(); + if ( retval ) + return retval; + + STATBUG("stop_clock"); + + lh7a400_set_command( request->cmd, request->arg ); + + STATBUG("set_command"); + + switch (request->cmd) { + case MMC_READ_SINGLE_BLOCK: + case MMC_READ_MULTIPLE_BLOCK: + lh7a400_set_transfer( request->block_len, request->nob ); + cdc = MMC_CMD_DATA_CONT_READ | MMC_CMD_DATA_CONT_DATA_ENABLE; + irq = MMC_INT_MASK_BUFFER_READY | MMC_INT_MASK_DATA_TRANSFER_DONE; + g_lh7a400_data.type = RT_READ; + break; + case MMC_WRITE_BLOCK: + case MMC_WRITE_MULTIPLE_BLOCK: + lh7a400_set_transfer( request->block_len, request->nob ); + cdc = MMC_CMD_DATA_CONT_WRITE | MMC_CMD_DATA_CONT_DATA_ENABLE; + irq = MMC_INT_MASK_BUFFER_READY | MMC_INT_MASK_PROGRAM_DONE; + g_lh7a400_data.type = RT_WRITE; + break; + default: + irq = MMC_INT_MASK_END_COMMAND_RESPONSE; + g_lh7a400_data.type = RT_RESPONSE_ONLY; + break; + } + + cdc |= rinfo[request->rtype].cdc_flags; + + mmc->CmdDataControl = cdc; + DEBUG( 1, ": set CmdDataCont=0x%x\n", cdc); + mmc_delay(); + + STATBUG("cmd_data_cont"); + + /* these are the interrupts we *want* */ + mmc->InterruptMask = irq; + mmc_delay(); + + STATBUG("irq_mask"); + + lh7a400_start_clock(); + + START_DEBUG(2) { + u16 status = mmc->Status; + printk("%s: enabling irq mask=%04x status=0x%04x (", + __FUNCTION__, mmc->InterruptMask, status); + decode_status(status); + printk(")\n"); + } END_DEBUG; + + mod_timer( &g_lh7a400_data.irq_timer, jiffies + MMC_IRQ_TIMEOUT); + enable_irq( IRQ_MMC ); + g_lh7a400_mmc_statistics.mmc_command++; + return MMC_NO_ERROR; +} + +static void lh7a400_send_command( struct mmc_request *request ) +{ + int retval; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + START_DEBUG(1) { + printk("\n\n"); + } END_DEBUG; + DEBUG(1,": request=%p cmd=%d (%s) arg=%08x status=%04x\n", request, + request->cmd, get_cmd_name(request->cmd), request->arg, mmc->Status); + + /* TODO: Grab a lock???? */ + g_lh7a400_data.request = request; + request->result = MMC_NO_RESPONSE; /* Flag to indicate don't have a result yet */ + + if ( request->cmd == MMC_CIM_RESET ) { + retval = lh7a400_reset( &g_lh7a400_data ); + } + else { + retval = lh7a400_exec_command( request ); + if ( retval ) { + g_lh7a400_mmc_statistics.mmc_error++; + DEBUG(0,": ASIC not responding! Trying to reset\n"); + lh7a400_start_clock(); + + retval = reset_mmc_controller( g_lh7a400_data.clock ); + if ( retval ) { + DEBUG(0,": ASIC doesn't reset! Panic now!\n"); + } + else { + retval = lh7a400_exec_command( request ); + if ( retval ) { + DEBUG(0,": ASIC unable to exec!\n"); + } + } + } + } + + if ( retval ) { + request->result = retval; + mmc_cmd_complete( request ); + } +} + +/**************************************************************************/ +/* TODO: Need to mask interrupts?? */ + +static void lh7a400_get_response( struct mmc_request *request ) +{ + int i; + int len = rinfo[request->rtype].length; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + u8 *buf = request->response; + + /* Mark this as having a request result of some kind */ + request->result = MMC_NO_ERROR; + + if ( len <= 0 ) + return; + + for ( i = 0 ; i < len ; ) { + u16 data = mmc->ResultFifo; +#if ROTATE_RESP_FIFO /* only on older (-01) EVBs */ + buf[i++] = data >> 8; + buf[i++] = data & 0xff; +#else + buf[i++] = data & 0xff; + buf[i++] = data >> 8; +#endif + } + + START_DEBUG(2) { + printk("%s Raw byte stream: ", __FUNCTION__); + for ( i = 0 ; i < len; i++ ) + printk("%02x ", buf[i]); + printk("\n"); + } END_DEBUG; +} + +static void lh7a400_handle_int( struct lh7a400_mmc_data *sd, u16 status, int timeout ) +{ + int retval = MMC_NO_ERROR; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + START_DEBUG( 1) { + printk("%s: status=%04x intStatus=%04x type=", + __FUNCTION__, status, mmc->InterruptStatus); + switch (g_lh7a400_data.type) { + case RT_NO_RESPONSE: printk( "RT_NO_RESPONSE\n"); break; + case RT_RESPONSE_ONLY: printk( "RT_RESPONSE_ONLY\n"); break; + case RT_READ: printk( "RT_READ\n"); break; + case RT_WRITE: printk( "RT_WRITE\n"); break; + } + } END_DEBUG; + + disable_irq( IRQ_MMC ); + + if ( status & (MMC_STATUS_READ_TIMEOUT + | MMC_STATUS_RESPONSE_TIMEOUT )) { + retval = MMC_ERROR_TIMEOUT; + goto terminate_int; + } + + if ( status & ( MMC_STATUS_CRC_WRITE_ERROR + | MMC_STATUS_CRC_READ_ERROR + | MMC_STATUS_SPI_READ_ERROR + | MMC_STATUS_CRC_RESPONSE_ERROR)) { + + while( mmc->Status & MMC_STATUS_FIFO_FULL) { + u16 foo; + DEBUG(0,": CRC error: Flushing FIFO\n"); + foo = mmc->DataFifo; + } + + retval = MMC_ERROR_CRC; + goto terminate_int; + } + + if ( (status & MMC_STATUS_END_COMMAND_RESPONSE) && + sd->request->result == MMC_NO_RESPONSE ) + { + lh7a400_get_response( sd->request ); + } + + if (g_lh7a400_data.type == RT_READ && + (status & (MMC_STATUS_FIFO_FULL | + MMC_STATUS_DATA_TRANSFER_DONE)) != 0) + { + lh7a400_receive_data( sd->request ); + } + + if (g_lh7a400_data.type == RT_WRITE && + (status & MMC_STATUS_FIFO_EMPTY ) != 0 && sd->request->nob > 0 ) + { + lh7a400_transmit_data( sd->request ); + } + + switch (g_lh7a400_data.type) { + case RT_NO_RESPONSE: + break; + + case RT_RESPONSE_ONLY: + if ( sd->request->result < 0 ) { + printk(KERN_INFO + "%s: illegal interrupt - " + "command hasn't finished\n", + __FUNCTION__); + retval = MMC_ERROR_TIMEOUT; + } + break; + case RT_READ: + if ( sd->request->nob ) { + DEBUG(2,": read re-enabling IRQ status=0x%04x\n", + mmc->InterruptStatus); + mod_timer( &sd->irq_timer, jiffies + MMC_IRQ_TIMEOUT); + lh7a400_start_clock(); + enable_irq( IRQ_MMC ); + return; + } + break; + case RT_WRITE: + if ( sd->request->nob || !(status & MMC_STATUS_END_PROGRAM) ) { + DEBUG(2,": write re-enabling IRQ status=0x%04x\n", + mmc->InterruptStatus); + mod_timer( &sd->irq_timer, jiffies + MMC_IRQ_TIMEOUT); + lh7a400_start_clock(); + enable_irq( IRQ_MMC ); + return; + } + break; + } + + DEBUG(2,": terminating status=0x%04x\n", mmc->Status ); + +terminate_int: + mmc->InterruptMask = MMC_INT_MASK_END_COMMAND_RESPONSE; + mmc->EOI = 0x1f; + + del_timer_sync( &sd->irq_timer ); + sd->request->result = retval; + mmc_cmd_complete( sd->request ); +} + +static void mmc_lh7a400_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct lh7a400_mmc_data *sd = (struct lh7a400_mmc_data *) dev_id; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + u16 status = mmc->Status; + START_DEBUG(2) { + printk_mmc_state( "IRQ "); + } END_DEBUG; + + START_DEBUG(2) { + printk("%s sd=%p status=0x%04x (", + __FUNCTION__, sd, status); + decode_status(status); + printk(")\n"); + } END_DEBUG; + + lh7a400_handle_int( sd, status, 0 ); +} + +static void lh7a400_irq_timeout( unsigned long nr ) +{ + struct lh7a400_mmc_data *sd = (struct lh7a400_mmc_data *) nr; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + u16 status = mmc->Status; + + START_DEBUG(1) { + printk("%s: irq_status=0x%x irq_mask=%04x status=0x%04x (", + __FUNCTION__, + mmc->InterruptStatus, mmc->InterruptMask, status); + decode_status(status); + printk(")\nRequest info:\n"); + printk_request( sd->request, " " ); + + printk_mmc_state( "IRQ timeout: "); + } END_DEBUG; + + g_lh7a400_mmc_statistics.mmc_timeout++; + lh7a400_handle_int( sd, status, 1 ); +} + + +/**************************************************************************/ + +static void lh7a400_fix_sd_detect( unsigned long nr ) +{ + int insert = lh7a400_slot_is_empty(0) ? 0 : 1; + + DEBUG(2,": insert=%d\n", insert); + + if ( insert ) { + mmc_insert(0); + g_lh7a400_mmc_statistics.mmc_insert++; + } + else { + mmc_eject(0); + g_lh7a400_mmc_statistics.mmc_eject++; + } +} + +static void mmc_lh7a400_detect_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct lh7a400_mmc_data *sd = (struct lh7a400_mmc_data *) dev_id; + + DEBUG( 1, ": slot_is_empty=%d\n", lh7a400_slot_is_empty(0) ); + + mod_timer( &sd->sd_detect_timer, jiffies + (250 * HZ) / 1000 ); +} + +static int lh7a400_slot_is_empty( int slot ) +{ +#ifdef CONFIG_MACH_KEV7A400 + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + + DEBUG( 1, "\n"); + + return(cpld->bootMMCstatus & MMC_DETECT ? 0 : 1); +#else + return 1; +#endif +} + + +/**************************************************************************/ + + +static void mmc_lh7a400_slot_up( void ) +{ + DEBUG( 1, "\n"); +} + +static void mmc_lh7a400_slot_down( void ) +{ + DEBUG( 1, "\n"); + disable_irq( IRQ_MMC ); +} + + +static int lh7a400_slot_init( void ) +{ + int retval; + int i; + mmcRegs_t *mmc = (mmcRegs_t *)IO_ADDRESS(MMC_PHYS); + + DEBUG(1,"\n"); + +#ifdef CONFIG_MACH_KEV7A400 +#ifdef LH7A400_EVB_01 /* only on older (-01) EVBs */ + /* Enable power to the MMC slot */ + set_ioBrdCtl_bit( CPLD_IOB_MMC_POWER_ON); + DEBUG(1," MMC slot Power On, before loop.\n"); + for( i=0; i<2500000; i++) + ; + DEBUG(1," MMC slot Power On, loop done.\n"); +#endif +#endif + + /* + * flush the fifos + */ + for( i=0; i < 16; i++) { + u16 foo; + foo = mmc->DataFifo; + foo = mmc->ResultFifo; + } + + /* Set up timers */ + g_lh7a400_data.sd_detect_timer.function = lh7a400_fix_sd_detect; + g_lh7a400_data.sd_detect_timer.data = (unsigned long) &g_lh7a400_data; + init_timer(&g_lh7a400_data.sd_detect_timer); + + g_lh7a400_data.reset_timer.function = lh7a400_reset_timeout; + g_lh7a400_data.reset_timer.data = (unsigned long) &g_lh7a400_data; + init_timer(&g_lh7a400_data.reset_timer); + + g_lh7a400_data.irq_timer.function = lh7a400_irq_timeout; + g_lh7a400_data.irq_timer.data = (unsigned long) &g_lh7a400_data; + init_timer(&g_lh7a400_data.irq_timer); + + /* Basic service interrupt */ + mmc->InterruptMask = 0; + retval = request_irq( IRQ_MMC, mmc_lh7a400_int, + SA_INTERRUPT, "MMC", &g_lh7a400_data ); + + if( retval ) { + printk(KERN_CRIT "%s: unable to grab MMC IRQ, retval=0x%x\n", + __FUNCTION__, retval); + return retval; + } + disable_irq( IRQ_MMC ); + + /* + * Enable FIFO reads via APB, enable the MMC, and set the PreDivider. + */ + mmc->PreDivider = + (MMC_PREDIV_ENABLE | MMC_PREDIV_APB_ENABLE | HCLK_DIVISOR); + + DEBUG(1,": " + "status=0x%04x ClockControl=0x%x PreDivider=0x%x\n", + mmc->Status, mmc->ClockControl, mmc->PreDivider); + + /* Disable SPI mode control functions */ + mmc->SPIModeControl = 0; + + /* Fixes the sd_detect interrupt direction */ + mmc_lh7a400_slot_up(); + + retval = request_irq(IRQ_KEV7A400_MMC_DETECT, mmc_lh7a400_detect_int, + SA_INTERRUPT, "MMC Detect", &g_lh7a400_data ); + + if( retval ) { + printk(KERN_CRIT + "%s: unable to grab MMC DETECT IRQ, retval=0x%x\n", + __FUNCTION__, retval); + mmc_lh7a400_slot_down(); + free_irq( IRQ_MMC, &g_lh7a400_data); + } + return retval; +} + +static void lh7a400_slot_cleanup( void ) +{ + DEBUG(1,"\n"); + + del_timer_sync(&g_lh7a400_data.sd_detect_timer); + del_timer_sync(&g_lh7a400_data.reset_timer); + del_timer_sync(&g_lh7a400_data.irq_timer); + + mmc_lh7a400_slot_down(); + + free_irq(IRQ_KEV7A400_MMC_DETECT, &g_lh7a400_data); + free_irq(IRQ_MMC, &g_lh7a400_data); +} + + +/***********************************************************/ + +static struct mmc_slot_driver dops = { + owner: THIS_MODULE, + name: "LH7A400 MMC", + ocr: 0x00ffc000, + flags: MMC_SDFLAG_MMC_MODE, + + init: lh7a400_slot_init, + cleanup: lh7a400_slot_cleanup, + is_empty: lh7a400_slot_is_empty, + send_cmd: lh7a400_send_command, + set_clock: lh7a400_set_clock, +}; + +#ifdef CONFIG_CPU_FREQ +/* + * HCLK clock speed change handler. + */ +static int +mmc_clkchg_notifier(struct notifier_block *nb, unsigned long val, void *data) +{ + switch (val) { + case HCLKFREQ_PRECHANGE: + DEBUG( 2,": mmc PRE CHANGE\n"); + break; + + case HCLKFREQ_POSTCHANGE: + DEBUG( 2,": mmc POST CHANGE\n"); + if( g_lh7a400_data.rate != 0) + lh7a400_set_clock( g_lh7a400_data.rate); + break; + } + return 0; +} + +static struct notifier_block mmc_hclk_nb = { + notifier_call: mmc_clkchg_notifier, +}; + +#endif /* CONFIG_CPU_FREQ */ + + +static int +__init lh7a400_mmc_init(void) +{ + int retval; + + DEBUG(1,"\n"); + + retval = mmc_register_slot_driver(&dops, 1); + if ( retval < 0 ) { + printk(KERN_INFO "%s: unable to register slot\n",__FUNCTION__); + return retval; + } +#ifdef CONFIG_CPU_FREQ + hclkfreq_register_notifier( &mmc_hclk_nb); +#endif + return 0; +} + +void __exit lh7a400_mmc_cleanup(void) +{ + DEBUG(1,"\n"); +#ifdef CONFIG_CPU_FREQ + hclkfreq_unregister_notifier( &mmc_hclk_nb); +#endif + mmc_unregister_slot_driver(&dops); +} + +module_init(lh7a400_mmc_init); +module_exit(lh7a400_mmc_cleanup); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mach-lh7a400/mmc.h linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/mmc.h --- linux-2.4.21-rmk1/arch/arm/mach-lh7a400/mmc.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mach-lh7a400/mmc.h Thu Oct 16 15:20:44 2003 @@ -0,0 +1,154 @@ +/* + * Driver interface to the MMC controller on the Sharp LH7A400 SoC. + * + * Portions Copyright (C) 2002 Embedix, Inc + * Strongly based on code for the iPAQ H3800, see below. + * + * 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 + */ + +/* +* Driver interface to the ASIC Complasion chip on the iPAQ H3800 +* +* Copyright 2001 Compaq Computer Corporation. +* +* Use consistent with the GNU GPL is permitted, +* provided that this copyright notice is +* preserved in its entirety in all copies and derived works. +* +* COMPAQ COMPUTER CORPORATION MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, +* AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS +* FITNESS FOR ANY PARTICULAR PURPOSE. +* +* Author: Andrew Christian +* +* October 2001 +* +* Restrutured June 2002 +*/ + +#ifndef MMC_H +#define MMC_H + +int lh7a400_asic_mmc_init(void); +void lh7a400_asic_mmc_cleanup(void); +int lh7a400_asic_mmc_suspend(void); +void lh7a400_asic_mmc_resume(void); + +/* + * MMC register set structure + */ +typedef struct { + volatile u32 ClockControl; /* Clock control register */ + volatile u32 Status; /* Adapter status */ + volatile u32 ClockRate; /* Clock divider */ + volatile u32 PreDivider; /* Clock pre-divider */ + volatile u32 SPIModeControl; /* SPI mode control */ + volatile u32 CmdDataControl; /* Command control */ + volatile u32 ResponseTimeout; /* Response timeout */ + volatile u32 ReadTimeout; /* Read timeout */ + volatile u32 BlockLength; /* Block length */ + volatile u32 NumOfBLocks; /* Number of blocks */ + volatile u32 InterruptStatus; /* Interrupt status */ + volatile u32 EOI; /* Interrupt clear register */ + volatile u32 rsv1; + volatile u32 InterruptMask; /* Interrupt enables */ + volatile u32 CommandNumber; /* Command number */ + volatile u32 CommandArg; /* Command argument */ + volatile u32 ResultFifo; /* Result FIFO */ + volatile u32 rsv2; + volatile u32 DataFifo; /* Data FIFO */ + volatile u32 BufferPartFull; /* Partial buffer selection */ +} mmcRegs_t; + + + +/* ClockControl register bits */ +#define MMC_STOP_CLOCK _BIT(0) +#define MMC_START_CLOCK _BIT(1) + + +/* Status register bits */ +#define MMC_STATUS_READ_TIMEOUT _BIT(0) +#define MMC_STATUS_RESPONSE_TIMEOUT _BIT(1) +#define MMC_STATUS_CRC_WRITE_ERROR _BIT(2) +#define MMC_STATUS_CRC_READ_ERROR _BIT(3) +#define MMC_STATUS_SPI_READ_ERROR _BIT(4) /* SPI data token error received */ +#define MMC_STATUS_CRC_RESPONSE_ERROR _BIT(5) +#define MMC_STATUS_FIFO_EMPTY _BIT(6) +#define MMC_STATUS_FIFO_FULL _BIT(7) +#define MMC_STATUS_CLOCK_STOPPED _BIT(8) /* MultiMediaCard clock stopped */ +#define MMC_STATUS_DATA_TRANSFER_DONE _BIT(11) /* Write operation, indicates transfer finished */ +#define MMC_STATUS_END_PROGRAM _BIT(12) /* End write and read operations */ +#define MMC_STATUS_END_COMMAND_RESPONSE _BIT(13) /* End command response */ + + +/* ClockRate register bits */ +#define MMC_CLOCK_RATE_FULL 0 +#define MMC_CLOCK_RATE_DIV_2 1 +#define MMC_CLOCK_RATE_DIV_4 2 +#define MMC_CLOCK_RATE_DIV_8 3 +#define MMC_CLOCK_RATE_DIV_16 4 +#define MMC_CLOCK_RATE_DIV_32 5 +#define MMC_CLOCK_RATE_DIV_64 6 + + +/* PreDivider register bits */ +#define MMC_PREDIV_ENABLE _BIT(4) /* Enables PCLK to the MMC */ +#define MMC_PREDIV_APB_ENABLE _BIT(5) /* Enables reading the FIFO via APB, not DMA */ + + +/* SPIModeControl register bits */ +#define MMC_SPI_REG_SPI_ENABLE _BIT(0) /* Enables SPI mode */ +#define MMC_SPI_REG_CRC_ON _BIT(1) /* 1:turn on CRC */ +#define MMC_SPI_REG_SPI_CS_ENABLE _BIT(2) /* 1:turn on SPI CS */ +#define MMC_SPI_REG_CS_ADDRESS _BIT(3) /* specifies the relative address of the card + to activate the SPI CS as 0 or 1 */ + +/* CmdDataControl register bits */ +#define MMC_CMD_DATA_CONT_FORMAT_NO_RESPONSE _SBF(0,0) /* Response format */ +#define MMC_CMD_DATA_CONT_FORMAT_R1 _SBF(0,1) +#define MMC_CMD_DATA_CONT_FORMAT_R2 _SBF(0,2) +#define MMC_CMD_DATA_CONT_FORMAT_R3 _SBF(0,3) +#define MMC_CMD_DATA_CONT_DATA_ENABLE _BIT(2) /* This command contains a data transfer */ +#define MMC_CMD_DATA_CONT_READ _SBF(3,0) /* This data transfer is a read */ +#define MMC_CMD_DATA_CONT_WRITE _SBF(3,1) /* This data transfer is a write */ +#define MMC_CMD_DATA_CONT_STREAM_BLOCK _BIT(4) /* This data transfer is in stream mode */ +#define MMC_CMD_DATA_CONT_BUSY_BIT _BIT(5) +#define MMC_CMD_DATA_CONT_INITIALIZE _BIT(6) /* Enables the 80 bits for initializing card */ + + +/* Interrupt Status and InterruptMask register bits */ +#define MMC_INT_MASK_DATA_TRANSFER_DONE _BIT(0) +#define MMC_INT_MASK_PROGRAM_DONE _BIT(1) +#define MMC_INT_MASK_END_COMMAND_RESPONSE _BIT(2) +#define MMC_INT_MASK_BUFFER_READY _BIT(3) +#define MMC_INT_MASK_ALL (0xf) + + + +/* Statistics */ +struct mmc_statistics { + u32 mmc_insert; + u32 mmc_eject; + u32 mmc_reset; /* Reset commands issued */ + u32 mmc_command; /* General commands issued */ + u32 mmc_read; /* Blocks */ + u32 mmc_written; /* Blocks */ + u32 mmc_timeout; /* Timeout interrupts */ + u32 mmc_error; /* Response errors */ +}; + +#endif /* MMC_H */ diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mm/discontig.c linux-2.4.21-rmk1-lh7a400/arch/arm/mm/discontig.c --- linux-2.4.21-rmk1/arch/arm/mm/discontig.c Fri Jun 13 10:51:29 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mm/discontig.c Thu Oct 16 14:27:01 2003 @@ -16,8 +16,11 @@ #include #if NR_NODES != 4 +#ifdef CONFIG_ARCH_LH7A400 +#else #error Fix Me Please #endif +#endif /* * Our node_data structure for discontiguous memory. @@ -30,6 +33,21 @@ { bdata: &node_bootmem_data[1] }, { bdata: &node_bootmem_data[2] }, { bdata: &node_bootmem_data[3] } +#ifdef CONFIG_ARCH_LH7A400 + , + { bdata: &node_bootmem_data[4] }, + { bdata: &node_bootmem_data[5] }, + { bdata: &node_bootmem_data[6] }, + { bdata: &node_bootmem_data[7] }, + { bdata: &node_bootmem_data[8] }, + { bdata: &node_bootmem_data[9] }, + { bdata: &node_bootmem_data[10] }, + { bdata: &node_bootmem_data[11] }, + { bdata: &node_bootmem_data[12] }, + { bdata: &node_bootmem_data[13] }, + { bdata: &node_bootmem_data[14] }, + { bdata: &node_bootmem_data[15] } +#endif }; EXPORT_SYMBOL(discontig_node_data); diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mm/init.c linux-2.4.21-rmk1-lh7a400/arch/arm/mm/init.c --- linux-2.4.21-rmk1/arch/arm/mm/init.c Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mm/init.c Thu Oct 16 14:27:37 2003 @@ -35,7 +35,11 @@ #ifndef CONFIG_DISCONTIGMEM #define NR_NODES 1 #else -#define NR_NODES 4 + #ifdef CONFIG_ARCH_LH7A400 + #define NR_NODES 16 + #else + #define NR_NODES 4 + #endif #endif #ifdef CONFIG_CPU_32 diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/mm/proc-arm922.S linux-2.4.21-rmk1-lh7a400/arch/arm/mm/proc-arm922.S --- linux-2.4.21-rmk1/arch/arm/mm/proc-arm922.S Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/mm/proc-arm922.S Thu Oct 16 17:01:04 2003 @@ -647,7 +647,11 @@ __arm922_proc_info: .long 0x41009220 .long 0xff00fff0 +#if defined(CONFIG_CPU_ARM922_WRITETHROUGH) + .long 0x00000c1a @ mmuflags +#else .long 0x00000c1e @ mmuflags +#endif b __arm922_setup .long cpu_arch_name .long cpu_elf_name diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/arch/arm/tools/mach-types linux-2.4.21-rmk1-lh7a400/arch/arm/tools/mach-types --- linux-2.4.21-rmk1/arch/arm/tools/mach-types Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/arch/arm/tools/mach-types Sat Oct 18 07:53:13 2003 @@ -363,3 +363,5 @@ ixrd425 ARCH_IXRD425 IXRD425 352 iq80315 ARCH_IQ80315 IQ80315 353 nmp7312 ARCH_NMP7312 NMP7312 354 +kev7a400 MACH_KEV7A400 KEV7A400 388 +eframe MACH_EFRAME EFRAME 398 diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/build linux-2.4.21-rmk1-lh7a400/build --- linux-2.4.21-rmk1/build Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/build Fri Feb 6 15:17:25 2004 @@ -0,0 +1,2 @@ +#make zImage && cp arch/arm/boot/zImage /tftpboot/arm +make zImage && cp arch/arm/boot/zImage /tftpboot/sharp diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/dot.config linux-2.4.21-rmk1-lh7a400/dot.config --- linux-2.4.21-rmk1/dot.config Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/dot.config Thu Oct 16 17:05:41 2003 @@ -0,0 +1,999 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# 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_OMAHA is not set +CONFIG_ARCH_LH7A400=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# Sharp LH7A400 Implementations +# +CONFIG_ARCH_KEV7A400=y +# CONFIG_ARCH_ACORN is not set +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +CONFIG_CPU_ARM922T=y +CONFIG_PLD=y +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_CPU_FREQ is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_PCMCIA_PROBE=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_LH7A400=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_TOS is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_ROUTE_LARGE_TABLES is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +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=y +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +CONFIG_CS89x0=y +# CONFIG_TULIP is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=y + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=y +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=y + +# +# IrDA protocols +# +# CONFIG_IRLAN is not set +# CONFIG_IRNET is not set +CONFIG_IRCOMM=y +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=y +CONFIG_IRPORT_SIR=y + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_OLD is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_LH7X_KEYBOARD_DRIVER is not set +CONFIG_LH7X_BUTTON_DRIVER=y + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_LH7A400=y +CONFIG_SERIAL_LH7A400_CONSOLE=y +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=16 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +CONFIG_LH7A400_DC2DC=y +# CONFIG_RTC is not set +# CONFIG_LH7A400_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_UMSDOS_FS=y +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# 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_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_DBMX1 is not set +CONFIG_FB_PL110=y +CONFIG_PL110_LQ39=y +# CONFIG_PL110_LM57 is not set +# CONFIG_PL110_LQ57 is not set +# CONFIG_PL110_LQ121 is not set +# CONFIG_PL110_LQ104 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_LH7A400=y +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# Misc devices +# +CONFIG_TOUCHSCREEN_LH7X=y +# CONFIG_EEPROM_LH7X is not set +# CONFIG_7SEGMENT_LH7X is not set +# CONFIG_LH7A400_SCI is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/dot.config2 linux-2.4.21-rmk1-lh7a400/dot.config2 --- linux-2.4.21-rmk1/dot.config2 Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/dot.config2 Sun Oct 19 06:19:50 2003 @@ -0,0 +1,1008 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# 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_OMAHA is not set +CONFIG_ARCH_LH7A400=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# Sharp LH7A400 Implementations +# +CONFIG_MACH_KEV7A400=y +# CONFIG_MACH_EFRAME is not set + +# +# Acorn +# +# CONFIG_ARCH_ACORN is not set + +# +# Footbridge support +# +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +CONFIG_CPU_ARM922T=y +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_CPU_FREQ is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_PCMCIA_PROBE=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_LH7A400=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +# CONFIG_MTD is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_TOS is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_ROUTE_LARGE_TABLES is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +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=y +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +CONFIG_ARM_CIRRUS=y +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=y + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=y +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=y + +# +# IrDA protocols +# +# CONFIG_IRLAN is not set +# CONFIG_IRNET is not set +CONFIG_IRCOMM=y +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=y +CONFIG_IRPORT_SIR=y + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_OLD is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=y +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_LH7X_KEYBOARD_DRIVER is not set +CONFIG_LH7X_BUTTON_DRIVER=y + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_LH7A400=y +CONFIG_SERIAL_LH7A400_CONSOLE=y +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=16 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +CONFIG_LH7A400_DC2DC=y +# CONFIG_RTC is not set +# CONFIG_LH7A400_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_UMSDOS_FS=y +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# 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_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_DBMX1 is not set +CONFIG_FB_PL110=y +CONFIG_PL110_LQ39=y +# CONFIG_PL110_LM57 is not set +# CONFIG_PL110_LQ57 is not set +# CONFIG_PL110_LQ121 is not set +# CONFIG_PL110_LQ104 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_LH7A400=y +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# Misc devices +# +CONFIG_TOUCHSCREEN_LH7X=y +# CONFIG_EEPROM_LH7X is not set +# CONFIG_7SEGMENT_LH7X is not set +# CONFIG_LH7A400_SCI is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/dot.config3 linux-2.4.21-rmk1-lh7a400/dot.config3 --- linux-2.4.21-rmk1/dot.config3 Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/dot.config3 Sun Feb 8 19:04:08 2004 @@ -0,0 +1,1083 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# 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_OMAHA is not set +CONFIG_ARCH_LH7A400=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# Sharp LH7A400 Implementations +# +CONFIG_MACH_KEV7A400=y +# CONFIG_MACH_EFRAME is not set + +# +# Acorn +# +# CONFIG_ARCH_ACORN is not set + +# +# Footbridge support +# +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +CONFIG_CPU_ARM922T=y +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_CPU_FREQ is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_PCMCIA_PROBE=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_LH7A400=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# 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 + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +# CONFIG_MTD_SYNCFLASH_PROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_CEIVA is not set +CONFIG_MTD_KEV7A400=y +# CONFIG_MTD_KEV7A400_SYNC is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_TOS is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_ROUTE_LARGE_TABLES is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +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=y +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +CONFIG_ARM_CIRRUS=y +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +# CONFIG_CS89x0 is not set +# CONFIG_TULIP is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=y + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=y +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=y + +# +# IrDA protocols +# +# CONFIG_IRLAN is not set +# CONFIG_IRNET is not set +CONFIG_IRCOMM=y +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=y +CONFIG_IRPORT_SIR=y + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_OLD is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_LH7X_KEYBOARD_DRIVER is not set +CONFIG_LH7X_BUTTON_DRIVER=y + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_LH7A400=y +CONFIG_SERIAL_LH7A400_CONSOLE=y +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=16 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +CONFIG_LH7A400_DC2DC=y +# CONFIG_RTC is not set +# CONFIG_LH7A400_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_UMSDOS_FS=y +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# 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_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_DBMX1 is not set +CONFIG_FB_PL110=y +CONFIG_PL110_LQ39=y +# CONFIG_PL110_LM57 is not set +# CONFIG_PL110_LQ57 is not set +# CONFIG_PL110_LQ121 is not set +# CONFIG_PL110_LQ104 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_LH7A400=y +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# Misc devices +# +CONFIG_TOUCHSCREEN_LH7X=y +# CONFIG_EEPROM_LH7X is not set +# CONFIG_7SEGMENT_LH7X is not set +# CONFIG_LH7A400_SCI is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/dot.config4 linux-2.4.21-rmk1-lh7a400/dot.config4 --- linux-2.4.21-rmk1/dot.config4 Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/dot.config4 Thu Feb 19 21:22:16 2004 @@ -0,0 +1,1083 @@ +# +# Automatically generated make config: don't edit +# +CONFIG_ARM=y +# CONFIG_EISA is not set +# CONFIG_SBUS is not set +# CONFIG_MCA is not set +CONFIG_UID16=y +CONFIG_RWSEM_GENERIC_SPINLOCK=y +# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set +# CONFIG_GENERIC_BUST_SPINLOCK is not set +# CONFIG_GENERIC_ISA_DMA is not set + +# +# Code maturity level options +# +CONFIG_EXPERIMENTAL=y +# CONFIG_OBSOLETE is not set + +# +# Loadable module support +# +CONFIG_MODULES=y +# CONFIG_MODVERSIONS is not set +CONFIG_KMOD=y + +# +# System Type +# +# CONFIG_ARCH_ANAKIN is not set +# CONFIG_ARCH_ARCA5K is not set +# 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_OMAHA is not set +CONFIG_ARCH_LH7A400=y +# CONFIG_ARCH_L7200 is not set +# CONFIG_ARCH_MX1ADS is not set +# CONFIG_ARCH_RPC is not set +# CONFIG_ARCH_RISCSTATION is not set +# CONFIG_ARCH_SA1100 is not set +# CONFIG_ARCH_SHARK is not set +# CONFIG_ARCH_AT91RM9200 is not set + +# +# Archimedes/A5000 Implementations +# + +# +# Archimedes/A5000 Implementations (select only ONE) +# +# CONFIG_ARCH_ARC is not set +# CONFIG_ARCH_A5K is not set + +# +# Footbridge Implementations +# +# CONFIG_ARCH_CATS is not set +# CONFIG_ARCH_PERSONAL_SERVER is not set +# CONFIG_ARCH_EBSA285_ADDIN is not set +# CONFIG_ARCH_EBSA285_HOST is not set +# CONFIG_ARCH_NETWINDER is not set + +# +# SA11x0 Implementations +# +# CONFIG_SA1100_ACCELENT is not set +# CONFIG_SA1100_ASSABET is not set +# CONFIG_ASSABET_NEPONSET is not set +# CONFIG_SA1100_ADSAGC is not set +# CONFIG_SA1100_ADSBITSY is not set +# CONFIG_SA1100_ADSBITSYPLUS is not set +# CONFIG_SA1100_BRUTUS is not set +# CONFIG_SA1100_CEP is not set +# CONFIG_SA1100_CERF is not set +# CONFIG_SA1100_H3100 is not set +# CONFIG_SA1100_H3600 is not set +# CONFIG_SA1100_H3800 is not set +# CONFIG_SA1100_H3XXX is not set +# CONFIG_H3600_SLEEVE is not set +# CONFIG_SA1100_EXTENEX1 is not set +# CONFIG_SA1100_FLEXANET is not set +# CONFIG_SA1100_FREEBIRD is not set +# CONFIG_SA1100_FRODO is not set +# CONFIG_SA1100_GRAPHICSCLIENT is not set +# CONFIG_SA1100_GRAPHICSMASTER is not set +# CONFIG_SA1100_HACKKIT is not set +# CONFIG_SA1100_BADGE4 is not set +# CONFIG_SA1100_JORNADA720 is not set +# CONFIG_SA1100_HUW_WEBPANEL is not set +# CONFIG_SA1100_ITSY is not set +# CONFIG_SA1100_LART is not set +# CONFIG_SA1100_NANOENGINE is not set +# CONFIG_SA1100_OMNIMETER is not set +# CONFIG_SA1100_PANGOLIN is not set +# CONFIG_SA1100_PLEB is not set +# CONFIG_SA1100_PT_SYSTEM3 is not set +# CONFIG_SA1100_SHANNON is not set +# CONFIG_SA1100_SHERMAN is not set +# CONFIG_SA1100_SIMPAD is not set +# CONFIG_SA1100_SIMPUTER is not set +# CONFIG_SA1100_PFS168 is not set +# CONFIG_SA1100_VICTOR is not set +# CONFIG_SA1100_XP860 is not set +# CONFIG_SA1100_YOPY is not set +# CONFIG_SA1100_USB is not set +# CONFIG_SA1100_USB_NETLINK is not set +# CONFIG_SA1100_USB_CHAR is not set +# CONFIG_SA1100_SSP is not set + +# +# AT91RM9200 Implementations +# +# CONFIG_ARCH_AT91RM9200DK is not set + +# +# CLPS711X/EP721X Implementations +# +# CONFIG_ARCH_AUTCPU12 is not set +# CONFIG_ARCH_CDB89712 is not set +# CONFIG_ARCH_CLEP7312 is not set +# CONFIG_ARCH_EDB7211 is not set +# CONFIG_ARCH_FORTUNET is not set +# CONFIG_ARCH_GUIDEA07 is not set +# CONFIG_ARCH_P720T is not set +# CONFIG_ARCH_EP7211 is not set +# CONFIG_ARCH_EP7212 is not set + +# +# Sharp LH7A400 Implementations +# +CONFIG_MACH_KEV7A400=y +# CONFIG_MACH_EFRAME is not set + +# +# Acorn +# +# CONFIG_ARCH_ACORN is not set + +# +# Footbridge support +# +# CONFIG_FOOTBRIDGE is not set +# CONFIG_FOOTBRIDGE_HOST is not set +# CONFIG_FOOTBRIDGE_ADDIN is not set + +# +# Processor Type +# +CONFIG_CPU_32=y +# CONFIG_CPU_26 is not set +# CONFIG_CPU_ARM610 is not set +# CONFIG_CPU_ARM710 is not set +# CONFIG_CPU_ARM720T is not set +# CONFIG_CPU_ARM920T is not set +CONFIG_CPU_ARM922T=y +# CONFIG_PLD is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1026 is not set +# CONFIG_CPU_SA110 is not set +# CONFIG_CPU_SA1100 is not set +# CONFIG_CPU_32v3 is not set +CONFIG_CPU_32v4=y + +# +# Processor Features +# +# CONFIG_ARM_THUMB is not set +# CONFIG_CPU_ICACHE_DISABLE is not set +# CONFIG_CPU_DCACHE_DISABLE is not set +CONFIG_DISCONTIGMEM=y + +# +# General setup +# +# CONFIG_PCI is not set +CONFIG_ISA=y +# CONFIG_ISA_DMA is not set +# CONFIG_ZBOOT_ROM is not set +CONFIG_ZBOOT_ROM_TEXT=0 +CONFIG_ZBOOT_ROM_BSS=0 +# CONFIG_CPU_FREQ is not set +CONFIG_HOTPLUG=y + +# +# PCMCIA/CardBus support +# +CONFIG_PCMCIA=y +CONFIG_PCMCIA_PROBE=y +# CONFIG_I82092 is not set +# CONFIG_I82365 is not set +# CONFIG_TCIC is not set +# CONFIG_PCMCIA_CLPS6700 is not set +# CONFIG_PCMCIA_SA1100 is not set +CONFIG_PCMCIA_LH7A400=y +CONFIG_NET=y +CONFIG_SYSVIPC=y +# CONFIG_BSD_PROCESS_ACCT is not set +CONFIG_SYSCTL=y + +# +# At least one math emulation must be selected +# +CONFIG_FPE_NWFPE=y +# CONFIG_FPE_NWFPE_XP is not set +# CONFIG_FPE_FASTFPE is not set +CONFIG_KCORE_ELF=y +# CONFIG_KCORE_AOUT is not set +# CONFIG_BINFMT_AOUT is not set +CONFIG_BINFMT_ELF=y +# CONFIG_BINFMT_MISC is not set +# CONFIG_PM is not set +# CONFIG_ARTHUR is not set +CONFIG_CMDLINE="" +CONFIG_ALIGNMENT_TRAP=y + +# +# Parallel port support +# +# CONFIG_PARPORT is not set + +# +# Memory Technology Devices (MTD) +# +CONFIG_MTD=y +# CONFIG_MTD_DEBUG is not set +CONFIG_MTD_PARTITIONS=y +# CONFIG_MTD_CONCAT is not set +# 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 + +# +# RAM/ROM/Flash chip drivers +# +CONFIG_MTD_CFI=y +CONFIG_MTD_JEDECPROBE=y +# CONFIG_MTD_SYNCFLASH_PROBE is not set +CONFIG_MTD_GEN_PROBE=y +# CONFIG_MTD_CFI_ADV_OPTIONS is not set +CONFIG_MTD_CFI_INTELEXT=y +# CONFIG_MTD_CFI_AMDSTD is not set +# CONFIG_MTD_CFI_STAA is not set +# CONFIG_MTD_RAM is not set +# CONFIG_MTD_ROM is not set +# CONFIG_MTD_ABSENT is not set +# CONFIG_MTD_OBSOLETE_CHIPS is not set +# CONFIG_MTD_AMDSTD is not set +# CONFIG_MTD_SHARP is not set +# CONFIG_MTD_JEDEC is not set + +# +# Mapping drivers for chip access +# +# CONFIG_MTD_PHYSMAP is not set +# CONFIG_MTD_NORA is not set +# CONFIG_MTD_ARM_INTEGRATOR is not set +# CONFIG_MTD_CDB89712 is not set +# CONFIG_MTD_SA1100 is not set +# CONFIG_MTD_DC21285 is not set +# CONFIG_MTD_IQ80310 is not set +# CONFIG_MTD_FORTUNET is not set +# CONFIG_MTD_EPXA is not set +# CONFIG_MTD_AUTCPU12 is not set +# CONFIG_MTD_EDB7312 is not set +# CONFIG_MTD_IMPA7 is not set +# CONFIG_MTD_CEIVA is not set +CONFIG_MTD_KEV7A400=y +# CONFIG_MTD_KEV7A400_SYNC is not set +# CONFIG_MTD_PCI is not set +# CONFIG_MTD_PCMCIA is not set + +# +# Self-contained MTD device drivers +# +# CONFIG_MTD_PMC551 is not set +# CONFIG_MTD_SLRAM is not set +# CONFIG_MTD_MTDRAM is not set +# CONFIG_MTD_BLKMTD is not set + +# +# Disk-On-Chip Device Drivers +# +# CONFIG_MTD_DOC1000 is not set +# CONFIG_MTD_DOC2000 is not set +# CONFIG_MTD_DOC2001 is not set +# CONFIG_MTD_DOCPROBE is not set + +# +# NAND Flash Device Drivers +# +# CONFIG_MTD_NAND is not set + +# +# Plug and Play configuration +# +# CONFIG_PNP is not set +# CONFIG_ISAPNP is not set + +# +# Block devices +# +# CONFIG_BLK_DEV_FD is not set +# CONFIG_BLK_DEV_XD is not set +# CONFIG_PARIDE is not set +# CONFIG_BLK_CPQ_DA is not set +# CONFIG_BLK_CPQ_CISS_DA is not set +# CONFIG_CISS_SCSI_TAPE is not set +# CONFIG_BLK_DEV_DAC960 is not set +# CONFIG_BLK_DEV_UMEM is not set +# CONFIG_BLK_DEV_LOOP is not set +# CONFIG_BLK_DEV_NBD is not set +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_BLK_DEV_INITRD=y +# CONFIG_BLK_STATS is not set + +# +# Multi-device support (RAID and LVM) +# +# CONFIG_MD is not set +# CONFIG_BLK_DEV_MD is not set +# CONFIG_MD_LINEAR is not set +# CONFIG_MD_RAID0 is not set +# CONFIG_MD_RAID1 is not set +# CONFIG_MD_RAID5 is not set +# CONFIG_MD_MULTIPATH is not set +# CONFIG_BLK_DEV_LVM is not set + +# +# Networking options +# +CONFIG_PACKET=y +# CONFIG_PACKET_MMAP is not set +CONFIG_NETLINK_DEV=y +# CONFIG_NETFILTER is not set +# CONFIG_FILTER is not set +CONFIG_UNIX=y +CONFIG_INET=y +# CONFIG_IP_MULTICAST is not set +CONFIG_IP_ADVANCED_ROUTER=y +# CONFIG_IP_MULTIPLE_TABLES is not set +# CONFIG_IP_ROUTE_MULTIPATH is not set +# CONFIG_IP_ROUTE_TOS is not set +# CONFIG_IP_ROUTE_VERBOSE is not set +# CONFIG_IP_ROUTE_LARGE_TABLES is not set +CONFIG_IP_PNP=y +# CONFIG_IP_PNP_DHCP is not set +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=y +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set +# CONFIG_ATM is not set +# CONFIG_VLAN_8021Q is not set + +# +# +# +# CONFIG_IPX is not set +# CONFIG_ATALK is not set + +# +# Appletalk devices +# +# CONFIG_DEV_APPLETALK is not set +# CONFIG_DECNET is not set +# CONFIG_BRIDGE is not set +# CONFIG_X25 is not set +# CONFIG_LAPB is not set +# CONFIG_LLC is not set +# CONFIG_NET_DIVERT is not set +# CONFIG_ECONET is not set +# CONFIG_WAN_ROUTER is not set +# CONFIG_NET_FASTROUTE is not set +# CONFIG_NET_HW_FLOWCONTROL is not set + +# +# QoS and/or fair queueing +# +# CONFIG_NET_SCHED is not set + +# +# Network testing +# +# CONFIG_NET_PKTGEN is not set + +# +# Network device support +# +CONFIG_NETDEVICES=y + +# +# ARCnet devices +# +# CONFIG_ARCNET is not set +# CONFIG_DUMMY is not set +# CONFIG_BONDING is not set +# CONFIG_EQUALIZER is not set +# CONFIG_TUN is not set +# CONFIG_ETHERTAP is not set + +# +# Ethernet (10 or 100Mbit) +# +CONFIG_NET_ETHERNET=y +# CONFIG_ARM_AM79C961A is not set +# CONFIG_ARM_CIRRUS is not set +# CONFIG_SUNLANCE is not set +# CONFIG_SUNBMAC is not set +# CONFIG_SUNQE is not set +# CONFIG_SUNGEM is not set +# CONFIG_NET_VENDOR_3COM is not set +# CONFIG_LANCE is not set +# CONFIG_NET_VENDOR_SMC is not set +# CONFIG_NET_VENDOR_RACAL is not set +# CONFIG_AT1700 is not set +# CONFIG_DEPCA is not set +# CONFIG_HP100 is not set +# CONFIG_NET_ISA is not set +CONFIG_NET_PCI=y +# CONFIG_PCNET32 is not set +# CONFIG_AMD8111_ETH is not set +# CONFIG_ADAPTEC_STARFIRE is not set +# CONFIG_AC3200 is not set +# CONFIG_APRICOT is not set +CONFIG_CS89x0=y +# CONFIG_TULIP is not set +# CONFIG_DM9102 is not set +# CONFIG_EEPRO100 is not set +# CONFIG_EEPRO100_PIO is not set +# CONFIG_E100 is not set +# CONFIG_LNE390 is not set +# CONFIG_FEALNX is not set +# CONFIG_NATSEMI is not set +# CONFIG_NE2K_PCI is not set +# CONFIG_NE3210 is not set +# CONFIG_ES3210 is not set +# CONFIG_8139CP is not set +# CONFIG_8139TOO is not set +# CONFIG_8139TOO_PIO is not set +# CONFIG_8139TOO_TUNE_TWISTER is not set +# CONFIG_8139TOO_8129 is not set +# CONFIG_8139_OLD_RX_RESET is not set +# CONFIG_SIS900 is not set +# CONFIG_EPIC100 is not set +# CONFIG_SUNDANCE is not set +# CONFIG_SUNDANCE_MMIO is not set +# CONFIG_TC35815 is not set +# CONFIG_VIA_RHINE is not set +# CONFIG_VIA_RHINE_MMIO is not set +# CONFIG_WINBOND_840 is not set +# CONFIG_NET_POCKET is not set + +# +# Ethernet (1000 Mbit) +# +# CONFIG_ACENIC is not set +# CONFIG_DL2K is not set +# CONFIG_E1000 is not set +# CONFIG_MYRI_SBUS is not set +# CONFIG_NS83820 is not set +# CONFIG_HAMACHI is not set +# CONFIG_YELLOWFIN is not set +# CONFIG_R8169 is not set +# CONFIG_SK98LIN is not set +# CONFIG_TIGON3 is not set +# CONFIG_FDDI is not set +# CONFIG_HIPPI is not set +# CONFIG_PLIP is not set +# CONFIG_PPP is not set +# CONFIG_SLIP is not set + +# +# Wireless LAN (non-hamradio) +# +CONFIG_NET_RADIO=y +# CONFIG_STRIP is not set +# CONFIG_WAVELAN is not set +# CONFIG_ARLAN is not set +# CONFIG_AIRONET4500 is not set +# CONFIG_AIRONET4500_NONCS is not set +# CONFIG_AIRONET4500_PROC is not set +# CONFIG_AIRO is not set +CONFIG_HERMES=y + +# +# Wireless Pcmcia cards support +# +CONFIG_PCMCIA_HERMES=y +# CONFIG_AIRO_CS is not set +CONFIG_NET_WIRELESS=y + +# +# Token Ring devices +# +# CONFIG_TR is not set +# CONFIG_NET_FC is not set +# CONFIG_RCPCI is not set +# CONFIG_SHAPER is not set + +# +# Wan interfaces +# +# CONFIG_WAN is not set + +# +# PCMCIA network device support +# +CONFIG_NET_PCMCIA=y +# CONFIG_PCMCIA_3C589 is not set +# CONFIG_PCMCIA_3C574 is not set +# CONFIG_PCMCIA_FMVJ18X is not set +CONFIG_PCMCIA_PCNET=y +# CONFIG_PCMCIA_AXNET is not set +# CONFIG_PCMCIA_NMCLAN is not set +# CONFIG_PCMCIA_SMC91C92 is not set +# CONFIG_PCMCIA_XIRC2PS is not set +# CONFIG_ARCNET_COM20020_CS is not set +# CONFIG_PCMCIA_IBMTR is not set +# CONFIG_NET_PCMCIA_RADIO is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +CONFIG_IRDA=y + +# +# IrDA protocols +# +# CONFIG_IRLAN is not set +# CONFIG_IRNET is not set +CONFIG_IRCOMM=y +# CONFIG_IRDA_ULTRA is not set + +# +# IrDA options +# +# CONFIG_IRDA_CACHE_LAST_LSAP is not set +# CONFIG_IRDA_FAST_RR is not set +# CONFIG_IRDA_DEBUG is not set + +# +# Infrared-port device drivers +# + +# +# SIR device drivers +# +CONFIG_IRTTY_SIR=y +CONFIG_IRPORT_SIR=y + +# +# Dongle support +# +# CONFIG_DONGLE is not set + +# +# FIR device drivers +# +# CONFIG_USB_IRDA is not set +# CONFIG_NSC_FIR is not set +# CONFIG_WINBOND_FIR is not set +# CONFIG_TOSHIBA_OLD is not set +# CONFIG_TOSHIBA_FIR is not set +# CONFIG_SMC_IRCC_FIR is not set +# CONFIG_ALI_FIR is not set +# CONFIG_VLSI_FIR is not set + +# +# ATA/ATAPI/MFM/RLL support +# +CONFIG_IDE=y + +# +# IDE, ATA and ATAPI Block devices +# +CONFIG_BLK_DEV_IDE=y + +# +# Please see Documentation/ide.txt for help/info on IDE drives +# +# CONFIG_BLK_DEV_HD_IDE is not set +# CONFIG_BLK_DEV_HD is not set +CONFIG_BLK_DEV_IDEDISK=y +# CONFIG_IDEDISK_MULTI_MODE is not set +# CONFIG_IDEDISK_STROKE is not set +CONFIG_BLK_DEV_IDECS=m +# CONFIG_BLK_DEV_IDECD is not set +# CONFIG_BLK_DEV_IDETAPE is not set +# CONFIG_BLK_DEV_IDEFLOPPY is not set +# CONFIG_BLK_DEV_IDESCSI is not set +# CONFIG_IDE_TASK_IOCTL is not set + +# +# IDE chipset support/bugfixes +# +# CONFIG_BLK_DEV_CMD640 is not set +# CONFIG_BLK_DEV_CMD640_ENHANCED is not set +# CONFIG_BLK_DEV_ISAPNP is not set +# CONFIG_IDE_CHIPSETS is not set +# CONFIG_IDEDMA_AUTO is not set +# CONFIG_DMA_NONPCI is not set +CONFIG_BLK_DEV_IDE_MODES=y +# CONFIG_BLK_DEV_ATARAID is not set +# CONFIG_BLK_DEV_ATARAID_PDC is not set +# CONFIG_BLK_DEV_ATARAID_HPT is not set +# CONFIG_BLK_DEV_ATARAID_SII is not set + +# +# SCSI support +# +# CONFIG_SCSI is not set + +# +# I2O device support +# +# CONFIG_I2O is not set +# CONFIG_I2O_BLOCK is not set +# CONFIG_I2O_LAN is not set +# CONFIG_I2O_SCSI is not set +# CONFIG_I2O_PROC is not set + +# +# ISDN subsystem +# +# CONFIG_ISDN is not set + +# +# Input core support +# +CONFIG_INPUT=y +CONFIG_INPUT_KEYBDEV=y +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +CONFIG_INPUT_EVDEV=y +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +CONFIG_VT=y +# CONFIG_VT_CONSOLE is not set +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set +# CONFIG_KEV7X_KEYBOARD_DRIVER is not set +CONFIG_KEV7X_BUTTON_DRIVER=y + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_PL011 is not set +CONFIG_SERIAL_LH7A400=y +CONFIG_SERIAL_LH7A400_CONSOLE=y +# CONFIG_SERIAL_CLPS711X is not set +# CONFIG_SERIAL_CLPS711X_CONSOLE is not set +# CONFIG_SERIAL_21285 is not set +# CONFIG_SERIAL_21285_OLD is not set +# CONFIG_SERIAL_21285_CONSOLE is not set +# CONFIG_SERIAL_UART00 is not set +# CONFIG_SERIAL_UART00_CONSOLE is not set +# CONFIG_SERIAL_SA1100 is not set +# CONFIG_SERIAL_SA1100_CONSOLE is not set +# CONFIG_SERIAL_OMAHA is not set +# CONFIG_SERIAL_OMAHA_CONSOLE is not set +# CONFIG_SERIAL_AT91 is not set +# CONFIG_SERIAL_AT91_CONSOLE is not set +# CONFIG_SERIAL_8250 is not set +# CONFIG_SERIAL_8250_CONSOLE is not set +# CONFIG_SERIAL_8250_EXTENDED is not set +# CONFIG_SERIAL_8250_MANY_PORTS is not set +# CONFIG_SERIAL_8250_SHARE_IRQ is not set +# CONFIG_SERIAL_8250_DETECT_IRQ is not set +# CONFIG_SERIAL_8250_MULTIPORT is not set +# CONFIG_SERIAL_8250_HUB6 is not set +CONFIG_SERIAL_CORE=y +CONFIG_SERIAL_CORE_CONSOLE=y +CONFIG_UNIX98_PTYS=y +CONFIG_UNIX98_PTY_COUNT=16 + +# +# I2C support +# +# CONFIG_I2C is not set + +# +# L3 serial bus support +# +# CONFIG_L3 is not set +# CONFIG_L3_ALGOBIT is not set +# CONFIG_L3_BIT_SA1100_GPIO is not set + +# +# Other L3 adapters +# +# CONFIG_L3_SA1111 is not set +# CONFIG_BIT_SA1100_GPIO is not set + +# +# Mice +# +# CONFIG_BUSMOUSE is not set +# CONFIG_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set +# CONFIG_INPUT_NS558 is not set +# CONFIG_INPUT_LIGHTNING is not set +# CONFIG_INPUT_PCIGAME is not set +# CONFIG_INPUT_CS461X is not set +# CONFIG_INPUT_EMU10K1 is not set +# CONFIG_INPUT_SERIO is not set +# CONFIG_INPUT_SERPORT is not set + +# +# Joysticks +# +# CONFIG_INPUT_ANALOG is not set +# CONFIG_INPUT_A3D is not set +# CONFIG_INPUT_ADI is not set +# CONFIG_INPUT_COBRA is not set +# CONFIG_INPUT_GF2K is not set +# CONFIG_INPUT_GRIP is not set +# CONFIG_INPUT_INTERACT is not set +# CONFIG_INPUT_TMDC is not set +# CONFIG_INPUT_SIDEWINDER is not set +# CONFIG_INPUT_IFORCE_USB is not set +# CONFIG_INPUT_IFORCE_232 is not set +# CONFIG_INPUT_WARRIOR is not set +# CONFIG_INPUT_MAGELLAN is not set +# CONFIG_INPUT_SPACEORB is not set +# CONFIG_INPUT_SPACEBALL is not set +# CONFIG_INPUT_STINGER is not set +# CONFIG_INPUT_DB9 is not set +# CONFIG_INPUT_GAMECON is not set +# CONFIG_INPUT_TURBOGRAFX is not set +# CONFIG_QIC02_TAPE is not set +# CONFIG_IPMI_HANDLER is not set +# CONFIG_IPMI_PANIC_EVENT is not set +# CONFIG_IPMI_DEVICE_INTERFACE is not set +# CONFIG_IPMI_KCS is not set +# CONFIG_IPMI_WATCHDOG is not set + +# +# Watchdog Cards +# +# CONFIG_WATCHDOG is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +CONFIG_LH7A400_DC2DC=y +# CONFIG_RTC is not set +# CONFIG_LH7A400_RTC is not set +# CONFIG_DTLK is not set +# CONFIG_R3964 is not set +# CONFIG_APPLICOM is not set + +# +# Ftape, the floppy tape device driver +# +# CONFIG_FTAPE is not set +# CONFIG_AGP is not set +# CONFIG_DRM is not set + +# +# PCMCIA character devices +# +# CONFIG_SYNCLINK_CS is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_AUTOFS_FS is not set +# CONFIG_AUTOFS4_FS is not set +# CONFIG_REISERFS_FS is not set +# CONFIG_REISERFS_CHECK is not set +# CONFIG_REISERFS_PROC_INFO is not set +# CONFIG_ADFS_FS is not set +# CONFIG_ADFS_FS_RW is not set +# CONFIG_AFFS_FS is not set +# CONFIG_HFS_FS is not set +# CONFIG_BEFS_FS is not set +# CONFIG_BEFS_DEBUG is not set +# CONFIG_BFS_FS is not set +# CONFIG_EXT3_FS is not set +# CONFIG_JBD is not set +# CONFIG_JBD_DEBUG is not set +CONFIG_FAT_FS=y +CONFIG_MSDOS_FS=y +CONFIG_UMSDOS_FS=y +# CONFIG_VFAT_FS is not set +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +# CONFIG_JFFS2_FS is not set +# CONFIG_CRAMFS is not set +# CONFIG_TMPFS is not set +CONFIG_RAMFS=y +# CONFIG_ISO9660_FS is not set +# CONFIG_JOLIET is not set +# CONFIG_ZISOFS is not set +# CONFIG_JFS_FS is not set +# CONFIG_JFS_DEBUG is not set +# CONFIG_JFS_STATISTICS is not set +# CONFIG_MINIX_FS is not set +# CONFIG_VXFS_FS is not set +# CONFIG_NTFS_FS is not set +# CONFIG_NTFS_RW is not set +# CONFIG_HPFS_FS is not set +CONFIG_PROC_FS=y +# CONFIG_DEVFS_FS is not set +# CONFIG_DEVFS_MOUNT is not set +# CONFIG_DEVFS_DEBUG is not set +CONFIG_DEVPTS_FS=y +# CONFIG_QNX4FS_FS is not set +# CONFIG_QNX4FS_RW is not set +CONFIG_ROMFS_FS=y +CONFIG_EXT2_FS=y +# CONFIG_SYSV_FS is not set +# CONFIG_UDF_FS is not set +# CONFIG_UDF_RW is not set +# CONFIG_UFS_FS is not set +# CONFIG_UFS_FS_WRITE is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +CONFIG_NFS_FS=y +CONFIG_NFS_V3=y +CONFIG_ROOT_NFS=y +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y +CONFIG_LOCKD_V4=y +# CONFIG_SMB_FS is not set +# CONFIG_NCP_FS is not set +# CONFIG_NCPFS_PACKET_SIGNING is not set +# CONFIG_NCPFS_IOCTL_LOCKING is not set +# CONFIG_NCPFS_STRONG is not set +# CONFIG_NCPFS_NFS_NS is not set +# CONFIG_NCPFS_OS2_NS is not set +# CONFIG_NCPFS_SMALLDOS is not set +# CONFIG_NCPFS_NLS is not set +# CONFIG_NCPFS_EXTRAS is not set +# CONFIG_ZISOFS_FS is not set + +# +# Partition Types +# +CONFIG_PARTITION_ADVANCED=y +# CONFIG_ACORN_PARTITION is not set +# CONFIG_OSF_PARTITION is not set +# CONFIG_AMIGA_PARTITION is not set +# CONFIG_ATARI_PARTITION is not set +# CONFIG_MAC_PARTITION is not set +CONFIG_MSDOS_PARTITION=y +# CONFIG_BSD_DISKLABEL is not set +# CONFIG_MINIX_SUBPARTITION is not set +# CONFIG_SOLARIS_X86_PARTITION is not set +# CONFIG_UNIXWARE_DISKLABEL is not set +# CONFIG_LDM_PARTITION is not set +# CONFIG_SGI_PARTITION is not set +# CONFIG_ULTRIX_PARTITION is not set +# CONFIG_SUN_PARTITION is not set +# CONFIG_EFI_PARTITION is not set +# CONFIG_SMB_NLS is not set +CONFIG_NLS=y + +# +# Native Language Support +# +CONFIG_NLS_DEFAULT="iso8859-1" +# CONFIG_NLS_CODEPAGE_437 is not set +# CONFIG_NLS_CODEPAGE_737 is not set +# CONFIG_NLS_CODEPAGE_775 is not set +# CONFIG_NLS_CODEPAGE_850 is not set +# 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_ISO8859_1 is not set +# CONFIG_NLS_ISO8859_2 is not set +# CONFIG_NLS_ISO8859_3 is not set +# CONFIG_NLS_ISO8859_4 is not set +# CONFIG_NLS_ISO8859_5 is not set +# CONFIG_NLS_ISO8859_6 is not set +# CONFIG_NLS_ISO8859_7 is not set +# CONFIG_NLS_ISO8859_9 is not set +# CONFIG_NLS_ISO8859_13 is not set +# CONFIG_NLS_ISO8859_14 is not set +# CONFIG_NLS_ISO8859_15 is not set +# CONFIG_NLS_KOI8_R is not set +# CONFIG_NLS_KOI8_U is not set +# CONFIG_NLS_UTF8 is not set + +# +# Console drivers +# +CONFIG_PC_KEYMAP=y +# CONFIG_VGA_CONSOLE is not set + +# +# Frame-buffer support +# +CONFIG_FB=y +CONFIG_DUMMY_CONSOLE=y +# CONFIG_FB_ACORN is not set +# CONFIG_FB_ANAKIN is not set +# CONFIG_FB_CLPS711X is not set +# CONFIG_FB_SA1100 is not set +# CONFIG_FB_DBMX1 is not set +CONFIG_FB_PL110=y +CONFIG_PL110_LQ39=y +# CONFIG_PL110_LM57 is not set +# CONFIG_PL110_LQ57 is not set +# CONFIG_PL110_LQ121 is not set +# CONFIG_PL110_LQ104 is not set +# CONFIG_FB_CYBER2000 is not set +# CONFIG_FB_VIRTUAL is not set +CONFIG_FBCON_ADVANCED=y +# CONFIG_FBCON_MFB is not set +# CONFIG_FBCON_CFB2 is not set +# CONFIG_FBCON_CFB4 is not set +CONFIG_FBCON_CFB8=y +CONFIG_FBCON_CFB16=y +# CONFIG_FBCON_CFB24 is not set +# CONFIG_FBCON_CFB32 is not set +# CONFIG_FBCON_AFB is not set +# CONFIG_FBCON_ILBM is not set +# CONFIG_FBCON_IPLAN2P2 is not set +# CONFIG_FBCON_IPLAN2P4 is not set +# CONFIG_FBCON_IPLAN2P8 is not set +# CONFIG_FBCON_MAC is not set +# CONFIG_FBCON_VGA_PLANES is not set +# CONFIG_FBCON_VGA is not set +# CONFIG_FBCON_HGA is not set +CONFIG_FBCON_FONTWIDTH8_ONLY=y +CONFIG_FBCON_FONTS=y +CONFIG_FONT_8x8=y +# CONFIG_FONT_8x16 is not set +# CONFIG_FONT_SUN8x16 is not set +# CONFIG_FONT_PEARL_8x8 is not set +# CONFIG_FONT_ACORN_8x8 is not set + +# +# Sound +# +CONFIG_SOUND=y +# CONFIG_SOUND_ALI5455 is not set +# CONFIG_SOUND_BT878 is not set +# CONFIG_SOUND_CMPCI is not set +# CONFIG_SOUND_EMU10K1 is not set +# CONFIG_MIDI_EMU10K1 is not set +# CONFIG_SOUND_FUSION is not set +# CONFIG_SOUND_CS4281 is not set +# CONFIG_SOUND_ES1370 is not set +# CONFIG_SOUND_ES1371 is not set +# CONFIG_SOUND_ESSSOLO1 is not set +# CONFIG_SOUND_MAESTRO is not set +# CONFIG_SOUND_MAESTRO3 is not set +# CONFIG_SOUND_FORTE is not set +# CONFIG_SOUND_ICH is not set +# CONFIG_SOUND_RME96XX is not set +# CONFIG_SOUND_SONICVIBES is not set +# CONFIG_SOUND_TRIDENT is not set +# CONFIG_SOUND_MSNDCLAS is not set +# CONFIG_SOUND_MSNDPIN is not set +# CONFIG_SOUND_VIA82CXXX is not set +# CONFIG_MIDI_VIA82CXXX is not set +CONFIG_SOUND_LH7A400=y +# CONFIG_SOUND_OSS is not set +# CONFIG_SOUND_VIDC is not set +# CONFIG_SOUND_WAVEARTIST is not set +# CONFIG_SOUND_TVMIXER is not set + +# +# Multimedia Capabilities Port drivers +# +# CONFIG_MCP is not set +# CONFIG_MCP_SA1100 is not set +# CONFIG_MCP_UCB1200 is not set +# CONFIG_MCP_UCB1200_AUDIO is not set +# CONFIG_MCP_UCB1200_TS is not set + +# +# Misc devices +# +CONFIG_KEV7X_TOUCHSCREEN=y +CONFIG_KEV7X_EEPROM=y +CONFIG_KEV7X_7SEGMENT=y +# CONFIG_LH7A400_SCI is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# MMC/SD Card support +# +CONFIG_MMC=y +# CONFIG_MMC_DEBUG is not set + +# +# Bluetooth support +# +# CONFIG_BLUEZ is not set + +# +# Kernel hacking +# +CONFIG_FRAME_POINTER=y +CONFIG_DEBUG_USER=y +CONFIG_DEBUG_INFO=y +# CONFIG_NO_PGT_CACHE is not set +CONFIG_DEBUG_KERNEL=y +# CONFIG_DEBUG_SLAB is not set +# CONFIG_MAGIC_SYSRQ is not set +# CONFIG_DEBUG_SPINLOCK is not set +# CONFIG_DEBUG_WAITQ is not set +CONFIG_DEBUG_BUGVERBOSE=y +CONFIG_DEBUG_ERRORS=y +CONFIG_DEBUG_LL=y +# CONFIG_DEBUG_DC21285_PORT is not set +# CONFIG_DEBUG_CLPS711X_UART2 is not set + +# +# Library routines +# +# CONFIG_ZLIB_INFLATE is not set +# CONFIG_ZLIB_DEFLATE is not set diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/Makefile linux-2.4.21-rmk1-lh7a400/drivers/Makefile --- linux-2.4.21-rmk1/drivers/Makefile Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/Makefile Thu Oct 16 15:20:44 2003 @@ -8,7 +8,7 @@ mod-subdirs := dio hil mtd sbus video macintosh usb input telephony sgi ide \ message/i2o message/fusion scsi md ieee1394 pnp isdn atm \ - fc4 net/hamradio i2c l3 acpi bluetooth serial + fc4 net/hamradio i2c l3 acpi bluetooth serial mmc subdir-y := parport serial char block net sound misc media cdrom hotplug pld subdir-m := $(subdir-y) @@ -49,6 +49,7 @@ subdir-$(CONFIG_ACPI) += acpi subdir-$(CONFIG_BLUEZ) += bluetooth +subdir-$(CONFIG_MMC) += mmc subdir-$(CONFIG_SSI) += ssi subdir-$(CONFIG_ARCH_AT91RM9200)+= at91 diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/char/Config.in linux-2.4.21-rmk1-lh7a400/drivers/char/Config.in --- linux-2.4.21-rmk1/drivers/char/Config.in Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/char/Config.in Sun Feb 8 20:26:52 2004 @@ -137,6 +137,11 @@ tristate 'AT91RM9200 SPI device interface' CONFIG_AT91_SPIDEV fi +if [ "$CONFIG_ARCH_LH7A400" = "y" -o "$CONFIG_ARCH_LH79520" = "y" ]; then + dep_tristate 'Enable KEV7A400/79520 Keyboard Driver' CONFIG_KEV7X_KEYBOARD_DRIVER $CONFIG_INPUT + dep_tristate 'Enable KEV7A400/79520 Button Driver' CONFIG_KEV7X_BUTTON_DRIVER $CONFIG_INPUT +fi + source drivers/serial/Config.in if [ "$CONFIG_ARCH_ANAKIN" = "y" ]; then @@ -271,6 +276,7 @@ fi dep_tristate 'AMD 76x native power management (Experimental)' CONFIG_AMD_PM768 $CONFIG_PCI tristate '/dev/nvram support' CONFIG_NVRAM +tristate 'LH7A400 DC to DC Support' CONFIG_LH7A400_DC2DC tristate 'Enhanced Real Time Clock Support' CONFIG_RTC if [ "$CONFIG_IA64" = "y" ]; then bool 'EFI Real Time Clock Services' CONFIG_EFI_RTC @@ -287,6 +293,9 @@ if [ "$CONFIG_ARCH_AT91RM9200" = "y" ]; then tristate 'AT91RM9200 Real Time Clock' CONFIG_AT91_RTC fi +if [ "$CONFIG_ARCH_LH7A400" = "y" ]; then + tristate 'LH7A400 Real Time Clock' CONFIG_LH7A400_RTC +fi tristate 'Double Talk PC internal speech card support' CONFIG_DTLK tristate 'Siemens R3964 line discipline' CONFIG_R3964 diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/char/Makefile linux-2.4.21-rmk1-lh7a400/drivers/char/Makefile --- linux-2.4.21-rmk1/drivers/char/Makefile Thu Oct 16 10:10:08 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/char/Makefile Sun Feb 8 20:21:05 2004 @@ -135,6 +135,12 @@ ifeq ($(CONFIG_ARCH_GUIDEA07),y) KEYMAP := defkeymap.o endif + ifeq ($(CONFIG_ARCH_LH79520),y) + KEYBD += lh7x-keyb.o + endif + ifeq ($(CONFIG_ARCH_LH7A400),y) + KEYBD += lh7x-keyb.o + endif endif ifeq ($(ARCH),sh) @@ -262,11 +268,13 @@ obj-$(CONFIG_ADBMOUSE) += adbmouse.o obj-$(CONFIG_PC110_PAD) += pc110pad.o obj-$(CONFIG_MK712_MOUSE) += mk712.o +obj-$(CONFIG_LH7A400_DC2DC) += lh7a400_dc2dc.o obj-$(CONFIG_RTC) += rtc.o obj-$(CONFIG_GEN_RTC) += genrtc.o obj-$(CONFIG_EFI_RTC) += efirtc.o obj-$(CONFIG_SA1100_RTC) += sa1100-rtc.o obj-$(CONFIG_OMAHA_RTC) += omaha-rtc.o +obj-$(CONFIG_LH7A400_RTC) +=lh7a400_rtc.o ifeq ($(CONFIG_PPC),) obj-$(CONFIG_NVRAM) += nvram.o endif diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/char/lh7a400_dc2dc.c linux-2.4.21-rmk1-lh7a400/drivers/char/lh7a400_dc2dc.c --- linux-2.4.21-rmk1/drivers/char/lh7a400_dc2dc.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/char/lh7a400_dc2dc.c Sat Oct 18 13:12:50 2003 @@ -0,0 +1,345 @@ +/* + * linux/drivers/char/dc2dc.c + * + * Copyright (C) 2002 Embedix. + * + * Original code write was authored by Craig Matsuura + * Parts of this code are from Sharp. + * This code falls under the license of the GPL. + * + * This modules is for controlling the DC to DC converter. + * Jumps for backlighting and audio must be set correctly on the LH7a400 + * Board for this module to work properly. See Sharp LH7a400 Documentation + * for jumper settings. + */ +#define MODULES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "lh7a400_dc2dc.h" + + +dc2dcRegs_t *dc2dcregs = (dc2dcRegs_t *) IO_ADDRESS( DCDC_PHYS); +cpldRegs_t *cpldregs = (cpldRegs_t *) CPLD_BASE; + +#define TYPE(dev) (MINOR(dev) >> 4) /* high nibble */ +#define NUM(dev) (MINOR(dev) & 0xf) /* low nibble */ + +static int dc2dc_major=0; // Major Number for Driver 0 indicates dynamic assignment +static int dc2dc_debug=0; +static int dc2dc_bl=0; /* 0=Not backlight control via cpld, 1=Control Backlight */ +static int audio_freq=0x7777; +static int audio_vol=0x7777; +static int audio_duration=100000; + +#ifdef MODULES +MODULE_PARM(dc2dc_bl,"i"); +MODULE_PARM(dc2dc_major,"i"); +MODULE_PARM(dc2dc_debug,"i"); +MODULE_PARM(audio_freq,"i"); +MODULE_PARM(audio_vol,"i"); +MODULE_PARM(audio_duration,"i"); +#endif + +/*********************************************************************** + * + * Function: lcd_priv_set_bl + * + * Purpose: + * Sets the backlight intensity (variable intensity). + * + * Processing: + * The passed value must be a value between 0 and max_intens. The + * value of max_intens may be different for different panel types. + * On panel types where max_intens = 1, the value of '1' will simply + * turn the backlight on. '0' will always turn the backlight off. + * + * Parameters: + * intens: Backlight intensity value + * + * Outputs: + * None + * + * Returns: + * Nothing + * + * Notes: + * The DC-DC converter 0 is used by default for backlight intensity + * control. + * + **********************************************************************/ +static void lcd_priv_set_bl (unsigned short intens) +{ + + if (dc2dc_bl != 1) + { + if (intens == 0) + { + // Disable backlight power + cpldregs->lcd_pwr_cntl &= ~CPLD_BACKLIGHT_ON; + } + else + { + // Enable backlight power + cpldregs->lcd_pwr_cntl |= CPLD_BACKLIGHT_ON; + + // Limit value of intens to PWM value + intens = intens & 0xF; + intens = intens | (intens << 4); + + dc2dcregs->dcdcfreq = PMPFREQ_DRV0_PREHI (7) | PMPFREQ_DRV0_PRELO (7); + dc2dcregs->dcdccon = intens; + } + } + else + { + + // Limit value of intens to PWM value + intens = intens & 0xF; + intens = intens | (intens << 4); + + dc2dcregs->dcdcfreq = PMPFREQ_DRV0_PREHI (7) | PMPFREQ_DRV0_PRELO (7); + dc2dcregs->dcdccon = intens; + } +} + +/* + * Test code for speaker sounds. + */ +static void spk_priv_set_sound (unsigned short intens) +{ + dc2dcregs->dcdcfreq = audio_freq; + dc2dcregs->dcdccon = intens; /* Voule Level */ +} + + +/* + * Start Sound with values in audio_freq and audio_vol + */ +static void startSnd(void) +{ + dc2dcregs->dcdcfreq = audio_freq; + dc2dcregs->dcdccon = audio_vol; +} + +/* + * Stop sound, reset freq and vol to zero. + */ +static void stopSnd(void) +{ + dc2dcregs->dcdcfreq = 0; + dc2dcregs->dcdccon = 0; +} +/* + * Beep a freq, vol for a duration. + */ +static void beep(void) +{ + startSnd(); + udelay(audio_duration); + stopSnd(); +} + + +/**************************************************************************** + * Open Function - Open the device either the Backlight or the Audio + * /dev/bl c 254 0 is the Backlighting + * /dev/dcdc1 c 254 1 is the Audio + * Keep in mind the 254 is only an example. If you do not specify a + * major code then a dynamic one will be assigned. You will have to + * look at /proc/devices to see the major code for pwm + */ +int dc2dc_open(struct inode * inode, struct file * filp) +{ + + MOD_INC_USE_COUNT; + +// printk("<4>open pwm... dc=%d, bl_dc=%d\n",pwmregs->pwm0.dc,pwm_backlight_dcycle); + switch (NUM(inode->i_rdev)) { + case 0: // Device 0 + break; + case 1: // Device 1 + break; + default: + printk("<4>Minor device unknown %d\n",NUM(inode->i_rdev)); + break; + } + + return 0; +} + +/**************************************************************************** + * + */ +int dc2dc_release(struct inode *inode, struct file * filp) +{ + //printk("<4>release dc2dc...\n"); + switch (NUM(inode->i_rdev)) { + case 0: // Device 0 + break; + case 1: // Device 1 + break; + default: + printk("<4>Minor device unknown %d\n",NUM(inode->i_rdev)); + break; + } + + MOD_DEC_USE_COUNT; + return 0; +} + +/**************************************************************************** + * + */ +ssize_t dc2dc_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +/**************************************************************************** + * + */ +ssize_t dc2dc_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +/**************************************************************************** + * + */ +int dc2dc_ioctl(struct inode *inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + //int err = 0, size = _IOC_SIZE(cmd); + + if (dc2dc_debug) + { + printk("IOCTL called!!!\n"); + } + + + if (_IOC_TYPE(cmd) != DC2DC_IOC_MAGIC) { + return -EINVAL; + } + if (_IOC_NR(cmd) > DC2DC_IOC_MAXNR) { + return -EINVAL; + } + + /* + Should check for direction bit's see page 101 in "Linux Device Drivers Book" + size and err used here. + */ + + switch (NUM(inode->i_rdev)) { + case 0: // device 0 (backlight) + switch (cmd) { + case DC2DC_IOCRESET: + printk("Reset dc2dc\n"); + break; + case DC2DC_IOCSETBL: + // printk("Set Backlight value to %ld\n",arg); + lcd_priv_set_bl(arg); + break; + + } + break; + + case 1: // Device 1 (Audio Device) + switch (cmd) { + case DC2DC_IOCBEEP: + beep(); + break; + case DC2DC_IOCSTARTSND: + startSnd(); + break; + case DC2DC_IOCSTOPSND: + stopSnd(); + break; + case DC2DC_IOCSETSND: + printk("Set Sound value to %ld\n",arg); + spk_priv_set_sound(arg); + break; + case DC2DC_IOCSETVOL: + audio_vol = arg; + break; + case DC2DC_IOCSETFREQ: + audio_freq = arg; + break; + case DC2DC_IOCGETVOL: + __put_user(audio_vol, (int *) arg); + break; + case DC2DC_IOCGETFREQ: + __put_user(audio_freq, (int *) arg); + break; + } + break; + } + + return 0; +} + + +/**************************************************************************** + * + */ +struct file_operations dc2dc_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + read: dc2dc_read, + write: dc2dc_write, + ioctl: dc2dc_ioctl, + open: dc2dc_open, + release: dc2dc_release, +}; + + +/**************************************************************************** + * + */ +static int __init dc2dc_init_module(void) +{ + int result; + + printk("<1>Sharp LH7a400 DC2DC Driver Copyright 2002 Embedix\n"); + + result = register_chrdev(dc2dc_major,"dc2dc",&dc2dc_fops); + if (result < 0) { + printk("<4>dc2dc: can't get major number %d\n",dc2dc_major); + return result; + } + if (dc2dc_major == 0) { + dc2dc_major = result; /* Dynamic Allocation of major number */ + printk("<4>DC2DC Dynamic Major Number %d\n",dc2dc_major); + } + + return 0; +} + +/**************************************************************************** + * + */ +static void __exit dc2dc_cleanup_module(void) +{ + int result; + + printk("<1>End DC2DC Module...\n"); + result = unregister_chrdev(dc2dc_major,"dc2dc"); +} + +module_init(dc2dc_init_module); +module_exit(dc2dc_cleanup_module); diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/char/lh7a400_dc2dc.h linux-2.4.21-rmk1-lh7a400/drivers/char/lh7a400_dc2dc.h --- linux-2.4.21-rmk1/drivers/char/lh7a400_dc2dc.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/char/lh7a400_dc2dc.h Thu Oct 16 15:17:24 2003 @@ -0,0 +1,79 @@ +/* + * linux/drivers/char/dc2dc.h + * + * Copyright (C) 2002 Embedix. + * + * Original code write was authored by Craig Matsuura + * Parts of this code are from Sharp. + * This code falls under the license of the GPL. + * + * This modules is for controlling the DC - DC audio and backlighting. + * Jumps for backlighting and audio must be set correctly on the LH7a400 + * Board for this module to work properly. See Sharp LH7a400 Documentation + * for jumper settings. + */ +#ifndef __DC2DC_H +#define __DC2DC_H + +typedef volatile struct { + volatile unsigned int dcdccon; // Drive0 and Drive1 configuration register RW + volatile unsigned int res1[1]; // Reserved: Reading this register returns 0x00000001 RO + volatile unsigned int dcdcfreq; // Frequency configuration register RW + volatile unsigned int res2[12]; // Reserved: Reading this register returns 0x00000001 RO + volatile unsigned int res3[24]; // Reserved: Unpredictable values. RO (DO not write) + volatile unsigned int res4[22]; // Reserved: Reading this register returns 0x00000001 RO +} dc2dcRegs_t; + +extern dc2dcRegs_t *dc2dcregs; + +/********************************************************************** + * DC-DC Converter Register Bit Fields + *********************************************************************/ + +/********************************************************************** + * PMPCON Register Bit Fields + *********************************************************************/ +#define PMPCON_DRV0_DTYHI(n) _SBF(0, (_BITMASK(4) & (n))) +#define PMPCON_DRV0_DTYLO(n) _SBF(4, (_BITMASK(4) & (n))) +#define PMPCON_DRV1_DTYHI(n) _SBF(8, (_BITMASK(4) & (n))) +#define PMPCON_DRV1_DTYLO(n) _SBF(12, (_BITMASK(4) & (n))) + +/********************************************************************** + * PMPFREQ Register Bit Fields + *********************************************************************/ +#define PMPFREQ_DRV0_PREHI(n) _SBF(0, (_BITMASK(3) & (n))) +#define PMPFREQ_DRV0_PRELO(n) _SBF(4, (_BITMASK(3) & (n))) +#define PMPFREQ_DRV1_PREHI(n) _SBF(8, (_BITMASK(3) & (n))) +#define PMPFREQ_DRV1_PRELO(n) _SBF(12, (_BITMASK(3) & (n))) + +// IOCTL's +#define DC2DC_IOC_MAGIC 'd' +#define DC2DC_IOCRESET _IO(DC2DC_IOC_MAGIC, 0) +#define DC2DC_IOCSETBL _IOW(DC2DC_IOC_MAGIC, 1, int) +#define DC2DC_IOCSETSND _IOW(DC2DC_IOC_MAGIC, 2, int) +#define DC2DC_IOCBEEP _IO(DC2DC_IOC_MAGIC, 3) +#define DC2DC_IOCSETFREQ _IOW(DC2DC_IOC_MAGIC, 4, int) +#define DC2DC_IOCSETVOL _IOW(DC2DC_IOC_MAGIC, 5, int) +#define DC2DC_IOCGETFREQ _IOR(DC2DC_IOC_MAGIC, 6, int) +#define DC2DC_IOCGETVOL _IOR(DC2DC_IOC_MAGIC, 7, int) +#define DC2DC_IOCSTARTSND _IO(DC2DC_IOC_MAGIC, 8) +#define DC2DC_IOCSTOPSND _IO(DC2DC_IOC_MAGIC, 9) +#define DC2DC_IOC_MAXNR 9 +/* +#define PWM520_IOCBEEP _IO(PWM520_IOC_MAGIC, 0) +#define PWM520_IOCSTARTSND _IO(PWM520_IOC_MAGIC, 1) +#define PWM520_IOCSTOPSND _IO(PWM520_IOC_MAGIC, 2) +#define PWM520_IOCSETFREQ _IOW(PWM520_IOC_MAGIC, 3, int) +#define PWM520_IOCSETDCYCLE _IOW(PWM520_IOC_MAGIC, 4, int) +#define PWM520_IOCGETFREQ _IOR(PWM520_IOC_MAGIC, 5, int) +#define PWM520_IOCGETDCYCLE _IOR(PWM520_IOC_MAGIC, 6, int) + +#define PWM520_IOCRESET _IO(PWM520_IOC_MAGIC, 7) +#define PWM520_IOCSTOPPWM0 _IO(PWM520_IOC_MAGIC, 8) +#define PWM520_IOCINCREASEBL _IO(PWM520_IOC_MAGIC, 9) +#define PWM520_IOCDECREASEBL _IO(PWM520_IOC_MAGIC, 10) +#define PWM520_IOCSETBL _IOW(PWM520_IOC_MAGIC, 11, int) + +#define PWM520_IOC_MAXNR 11 +*/ +#endif diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/char/lh7a400_rtc.c linux-2.4.21-rmk1-lh7a400/drivers/char/lh7a400_rtc.c --- linux-2.4.21-rmk1/drivers/char/lh7a400_rtc.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/char/lh7a400_rtc.c Thu Oct 16 15:17:24 2003 @@ -0,0 +1,404 @@ +/* + * Real Time Clock interface for Linux on Sharp LH7a400 + * + * Copyright (c) 2002 Lineo + * + * Based on sa1100_rtc.c by Nils Faerber + * 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. + * + * 0.01 2002-07-08 Craig Matsuura (cmatsuura@lineo.com) + * - initial release + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lh7a400_rtc.h" + +#define DRIVER_VERSION "0.02" + +#define RTCR_MIE 0x00000001 /* Match Int Enable Bit */ + +/* Those are the bits from a classic RTC we want to mimic */ +#define RTC_IRQF 0x80 /* any of the following 3 is active */ +#define RTC_PF 0x40 +#define RTC_AF 0x20 +#define RTC_UF 0x10 + + +rtcRegs_t *rtcregs = (rtcRegs_t *) IO_ADDRESS(RTC_PHYS); + +static unsigned long rtc_status; +static unsigned long rtc_irq_data; +static unsigned long rtc_freq = 1024; + +static struct fasync_struct *rtc_async_queue; +static DECLARE_WAIT_QUEUE_HEAD(rtc_wait); + +extern spinlock_t rtc_lock; + +static const unsigned char days_in_mo[] = + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +#define is_leap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) + +/* + * Converts seconds since 1970-01-01 00:00:00 to Gregorian date. + */ +#define SECS_PER_MIN 60 +#define SECS_PER_HOUR (SECS_PER_MIN * SECS_PER_MIN) +#define SECS_PER_DAY (SECS_PER_HOUR * 24) +static unsigned int epoch=1970; +static void decodetime (unsigned long t, struct rtc_time *tval) +{ + long days, month, year, rem; + + days = t / SECS_PER_DAY; + rem = t % SECS_PER_DAY; + tval->tm_hour = rem / SECS_PER_HOUR; + rem %= SECS_PER_HOUR; + tval->tm_min = rem / SECS_PER_MIN; + tval->tm_sec = rem % SECS_PER_MIN; + tval->tm_wday = (4 + days) % 7; + +#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) + + year = epoch + days / 365; + days -= ((year - epoch) * 365 + + LEAPS_THRU_END_OF (year - 1) + - LEAPS_THRU_END_OF (epoch - 1)); + if (days < 0) { + year -= 1; + days += 365 + is_leap(year); + } + tval->tm_year = year - 1900; + tval->tm_yday = days + 1; + + month = 0; + if (days >= 31) { + days -= 31; + month++; + if (days >= (28 + is_leap(year))) { + days -= (28 + is_leap(year)); + month++; + while (days >= days_in_mo[month]) { + days -= days_in_mo[month]; + month++; + } + } + } + tval->tm_mon = month; + tval->tm_mday = days + 1; +} + + + +/* Converts Gregorian date to seconds since 1970-01-01 00:00:00. + * Assumes input in normal date format, i.e. 1980-12-31 23:59:59 + * => year=1980, mon=12, day=31, hour=23, min=59, sec=59. + * + * [For the Julian calendar (which was used in Russia before 1917, + * Britain & colonies before 1752, anywhere else before 1582, + * and is still in use by some communities) leave out the + * -year/100+year/400 terms, and add 10.] + * + * This algorithm was first published by Gauss (I think). + * + * WARNING: this function will overflow on 2106-02-07 06:28:16 on + * machines were long is 32-bit! (However, as time_t is signed, we + * will already get problems at other places on 2038-01-19 03:14:08) + */ +static inline unsigned long +encodetime (unsigned int year, unsigned int mon, + unsigned int day, unsigned int hour, + unsigned int min, unsigned int sec) +{ + if (0 >= (int) (mon -= 2)) { /* 1..12 -> 11,12,1..10 */ + mon += 12; /* Puts Feb last since it has leap day */ + year -= 1; + } + + return (((( + (unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) + year*365 - 719499 + )*24 + hour /* now have hours */ + )*60 + min /* now have minutes */ + )*60 + sec) ; /* finally seconds */ +} + + + + + +static void rtc_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + unsigned int rtsr = rtcregs->u.stat; + + /* Clear Interrupts */ + rtcregs->u.eoi = 1; + + if (rtsr) { + rtc_irq_data |= RTC_AF; + } + rtc_irq_data += 0x100; + + /* wake up waiting process */ + wake_up_interruptible(&rtc_wait); + kill_fasync (&rtc_async_queue, SIGIO, POLL_IN); +} + + +static int rtc_open(struct inode *inode, struct file *file) +{ + if (test_and_set_bit (1, &rtc_status)) + return -EBUSY; + rtc_irq_data = 0; + return 0; +} + +static int rtc_release(struct inode *inode, struct file *file) +{ + spin_lock_irq (&rtc_lock); + rtcregs->u.eoi = 1; + spin_unlock_irq (&rtc_lock); + rtc_status = 0; + return 0; +} + +static int rtc_fasync (int fd, struct file *filp, int on) +{ + return fasync_helper (fd, filp, on, &rtc_async_queue); +} + +static unsigned int rtc_poll(struct file *file, poll_table *wait) +{ + poll_wait (file, &rtc_wait, wait); + return (rtc_irq_data) ? 0 : POLLIN | POLLRDNORM; +} + +static loff_t rtc_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + +ssize_t rtc_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + unsigned long data; + ssize_t retval; + + if (count < sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&rtc_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + for (;;) { + spin_lock_irq (&rtc_lock); + data = rtc_irq_data; + if (data != 0) { + rtc_irq_data = 0; + break; + } + spin_unlock_irq (&rtc_lock); + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + schedule(); + } + + spin_unlock_irq (&rtc_lock); + + data -= 0x100; /* the first IRQ wasn't actually missed */ + + retval = put_user(data, (unsigned long *)buf); + if (!retval) + retval = sizeof(unsigned long); + +out: + set_current_state(TASK_RUNNING); + remove_wait_queue(&rtc_wait, &wait); + return retval; +} + +static int rtc_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + struct rtc_time tm, tm2; + + switch (cmd) { + case RTC_AIE_OFF: + spin_lock_irq(&rtc_lock); + rtcregs->u.stat = 0; + rtcregs->cr = ~RTCR_MIE; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + case RTC_AIE_ON: + spin_lock_irq(&rtc_lock); + rtcregs->u.stat = 0; + rtcregs->cr = RTCR_MIE; + rtc_irq_data = 0; + spin_unlock_irq(&rtc_lock); + return 0; + case RTC_UIE_OFF: + case RTC_UIE_ON: + case RTC_PIE_OFF: + case RTC_PIE_ON: + return -EINVAL; + + case RTC_ALM_READ: + decodetime (rtcregs->mr, &tm); + break; + case RTC_ALM_SET: + if (copy_from_user (&tm2, (struct rtc_time*)arg, sizeof (tm2))) + return -EFAULT; + decodetime (rtcregs->dr, &tm); + if ((unsigned)tm2.tm_hour < 24) + tm.tm_hour = tm2.tm_hour; + if ((unsigned)tm2.tm_min < 60) + tm.tm_min = tm2.tm_min; + if ((unsigned)tm2.tm_sec < 60) + tm.tm_sec = tm2.tm_sec; + rtcregs->mr = encodetime ( tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + return 0; + case RTC_RD_TIME: + decodetime (rtcregs->dr, &tm); + break; + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + return -EACCES; + if (copy_from_user (&tm, (struct rtc_time*)arg, sizeof (tm))) + return -EFAULT; + tm.tm_year += 1900; + if (tm.tm_year < 1970 || (unsigned)tm.tm_mon >= 12 || + tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] + + (tm.tm_mon == 1 && is_leap(tm.tm_year))) || + (unsigned)tm.tm_hour >= 24 || + (unsigned)tm.tm_min >= 60 || + (unsigned)tm.tm_sec >= 60) + return -EINVAL; + rtcregs->clr = encodetime ( tm.tm_year, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + return 0; + case RTC_IRQP_READ: + case RTC_IRQP_SET: + return -EINVAL; + case RTC_EPOCH_READ: + return put_user (epoch, (unsigned long *)arg); + default: + return -EINVAL; + } + return copy_to_user ((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0; +} + +static struct file_operations rtc_fops = { + owner: THIS_MODULE, + llseek: rtc_llseek, + read: rtc_read, + poll: rtc_poll, + ioctl: rtc_ioctl, + open: rtc_open, + release: rtc_release, + fasync: rtc_fasync, +}; + +static struct miscdevice lh7a400rtc_miscdev = { + RTC_MINOR, + "lh7a400rtc", + &rtc_fops +}; + +static int rtc_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + char *p = page; + int len; + struct rtc_time tm; + + decodetime (rtcregs->dr, &tm); + p += sprintf(p, "dr\t\t: %d\n" + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04d\n", + rtcregs->dr, + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + decodetime (rtcregs->mr, &tm); + p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n" + "alrm_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + p += sprintf(p, "update_IRQ\t: %s\n", (rtcregs->u.stat) ? "yes" : "no"); + p += sprintf(p, "periodic_freq\t: %ld\n", rtc_freq); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + return len; +} + +static int __init rtc_init(void) +{ + int ret; + + misc_register (&lh7a400rtc_miscdev); + create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL); + ret = request_irq (IRQ_RTC, rtc_interrupt, SA_INTERRUPT, "rtc 1Hz", NULL); + if (ret) { + printk (KERN_ERR "rtc: IRQ %d already in use.\n", IRQ_RTC); + goto IRQ_RTC_failed; + } + + printk (KERN_INFO "LH7A400 Real Time Clock driver v" DRIVER_VERSION "\n"); + + + /* Clear Interrupts */ + rtcregs->u.eoi = 1; + + + return 0; + +IRQ_RTC_failed: + remove_proc_entry ("driver/rtc", NULL); + misc_deregister (&lh7a400rtc_miscdev); + return ret; +} + +static void __exit rtc_exit(void) +{ + free_irq (IRQ_RTC, NULL); + remove_proc_entry ("driver/rtc", NULL); + misc_deregister (&lh7a400rtc_miscdev); +} + +module_init(rtc_init); +module_exit(rtc_exit); + +MODULE_AUTHOR("Craig Matsuura "); +MODULE_DESCRIPTION("Sharp LH7A400 Realtime Clock Driver (RTC)"); +EXPORT_NO_SYMBOLS; diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/char/lh7a400_rtc.h linux-2.4.21-rmk1-lh7a400/drivers/char/lh7a400_rtc.h --- linux-2.4.21-rmk1/drivers/char/lh7a400_rtc.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/char/lh7a400_rtc.h Thu Oct 16 15:17:24 2003 @@ -0,0 +1,61 @@ +/* + * linux/drivers/char/dc2dc.h + * + * Copyright (C) 2002 Embedix. + * + * Original code write was authored by Craig Matsuura + * Parts of this code are from Sharp. + * This code falls under the license of the GPL. + * + * This modules is for the RTC. + */ +#ifndef __LH7A400_RTC_H +#define __LH7A400_RTC_H + +/********************************************************************** + * Real Time Clock Module Register Structure + *********************************************************************/ +typedef volatile struct { + volatile unsigned int dr; /* Data */ + volatile unsigned int clr; /* Counter Load */ + volatile unsigned int mr; /* Match */ + volatile unsigned int reserved; + volatile union { + volatile unsigned int stat; /* Interrupt Status */ + volatile unsigned int eoi; /* Interrupt Clear */ + } u; + volatile unsigned int cr; /* Control */ +} rtcRegs_t; + +//extern rtcRegs_t *rtcregs; + + +/******************************************************************** + * Global Macros + *******************************************************************/ + +/* _BIT(n) sets the bit at position "n" + * _BIT(n) is intended to be used in "OR" and "AND" expressions: + * e.g., "(_BIT(3) | _BIT(7))". + */ +#undef _BIT +#define _BIT(n) (((unsigned int)(1)) << (n)) + +/********************************************************************** + * Real Time Clock Register Bit Fields + *********************************************************************/ + +/********************************************************************** + * RTC Status Register (rtcstat) Bit Fields + *********************************************************************/ +#define RTC_STAT_RTCINTR _BIT(0) + +/********************************************************************** + * RTC Control Register (cr) Bit Fields + *********************************************************************/ +#define RTC_CR_MIE _BIT(0) + +// IOCTL's +// See linux/rtc.h + +#endif diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/char/lh7x-keyb.c linux-2.4.21-rmk1-lh7a400/drivers/char/lh7x-keyb.c --- linux-2.4.21-rmk1/drivers/char/lh7x-keyb.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/char/lh7x-keyb.c Sun Feb 8 20:24:19 2004 @@ -0,0 +1,779 @@ +/* vi: set sw=4 ts=4 ai: */ + +/********************************************************************** +* drivers/char/lh7x-keyb.c +* +* Sharp LH7x EVB keyboard/button driver +* +* Based very loosely on: +* IDR keyboard/button driver, (C) 2002 Ross Wille +* Based on: +* Shannon IR keyboard driver, (C) 2001 Russ Dill +* +* Copyright (C) 2002 Lineo, Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License (GPL) version 2 +* as published by the Free Software Foundation. +* +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lh7x-keyb.h" + +#undef DEBUG +#undef VERBOSE +#define DRVNAME "lh7x-keyb" +#define LONG_DRVNAME "Sharp LH7x EVB Keyboard/Button driver" + +#include +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +#endif /* MODULE */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define PRESSED 1 +#define RELEASED 0 + +/********************************************************************** +**********************************************************************/ + +static cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; +static gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + +/********************************************************************** +**********************************************************************/ + + +/* +* WARNING: I recommend leaving IRQ_TRIGGERED_READS undefined. +* Not all of the Buttons cause dependable interrupts. +* On my board, buttons 10-14 worked good, but the others did not. +*/ +#undef IRQ_TRIGGERED_READS + +#define DEBOUNCE_BUTTONS +#define DEBOUNCE_BUTTON_USEC 3 + +#undef DEBOUNCE_KEYS +#define DEBOUNCE_KEY_USEC 3 + +typedef struct lh7x_btn_and_key_context lh7x_btn_and_key_context; +struct lh7x_btn_and_key_context { +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + uint16_t pbSwitchState; +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + uint16_t keyRow[N_KEY_COLUMNS]; +#endif /* CONFIG_KEV7X_KEYBOARD_DRIVER */ +}; + +typedef struct lh7x_kbd_context lh7x_kbd_context; +struct lh7x_kbd_context { + struct input_dev dev; + char name[128]; + int irq; + int open, open_failed; + spinlock_t hardware_lock; + int cleanup_flag; + unsigned int last_scan; + unsigned int last_scan_was_bogus; +#if defined(IRQ_TRIGGERED_READS) + int read_btns_and_keys; +#endif /* IRQ_TRIGGERED_READS */ + lh7x_btn_and_key_context bk_context; + lh7x_btn_and_key_context bk_context_last; +}; +static lh7x_kbd_context *global_kbd_context = NULL; + +/********************************************************************** +**********************************************************************/ + +static void lh7x_timer_irq_handler(void *data); +static DECLARE_WAIT_QUEUE_HEAD(cleanup_wait_queue); + +#if defined(IRQ_TRIGGERED_READS) +static void lh7x_btn_and_key_irq_handler(int irq, void *_kbd_context, + struct pt_regs *regs); +static int lh7x_init_irq(struct lh7x_kbd_context *kbd_context); +#endif /* IRQ_TRIGGERED_READS */ + +/********************************************************************** +**********************************************************************/ + +//static unsigned int last_btn_state = 0; + +static struct tq_struct lh7x_btn_task = { + routine: lh7x_timer_irq_handler, + data: NULL +}; + +#ifdef DEBUG +//static char btn_chars[] = "x^VP+-RpfrM"; +#endif /* DEBUG */ + +#define SCAN_BREAK 0xf0 + +/********************************************************************** +**********************************************************************/ + +#ifdef CONFIG_MAGIC_SYSRQ +static unsigned char lh7x_sysrq_xlate[128] = + "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */ + "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */ + "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */ + "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */ + "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */ + "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */ + "\r\000/"; /* 0x60 - 0x6f */ +#endif + +/* +* Translation of escaped scancodes to keycodes. +* This is now user-settable. +* The keycodes 1-88,96-111,119 are fairly standard, and +* should probably not be changed - changing might confuse X. +* X also interprets scancode 0x5d (KEY_Begin). +* +* For 1-88 keycode equals scancode. +*/ + +#define E0_KPENTER 96 +#define E0_RCTRL 97 +#define E0_KPSLASH 98 +#define E0_PRSCR 99 +#define E0_RALT 100 +#define E0_BREAK 101 /* (control-pause) */ +#define E0_HOME 102 +#define E0_UP 103 +#define E0_PGUP 104 +#define E0_LEFT 105 +#define E0_RIGHT 106 +#define E0_END 107 +#define E0_DOWN 108 +#define E0_PGDN 109 +#define E0_INS 110 +#define E0_DEL 111 + +#define E1_PAUSE 119 + +/* +* New microsoft keyboard is rumoured to have +* e0 5b (left window button), e0 5c (right window button), +* e0 5d (menu button). [or: LBANNER, RBANNER, RMENU] +* [or: Windows_L, Windows_R, TaskMan] +*/ +#define E0_MSLW 125 + +static unsigned char e0_keys[128] = { + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */ + 0, 0, 0, 0, 0, E0_RCTRL, 0, 0, /* 0x18-0x1f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */ + 0, 0, 0, 0, 0, 0, 0, E0_PRSCR, /* 0x30-0x37 */ + E0_RALT, 0, 0, 0, 0, 0, 0, 0, /* 0x38-0x3f */ + 0, 0, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */ + E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, 0, E0_END, /* 0x48-0x4f */ + E0_DOWN, E0_PGDN, 0, 0, 0, 0, 0, 0, /* 0x50-0x57 */ + 0, 0, 0, E0_MSLW, 0, 0, 0, 0, /* 0x58-0x5f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x68-0x6f */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */ + 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */ +}; + +#define vdprintk if (0) printk +#define dprintk if (0) printk + +static int lh7x_setkeycode(unsigned int scancode, unsigned int keycode) +{ + int sts = 0; + + vdprintk("ENTER: lh7x_setkeycode(s=0x%02X,k=0x%02X)\n", scancode, keycode); + if (scancode > 255 || keycode > 127) { + sts = -EINVAL; + } else { + e0_keys[scancode - 128] = keycode; + } + + return(sts); +} + +static int lh7x_getkeycode(unsigned int scancode) +{ + int keycode; + + vdprintk("ENTER: lh7x_getkeycode(s=0x%02X)\n", scancode); + keycode = scancode > 255 ? -EINVAL : e0_keys[scancode - 128]; + + return(keycode); +} + +/* #define KBD_REPORT_UNKN */ +static int lh7x_translate(unsigned char scancode, unsigned char *keycode, + char raw_mode) +{ + static int prev_scancode; + + vdprintk("ENTER: lh7x_translate(s=0x%02X,r=%d)\n", scancode, raw_mode); + /* special prefix scancodes.. */ + if (scancode == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + return 0; + } + + if (prev_scancode) { + /* + * usually it will be 0xe0, but a Pause key generates + * e1 1d 45 e1 9d c5 when pressed, and nothing when released + */ + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + return 0; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + *keycode = E1_PAUSE; + prev_scancode = 0; + } else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) + printk(KERN_INFO "keyboard: unknown e1 escape sequence\n"); +#endif + prev_scancode = 0; + return 0; + } + } else { + prev_scancode = 0; + + if (e0_keys[scancode]) { + *keycode = e0_keys[scancode]; + } else { +#ifdef KBD_REPORT_UNKN + if (!raw_mode) { + printk(KERN_INFO "keyboard: unknown scancode e0 %02x\n", + scancode); + } +#endif + return 0; + } + } + } else { + *keycode = scancode; + } + vdprintk("LEAVE: lh7x_translate(k=0x%02X)\n", *keycode); + + return 1; +} + +static char lh7x_unexpected_up(unsigned char keycode) +{ + vdprintk("ENTER: lh7x_unexpected_up(k=0x%02X)\n", keycode); + return(0200); +} + +/********************************************************************** +* Function: lh7x_read_btn_and_key_hardware() +* +* Purpose: +* FUNCTION_DESCRIPTION +**********************************************************************/ +static void lh7x_read_btn_and_key_hardware(lh7x_btn_and_key_context *bk_context) +{ +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + uint16_t button_state_1; +#if defined(DEBOUNCE_BUTTONS) + uint16_t button_state_2; +#endif /* DEBOUNCE_BUTTONS */ +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ + +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + int col; + uint16_t key_state_1; +#if defined(DEBOUNCE_KEYS) + uint16_t key_state_2; +#endif /* DEBOUNCE_KEYS */ +#endif /* LH7X_KEYBARD_DRIVER */ + +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + /* Read the buttons */ + /* while doing a little switch debounce dance */ + /* NOTE: Buttons are considered active with a value of 1 */ + button_state_1 = cpld->pbSwitchState & LH7X_BUTTON_MASK; +#if defined(DEBOUNCE_BUTTONS) + do { + button_state_2 = button_state_1; + udelay(DEBOUNCE_BUTTON_USEC); + button_state_1 = cpld->pbSwitchState & LH7X_BUTTON_MASK; + } while (button_state_1 != button_state_2); +#endif /* DEBOUNCE_BUTTONS */ + bk_context->pbSwitchState = button_state_1; +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ + +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + /* Read the keyboard */ + for (col = 0; col < N_KEY_COLUMNS; col++) { + /* Enable the col we want to read */ + gpio->kscan = 1 << col; + /* Read the col we just setup for (row values) */ + /* while doing a little switch debounce dance */ + /* NOTE: Keys are considered active with a value of 0 */ + /* SO - we invert the values */ + // JMG - key_state_1 = (~(cpld->u2.kpdRowSense)) & LH7X_KEY_MASK; + key_state_1 = cpld->u2.kpdRowSense & LH7X_KEY_MASK; +#if defined(DEBOUNCE_KEYS) + do { + key_state_2 = key_state_1; + udelay(DEBOUNCE_KEY_USEC); + // JMG - key_state_1 = (~(cpld->u2.kpdRowSense)) & LH7X_KEY_MASK; + key_state_1 = cpld->u2.kpdRowSense & LH7X_KEY_MASK; + } while (key_state_1 != key_state_2); +#endif /* DEBOUNCE_KEYS */ + bk_context->keyRow[col] = key_state_1; + } +#endif /* LH7X_KEYBARD_DRIVER */ + + return; +} /* lh7x_read_btn_and_key_hardware() */ + +#if defined(IRQ_TRIGGERED_READS) +/********************************************************************** +* Function: enable_lh7x_btn_and_key_irq() +**********************************************************************/ +static void enable_lh7x_btn_and_key_irq(void) +{ +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + /* Enable the button IRQ causing events */ + cpld->u2.pbIntMask = LH7X_BUTTON_MASK; +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ + +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + /* Enable the keyboard IRQ causing events */ + /* ? HOW ? */ +#endif /* CONFIG_KEV7X_KEYBOARD_DRIVER */ + + return; +} /* enable_lh7x_btn_and_key_irq() */ +#endif /* IRQ_TRIGGERED_READS */ + +#if defined(IRQ_TRIGGERED_READS) +/********************************************************************** +* Function: disable_lh7x_btn_and_key_irq() +**********************************************************************/ +static void disable_lh7x_btn_and_key_irq(void) +{ +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + /* Disable the button IRQ causing events */ + cpld->u2.pbIntMask = 0; +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ + +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + /* Disable the keyboard IRQ causing events */ + /* ? HOW ? */ +#endif /* CONFIG_KEV7X_KEYBOARD_DRIVER */ + + return; +} /* enable_lh7x_btn_and_key_irq() */ +#endif /* IRQ_TRIGGERED_READS */ + +#if defined(IRQ_TRIGGERED_READS) +/********************************************************************** +* Function: lh7x_btn_and_key_irq_handler() +* +* Purpose: +* FUNCTION_DESCRIPTION +**********************************************************************/ +static void lh7x_btn_and_key_irq_handler(int irq, void *_kbd_context, + struct pt_regs *regs) +{ + lh7x_kbd_context *kbd_context = (struct lh7x_kbd_context *)_kbd_context; + + // Too noisy --- vdprintk("ENTER: lh7x_btn_and_key_irq_handler()\n"); + + /* + * NOTE: Processing of keys and buttons will be started when the + * "read_btns_and_keys" variable goes to non-zero. It will be + * halted when it goes to zero. + */ + /* Check if this is a button generated interrupt */ + if (cpld->pbSwitchState & LH7X_BUTTON_MASK) { + disable_lh7x_btn_and_key_irq(); + kbd_context->read_btns_and_keys = 1; + } + + // Too noisy --- vdprintk("LEAVE: lh7x_btn_and_key_irq_handler()\n"); + + return; +} /* lh7x_btn_and_key_irq_handler() */ +#endif /* IRQ_TRIGGERED_READS */ + +/********************************************************************** +* Function: lh7x_timer_irq_handler() +* +* Purpose: +* FUNCTION_DESCRIPTION +**********************************************************************/ +static void lh7x_timer_irq_handler(void *data) +{ + struct lh7x_kbd_context *kbd_context = (struct lh7x_kbd_context *)data; +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) || defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + int lst, cur; + int lst_b, cur_b; + int bit; + int bit_index; +#endif /* CONFIG_KEV7X_BUTTON_DRIVER || CONFIG_KEV7X_KEYBOARD_DRIVER */ +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + int col; +#endif /* LH7X_KEYBARD_DRIVER */ + + // Too noisy // vdprintk("ENTER: lh7x_timer_irq_handler()\n"); + +#if defined(IRQ_TRIGGERED_READS) + if ( ! kbd_context->read_btns_and_keys) { + goto exit_timer_irq_handler; + } +#endif /* IRQ_TRIGGERED_READS */ + + /* Read the keys and buttons */ + /* NOTE: This function attempts to do debouncing */ + lh7x_read_btn_and_key_hardware(&kbd_context->bk_context); + +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + lst = kbd_context->bk_context_last.pbSwitchState; + cur = kbd_context->bk_context.pbSwitchState; + if (((cur != 0) || (lst != 0)) && (cur != lst)) { + vdprintk("BTN: LST:0x%04X, CUR:0x%04X\n", lst, cur); + /* We have detected button activity */ + /* Determine down/up actions */ + /* by walking through all the buttons individually */ + bit_index = 0; + for (bit = 1; bit & LH7X_BUTTON_MASK; bit <<= 1) { + uint16_t btn; + btn = lh7x_button_table[bit_index]; + bit_index++; + if (btn != KEY_RESERVED) { + lst_b = lst & bit; + cur_b = cur & bit; + if (lst_b != cur_b) { + if (lst_b) { + /* Button was released */ + dprintk("BTN: RELEASED: 0x%02X\n", bit); + input_report_key(&kbd_context->dev, btn, RELEASED); + } else { + /* Button was pressed */ + dprintk("BTN: PRESSED: 0x%02X\n", bit); + input_report_key(&kbd_context->dev, btn, PRESSED); + } + } + } + } + kbd_context->bk_context_last.pbSwitchState = cur; + } +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ + +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + for (col = 0; col < N_KEY_COLUMNS; col++) { + lst = kbd_context->bk_context_last.keyRow[col]; + cur = kbd_context->bk_context.keyRow[col]; + if (((cur != 0) || (lst != 0)) && (cur != lst)) { + vdprintk("KEY: col:%d, LST:0x%04X, CUR:0x%04X\n", col, lst, cur); + /* We have detected keyboard activity */ + /* Determine down/up actions */ + /* by walking through all the keys individually */ + bit_index = 0; + for (bit = 1; bit & LH7X_KEY_MASK; bit <<= 1) { + uint16_t key; + key = lh7x_key_table[col][bit_index]; + bit_index++; + if (key != KEY_RESERVED) { + lst_b = lst & bit; + cur_b = cur & bit; + if (lst_b != cur_b) { + if (lst_b) { + /* Key was released */ + dprintk("KEY: RELEASED: %d:0x%04X\n", col, bit); + input_report_key(&kbd_context->dev, key, RELEASED); + } else { + /* Key was pressed */ + dprintk("KEY: PRESSED: %d:0x%04X\n", col, bit); + input_report_key(&kbd_context->dev, key, PRESSED); + } + } + } + } + kbd_context->bk_context_last.keyRow[col] = cur; + } + } +#endif /* LH7X_KEYBARD_DRIVER */ + +#if defined(IRQ_TRIGGERED_READS) + /* + * NOTE: Processing of keys and buttons will be halted when the + * "read_btns_and_keys" variable goes to zero. It will be + * restarted when a button or key event (interrupt) occurs. + */ + kbd_context->read_btns_and_keys = 0; +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + kbd_context->read_btns_and_keys += + kbd_context->bk_context_last.pbSwitchState + + kbd_context->bk_context.pbSwitchState; +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + for (col = 0; col < N_KEY_COLUMNS; col++) { + kbd_context->read_btns_and_keys += + kbd_context->bk_context_last.keyRow[col] + + kbd_context->bk_context.keyRow[col]; + } +#endif /* LH7X_KEYBARD_DRIVER */ + + if ( ! kbd_context->read_btns_and_keys) { + enable_lh7x_btn_and_key_irq(); + } +#endif /* IRQ_TRIGGERED_READS */ + +exit_timer_irq_handler: + + // If cleanup wants us to die + if (kbd_context->cleanup_flag) { + wake_up(&cleanup_wait_queue); // now cleanup_module can return + } + else { + queue_task(&lh7x_btn_task, &tq_timer); // put us back in the task queue + } + + // too noisy // vdprintk("LEAVE: lh7x_timer_irq_handler()\n"); + + return; +} /* lh7x_timer_irq_handler() */ + +#if defined(IRQ_TRIGGERED_READS) +/********************************************************************** +* Function: lh7x_init_irq() +* +* Purpose: +* FUNCTION_DESCRIPTION +**********************************************************************/ +static int lh7x_init_irq(struct lh7x_kbd_context *kbd_context) +{ + int retval = 0; + + vdprintk("ENTER: lh7x_init_irq()\n"); + + kbd_context->irq = IRQ_CPLD; + retval = request_irq(kbd_context->irq, lh7x_btn_and_key_irq_handler, + SA_SHIRQ | SA_SAMPLE_RANDOM, DRVNAME, kbd_context); + if (retval < 0) { + printk(KERN_ERR "IRQ %d already in use.\n", kbd_context->irq); + return retval; + } + +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + /* Enable the button IRQ causing events */ + enable_lh7x_btn_and_key_irq(); +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ + + vdprintk("LEAVE: lh7x_init_irq()\n"); + + return 0; +} /* lh7x_init_irq() */ +#endif /* IRQ_TRIGGERED_READS */ + +/********************************************************************** +* Function: lh7x_kbd_open() +* +* Purpose: +* FUNCTION_DESCRIPTION +**********************************************************************/ +static int lh7x_kbd_open(struct input_dev *dev) +{ + struct lh7x_kbd_context *kbd_context = dev->private; + + vdprintk("ENTER: lh7x_kbd_open()\n"); + + if (kbd_context->open++) return 0; + +#if defined(IRQ_TRIGGERED_READS) + { + int retval; + + retval = lh7x_init_irq(kbd_context); + if (retval < 0) { + kbd_context->open_failed = 1; + return retval; + } + + enable_irq(kbd_context->irq); + } +#endif /* IRQ_TRIGGERED_READS */ + + lh7x_btn_task.data = kbd_context; + queue_task(&lh7x_btn_task, &tq_timer); + + vdprintk("LEAVE: lh7x_kbd_open()\n"); + + return 0; +} /* lh7x_kbd_open() */ + +/********************************************************************** +* Function: lh7x_kbd_close() +* +* Purpose: +* FUNCTION_DESCRIPTION +**********************************************************************/ +static void lh7x_kbd_close(struct input_dev *dev) +{ + struct lh7x_kbd_context *kbd_context = dev->private; + int flags; + + vdprintk("ENTER: lh7x_kbd_close()\n"); + + if ( ! --kbd_context->open && ! kbd_context->open_failed ) { + spin_lock_irqsave(&kbd_context->hardware_lock, flags); + + disable_irq(kbd_context->irq); + free_irq(kbd_context->irq, kbd_context); + + spin_unlock_irqrestore(&kbd_context->hardware_lock, flags); + + kbd_context->cleanup_flag = 1; + sleep_on(&cleanup_wait_queue); + } + + vdprintk("LEAVE: lh7x_kbd_close()\n"); + + return; +} /* lh7x_kbd_close() */ + +/********************************************************************** +* Function: lh7x_kbd_init() +* +* Purpose: +* FUNCTION_DESCRIPTION +**********************************************************************/ +static int __init lh7x_kbd_init(void) +{ + struct lh7x_kbd_context *kbd_context; +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) || defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + int row; +#endif /* CONFIG_KEV7X_BUTTON_DRIVER || CONFIG_KEV7X_KEYBOARD_DRIVER */ +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + int col; +#endif /* LH7X_KEYBARD_DRIVER */ + + vdprintk("ENTER: lh7x_kbd_init()\n"); + + global_kbd_context = kmalloc(sizeof(struct lh7x_kbd_context), GFP_KERNEL); + kbd_context = global_kbd_context; + if ( ! kbd_context) return -ENOMEM; + + /* Initialize the keyboard and button/key context structure(s) */ + memset(kbd_context, 0, sizeof(struct lh7x_kbd_context)); + + // kbd_context->cleanup_flag = 0; // Done above + kbd_context->hardware_lock = SPIN_LOCK_UNLOCKED; + strcpy(kbd_context->name, LONG_DRVNAME); + kbd_context->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REP); + kbd_context->dev.private = kbd_context; + kbd_context->dev.open = lh7x_kbd_open; + kbd_context->dev.close = lh7x_kbd_close; + kbd_context->dev.name = kbd_context->name; + kbd_context->dev.idbus = BUS_RS232; /* JMG --- ??? */ + + k_setkeycode = lh7x_setkeycode; + k_getkeycode = lh7x_getkeycode; + k_translate = lh7x_translate; + k_unexpected_up = lh7x_unexpected_up; +#ifdef CONFIG_MAGIC_SYSRQ + k_sysrq_key = 0x54; + k_sysrq_xlate = lh7x_sysrq_xlate; +#endif /* CONFIG_MAGIC_SYSRQ */ + + input_register_device(&kbd_context->dev); + +#if defined(CONFIG_KEV7X_BUTTON_DRIVER) + /* Make the buttons we are dealing with active in the kernel */ + for (row = 0; row < N_BUTTON_ROWS; row++) { + if (lh7x_button_table[row] != KEY_RESERVED) { + set_bit(lh7x_button_table[row], kbd_context->dev.keybit); + } + } +#endif /* CONFIG_KEV7X_BUTTON_DRIVER */ + +#if defined(CONFIG_KEV7X_KEYBOARD_DRIVER) + /* Make the keys we are dealing with active in the kernel */ + for (col = 0; col < N_KEY_COLUMNS; col++) { + for (row = 0; row < N_KEY_ROWS; row++) { + if (lh7x_key_table[col][row] != KEY_RESERVED) { + set_bit(lh7x_key_table[col][row], kbd_context->dev.keybit); + } + } + } +#endif /* LH7X_KEYBARD_DRIVER */ + + printk(KERN_INFO "%s installed\n", LONG_DRVNAME); + + vdprintk("LEAVE: lh7x_kbd_init()\n"); + + return 0; +} /* lh7x_kbd_init() */ + +/********************************************************************** +* Function: lh7x_kbd_exit() +* +* Purpose: +* FUNCTION_DESCRIPTION +**********************************************************************/ +static void __exit lh7x_kbd_exit(void) +{ + vdprintk("ENTER: lh7x_kbd_exit()\n"); + + global_kbd_context->cleanup_flag = 1; + + sleep_on(&cleanup_wait_queue); + + input_unregister_device(&global_kbd_context->dev); + + kfree(global_kbd_context); + + printk(KERN_INFO "%s unloaded\n", LONG_DRVNAME); + + vdprintk("LEAVE: lh7x_kbd_exit()\n"); + + return; +} /* lh7x_kbd_exit() */ + +module_init(lh7x_kbd_init); +module_exit(lh7x_kbd_exit); + +MODULE_AUTHOR("Jim Gleason / Lineo, Inc."); +MODULE_DESCRIPTION(LONG_DRVNAME); +MODULE_LICENSE("Copyright (c) 2002 Lineo, Inc."); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/char/lh7x-keyb.h linux-2.4.21-rmk1-lh7a400/drivers/char/lh7x-keyb.h --- linux-2.4.21-rmk1/drivers/char/lh7x-keyb.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/char/lh7x-keyb.h Thu Oct 16 15:14:45 2003 @@ -0,0 +1,375 @@ +/* vi: set sw=4 ts=4 ai: */ + +/********************************************************************** +* drivers/char/lh7x-keyb.h +* +* Sharp LH7x EVB keyboard/buttons driver +* +* Copyright (C) 2002 Lineo, Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License (GPL) version 2 +* as published by the Free Software Foundation. +* +* Based on LH7A400_evb_keyboard_driver.h +* COPYRIGHT (C) 2002 SHARP MICROELECTRONICS OF THE AMERICAS, INC. +* CAMAS, WA +* +**********************************************************************/ + +#ifndef LH7X_KEYB_H +#define LH7X_KEYB_H + + +#define LH7X_BTN_10 _BIT(0) +#define LH7X_BTN_11 _BIT(1) +#define LH7X_BTN_12 _BIT(2) +#define LH7X_BTN_13 _BIT(3) +#define LH7X_BTN_14 _BIT(4) +#define LH7X_BTN_15 _BIT(5) +#define LH7X_BTN_16 _BIT(6) +#define LH7X_BTN_17 _BIT(7) + +#define N_BUTTON_ROWS 8 +#define LH7X_BUTTON_MASK 0xFF + +static uint16_t lh7x_button_table[N_BUTTON_ROWS] = +{ + KEY_F1, /* bit 0 --- LH7X_BTN_10 */ + KEY_F2, /* bit 1 --- LH7X_BTN_11 */ + KEY_F3, /* bit 2 --- LH7X_BTN_12 */ + KEY_F4, /* bit 3 --- LH7X_BTN_13 */ + KEY_F5, /* bit 4 --- LH7X_BTN_14 */ + KEY_F6, /* bit 5 --- LH7X_BTN_15 */ + KEY_F7, /* bit 6 --- LH7X_BTN_16 */ + KEY_F8 /* bit 7 --- LH7X_BTN_17 */ +}; + + +#define N_KEY_ROWS 16 +#define LH7X_KEY_MASK 0xFFFF + +/*****************************/ +/* control key row positions */ +/*****************************/ + +/* column 0 */ +#define KB_ALT_KEY _BIT(0) +#define KB_CTRL_KEY _BIT(3) +#define KB_FN_KEY _BIT(4) + +/* column 1 */ +#define KB_LEFT_SHIFT_KEY _BIT(2) +#define KB_RIGHT_SHIFT_KEY _BIT(12) + +/*********************/ +/* key row positions */ +/*********************/ + +/* column 0 */ +#define KB_GRAVE_KEY _BIT(1) +#define KB_ESC_KEY _BIT(5) +#define KB_ONE_KEY _BIT(6) +#define KB_TWO_KEY _BIT(7) +#define KB_NINE_KEY _BIT(8) +#define KB_ZERO_KEY _BIT(9) +#define KB_MINUS_KEY _BIT(10) +#define KB_EQUALS_KEY _BIT(11) +#define KB_BACKSPACE_KEY _BIT(13) + +/* Account for column 0 control key row positions also */ +static uint16_t lh7x_key_row_0[N_KEY_ROWS] = +{ + KEY_LEFTALT, /* bit 0 --- KB_ALT_KEY */ + KEY_GRAVE, /* bit 1 --- KB_GRAVE_KEY */ + KEY_RESERVED, /* bit 2 --- */ + KEY_LEFTCTRL, /* bit 3 --- KB_CTRL_KEY */ + KEY_LEFTMETA, /* bit 4 --- KB_FN_KEY */ /* JMG ? */ + KEY_ESC, /* bit 5 --- KB_ESC_KEY */ + KEY_1, /* bit 6 --- KB_ONE_KEY */ + KEY_2, /* bit 7 --- KB_TWO_KEY */ + KEY_9, /* bit 8 --- KB_NINE_KEY */ + KEY_0, /* bit 9 --- KB_ZERO_KEY */ + KEY_MINUS, /* bit 10 -- KB_MINUS_KEY */ + KEY_EQUAL, /* bit 11 -- KB_EQUALS_KEY */ + KEY_RESERVED, /* bit 12 -- */ + KEY_BACKSPACE, /* bit 13 -- KB_BACKSPACE_KEY */ + KEY_RESERVED, /* bit 14 -- */ + KEY_RESERVED /* bit 15 -- */ +}; + +/* column 1 */ +#define KB_BACKSLASH_KEY _BIT(1) +#define KB_DEL_KEY _BIT(5) +#define KB_T_KEY _BIT(7) +#define KB_Y_KEY _BIT(8) +#define KB_U_KEY _BIT(9) +#define KB_I_KEY _BIT(10) +#define KB_ENTER_KEY _BIT(11) +#define KB_DOWN_KEY _BIT(13) + +/* Account for column 1 control key row positions also */ +static uint16_t lh7x_key_row_1[N_KEY_ROWS] = +{ + KEY_RESERVED, /* bit 0 --- */ + KEY_BACKSLASH, /* bit 1 --- KB_BACKSLASH_KEY */ + KEY_LEFTSHIFT, /* bit 2 --- KB_LEFT_SHIFT_KEY */ + KEY_RESERVED, /* bit 3 --- */ + KEY_RESERVED, /* bit 4 --- */ + KEY_DELETE, /* bit 5 --- KB_DEL_KEY */ + KEY_RESERVED, /* bit 6 --- */ + KEY_T, /* bit 7 --- KB_T_KEY */ + KEY_Y, /* bit 8 --- KB_Y_KEY */ + KEY_U, /* bit 9 --- KB_U_KEY */ + KEY_I, /* bit 10 -- KB_I_KEY */ + KEY_ENTER, /* bit 11 -- KB_ENTER_KEY */ + KEY_RIGHTSHIFT, /* bit 12 -- KB_RIGHT_SHIFT_KEY */ + KEY_DOWN, /* bit 13 -- KB_DOWN_KEY */ + KEY_RESERVED, /* bit 14 -- */ + KEY_RESERVED /* bit 15 -- */ +}; + +/* column 2 */ +#define KB_TAB_KEY _BIT(1) +#define KB_Q_KEY _BIT(5) +#define KB_W_KEY _BIT(6) +#define KB_E_KEY _BIT(7) +#define KB_R_KEY _BIT(8) +#define KB_O_KEY _BIT(9) +#define KB_P_KEY _BIT(10) +#define KB_LBRACKET_KEY _BIT(11) +#define KB_RBRACKET_KEY _BIT(13) + +static uint16_t lh7x_key_row_2[N_KEY_ROWS] = +{ + KEY_RESERVED, /* bit 0 --- */ + KEY_TAB, /* bit 1 --- KB_TAB_KEY */ + KEY_RESERVED, /* bit 2 --- */ + KEY_RESERVED, /* bit 3 --- */ + KEY_RESERVED, /* bit 4 --- */ + KEY_Q, /* bit 5 --- KB_Q_KEY */ + KEY_W, /* bit 6 --- KB_W_KEY */ + KEY_E, /* bit 7 --- KB_E_KEY */ + KEY_R, /* bit 8 --- KB_R_KEY */ + KEY_O, /* bit 9 --- KB_O_KEY */ + KEY_P, /* bit 10 -- KB_P_KEY */ + KEY_LEFTBRACE, /* bit 11 -- KB_LBRACKET_KEY */ /* JMG ? */ + KEY_RESERVED, /* bit 12 -- */ + KEY_RIGHTBRACE, /* bit 13 -- KB_RBRACKET_KEY */ /* JMG ? */ + KEY_RESERVED, /* bit 14 -- */ + KEY_RESERVED /* bit 15 -- */ +}; + +/*column 3 */ +#define KB_Z_KEY _BIT(1) +#define KB_CAPS_LOCK_KEY _BIT(5) +#define KB_K_KEY _BIT(8) +#define KB_L_KEY _BIT(9) +#define KB_SEMICOLON_KEY _BIT(10) +#define KB_APOSTROPHE_KEY _BIT(11) +#define KB_UP_KEY _BIT(13) + +static uint16_t lh7x_key_row_3[N_KEY_ROWS] = +{ + KEY_RESERVED, /* bit 0 --- */ + KEY_Z, /* bit 1 --- KB_Z_KEY */ + KEY_RESERVED, /* bit 2 --- */ + KEY_RESERVED, /* bit 3 --- */ + KEY_RESERVED, /* bit 4 --- */ + KEY_CAPSLOCK, /* bit 5 --- KB_CAPS_LOCK_KEY */ + KEY_RESERVED, /* bit 6 --- */ + KEY_RESERVED, /* bit 7 --- */ + KEY_K, /* bit 8 --- KB_K_KEY */ + KEY_L, /* bit 9 --- KB_L_KEY */ + KEY_SEMICOLON, /* bit 10 -- KB_SEMICOLON_KEY */ + KEY_APOSTROPHE, /* bit 11 -- KB_APOSTROPHE_KEY */ + KEY_RESERVED, /* bit 12 -- */ + KEY_UP, /* bit 13 -- KB_UP_KEY */ + KEY_RESERVED, /* bit 14 -- */ + KEY_RESERVED /* bit 15 -- */ +}; + +/* column 4 */ +#define KB_A_KEY _BIT(1) +#define KB_S_KEY _BIT(5) +#define KB_D_KEY _BIT(6) +#define KB_F_KEY _BIT(7) +#define KB_G_KEY _BIT(8) +#define KB_H_KEY _BIT(9) +#define KB_J_KEY _BIT(10) +#define KB_SLASH_KEY _BIT(11) +#define KB_LEFT_KEY _BIT(13) + +static uint16_t lh7x_key_row_4[N_KEY_ROWS] = +{ + KEY_RESERVED, /* bit 0 --- */ + KEY_A, /* bit 1 --- KB_A_KEY */ + KEY_RESERVED, /* bit 2 --- */ + KEY_RESERVED, /* bit 3 --- */ + KEY_RESERVED, /* bit 4 --- */ + KEY_S, /* bit 5 --- KB_S_KEY */ + KEY_D, /* bit 6 --- KB_D_KEY */ + KEY_F, /* bit 7 --- KB_F_KEY */ + KEY_G, /* bit 8 --- KB_G_KEY */ + KEY_H, /* bit 9 --- KB_H_KEY */ + KEY_J, /* bit 10 -- KB_J_KEY */ + KEY_SLASH, /* bit 11 -- KB_SLASH_KEY */ + KEY_RESERVED, /* bit 12 -- */ + KEY_LEFT, /* bit 13 -- KB_LEFT_KEY */ + KEY_RESERVED, /* bit 14 -- */ + KEY_RESERVED /* bit 15 -- */ +}; + +/* column 5 */ +#define KB_X_KEY _BIT(1) +#define KB_C_KEY _BIT(5) +#define KB_V_KEY _BIT(6) +#define KB_B_KEY _BIT(7) +#define KB_N_KEY _BIT(8) +#define KB_M_KEY _BIT(9) +#define KB_COMMA_KEY _BIT(10) +#define KB_PERIOD_KEY _BIT(11) +#define KB_SPACE_KEY _BIT(13) + +static uint16_t lh7x_key_row_5[N_KEY_ROWS] = +{ + KEY_RESERVED, /* bit 0 --- */ + KEY_X, /* bit 1 --- KB_X_KEY */ + KEY_RESERVED, /* bit 2 --- */ + KEY_RESERVED, /* bit 3 --- */ + KEY_RESERVED, /* bit 4 --- */ + KEY_C, /* bit 5 --- KB_C_KEY */ + KEY_V, /* bit 6 --- KB_V_KEY */ + KEY_B, /* bit 7 --- KB_B_KEY */ + KEY_N, /* bit 8 --- KB_N_KEY */ + KEY_M, /* bit 9 --- KB_M_KEY */ + KEY_COMMA, /* bit 10 -- KB_COMMA_KEY */ + KEY_DOT, /* bit 11 -- KB_PERIOD_KEY */ + KEY_RESERVED, /* bit 12 -- */ + KEY_SPACE, /* bit 13 -- KB_SPACE_KEY */ + KEY_RESERVED, /* bit 14 -- */ + KEY_RESERVED /* bit 15 -- */ +}; + +/* column 6 */ +#define KB_THREE_KEY _BIT(5) +#define KB_FOUR_KEY _BIT(6) +#define KB_FIVE_KEY _BIT(7) +#define KB_SIX_KEY _BIT(8) +#define KB_SEVEN_KEY _BIT(9) +#define KB_EIGHT_KEY _BIT(10) +#define KB_PROG_KEY _BIT(11) +#define KB_RIGHT_KEY _BIT(13) + +static uint16_t lh7x_key_row_6[N_KEY_ROWS] = +{ + KEY_RESERVED, /* bit 0 --- */ + KEY_RESERVED, /* bit 1 --- */ + KEY_RESERVED, /* bit 2 --- */ + KEY_RESERVED, /* bit 3 --- */ + KEY_RESERVED, /* bit 4 --- */ + KEY_3, /* bit 5 --- KB_THREE_KEY */ + KEY_4, /* bit 6 --- KB_FOUR_KEY */ + KEY_5, /* bit 7 --- KB_FIVE_KEY */ + KEY_6, /* bit 8 --- KB_SIX_KEY */ + KEY_7, /* bit 9 --- KB_SEVEN_KEY */ + KEY_8, /* bit 10 -- KB_EIGHT_KEY */ + KEY_PROG1, /* bit 11 -- KB_PROG_KEY */ + KEY_RESERVED, /* bit 12 -- */ + KEY_RIGHT, /* bit 13 -- KB_RIGHT_KEY */ + KEY_RESERVED, /* bit 14 -- */ + KEY_RESERVED /* bit 15 -- */ +}; + +static uint16_t lh7x_key_row_7[N_KEY_ROWS] = +{ + KEY_RESERVED, /* bit 0 --- */ + KEY_RESERVED, /* bit 1 --- */ + KEY_RESERVED, /* bit 2 --- */ + KEY_RESERVED, /* bit 3 --- */ + KEY_RESERVED, /* bit 4 --- */ + KEY_RESERVED, /* bit 5 --- */ + KEY_RESERVED, /* bit 6 --- */ + KEY_RESERVED, /* bit 7 --- */ + KEY_RESERVED, /* bit 8 --- */ + KEY_RESERVED, /* bit 9 --- */ + KEY_RESERVED, /* bit 10 -- */ + KEY_RESERVED, /* bit 11 -- */ + KEY_RESERVED, /* bit 12 -- */ + KEY_RESERVED, /* bit 13 -- */ + KEY_RESERVED, /* bit 14 -- */ + KEY_RESERVED /* bit 15 -- */ +}; + +#define N_KEY_COLUMNS 8 +static uint16_t *lh7x_key_table[N_KEY_COLUMNS] = +{ + lh7x_key_row_0, /* Column 0 */ + lh7x_key_row_1, /* Column 1 */ + lh7x_key_row_2, /* Column 2 */ + lh7x_key_row_3, /* Column 3 */ + lh7x_key_row_4, /* Column 4 */ + lh7x_key_row_5, /* Column 5 */ + lh7x_key_row_6, /* Column 6 */ + lh7x_key_row_7 /* Column 7 */ +}; + +#endif /* LH7X_KEYB_H */ + + + +#ifdef SHARP_STUFF_NOT_IN_USE + +/* key values (ASCII) */ +#define KB_TAB '\t' +#define KB_ESC '\x1b' +#define KB_BREAK '\x03' /* control-C */ +#define KB_BACKSPACE '\x08' +#define KB_DEL '\x7f' +#define KB_SCRLK '\x11' /* x-on */ +#define KB_ENTER '\x0d' + +/* key values (arbitrary) */ +#define KB_NUMLOCK '\x80' +#define KB_BACKTAB '\x81' +#define KB_PAUSE '\x82' +#define KB_CAPSLOCK '\x83' +#define KB_PRTSCR '\x84' +#define KB_DOWN '\x85' +#define KB_UP '\x86' +#define KB_INS '\x87' +#define KB_PAGE_UP '\x88' +#define KB_PAGE_DOWN '\x89' +#define KB_LEFT '\x8a' +#define KB_HOME '\x8b' +#define KB_RIGHT '\x8c' +#define KB_END '\x8d' +#define KB_PROG '\x8e' +#define KB_SYSREQ '\x8f' +#define KB_PF1 '\x90' +#define KB_PF2 '\x91' +#define KB_PF3 '\x92' +#define KB_PF4 '\x93' +#define KB_PF5 '\x94' +#define KB_PF6 '\x95' +#define KB_PF7 '\x96' +#define KB_PF8 '\x97' +#define KB_PF9 '\x98' +#define KB_PF10 '\x99' + +typedef union +{ + struct + { + UNS_32 c:8; + UNS_32 fn:1; + UNS_32 left_shift:1; + UNS_32 right_shift:1; + UNS_32 ctrl:1; + UNS_32 alt:1; + } decoded; + UNS_32 raw; +} KEYVAL; + +#endif /* SHARP_STUFF_NOT_IN_USE */ + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/ide/ide-disk.c linux-2.4.21-rmk1-lh7a400/drivers/ide/ide-disk.c --- linux-2.4.21-rmk1/drivers/ide/ide-disk.c Fri Jun 13 10:51:33 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/ide/ide-disk.c Sun Feb 8 17:33:59 2004 @@ -734,6 +734,9 @@ if((cf & 0xC0) == 0x40 && (cf & 0x30) != 0) drive->wcache = 1; } +/*XXXbrad@heeltoe.com*/ +printk("idedisk_open() wcache %d\n", drive->wcache); +drive->wcache = 0; return 0; } @@ -741,6 +744,7 @@ static int ide_cacheflush_p(ide_drive_t *drive) { +printk("ide_cacheflush_p() wcache %d\n", drive->wcache); if(drive->wcache) { if (do_idedisk_flushcache(drive)) diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/ide/legacy/ide-cs.c linux-2.4.21-rmk1-lh7a400/drivers/ide/legacy/ide-cs.c --- linux-2.4.21-rmk1/drivers/ide/legacy/ide-cs.c Fri Jun 13 10:51:33 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/ide/legacy/ide-cs.c Fri Feb 6 16:27:35 2004 @@ -100,7 +100,8 @@ static int ide_event(event_t event, int priority, event_callback_args_t *args); -static dev_info_t dev_info = "ide-cs"; +//static dev_info_t dev_info = "ide-cs"; +static dev_info_t dev_info = "ide_cs"; static dev_link_t *ide_attach(void); static void ide_detach(dev_link_t *); diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/misc/Config.in linux-2.4.21-rmk1-lh7a400/drivers/misc/Config.in --- linux-2.4.21-rmk1/drivers/misc/Config.in Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/misc/Config.in Sun Feb 8 20:25:17 2004 @@ -15,3 +15,18 @@ dep_tristate ' Touchscreen interface support' CONFIG_MCP_UCB1200_TS $CONFIG_MCP_UCB1200 endmenu +mainmenu_option next_comment + +comment 'Misc devices' + +if [ "$CONFIG_ARCH_LH79520" = "y" -o "$CONFIG_ARCH_LH7A400" = "y" ]; then + tristate 'Sharp LH7A400/LH79520 touchscreen support' CONFIG_KEV7X_TOUCHSCREEN + tristate 'Sharp LH7A400/LH79520 serial eeprom support' CONFIG_KEV7X_EEPROM + tristate 'Sharp LH7A400/LH70520 7-segment support' CONFIG_KEV7X_7SEGMENT +fi + +if [ "$CONFIG_ARCH_LH7A400" = "y" ]; then + tristate 'LH7A400 Smart Card Interface' CONFIG_LH7A400_SCI +fi + +endmenu diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/misc/Makefile linux-2.4.21-rmk1-lh7a400/drivers/misc/Makefile --- linux-2.4.21-rmk1/drivers/misc/Makefile Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/misc/Makefile Sun Feb 8 20:25:43 2004 @@ -18,6 +18,10 @@ obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o obj-$(CONFIG_MCP_UCB1200_AUDIO) += ucb1x00-audio.o obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o +obj-$(CONFIG_KEV7X_TOUCHSCREEN) += ads784x.o ssp-lh7a400.o +obj-$(CONFIG_KEV7X_EEPROM) += eeprom-lh7a400.o +obj-$(CONFIG_KEV7X_7SEGMENT) += led-lh7a400.o +obj-$(CONFIG_LH7A400_SCI) += sci-lh7a400.o include $(TOPDIR)/Rules.make diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/misc/ads784x.c linux-2.4.21-rmk1-lh7a400/drivers/misc/ads784x.c --- linux-2.4.21-rmk1/drivers/misc/ads784x.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/misc/ads784x.c Thu Oct 16 17:15:59 2003 @@ -0,0 +1,967 @@ +/* vi: set sw=4 ts=4 ai: */ + +// #define MODULE + +#define TS_DATA_LH7X + +/********************************************************************** +* linux/drivers/misc/ads784x.c +* +* Provide ADS_784x (touchscreen) functionality for LH7x EVB boards +* +* Copyright (C) 2002 Lineo, Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License (GPL) version 2 +* as published by the Free Software Foundation. +* +**********************************************************************/ + +/********************************************************************** +* Algorithm: +* +* The driver sleeps when there is no pen on the screen. When a pen_down +* interrupt occurs, the pen_down interrupt handler wakes the polling thread. +* The polling thread polls the ADS chip SAMPLES_PER_SECOND. When the polling +* thread polls the ADS chip and the pen is no longer down, the polling +* thread goes to sleep and the pen_down interrupt handler is enabled. +* +* The ADS device sleeps between conversions to save power. +* +* The driver stores pen coordinates in a queue. An application can access +* the coordinate queue by opening and reading the associated device file +* (char major=10 minor=20). An application can poll the queue to see if +* it contains coordinates. If it does, the application can read a coordinate +* structure back. The coordinate queue is flushed when the application +* opens the device file. +* +**********************************************************************/ + +#include +#include +#include +#include +#include +//#include +//#include +#include +//#include +//#include +#include +#include +#include +#include + +// #define DEBUG +// #define VERBOSE +#define DRVNAME "ads_784x" + +#include +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +#endif /* MODULE */ + +#include "ssp.h" + +#if defined(CONFIG_ADS7846) && defined(CONFIG_PROC_FS) +# define PROC_TEMPERATURE +# define PROC_BATTERY +#endif + +#ifdef PROC_BATTERY +static struct proc_dir_entry *ads_784x_proc_battery; +#endif +#ifdef PROC_TEMPERATURE +static struct proc_dir_entry *ads_784x_proc_temperature; +#endif + +/********************************************************************* +* A couple of macros we use here... +*********************************************************************/ +#ifndef _BIT +#define _BIT(n) (1 << (n)) +#endif +#ifndef _SBF +#define _SBF(f,v) ((v) << (f)) +#endif +#ifndef _BITMASK +#define _BITMASK(field_width) ( _BIT(field_width) - 1) +#endif + +/********************************************************************** +* Define ADS 784x Control byte +**********************************************************************/ + +#define CTRL_S _BIT(7) /* Start bit (REQUIRED) */ + +// #define CTRL_ADDR(n) _SBF(4,(n&0x7)) +#define CTRL_X _SBF(4,0x5) /* Read X value */ +#define CTRL_Y _SBF(4,0x1) /* Read Y value */ +#define CTRL_P1 _SBF(4,0x3) /* Read P1 value */ +#define CTRL_P2 _SBF(4,0x4) /* Read P2 value */ +#define CTRL_BATTERY _SBF(4,0x2) /* Read BATTERY value */ +#define CTRL_TEMP0 _SBF(4,0x0) /* Read Temperature-0 value */ +#define CTRL_TEMP1 _SBF(4,0x7) /* Read Temperature-1 value */ + +// #define CTRL_MODE(n) _SBF(3,(n&0x1)) +#define CTRL_12BIT _SBF(3,0x0) /* 12-Bit conversions */ +#define CTRL_8BIT _SBF(3,0x1) /* 8-Bit conversions */ + +// #define CTRL_SER_DFR(n) _SBF(2,(n&0x1)) +#define CTRL_SER _SBF(2,0x1) /* Single-Ended reference */ +#define CTRL_DFR _SBF(2,0x0) /* Differential reference */ + +// #define CTRL_PD(n) (n&0x3) +#define CTRL_PD_ZERO (0x0) /* PenIRQ enabled - PowerDown after */ +#define CTRL_PD_ONE (0x1) /* PenIRQ disabled - PowerDown after */ +#define CTRL_PD_TWO (0x2) /* PenIRQ disabled - RESERVED */ +#define CTRL_PD_THREE (0x3) /* PenIRQ disabled - Powered ON */ + +/********************************************************************** +* Define Simplified ADS 784x Control Codes +**********************************************************************/ + +//#define ADS_784x_PD 0 /* Power Down Settings */ +//#define ADS_784x_PD_INIT 0 /* Init setting reference and ADC Off */ + +#define ADS_784x_INIT \ + ( CTRL_S | CTRL_BATTERY | CTRL_12BIT | CTRL_SER | CTRL_PD_ZERO) +#define ADS_784x_READ_X \ + ( CTRL_S | CTRL_X | CTRL_12BIT | CTRL_DFR | CTRL_PD_ZERO) +#define ADS_784x_READ_Y \ + ( CTRL_S | CTRL_Y | CTRL_12BIT | CTRL_DFR | CTRL_PD_ZERO) +#define ADS_784x_READ_P1 \ + ( CTRL_S | CTRL_P1 | CTRL_12BIT | CTRL_DFR | CTRL_PD_ZERO) +#define ADS_784x_READ_P2 \ + ( CTRL_S | CTRL_P2 | CTRL_12BIT | CTRL_DFR | CTRL_PD_ZERO) +#define ADS_784x_READ_BATTERY \ + ( CTRL_S | CTRL_BATTERY | CTRL_12BIT | CTRL_SER | CTRL_PD_ZERO) +#define ADS_784x_READ_TEMP0 \ + ( CTRL_S | CTRL_TEMP0 | CTRL_12BIT | CTRL_SER | CTRL_PD_ZERO) +#define ADS_784x_READ_TEMP1 \ + ( CTRL_S | CTRL_TEMP1 | CTRL_12BIT | CTRL_SER | CTRL_PD_ZERO) + +/********************************************************************** +* Define our touchscreen data type +* +* This structure is nonsense - millisecs is not very useful +* since the field size is too small. Also, we SHOULD NOT +* be exposing jiffies to user space directly. +**********************************************************************/ +typedef struct tsData_t tsData_t; + +#ifdef TS_DATA_COLLIE +#define TS_DATA_STRUCT +#define PROVIDE_TS_MILLISECS +struct tsData_t { + long x; + long y; + long pressure; + long long millisecs; +}; +#endif + +#ifdef TS_DATA_IPAQ +#define TS_DATA_STRUCT +struct tsData_t { + unsigned short pressure; + unsigned short x; + unsigned short y; + unsigned short pad; +}; +#endif + +#ifdef TS_DATA_LH7X +#define TS_DATA_STRUCT +struct tsData_t { + uint16_t pressure; + uint16_t y; /* Will be read as X */ + uint16_t x; /* Will be read as Y */ + uint16_t pad; +}; +#endif + +#ifndef TS_DATA_STRUCT +#define TS_DATA_DEFAULT +#define PROVIDE_TS_TIMESTAMP +struct tsData_t { + uint16_t pressure; + uint16_t x; + uint16_t y; + uint16_t pad; + struct timeval stamp; +}; +#endif + +#define MAX_TS_DATA 16 + +#define X_DELTA_MAX 20 +#define Y_DELTA_MAX 30 + +/* Define the readings we are to take per second (default to 50) */ +#define SAMPLES_PER_SECOND 50 + +/* +* Define the pen down debounce we are to take. +* (default of 20 == 1/20 of a second) +*/ +#define DEBOUNCE_FRACTION_OF_A_SECOND 50 + +/********************************************************************** +* Define our ADS context structure +**********************************************************************/ +typedef struct adsContext_t adsContext_t; +struct adsContext_t { + + void *sspContext; + void (*write) (void *sspContext, unsigned int data); + unsigned int (*read) (void *sspContext); + int (*enable_pen_down_irq)(void *sspContext); + int (*disable_pen_down_irq)(void *sspContext); + int (*is_pen_down)(void *sspContext); + int (*lock)(void *sspContext, int device); + int (*unlock)(void *sspContext, int device); + + struct fasync_struct *fasync; + struct completion complete; + struct task_struct *rtask; + + wait_queue_head_t read_wait; + wait_queue_head_t irq_wait; + + int tsDataHead; + int tsDataTail; + tsData_t tsData[MAX_TS_DATA]; +}; +static adsContext_t adsContext_l; + +/********************************************************************** +* Macro: ads_784x_tsData_pending +**********************************************************************/ +#define ads_784x_tsData_pending(adsContext) \ + ((adsContext)->tsDataHead != (adsContext)->tsDataTail) + +/********************************************************************** +* Macro: ads_784x_tsData_get +**********************************************************************/ +#define ads_784x_tsData_get(adsContext) \ + ((adsContext)->tsData + (adsContext)->tsDataTail) + +/********************************************************************** +* Macro: ads_784x_tsData_pull +**********************************************************************/ +#define ads_784x_tsData_pull(adsContext) \ + ((adsContext)->tsDataTail = \ + ((adsContext)->tsDataTail + 1) & (MAX_TS_DATA - 1)) + +/********************************************************************** +* Macro: ads_784x_tsData_flush +**********************************************************************/ +#define ads_784x_tsData_flush(adsContext) \ + ((adsContext)->tsDataTail = (adsContext)->tsDataHead) + +#define vdprintk if (0) printk +#define dprintk if (0) printk + +/********************************************************************** +* Function: ads_784x_tsData_add +**********************************************************************/ +static inline void ads_784x_tsData_add( + adsContext_t *adsContext, + unsigned int pressure, + unsigned int x, + unsigned int y) +{ + int next_head; + + vdprintk("ENTER: ads_784x_tsData_add()\n"); + next_head = (adsContext->tsDataHead + 1) & (MAX_TS_DATA - 1); + if (next_head != adsContext->tsDataTail) { + adsContext->tsData[adsContext->tsDataHead].pressure = pressure; + adsContext->tsData[adsContext->tsDataHead].x = x; + adsContext->tsData[adsContext->tsDataHead].y = y; +#ifdef PROVIDE_TS_TIMESTAMP + get_fast_time(&adsContext->tsData[adsContext->tsDataHead].stamp); +#endif + adsContext->tsDataHead = next_head; + if (adsContext->fasync) + kill_fasync(&adsContext->fasync, SIGIO, POLL_IN); + wake_up_interruptible(&adsContext->read_wait); + } + vdprintk("LEAVE: ads_784x_tsData_add()\n"); + return; +} + +/********************************************************************** +* Function: ads_784x_Read_tsData +**********************************************************************/ +static int ads_784x_Read_tsData(adsContext_t *adsContext) +{ + void *sspContext = adsContext->sspContext; + int x=0, x_1=0, x_2=0; + int y=0, y_1=0, y_2=0; + int pen_down = 0; + int p = 0; +#ifdef CONFIG_ADS7846 + int p1=0, p1_1=0, p1_2=0; + int p2=0, p2_1=0, p2_2=0; +#endif + + vdprintk("ENTER: ads_784x_Read_tsData()\n"); + + /* + * Filtering is policy. Policy belongs in user space. We + * therefore leave it to user space to do any filtering + * they please. + * + * We do however, read twice and check against maximum x & y deltas + * to reduce the amount of garbage returned. + * + * Note: There will be one reading with p=0 given when the pen is raised. + */ + + /* Read the pen_down data first as it jitters after the other reads */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + pen_down = adsContext->is_pen_down(sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + + do { + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + /* + * Read the pressure, X position, and Y position. + * Interleave them for better performance + */ +#ifdef CONFIG_ADS7846 + adsContext->write(sspContext, ADS_784x_READ_P1); + adsContext->write(sspContext, ADS_784x_READ_P2); + p1_1 = adsContext->read(sspContext); + p2_1 = adsContext->read(sspContext); +#endif + adsContext->write(sspContext, ADS_784x_READ_X); + adsContext->write(sspContext, ADS_784x_READ_Y); + x_1 = adsContext->read(sspContext); + y_1 = adsContext->read(sspContext); + + /* + * ... AGAIN ... + * Read the pressure, X position, and Y position. + * Interleave them for better performance + */ +#ifdef CONFIG_ADS7846 + adsContext->write(sspContext, ADS_784x_READ_P1); + adsContext->write(sspContext, ADS_784x_READ_P2); + p1_2 = adsContext->read(sspContext); + p2_2 = adsContext->read(sspContext); +#endif + adsContext->write(sspContext, ADS_784x_READ_X); + adsContext->write(sspContext, ADS_784x_READ_Y); + x_2 = adsContext->read(sspContext); + y_2 = adsContext->read(sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + } while ((x_1 > (x_2+X_DELTA_MAX)) || (x_2 > (x_1+X_DELTA_MAX)) + || (y_1 > (y_2+Y_DELTA_MAX)) || (y_2 > (y_1+Y_DELTA_MAX))); + + +#ifdef CONFIG_ADS7846 + p1 = (p1_1 + p1_2) / 2; + p2 = (p2_1 + p2_2) / 2; + p = p2 - p1; +#else + p = pen_down; +#endif + x = (x_1 + x_2) / 2; + y = (y_1 + y_2) / 2; + + ads_784x_tsData_add(adsContext, p, x, y); + + dprintk("LEAVE: ads_784x_Read_tsData(p=0x%03x, x=0x%03x, y=0x%03x)\n", + p, x, y); + + return(pen_down); +} + +/********************************************************************** +* Function: ads_784x_thread +* +* This is a RT kernel thread that handles the ADC accesses +* (mainly so we can use semaphores to serialise accesses to the ADC). +**********************************************************************/ +static int ads_784x_thread(void *_adsContext) +{ + adsContext_t *adsContext = _adsContext; + void *sspContext = adsContext->sspContext; + struct task_struct *tsk = current; + DECLARE_WAITQUEUE(wait, tsk); + int pen_down = 0; + + vdprintk("ENTER: ads_784x_thread()\n"); + adsContext->rtask = tsk; + + daemonize(); + tsk->tty = NULL; + strcpy(tsk->comm, "ktsd"); + + /* only want to receive SIGKILL */ + spin_lock_irq(&tsk->sigmask_lock); + siginitsetinv(&tsk->blocked, sigmask(SIGKILL)); + recalc_sigpending(tsk); + spin_unlock_irq(&tsk->sigmask_lock); + + add_wait_queue(&adsContext->irq_wait, &wait); + + complete(&adsContext->complete); + + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + pen_down = adsContext->is_pen_down(sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + for (;;) { + signed long interval; + + /* + * Set to interrupt mode and wait a settling time. + */ + set_task_state(tsk, TASK_INTERRUPTIBLE); + if (sspContext == NULL) { + interval = HZ; /* Check for change once per second */ + } else if (pen_down) { + /* If pen is down then periodically read pen position */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->disable_pen_down_irq(sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + interval = HZ/SAMPLES_PER_SECOND; + } else { + /* If pen is not down then sleep until pen down interrupt */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->enable_pen_down_irq(sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + interval = MAX_SCHEDULE_TIMEOUT; + } + schedule_timeout(interval); + if (signal_pending(tsk)) { + break; + } + if (pen_down == 0) { + /* + * On pen down there is some bounce. + * Wait a debounce period and read it again. + */ + schedule_timeout(HZ/DEBOUNCE_FRACTION_OF_A_SECOND); + if (signal_pending(tsk)) { + break; + } + /* + * If the pen is not down after the debounce period, + * ignore the pen down signal. + */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + pen_down = adsContext->is_pen_down(sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + if (pen_down == 0) + continue; + } + adsContext->disable_pen_down_irq(sspContext); + /* + * We got an IRQ, which works us up. Process the touchscreen. + */ + pen_down = ads_784x_Read_tsData(adsContext); + } + + remove_wait_queue(&adsContext->irq_wait, &wait); + adsContext->rtask = NULL; + vdprintk("LEAVE: ads_784x_thread()\n"); + + return(0); +} + +/********************************************************************** +* Function: ads_784x_read +* +* *********************************** +* *** User space driver interface *** +* *********************************** +**********************************************************************/ +static ssize_t ads_784x_read(struct file *filp, char *buffer, size_t _count, loff_t *ppos) +{ + DECLARE_WAITQUEUE(wait, current); + adsContext_t *adsContext = filp->private_data; + char *ptr = buffer; + int err = 0; + int count = (int)_count; /* Force a sigened value to be used */ + + vdprintk("ENTER: ads_784x_read()\n"); + add_wait_queue(&adsContext->read_wait, &wait); + while (count >= sizeof(tsData_t)) { + err = -ERESTARTSYS; + if (signal_pending(current)) + break; + + if (ads_784x_tsData_pending(adsContext)) { + tsData_t *tsData = ads_784x_tsData_get(adsContext); + + err = copy_to_user(ptr, tsData, sizeof(tsData_t)); + ads_784x_tsData_pull(adsContext); + + if (err) + break; + + ptr += sizeof(tsData_t); + count -= sizeof(tsData_t); + continue; + } + + set_current_state(TASK_INTERRUPTIBLE); + err = -EAGAIN; + if (filp->f_flags & O_NONBLOCK) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&adsContext->read_wait, &wait); + vdprintk("LEAVE: ads_784x_read()\n"); + + return(ptr == buffer ? err : ptr - buffer); +} + +/********************************************************************** +* Function: ads_784x_poll +* +* *********************************** +* *** User space driver interface *** +* *********************************** +**********************************************************************/ +static unsigned int ads_784x_poll(struct file *filp, poll_table *wait) +{ + adsContext_t *adsContext = filp->private_data; + int ret = 0; + + vdprintk("ENTER: ads_784x_poll()\n"); + poll_wait(filp, &adsContext->read_wait, wait); + if (ads_784x_tsData_pending(adsContext)) + ret = POLLIN | POLLRDNORM; + vdprintk("LEAVE: ads_784x_poll()\n"); + + return(ret); +} + +/********************************************************************** +* Function: ads_784x_open +* +* *********************************** +* *** User space driver interface *** +* *********************************** +**********************************************************************/ +static int ads_784x_open(struct inode *inode, struct file *filp) +{ + adsContext_t *adsContext = &adsContext_l; + int ret = 0; + + vdprintk("ENTER: ads_784x_open()\n"); + + filp->private_data = adsContext; + + /* Flush the ts data queue here */ + ads_784x_tsData_flush(adsContext); + + vdprintk("LEAVE: ads_784x_open()\n"); + return(ret); +} + +/********************************************************************** +* Function: ads_784x_fasync +* +* *********************************** +* *** User space driver interface *** +* *********************************** +**********************************************************************/ +static int ads_784x_fasync(int fd, struct file *filp, int on) +{ + int sts; + adsContext_t *adsContext = filp->private_data; + + vdprintk("ENTER: ads_784x_fasync()\n"); + sts = fasync_helper(fd, filp, on, &adsContext->fasync); + vdprintk("LEAVE: ads_784x_fasync()\n"); + + return(sts); +} + +/********************************************************************** +* Function: ads_784x_release +* +* *********************************** +* *** User space driver interface *** +* *********************************** +* +* Release touchscreen resources. Disable IRQs. +**********************************************************************/ +static int ads_784x_release(struct inode *inode, struct file *filp) +{ + // adsContext_t *adsContext = filp->private_data; + + vdprintk("ENTER: ads_784x_release()\n"); + lock_kernel(); + ads_784x_fasync(-1, filp, 0); + unlock_kernel(); + vdprintk("LEAVE: ads_784x_release()\n"); + + return(0); +} + +/********************************************************************** +* Define (fill in) the user space file operations for this driver +* and initialize the ADS touchscreen driver as a "miscdevice": +* Character device +* Major(10) --- Non-serial mice, misc features +* Minor(20) --- /dev/touchscreen/ads_784x +**********************************************************************/ +static struct file_operations ads_784x_fops = { + owner: THIS_MODULE, + read: ads_784x_read, + poll: ads_784x_poll, + open: ads_784x_open, + fasync: ads_784x_fasync, + release: ads_784x_release, +}; + +static struct miscdevice ads_784x_dev = { + minor: 20, + name: "touchscreen/ads_784x", + fops: &ads_784x_fops, +}; + +#ifdef PROC_BATTERY +/********************************************************************** +* ads_784x_proc_battery_read +**********************************************************************/ +static int ads_784x_proc_battery_read(char *buf, char **start, off_t offset, + int len, int *eof, void *unused) +{ + adsContext_t *adsContext = &adsContext_l; + ads784x_sspContext_t *ads784x_sspContext = adsContext->ads784x_sspContext; + int milliVolts; + int volts; + int hundredthsVolts; + int sample; + int size; + int count; + int last_irq_state; + + vdprintk("ENTER: ads_784x_proc_battery_read(len=%d)\n", len); + /* + * Reading the ADS784X takes the part out of pen down interrupt mode + * causing spurious pen down interrupts. So we must disable + * pen down interrupts while reading battery voltage. + */ + last_irq_state = adsContext->disable_pen_down_irq(ads784x_sspContext); + + /* Do a dummy read to turn on the internal reference voltage */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_BATTERY); + sample = adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + udelay(100); /* wait until the reference voltage settle */ + + sample = 0; + for (count = 0; count < 3; count++) { + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_BATTERY); + sample += adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + } + sample /= count; + milliVolts = (sample * 1000 * 10) / 4096; + volts = milliVolts / 1000; + hundredthsVolts = (milliVolts - (volts * 1000)) / 10; + size = sprintf(buf, "battery: %i.%02iV\n", volts, hundredthsVolts); + + /* Do a dummy read to turn off the internal reference voltage */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_X); + sample = adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + + /* Restore the interrupt enable state */ + if (last_irq_state) { + udelay(100); /* Wait until the pen down interrupt settles */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->enable_pen_down_irq(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + } + vdprintk("LEAVE: ads_784x_proc_battery_read(len=%d)\n", len); + + return(size); +} +#endif + +#ifdef PROC_TEMPERATURE +/********************************************************************** +* ads_784x_proc_temperature_read +**********************************************************************/ +static int ads_784x_proc_temperature_read(char *buf, char **start, + off_t offset, int len, int *eof, void *unused) +{ + adsContext_t *adsContext = &adsContext_l; + ads784x_sspContext_t *ads784x_sspContext = adsContext->ads784x_sspContext; + int size; + int count; + int C10, F10; + int sample1; + int sample91; + int last_irq_state; + + vdprintk("ENTER: ads_784x_proc_temperature_read(len=%d)\n", len); + /* + * Reading the ADS784X takes the part out of pen down interrupt mode + * causing spurious pen down interrupts. So we must disable + * pen down interrupts while reading temperature. + */ + last_irq_state = adsContext->disable_pen_down_irq(ads784x_sspContext); + + /* do a dummy read to turn on the internal reference voltage */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_TEMP0); + sample1 = adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + udelay(100); /* wait until the reference voltage settle */ + + sample1 = 0; + sample91 = 0; + /* read the temperature values */ + for (count = 0; count < 3; count++) { + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_TEMP0); + adsContext->write(ads784x_sspContext, ADS_784x_READ_TEMP1); + sample1 += adsContext->read(ads784x_sspContext); + sample91 += adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + } + /* average values */ + sample1 /= count; + sample91 /= count; + + C10 = (((sample91 - sample1) * (25 * 2573)) / 4095) - 2730; + F10 = (C10*9)/5 + 320; + + size = sprintf(buf, "Temperature: %iC, %iF\n", (C10+5)/10, (F10+5)/10); + + /* do a dummy read to turn off the internal reference voltage */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_X); + sample1 = adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + + /* restore the interrupt enable state */ + if (last_irq_state) { + udelay(100); /* wait until the pen down interrupt settles */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->enable_pen_down_irq(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + } + vdprintk("LEAVE: ads_784x_proc_temperature_read(len=%d)\n", len); + + return(size); +} +#endif + +/********************************************************************** +* Function: ads_784x_make_ssp_association +* +* Purpose: +* Make the association between the eeprom driver and the ssp driver +**********************************************************************/ +static int ads_784x__make_ssp_association(adsContext_t *adsContext) +{ + int sts = 0; + void *vp; + +/* NOTE: -EOPNOTSUPP == Operation not supported on transport endpoint */ +#define ASSOCIATION_ERROR -EOPNOTSUPP + + dprintk("ENTER: ads_784x_make_ssp_association()\n"); + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "sspContext"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->sspContext = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "write"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->write = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "read"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->read = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "enable_pen_down_irq"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->enable_pen_down_irq = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "disable_pen_down_irq"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->disable_pen_down_irq = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "is_pen_down"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->is_pen_down = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "lock"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->lock = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "unlock"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->unlock = vp; + + /* Note: The following need reset to NULL when we are finished */ + + vp = ssp_provide_pointer(SSP_DEV_TOUCHSCREEN, "irq_wait_ptr", + &(adsContext->irq_wait)); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + + dprintk("LEAVE: ads_784x_make_ssp_association(%d)\n", sts); + + return(sts); +} + +/********************************************************************** +* Function: ads_784x_init +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +static int __init ads_784x_init(void) +{ + adsContext_t *adsContext = &adsContext_l; + int sts = -ENODEV; + + vdprintk("ENTER: ads_784x_init()\n"); + init_waitqueue_head(&adsContext->read_wait); + /* Retrieve the service information from the SSP driver */ + sts = ads_784x__make_ssp_association(adsContext); + if (sts == 0) { + void *sspContext = adsContext->sspContext; + + /* Start the ADS polling thread */ + lock_kernel(); + if (adsContext->rtask == NULL) { + init_completion(&adsContext->complete); + init_waitqueue_head(&adsContext->irq_wait); + sts = kernel_thread(ads_784x_thread, adsContext, + CLONE_FS | CLONE_FILES); + if (sts >= 0) { + sts = 0; + /* Only do this is the tread started correctly */ + wait_for_completion(&adsContext->complete); + } + } + unlock_kernel(); + + /* MUST lock the SSP before accessing it */ + adsContext->lock(sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(sspContext, ADS_784x_INIT); + adsContext->read(sspContext); /* dummy read */ + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(sspContext, SSP_DEV_TOUCHSCREEN); + + sts = misc_register(&ads_784x_dev); + +#ifdef PROC_BATTERY + ads_784x_proc_battery = create_proc_entry("battery", 0, 0); + if (ads_784x_proc_battery) { + ads_784x_proc_battery->read_proc = ads_784x_proc_battery_read; + } else { + printk(KERN_ERR "%s: unable to register /proc/battery\n", DRVNAME); + } +#endif +#ifdef PROC_TEMPERATURE + ads_784x_proc_temperature = create_proc_entry("temperature", 0, 0); + if (ads_784x_proc_temperature) { + ads_784x_proc_temperature->read_proc = ads_784x_proc_temperature_read; + } else { + printk(KERN_ERR "%s: unable to register /proc/temperature\n", DRVNAME); + } +#endif + } + + vdprintk("LEAVE: ads_784x_init()\n"); + return(sts); +} + +/********************************************************************** +* Function: ads_784x_exit +* +* Purpose: +* Un-Register & Cleanup the module +**********************************************************************/ +static void ads_784x_exit(void) +{ + adsContext_t *adsContext = &adsContext_l; + + vdprintk("ENTER: ads_784x_exit()\n"); + + if (adsContext->rtask) { + send_sig(SIGKILL, adsContext->rtask, 1); + schedule(); + } + + vdprintk("ads_784x_exit(): misc_deregister()\n"); + misc_deregister(&ads_784x_dev); + + /* Back out the pointer(s) we gave to the SSP driver */ + (void) ssp_provide_pointer(SSP_DEV_TOUCHSCREEN, "irq_wait_ptr", NULL); + +#ifdef PROC_BATTERY + remove_proc_entry("battery", NULL); +#endif +#ifdef PROC_TEMPERATURE + remove_proc_entry("temperature", NULL); +#endif + + vdprintk("LEAVE: ads_784x_exit()\n"); + + return; +} + +module_init(ads_784x_init); +module_exit(ads_784x_exit); + +MODULE_AUTHOR("Jim Gleason"); +MODULE_DESCRIPTION("ADS 784x Driver for Sharp LH7x EVB"); +MODULE_LICENSE("Copyright (c) 2002 Lineo, Inc."); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/misc/eeprom-lh7a400.c linux-2.4.21-rmk1-lh7a400/drivers/misc/eeprom-lh7a400.c --- linux-2.4.21-rmk1/drivers/misc/eeprom-lh7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/misc/eeprom-lh7a400.c Sun Feb 8 20:32:52 2004 @@ -0,0 +1,749 @@ +/* vi: set sw=4 ts=4 ai: */ + +// #define MODULE + +#define READ_AFTER_WRITE + +/********************************************************************** +* linux/drivers/misc/eeprom-lh7x.c +* +* Provide Microchip 93LC46B 64 x 16 EEPROM access for LH7x EVB boards +* +* Copyright (C) 2002 Lineo, Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License (GPL) version 2 +* as published by the Free Software Foundation. +* +* References: +* SHARP_EVB_DISPLAY_BOARD_REV2.pdf +* 93LC46.pdf (Microchip 1K Microwire(R) EEPROM chip spec) +* +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#undef VERBOSE +#define DRVNAME "eeprom-lh7x" +//#include +#define vdprintk(...) +#define dprintk(...) + +#include +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +#endif /* MODULE */ + +#include + +#include "ssp.h" + +#define SIXmsJIFFIES (((HZ*6)/1000)+2) + +/********************************************************************** +* Define EEPROM Control macros for "Microchip 93LC46B Microwire Serial EEPROM" +**********************************************************************/ + +/* Erase one 16 bit word at addr */ +#define EEPROM_ERASE(addr) (0x01C0 | (addr & 0x3F)) +/* Erase entire eeprom */ +#define EEPROM_ERAL() (0x0120) +/* Erase/Write disable */ +#define EEPROM_EWDS() (0x0100) +/* Erase/Write enable */ +#define EEPROM_EWEN() (0x0130) +/* Read one 16 bit word at addr */ +#define EEPROM_READ(addr) (0x0180 | (addr & 0x3F)) +/* (Erase and) Write one 16 bit word at addr */ +#define EEPROM_WRITE(addr) (0x0140 | (addr & 0x3F)) +/* Write one 16 bit value throught entire eeprom */ +#define EEPROM_WRAL() (0x0110) + +/********************************************************************** +* Define our eeprom context structure +**********************************************************************/ + +#define EEPROM_SIZE_16BIT 64 +#define EEPROM_SIZE_8BIT 128 + +typedef struct eepromContext_t eepromContext_t; +struct eepromContext_t { + union { + uint16_t w[EEPROM_SIZE_16BIT]; /* Actual device size */ + u_char c[EEPROM_SIZE_8BIT]; + } cache; + union { + uint16_t w[EEPROM_SIZE_16BIT]; /* Actual device size */ + u_char c[EEPROM_SIZE_8BIT]; + } state; + wait_queue_head_t read_and_write_wait; + + void *sspContext; + void (*write) (void *sspContext, unsigned int data); + unsigned int (*read) (void *sspContext); + int (*lock)(void *sspContext, int device); + int (*unlock)(void *sspContext, int device); +#if defined(CONFIG_ARCH_LH79520) + void (*ssp_chipselect_automatic)(void); + void (*ssp_chipselect_manual)(void); + void (*ssp_chipselect_enable)(void); + void (*ssp_chipselect_disable)(void); +#elif defined(CONFIG_ARCH_LH7A400) + int (*ssp_eeprom_busy_poll)(void *sspContext, int timeout_ms); +#endif + void (*ssp_flush_tx_fifo)(void *sspContext); + void (*ssp_flush_rx_fifo)(void *sspContext); + void (*ssp_busy_wait)(void); +}; +static eepromContext_t eepromContext_l; + +#define CACHE_STATE_VALID_8 0x01 +#define CACHE_STATE_MODIFIED_8 0x02 + +#define CACHE_STATE_VALID_16 0x0101 +#define CACHE_STATE_MODIFIED_16 0x0202 + +/********************************************************************** +* Function: eeprom_lh7x_erase_write_enable +* Function: eeprom_lh7x_erase_write_disable +**********************************************************************/ +static void +eeprom_lh7x_erase_write_enable(eepromContext_t *eepromContext) +{ + void *sspContext = eepromContext->sspContext; + + /* Lock the SSP before accessing it */ + eepromContext->lock(sspContext, SSP_DEV_EEPROM); + + eepromContext->ssp_busy_wait(); /* Wait for the SSP to not be busy */ + eepromContext->ssp_flush_rx_fifo(sspContext); + +#if defined(CONFIG_ARCH_LH79520) + /* EEPROM Writes must be done using manual control of the ChipSelect */ + eepromContext->ssp_chipselect_manual(); + eepromContext->ssp_chipselect_enable(); +#endif + + eepromContext->write(sspContext, EEPROM_EWEN()); /* Enable Erase/Write */ + + eepromContext->ssp_busy_wait(); /* Wait for the SSP to not be busy */ + eepromContext->ssp_flush_rx_fifo(sspContext); + +#if defined(CONFIG_ARCH_LH79520) + /* Reset back to automatic control of the EEPROM ChipSelect */ + eepromContext->ssp_chipselect_disable(); + eepromContext->ssp_chipselect_automatic(); +#endif + + /* Unlock the SSP after it has been locked */ + eepromContext->unlock(sspContext, SSP_DEV_EEPROM); + + return; +} + +static void +eeprom_lh7x_erase_write_disable(eepromContext_t *eepromContext) +{ + void *sspContext = eepromContext->sspContext; + + /* Lock the SSP before accessing it */ + eepromContext->lock(sspContext, SSP_DEV_EEPROM); + + eepromContext->ssp_busy_wait(); /* Wait for the SSP to not be busy */ + eepromContext->ssp_flush_rx_fifo(sspContext); + +#if defined(CONFIG_ARCH_LH79520) + /* EEPROM Writes must be done using manual control of the ChipSelect */ + eepromContext->ssp_chipselect_manual(); + eepromContext->ssp_chipselect_enable(); +#endif + + eepromContext->write(sspContext, EEPROM_EWDS()); /* Disable Erase/Write */ + + eepromContext->ssp_busy_wait(); /* Wait for the SSP to not be busy */ + eepromContext->ssp_flush_rx_fifo(sspContext); + +#if defined(CONFIG_ARCH_LH79520) + /* Reset back to automatic control of the EEPROM ChipSelect */ + eepromContext->ssp_chipselect_disable(); + eepromContext->ssp_chipselect_automatic(); +#endif + + /* Unlock the SSP after it has been locked */ + eepromContext->unlock(sspContext, SSP_DEV_EEPROM); + + return; +} + +/********************************************************************** +* Function: eeprom_lh7x_read_device_word +**********************************************************************/ +static void +eeprom_lh7x_read_device_word(eepromContext_t *eepromContext, int offset_w) +{ + void *sspContext = eepromContext->sspContext; + uint16_t word = 0; + + /* Lock the SSP before accessing it */ + eepromContext->lock(sspContext, SSP_DEV_EEPROM); + + eepromContext->ssp_busy_wait(); /* Wait for the SSP to not be busy */ + eepromContext->ssp_flush_rx_fifo(sspContext); + +#if defined(CONFIG_ARCH_LH79520) + /* EEPROM Reads must be done using manual control of the ChipSelect */ + eepromContext->ssp_chipselect_manual(); + eepromContext->ssp_chipselect_enable(); +#endif + + /* Read eeprom into cache */ + /* Note: We shift to take care of the "dummy 0" the eeprom sends */ + eepromContext->write(sspContext, (EEPROM_READ(offset_w))<<1); + /* Following is a Dummy/Invalid command to allow the eeprom to be read */ + eepromContext->write(sspContext, 0); + eepromContext->ssp_busy_wait(); /* Wait for the SSP to not be busy */ + word = eepromContext->read(sspContext); /* Dummy Word */ + word = eepromContext->read(sspContext); /* Real Word */ + +#if defined(CONFIG_ARCH_LH79520) + /* Reset back to automatic control of the EEPROM ChipSelect */ + eepromContext->ssp_chipselect_disable(); + eepromContext->ssp_chipselect_automatic(); +#endif + + /* Unlock the SSP after it has been locked */ + eepromContext->unlock(sspContext, SSP_DEV_EEPROM); + + /* Modify the state of the cache data */ + eepromContext->cache.w[offset_w] = word; + eepromContext->state.w[offset_w] |= CACHE_STATE_VALID_16; + + schedule(); /* Give the rest of the system a chance to work */ + + return; +} + +/********************************************************************** +* Function: eeprom_lh7x_write_device_word +**********************************************************************/ +static void +eeprom_lh7x_write_device_word(eepromContext_t *eepromContext, int offset_w) +{ + void *sspContext = eepromContext->sspContext; + uint16_t word; + long timeoutJiffies; + + vdprintk("ENTER: eeprom_lh7x_write_device_word(,%d)\n", offset_w); + + /* Get the modified cache data to write to the eeprom */ + word = eepromContext->cache.w[offset_w]; + + /* Lock the SSP before accessing it */ + eepromContext->lock(sspContext, SSP_DEV_EEPROM); + + eepromContext->ssp_busy_wait(); /* Wait for the SSP to not be busy */ + eepromContext->ssp_flush_rx_fifo(sspContext); + +#if defined(CONFIG_ARCH_LH79520) + /* EEPROM Writes must be done using manual control of the ChipSelect */ + eepromContext->ssp_chipselect_manual(); + eepromContext->ssp_chipselect_enable(); +#endif + + /* Write modified cache data to the eeprom */ + eepromContext->write(sspContext, EEPROM_WRITE(offset_w)); + eepromContext->write(sspContext, word); + +#if defined(CONFIG_ARCH_LH79520) + /* Reset back to automatic control of the EEPROM ChipSelect */ + eepromContext->ssp_chipselect_disable(); + eepromContext->ssp_chipselect_automatic(); +#elif defined(CONFIG_ARCH_LH7A400) + (void) eepromContext->ssp_eeprom_busy_poll(sspContext, 7); /* Min of 6 */ +#endif + + eepromContext->ssp_busy_wait(); /* Wait for the SSP to not be busy */ + eepromContext->ssp_flush_rx_fifo(sspContext); + + /* Unlock the SSP after it has been locked */ + eepromContext->unlock(sspContext, SSP_DEV_EEPROM); + + /* Modify the state of the cache data */ + eepromContext->state.w[offset_w] &= ~CACHE_STATE_MODIFIED_16; + +#ifdef READ_AFTER_WRITE + /* Force the modified cache data to be reread from the eeprom */ + eepromContext->state.w[offset_w] &= ~CACHE_STATE_VALID_16; +#endif /* READ_AFTER_WRITE */ + + /* Cause ~ 6ms delay (actually does 10 on the Sharp LH79520) */ + timeoutJiffies = SIXmsJIFFIES; + while (timeoutJiffies > 0) { + __set_current_state(TASK_UNINTERRUPTIBLE); + timeoutJiffies = schedule_timeout(timeoutJiffies); + } + // __set_current_state(TASK_RUNNING); + + schedule(); /* Give the rest of the system a chance to work */ + + vdprintk("LEAVE: eeprom_lh7x_write_device_word()\n"); + + return; +} + +/********************************************************************** +* Function: eeprom_lh7x_read_device +**********************************************************************/ +static void +eeprom_lh7x_read_device(eepromContext_t *eepromContext) +{ + uint16_t *scwp; + int offset_w; + + scwp = eepromContext->state.w; + for (offset_w = 0; offset_w < EEPROM_SIZE_16BIT; offset_w++) { + if ((*scwp & CACHE_STATE_VALID_16) != CACHE_STATE_VALID_16) { + eeprom_lh7x_read_device_word(eepromContext, offset_w); + } + scwp++; + } + + return; +} + +/********************************************************************** +* Function: eeprom_lh7x_write_device +**********************************************************************/ +static void +eeprom_lh7x_write_device(eepromContext_t *eepromContext) +{ + uint16_t *scwp; + int offset_w; + int timeoutJiffies; + + vdprintk("ENTER: eeprom_lh7x_write_device()\n"); + + /* Enable erase/write of the eeprom */ + eeprom_lh7x_erase_write_enable(eepromContext); + + /* Just to get the timeouts in a desirable sequence */ + /* and so we don't get a "partial" timeout we do the following... */ + /* Cause ~ 6ms delay (actually does 10 on the Sharp LH79520) */ + timeoutJiffies = SIXmsJIFFIES; + while (timeoutJiffies > 0) { + __set_current_state(TASK_UNINTERRUPTIBLE); + timeoutJiffies = schedule_timeout(timeoutJiffies); + } + // __set_current_state(TASK_RUNNING); + + scwp = eepromContext->state.w; + for (offset_w = 0; offset_w < EEPROM_SIZE_16BIT; offset_w++) { + if (*scwp & CACHE_STATE_MODIFIED_16) { + eeprom_lh7x_write_device_word(eepromContext, offset_w); + } + scwp++; + } + + /* Disable erase/write of the eeprom */ + eeprom_lh7x_erase_write_disable(eepromContext); + +#ifdef READ_AFTER_WRITE + /* + * NOW ... Update the eeprom cache. + * ( Read the actual contents of the eeprom that were + * modified instead of relying on what we wrote. ) + */ + eeprom_lh7x_read_device(eepromContext); +#endif /* READ_AFTER_WRITE */ + + vdprintk("LEAVE: eeprom_lh7x_write_device()\n"); + + return; +} + +/********************************************************************** +* ***************************************************** +* *** User space "file operation" driver interfaces *** +* ***************************************************** +* Function: lh7x_eeprom_llseek +* Function: lh7x_eeprom_read +* Function: lh7x_eeprom_write +* Function: lh7x_eeprom_poll ( NOT USED --- YET ) +* Function: lh7x_eeprom_ioctl ( NOT USED --- YET ) +* Function: lh7x_eeprom_open +* Function: lh7x_eeprom_flush ( NOT USED --- YET ) +* Function: lh7x_eeprom_release ( NOT USED --- YET ) +* Function: lh7x_eeprom_fsync ( NOT USED --- YET ) +* Function: lh7x_eeprom_fasync ( NOT USED --- YET ) +* Function: lh7x_eeprom_lock ( NOT USED --- YET ) +**********************************************************************/ + +static loff_t +lh7x_eeprom_llseek(struct file *filp, loff_t offset, int origin) +{ + // eepromContext_t *eepromContext = filp->private_data; + loff_t new_offset = -EINVAL; + + switch (origin) { + case 0: /* SEEK_SET == 0, Offset from the start */ + new_offset = offset; + break; + case 1: /* SEEK_CUR == 1, Offset from the current position */ + new_offset = filp->f_pos + offset; + break; + case 2: /* SEEK_END == 2, Offset from the end */ + new_offset = EEPROM_SIZE_8BIT - offset; + break; + } + if ((new_offset < 0) || (new_offset > EEPROM_SIZE_8BIT)) { + new_offset = -EINVAL; + } else { + filp->f_pos = new_offset; + } + + return(new_offset); +} + +static ssize_t +lh7x_eeprom_read(struct file *filp, char *buffer, + size_t count, loff_t *offsetp) +{ + eepromContext_t *eepromContext = filp->private_data; + int sts = 0; + int err; + + vdprintk("ENTER: lh7x_eeprom_read(%d:%d)\n", *offsetp, count); + /* Ensure we still have data to read (relative to the offset we are at) */ + if (*offsetp < EEPROM_SIZE_8BIT) { + /* Adjust the size to be read if necessary */ + if ((*offsetp + count) > EEPROM_SIZE_8BIT) { + count = EEPROM_SIZE_8BIT - *offsetp; + } + /* Ensure the eeprom cache is valid */ + eeprom_lh7x_read_device(eepromContext); + /* Return the contents of the eeprom cache */ + err = copy_to_user(buffer, &eepromContext->cache.c[*offsetp], count); + if ( ! err) { + *offsetp += count; + sts = count; + } else { + sts = -EFAULT; + } + } + vdprintk("LEAVE: lh7x_eeprom_read(%d)\n", sts); + + return(sts); +} + +static ssize_t +lh7x_eeprom_write(struct file *filp, const char *buffer, + size_t count, loff_t *offsetp) +{ + eepromContext_t *eepromContext = filp->private_data; + u_char newcache_c[EEPROM_SIZE_8BIT]; + int sts = 0; + int err; + + vdprintk("ENTER: lh7x_eeprom_write(%d:%d)\n", *offsetp, count); + /* Ensure we still have room to write (relative to the offset we are at) */ + if (*offsetp < EEPROM_SIZE_8BIT) { + /* Adjust the size to be written if necessary */ + if ((*offsetp + count) > EEPROM_SIZE_8BIT) { + count = EEPROM_SIZE_8BIT - *offsetp; + } + /* Ensure the eeprom cache is valid to start with */ + eeprom_lh7x_read_device(eepromContext); + /* Get the new contents of the eeprom cache */ + err = copy_from_user(&newcache_c[*offsetp], buffer, count); + if ( ! err) { + u_char *ccp, *nccp, *sccp; + int i; + /* + * Transfer the new cache contents into the cache + * marking what has changed. + */ + ccp = &eepromContext->cache.c[*offsetp]; + nccp = &newcache_c[*offsetp]; + sccp = &eepromContext->state.c[*offsetp]; + for (i = 0; i < count; i++) { + if (*ccp != *nccp) { + *ccp = *nccp; + *sccp |= CACHE_STATE_MODIFIED_8; + } + ccp++; + nccp++; + sccp++; + } + /* Write the modified cache into the eeprom */ + eeprom_lh7x_write_device(eepromContext); + *offsetp += count; + sts = count; + } else { + sts = -EFAULT; + } + } + vdprintk("LEAVE: lh7x_eeprom_write(%d)\n", sts); + + return(sts); +} + +#if (0) /* NOT USED --- YET */ +static unsigned int +lh7x_eeprom_poll(struct file *filp, struct poll_table_struct *wait) +{ + eepromContext_t *eepromContext = filp->private_data; + int sts = 0; + + return(sts); +} +#endif /* NOT USED --- YET */ + +#if (0) /* NOT USED --- YET */ +static int +lh7x_eeprom_ioctl(struct inode *, struct file *filp, unsigned int cmd, unsigned long arg) +{ + eepromContext_t *eepromContext = filp->private_data; + int sts = 0; + + return(sts); +} +#endif /* NOT USED --- YET */ + +static int +lh7x_eeprom_open(struct inode *inode, struct file *filp) +{ + eepromContext_t *eepromContext = &eepromContext_l; + int sts = 0; + + filp->private_data = eepromContext; + + return(sts); +} + +#if (0) /* NOT USED --- YET */ +static int +lh7x_eeprom_flush(struct file *filp) +{ + eepromContext_t *eepromContext = filp->private_data; + int sts = 0; + + return(sts); +} +#endif /* NOT USED --- YET */ + +#if (0) /* NOT USED --- YET */ +static int +lh7x_eeprom_release(struct inode *inode, struct file *filp) +{ + eepromContext_t *eepromContext = filp->private_data; + int sts = 0; + + return(sts); +} +#endif /* NOT USED --- YET */ + +#if (0) /* NOT USED --- YET */ +static int +lh7x_eeprom_fsync(struct file *filp, struct dentry *dentry, int datasync) +{ + eepromContext_t *eepromContext = filp->private_data; + int sts = 0; + + return(sts); +} +#endif /* NOT USED --- YET */ + +#if (0) /* NOT USED --- YET */ +static int +lh7x_eeprom_fasync(int fd, struct file *filp, int on) +{ + eepromContext_t *eepromContext = filp->private_data; + int sts = 0; + + return(sts); +} +#endif /* NOT USED --- YET */ + +#if (0) /* NOT USED --- YET */ +static int +lh7x_eeprom_lock(struct file *filp, int XXX, struct file_lock *file_lock) +{ + eepromContext_t *eepromContext = filp->private_data; + int sts = 0; + + return(sts); +} +#endif /* NOT USED --- YET */ + +/********************************************************************** +* Define (fill in) the user space file operations for this driver +* and initialize the eeprom driver as a "miscdevice": +* Character device +* Major(10) --- Non-serial mice, misc features +* Minor(22) --- /dev/eeprom ( Microchip 93LC46B 64 x 16 EEPROM ) +**********************************************************************/ +static struct file_operations lh7x_eeprom_fops = { + owner: THIS_MODULE, + llseek: lh7x_eeprom_llseek, + read: lh7x_eeprom_read, + write: lh7x_eeprom_write, +// poll: lh7x_eeprom_poll, +// ioctl: lh7x_eeprom_ioctl, + open: lh7x_eeprom_open, +// flush: lh7x_eeprom_flush, +// release: lh7x_eeprom_release, +// fsync: lh7x_eeprom_fsync, +// fasync: lh7x_eeprom_fasync, +// lock: lh7x_eeprom_lock, +}; + +static struct miscdevice lh7x_eeprom_dev = { +minor: 22, +name: "eeprom", +fops: &lh7x_eeprom_fops, +}; + +/********************************************************************** +* Function: lh7x_eeprom_make_ssp_association +* +* Purpose: +* Make the association between the eeprom driver and the ssp driver +**********************************************************************/ +static int lh7x_eeprom_make_ssp_association(eepromContext_t *eepromContext) +{ + int sts = 0; + void *vp; + +/* NOTE: -EOPNOTSUPP == Operation not supported on transport endpoint */ +#define ASSOCIATION_ERROR -EOPNOTSUPP + + dprintk("ENTER: lh7x_eeprom_make_ssp_association()\n"); + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "sspContext"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->sspContext = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "write"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->write = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "read"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->read = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "lock"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->lock = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "unlock"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->unlock = vp; + +#if defined(CONFIG_ARCH_LH79520) + vp = ssp_request_pointer(SSP_DEV_EEPROM, "chipselect_enable"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->ssp_chipselect_enable = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "chipselect_disable"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->ssp_chipselect_disable = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "chipselect_manual"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->ssp_chipselect_manual = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "chipselect_automatic"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->ssp_chipselect_automatic = vp; +#elif defined(CONFIG_ARCH_LH7A400) + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "eeprom_busy_poll"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->ssp_eeprom_busy_poll = vp; +#endif + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "flush_tx_fifo"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->ssp_flush_tx_fifo = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "flush_rx_fifo"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->ssp_flush_rx_fifo = vp; + + vp = ssp_request_pointer(SSP_DEV_EEPROM, "ssp_busy_wait"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + eepromContext->ssp_busy_wait = vp; + + dprintk("LEAVE: lh7x_eeprom_make_ssp_association(%d)\n", sts); + + return(sts); +} + +/********************************************************************** +* Function: lh7x_eeprom_init +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +static int lh7x_eeprom_init(void) +{ + eepromContext_t *eepromContext = &eepromContext_l; + int sts = 0; + dprintk("ENTER: lh7x_eeprom_init()\n"); + init_waitqueue_head(&eepromContext->read_and_write_wait); + /* Retrieve the service information from the SSP driver */ + sts = lh7x_eeprom_make_ssp_association(eepromContext); + if (sts == 0) { + /* Ensure the eeprom cache is valid */ + eeprom_lh7x_read_device(eepromContext); + sts = misc_register(&lh7x_eeprom_dev); + } + dprintk("LEAVE: lh7x_eeprom_init(%d)\n", sts); + return(sts); +} + +/********************************************************************** +* Function: lh7x_eeprom_exit +* +* Purpose: +* Un-Register & Cleanup the module +**********************************************************************/ +static void lh7x_eeprom_exit(void) +{ + dprintk("ENTER: lh7x_eeprom_exit()\n"); + misc_deregister(&lh7x_eeprom_dev); + dprintk("LEAVE: lh7x_eeprom_exit()\n"); + return; +} + +module_init(lh7x_eeprom_init); +module_exit(lh7x_eeprom_exit); + +MODULE_AUTHOR("Jim Gleason / Lineo, Inc."); +MODULE_DESCRIPTION("Microchip 93LC46B 64 x 16 EEPROM access for LH7x EVB"); +MODULE_LICENSE("Copyright (c) 2002 Lineo, Inc."); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/misc/led-lh7a400.c linux-2.4.21-rmk1-lh7a400/drivers/misc/led-lh7a400.c --- linux-2.4.21-rmk1/drivers/misc/led-lh7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/misc/led-lh7a400.c Sun Feb 8 20:35:44 2004 @@ -0,0 +1,651 @@ +/* vi: set sw=4 ts=4 ai: */ + +//#define MODULE + +/********************************************************************** +* linux/drivers/misc/lh7x-7seg.c +* +* Provide ADS_784x 7-Segment access for LH7x EVB boards +* +* Copyright (C) 2002 Lineo, Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License (GPL) version 2 +* as published by the Free Software Foundation. +* +**********************************************************************/ + +/********************************************************************** +* To light up the 7-segment display, write a 16-bit value to +* +* cpld->seven_seg. +* +* The high-order byte is the most significant 7-segment digit, +* and the low-order byte is the lsb. +* +* NOTE: The 7-segment display bars are bit-mapped. +* NOTE: The 7-segment display bars are ACTIVE LOW. +* +* _ == a +* | | == f b +* - == g +* | | == e c +* -. == d dot +* +* a 0x01 +* b 0x02 +* c 0x04 +* d 0x08 +* e 0x10 +* f 0x20 +* g 0x40 +* dot 0x80 (also known as dp) +* +* The data to write looks like this: +* +* static u_char lednum[] = +* { 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, // 0-7 +* 0x80, 0x98, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E, // 8-F +* 0xBF, // hyphen +* 0xFF, // (blank) +* }; +* +* SO - to make "7F" show up, do this: +* +* cpld->seven_seg = 0xf88e; +* +* NOTE: When read, the 7-segment display does not return valid data. +* +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#undef VERBOSE +#define DRVNAME "lh7x-7seg" +//#include +#define vdprintk(...) +#define dprintk(...) + +#include +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +#endif /* MODULE */ + +#include +#include +#include + +static cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + +/********************************************************************** +* Define our Seven Segment context structure +**********************************************************************/ +typedef struct sevenSegmentContext_t sevenSegmentContext_t; +struct sevenSegmentContext_t { + struct fasync_struct *fasync; + wait_queue_head_t read_and_write_wait; + + int inEscape; /* 1 == We are in an escape sequence, 0 == NOT */ + int accessMode; /* See ACCESSMODE_xxx definitions below */ + int rawData; /* Raw == 1, Cooked == 0 */ + uint16_t currentRawVal; +}; +static sevenSegmentContext_t sevenSegmentContext_l; + +#define ESCAPE 27 + +#define ACCESSMODE_SHIFT 0 +#define ACCESSMODE_LSB 1 +#define ACCESSMODE_MSB 2 +#define ACCESSMODE_DAFAULT ACCESSMODE_SHIFT + +/********************************************************************** +* Define our Seven Segment Data +**********************************************************************/ + +typedef struct sevenSegmentData_t sevenSegmentData_t; +struct sevenSegmentData_t { + int val; + u_char raw_val; +}; + +#define SSD_BLANK ((u_char)~(0x00)) + +static sevenSegmentData_t sevenSegmentData[] = { + {'0', (u_char)~(SSD_A | SSD_B | SSD_C | SSD_D | SSD_E | SSD_F) }, + {'1', (u_char)~(SSD_B | SSD_C) }, + {'2', (u_char)~(SSD_A | SSD_B | SSD_G | SSD_E | SSD_D) }, + {'3', (u_char)~(SSD_A | SSD_B | SSD_G | SSD_C | SSD_D) }, + {'4', (u_char)~(SSD_F | SSD_G | SSD_B | SSD_C) }, + {'5', (u_char)~(SSD_A | SSD_F | SSD_G | SSD_C | SSD_D) }, + {'6', (u_char)~(SSD_A | SSD_F | SSD_E | SSD_D | SSD_C | SSD_G) }, + {'7', (u_char)~(SSD_A | SSD_B | SSD_C) }, + {'8', (u_char)~(SSD_A | SSD_B | SSD_C | SSD_D | SSD_E | SSD_F | SSD_G) }, + {'9', (u_char)~(SSD_G | SSD_F | SSD_A | SSD_B | SSD_C) }, + {'A', (u_char)~(SSD_E | SSD_F | SSD_A | SSD_B | SSD_C | SSD_G) }, + {'a', (u_char)~(SSD_E | SSD_F | SSD_A | SSD_B | SSD_C | SSD_G) }, + {'B', (u_char)~(SSD_F | SSD_E | SSD_D | SSD_C | SSD_G) }, + {'b', (u_char)~(SSD_F | SSD_E | SSD_D | SSD_C | SSD_G) }, + {'C', (u_char)~(SSD_A | SSD_F | SSD_E | SSD_D) }, + {'c', (u_char)~(SSD_A | SSD_F | SSD_E | SSD_D) }, + {'D', (u_char)~(SSD_B | SSD_C | SSD_D | SSD_E | SSD_G) }, + {'d', (u_char)~(SSD_B | SSD_C | SSD_D | SSD_E | SSD_G) }, + {'E', (u_char)~(SSD_A | SSD_F | SSD_G | SSD_E | SSD_D) }, + {'e', (u_char)~(SSD_A | SSD_F | SSD_G | SSD_E | SSD_D) }, + {'F', (u_char)~(SSD_A | SSD_F | SSD_G | SSD_E) }, + {'f', (u_char)~(SSD_A | SSD_F | SSD_G | SSD_E) }, + {'H', (u_char)~(SSD_F | SSD_E | SSD_G | SSD_B | SSD_C) }, + {'h', (u_char)~(SSD_F | SSD_E | SSD_G | SSD_B | SSD_C) }, + {'I', (u_char)~(SSD_F | SSD_E) }, + {'i', (u_char)~(SSD_F | SSD_E) }, + {'Y', (u_char)~(SSD_F | SSD_G | SSD_B | SSD_C | SSD_D) }, + {'y', (u_char)~(SSD_F | SSD_G | SSD_B | SSD_C | SSD_D) }, + {'-', (u_char)~(SSD_G) }, + {'_', (u_char)~(SSD_D) }, + {'.', (u_char)~(SSD_DOT) }, + {' ', SSD_BLANK }, + {0x00, SSD_BLANK }, + { -1, (u_char)~(0x00) } /* End Of Data --- Must Be Last */ +}; + +/********************************************************************** +* Function: val_to_raw_val +**********************************************************************/ +static u_char val_to_raw_val(u_char val) +{ + sevenSegmentData_t *data; + u_char raw_val = 0xFF; /* Assume a blank if not found */ + for (data = sevenSegmentData; data->val != -1; data++) { + if (val == data->val) { + raw_val = data->raw_val; + break; + } + } + return(raw_val); +} + +/********************************************************************** +* Function: raw_val_to_val +**********************************************************************/ +static u_char raw_val_to_val(u_char raw_val) +{ + sevenSegmentData_t *data; + u_char val = ' '; /* Assume a blank if not found */ + for (data = sevenSegmentData; data->val != -1; data++) { + if (raw_val == data->raw_val) { + val = data->val; + break; + } + } + return(val); +} + +/********************************************************************** +* Function: lh7x_7seg_read_raw_display +* Function: lh7x_7seg_read_raw_display_lsb +* Function: lh7x_7seg_read_raw_display_msb +**********************************************************************/ +uint16_t lh7x_7seg_read_raw_display(void) +{ + sevenSegmentContext_t *sevenSegmentContext = &sevenSegmentContext_l; + uint16_t raw_val; + + /* + * NOTE: The device does not read so we have to remember... + */ + raw_val = sevenSegmentContext->currentRawVal; + vdprintk("lh7x_7seg_read_raw_display(0x%04X)\n", raw_val); + + return(raw_val); +} + +u_char lh7x_7seg_read_raw_display_lsb(void) +{ + uint16_t raw_val; + u_char raw_lsb; + + raw_val = lh7x_7seg_read_raw_display(); + raw_lsb = (u_char)(raw_val & 0xFF); + + return(raw_lsb); +} + +u_char lh7x_7seg_read_raw_display_msb(void) +{ + uint16_t raw_val; + u_char raw_msb; + + raw_val = lh7x_7seg_read_raw_display(); + raw_msb = (u_char)((raw_val >> 8) & 0xFF); + + return(raw_msb); +} + +/********************************************************************** +* Function: lh7x_7seg_read_display +* Function: lh7x_7seg_read_display_lsb +* Function: lh7x_7seg_read_display_msb +**********************************************************************/ +uint16_t lh7x_7seg_read_display(void) +{ + uint16_t raw_val, val; + u_char raw_lsb, lsb; + u_char raw_msb, msb; + + raw_val = lh7x_7seg_read_raw_display(); + raw_lsb = (u_char)( raw_val & 0xFF); + raw_msb = (u_char)((raw_val >> 8) & 0xFF); + lsb = raw_val_to_val(raw_lsb); + msb = raw_val_to_val(raw_msb); + val = (uint16_t)((msb << 8) | lsb); + + return(val); +} + +u_char lh7x_7seg_read_display_lsb(void) +{ + u_char raw_lsb, lsb; + + raw_lsb = lh7x_7seg_read_raw_display_lsb(); + lsb = raw_val_to_val(raw_lsb); + + return(lsb); +} + +u_char lh7x_7seg_read_display_msb(void) +{ + u_char raw_msb, msb; + + raw_msb = lh7x_7seg_read_raw_display_msb(); + msb = raw_val_to_val(raw_msb); + + return(msb); +} + +/********************************************************************** +* Function: lh7x_7seg_write_raw_display +* Function: lh7x_7seg_write_raw_display_lsb +* Function: lh7x_7seg_write_raw_display_msb +**********************************************************************/ +void lh7x_7seg_write_raw_display(uint16_t raw_val) +{ + sevenSegmentContext_t *sevenSegmentContext = &sevenSegmentContext_l; + + vdprintk("lh7x_7seg_write_raw_display(0x%04X)\n", raw_val); + /* + * NOTE: The device does not read so we have to remember... + */ + sevenSegmentContext->currentRawVal = raw_val; + cpld->seven_seg = raw_val; + + return; +} + +void lh7x_7seg_write_raw_display_lsb(u_char raw_lsb) +{ + uint16_t raw_val; + + raw_val = lh7x_7seg_read_raw_display(); + raw_val &= 0xFF00; + raw_val &= ((uint16_t)raw_lsb) & 0x00FF; + lh7x_7seg_write_raw_display(raw_val); + + return; +} + +void lh7x_7seg_write_raw_display_msb(u_char raw_msb) +{ + uint16_t raw_val; + + raw_val = lh7x_7seg_read_raw_display(); + raw_val &= 0x00FF; + raw_val &= (((uint16_t)raw_msb) << 8) & 0xFF00; + lh7x_7seg_write_raw_display(raw_val); + + return; +} + +/********************************************************************** +* Function: lh7x_7seg_write_display +* Function: lh7x_7seg_write_display_lsb +* Function: lh7x_7seg_write_display_msb +* Function: lh7x_7seg_write_display_str +**********************************************************************/ +void lh7x_7seg_write_display(uint16_t val) +{ + u_char raw_lsb, lsb; + u_char raw_msb, msb; + uint16_t raw_val; + + lsb = (u_char)( val & 0xFF); + msb = (u_char)((val >> 8) & 0xFF); + raw_lsb = val_to_raw_val(lsb); + raw_msb = val_to_raw_val(msb); + raw_val = (uint16_t)((raw_msb << 8) | raw_lsb); + lh7x_7seg_write_raw_display(raw_val); + + return; +} + +void lh7x_7seg_write_display_lsb(u_char lsb) +{ + u_char raw_lsb; + + raw_lsb = val_to_raw_val(lsb); + lh7x_7seg_write_raw_display_lsb(raw_lsb); + + return; +} + +void lh7x_7seg_write_display_msb(u_char msb) +{ + u_char raw_msb; + + raw_msb = val_to_raw_val(msb); + lh7x_7seg_write_raw_display_msb(raw_msb); + + return; +} + +void lh7x_7seg_write_display_str(u_char *str) +{ + uint16_t val; + uint16_t c16; + u_char c; + + if (str) { + /* This is basically a read, shift, write lsb loop */ + for ( ; *str; str++) { + c = *str; + if (c == '\n') continue; + if (c == '\r') continue; + val = lh7x_7seg_read_display(); + val <<= 8; + val &= 0xFF00; + c16 = c & 0x00FF; + val |= c16; + lh7x_7seg_write_display(val); + } + } + return; +} + +/********************************************************************** +* Function: sevenSegment_read +* Function: sevenSegment_poll +* Function: sevenSegment_open +* Function: sevenSegment_fasync +* Function: sevenSegment_release +* ************************************ +* *** User space driver interfaces *** +* ************************************ +**********************************************************************/ + +/* +* NOTE: The read algorithm is wide open for interpretation. +* I am not sure what the behaviour ought to be here. +*/ +static ssize_t sevenSegment_read(struct file *filp, char *buffer, + size_t _count, loff_t *ppos) +{ + sevenSegmentContext_t *sevenSegmentContext = filp->private_data; + DECLARE_WAITQUEUE(wait, current); + ssize_t sizeRead = 0; + char *ptr = buffer; + int err = 0; + int count = (int)_count; + uint16_t c16; + u_char c; + int dataSize; + int dataByteCount; + + switch (sevenSegmentContext->accessMode) { + case ACCESSMODE_LSB: + case ACCESSMODE_MSB: + dataSize = 8; + break; + case ACCESSMODE_SHIFT: + default: + dataSize = 16; + break; + } + dataByteCount = dataSize / 8; + + add_wait_queue(&sevenSegmentContext->read_and_write_wait, &wait); + while (count >= dataByteCount) { + err = -ERESTARTSYS; + if (signal_pending(current)) + break; + /* NOTE: We always have data */ + switch (sevenSegmentContext->accessMode) { + case ACCESSMODE_LSB: + c = lh7x_7seg_read_display_lsb(); + break; + case ACCESSMODE_MSB: + c = lh7x_7seg_read_display_msb(); + break; + case ACCESSMODE_SHIFT: + default: + c16 = lh7x_7seg_read_display(); + /* Flip the bytes so they get returned in the correct order */ + c = (u_char)(c16 >> 8); + c16 = ((c16 << 8) & 0xFF00) | ((uint16_t)c); + break; + } + if (dataSize == 8) { + err = copy_to_user(ptr, &c, sizeof(c)); + if (err) + break; + ptr += sizeof(c); + count -= sizeof(c); + } else /* (dataSize == 16) */ { + err = copy_to_user(ptr, &c16, sizeof(c16)); + if (err) + break; + ptr += sizeof(c16); + count -= sizeof(c16); + } + } + remove_wait_queue(&sevenSegmentContext->read_and_write_wait, &wait); + sizeRead = (ptr == buffer ? err : ptr - buffer); + return(sizeRead); +} + +static ssize_t sevenSegment_write(struct file *filp, const char *buffer, + size_t _count, loff_t *ppos) +{ + sevenSegmentContext_t *sevenSegmentContext = filp->private_data; + ssize_t sizeWritten = 0; + const char *ptr = buffer; + int count; + u_char c; + uint16_t c16; + uint16_t val; + int err = 0; + + for (count = (int)_count; count > 0; count--) { + /* NOTE: We always have room for the data */ + get_user(c, ptr++); + /* Ignore new_line or carriage_return characters */ + if (c == '\n') continue; + if (c == '\r') continue; + vdprintk("JMG: (e:%d, r:%d, a:%d) Attempting to write (%c) == (0x%02X)\n", + sevenSegmentContext->inEscape, + sevenSegmentContext->rawData, + sevenSegmentContext->accessMode, + c, c); + if (sevenSegmentContext->inEscape) { + sevenSegmentContext->inEscape = 0; + if ( c != ESCAPE ) { + switch (c) { + case 'r': /* Raw Data */ + case 'R': /* Raw Data */ + sevenSegmentContext->rawData = 1; + break; + case 'c': /* Coooked Data */ + case 'C': /* Coooked Data */ + sevenSegmentContext->rawData = 0; + break; + case 'l': /* LSB */ + case 'L': /* LSB */ + sevenSegmentContext->accessMode = ACCESSMODE_LSB; + break; + case 'm': /* MSB */ + case 'M': /* MSB */ + sevenSegmentContext->accessMode = ACCESSMODE_MSB; + break; + case 's': /* Shift */ + case 'S': /* Shift */ + case 'n': /* Normal */ + case 'N': /* Normal */ + default: + sevenSegmentContext->accessMode = ACCESSMODE_SHIFT; + } + continue; + } + } else if ( c == ESCAPE ) { + sevenSegmentContext->inEscape = 1; + continue; + } + if (sevenSegmentContext->rawData) { + val = lh7x_7seg_read_raw_display(); + } else { + val = lh7x_7seg_read_display(); + } + switch (sevenSegmentContext->accessMode) { + case ACCESSMODE_LSB: + val &= 0xFF00; + c16 = c & 0x00FF; + val |= c16; + break; + case ACCESSMODE_MSB: + val &= 0x00FF; + c16 = ((uint16_t)c << 8) & 0xFF00; + val |= c16; + break; + case ACCESSMODE_SHIFT: + default: + val <<= 8; + val &= 0xFF00; + c16 = c & 0x00FF; + val |= c16; + break; + } + vdprintk("JMG: Writing (0x%04X)\n", val); + if (sevenSegmentContext->rawData) { + lh7x_7seg_write_raw_display(val); + } else { + lh7x_7seg_write_display(val); + } + } + filp->f_dentry->d_inode->i_mtime = CURRENT_TIME; + sizeWritten = (ptr == buffer ? err : ptr - buffer); + return(sizeWritten); +} + +static unsigned int sevenSegment_poll(struct file *filp, poll_table *wait) +{ + sevenSegmentContext_t *sevenSegmentContext = filp->private_data; + /* We ALWAYS have data waiting ;) */ + int sts = POLLIN | POLLRDNORM; + poll_wait(filp, &sevenSegmentContext->read_and_write_wait, wait); + return(sts); +} + +static int sevenSegment_open(struct inode *inode, struct file *filp) +{ + sevenSegmentContext_t *sevenSegmentContext = &sevenSegmentContext_l; + int sts = 0; + filp->private_data = sevenSegmentContext; + return(sts); +} + +static int sevenSegment_fasync(int fd, struct file *filp, int on) +{ + sevenSegmentContext_t *sevenSegmentContext = filp->private_data; + int sts; + sts = fasync_helper(fd, filp, on, &sevenSegmentContext->fasync); + return(sts); +} + +static int sevenSegment_release(struct inode *inode, struct file *filp) +{ + lock_kernel(); + sevenSegment_fasync(-1, filp, 0); + unlock_kernel(); + return(0); +} + +/********************************************************************** +* Define (fill in) the user space file operations for this driver +* and initialize the Seven Segment driver as a "miscdevice": +* Character device +* Major(10) --- Non-serial mice, misc features +* Minor(21) --- /dev/7seg (7-segment display) +**********************************************************************/ +static struct file_operations sevenSegment_fops = { +owner: THIS_MODULE, +read: sevenSegment_read, +write: sevenSegment_write, +poll: sevenSegment_poll, +open: sevenSegment_open, +fasync: sevenSegment_fasync, +release: sevenSegment_release, +}; + +static struct miscdevice sevenSegment_dev = { +minor: 21, +name: "7seg", +fops: &sevenSegment_fops, +}; + +/********************************************************************** +* Function: lh7x_7seg_init +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +static int lh7x_7seg_init(void) +{ + sevenSegmentContext_t *sevenSegmentContext = &sevenSegmentContext_l; + int sts = 0; + dprintk("ENTER: lh7x_7seg_init()\n"); + init_waitqueue_head(&sevenSegmentContext->read_and_write_wait); + sts = misc_register(&sevenSegment_dev); + lh7x_7seg_write_display_str((u_char *)"HI"); + dprintk("LEAVE: lh7x_7seg_init(%d)\n", sts); + return(sts); +} + +/********************************************************************** +* Function: lh7x_7seg_exit +* +* Purpose: +* Un-Register & Cleanup the module +**********************************************************************/ +static void lh7x_7seg_exit(void) +{ + dprintk("ENTER: lh7x_7seg_exit()\n"); + misc_deregister(&sevenSegment_dev); + lh7x_7seg_write_display_str((u_char *)"BY"); + dprintk("LEAVE: lh7x_7seg_exit()\n"); + return; +} + +module_init(lh7x_7seg_init); +module_exit(lh7x_7seg_exit); + +MODULE_AUTHOR("Jim Gleason / Lineo, Inc."); +MODULE_DESCRIPTION("Seven Segment Display Driver for Sharp LH7x EVB"); +MODULE_LICENSE("Copyright (c) 2002 Lineo, Inc."); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/misc/sci-lh7a400.c linux-2.4.21-rmk1-lh7a400/drivers/misc/sci-lh7a400.c --- linux-2.4.21-rmk1/drivers/misc/sci-lh7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/misc/sci-lh7a400.c Thu Oct 16 16:59:38 2003 @@ -0,0 +1,1476 @@ +/* +* linux/drivers/misc/sci-lh7a4500.c +* +* Provide SCI (Smart Card Interface) access/control for the LH7A400 +* +* Copyright (C) 2002 Embedix, Inc. +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License (GPL) version 2 +* as published by the Free Software Foundation. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#undef VERBOSE +#define DRVNAME "LH7A400 SCI" +#include + +static sciRegs_t *sci = (sciRegs_t *)IO_ADDRESS(SCI_PHYS); +static clkscRegs_t *clksc = (clkscRegs_t *)IO_ADDRESS(CLKSC_PHYS); + +extern uint32_t hclkfreq_get(void); + +#define DRIVER_VERSION "0.01" +#define LH7A400_SCI_MINOR 24 + + +static struct fasync_struct *sci_async_queue; +static DECLARE_WAIT_QUEUE_HEAD(sci_wait); + +extern spinlock_t sci_lock; + +/***************************************************************************** +* Initialization Values +*****************************************************************************/ +#define SCI_CLOCK_FREQUENCY 1000000 /* SCI Clock Frequency */ +#define SCI_BAUD_RATE 2400 +#define CARD_DEBOUNCE 7 /* Approx 136mSec (1/ .136) */ +#define CR0_INIT 0 +#define CR1_INIT (SCI_CR1_ATRDEN | SCI_CR1_CLKZ1) +#define CR2_INIT 0 +#define IER_INIT 0 +#define DSTAT_INIT 0 +// #define ETU_INIT 9600 /* Initial ETU should be 104uSec */ +// #define CYCLES_INIT 10 /* Start with a setting of 10 */ +#define DTIME_MAX 3415 /* (1 / 0.8mSec) / 3 */ +#define ATIME_INIT 42000 /* Must be between 40000 & 45000 */ +#define ATRS_INIT 40000 /* Max of 40000 */ +#define ATRD_INIT 19200 /* Measured in ETU's */ +#define CHTIME_MAX 9600 /* Measured in ETU's */ +#define DIRECT_MODE 0x3B /* Normal non-inverted data mode */ +#define INVERSE_MODE 0x3F /* Inverted backwards data mode */ + +/***************************************************************************** +* Useful Macros +*****************************************************************************/ +#define SCI_CLKDIV(n) (n & 0xFF) +#define SCI_STABLE(n) (n & 0xFF) +#define SCI_ATRDTIME(n) (n & 0xFFFF) +#define SCI_ATRSTIME(n) (n & 0xFFFF) +#define SCI_CHTIME(n) (n & 0xFFFF) +#define SCI_RXTIME(n) (n & 0xFFFF) +#define SCI_TXRETRY(n) (n & 0x7) +#define SCI_RXRETRY(n) ((n & 0x7) << 3) +#define SCI_TXCOUNTCLR 1 /* Actually any value woll do */ +#define SCI_RXCOUNTCLR 1 /* Actually any value woll do */ +#define SCI_BLKTIME(n) (n & 0xFF) +#define SCI_CHGUARD(n) (n & 0xFF) +#define SCI_BLKGUARD(n) (n & 0xFF) +#define SCI_BAUD(n) (n & 0xFFFF) +#define SCI_VALUE(n) (n & 0xFF) + +static uint32_t lh7a400_sci_atr_chars; +static uint8_t lh7a400_sci_data_from_card[32]; + +/***************************************************************************** +* lh7a400_sci_init_state = 0: NOT initialized +* lh7a400_sci_init_state = 2: Driver initialized +* lh7a400_sci_init_state = 4: Card inserted, ATR sequence initiated +* lh7a400_sci_init_state = 6: Received TS char (Async mode) +* lh7a400_sci_init_state = 8: Received T0 char (Async mode) +* lh7a400_sci_init_state = 10: Received all optional chars (Async mode) +* lh7a400_sci_init_state = 12: ATR complete, card is ready (Async mode) +*****************************************************************************/ +static uint32_t lh7a400_sci_init_state = 0; +#define SCI_INIT_STATE_NOT_INITIALIZED 0 +#define SCI_INIT_STATE_INITIALIZED 2 +#define SCI_INIT_STATE_CARD_INSERTED 4 +#define SCI_INIT_STATE_RECEIVED_TS 6 +#define SCI_INIT_STATE_RECEIVED_T0 8 +#define SCI_INIT_STATE_RECEIVED_ALL 10 +#define SCI_INIT_STATE_ATR_COMPLETE 12 + +/***************************************************************************** +* Map of "Smart Card Interface Memory Map" to sciRegs_t structure +*****************************************************************************/ +#define SCIDATA sci->Data +#define SCICR0 sci->Ctrl0 +#define SCICR1 sci->Ctrl1 +#define SCICR2 sci->Ctrl2 +#define SCIIIER sci->InterruptEnable +#define SCIRETRY sci->Retry +#define SCITIDE sci->TideMark +#define SCITXCOUNT sci->TxCount +#define SCIRXCOUNT sci->RxCount +#define SCIFR sci->FifoStatus +#define SCIRXTIME sci->RxTimeout +#define SCIISTAT sci->Status +#define SCISTABLE sci->Stable +#define SCIATIME sci->ActivationTime +#define SCIDTIME sci->DeactivationTime +#define SCIATRSTIME sci->ATRStartTimeout +#define SCIATRDTIME sci->ATRDurationTimeout +#define SCIBLKTIME sci->BlockTimeout +#define SCICHTIME sci->CharTimeout +#define SCICLKICC sci->ClockICC +#define SCIBAUD sci->Baud +#define SCIVALUE sci->Value +#define SCICHGUARD sci->CharGuardTime +#define SCIBLKGUARD sci->BlockGuardTime +#define SCISYNCCR sci->SyncCR +#define SCISYNCDATA sci->SyncData +#define SCIRAWSTAT sci->RawStatus +#define SCIIIR sci->IrqID_Clear +#define SCIICR sci->IrqID_Clear +#define SCI_CONTROL sci->Control + +static struct +{ + uint8_t char_T0; + uint8_t char_TA[4]; + uint8_t char_TB[4]; + uint8_t char_TC[4]; + uint8_t char_TD[4]; + uint8_t char_HC[15]; +} SCI_CARD_PARAMS; + +/***************************************************************************** +* Function Pre-Declarations +*****************************************************************************/ +static int lh7a400_sci_irq_bit_to_index(uint32_t bit); +static int lh7a400_sci_install_int_handler + (uint32_t bit, int priority, void (*handler(void))); +static void lh7a400_sci_interrupt + (int irq, void *dev_id, struct pt_regs *regs); +static int lh7a400_sci_open + (struct inode *inode, struct file *file); +static int lh7a400_sci_release + (struct inode *inode, struct file *file); +static int lh7a400_sci_fasync + (int fd, struct file *filp, int on); +static unsigned int lh7a400_sci_poll + (struct file *file, poll_table *wait); +static loff_t lh7a400_sci_llseek + (struct file *file, loff_t offset, int origin); +static ssize_t lh7a400_sci_read + (struct file *file, char *buf, size_t count, loff_t *ppos); +static int lh7a400_sci_ioctl + (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); +static int lh7a400_sci_read_proc + (char *page, char **start, off_t off, int count, int *eof, void *data); +static void lh7a400_sci_activate(void); +static void lh7a400_sci_deactivate(void); +static void lh7a400_sci_card_up(void); +static void lh7a400_sci_atr_timeout(void); +static void lh7a400_sci_atr_start_to(void); +static void lh7a400_sci_read_atr_ts(void); +static void lh7a400_sci_read_atr_t0(void); +static void lh7a400_sci_read_atr_op(void); +static void lh7a400_sci_read_atr_hc(void); +static void lh7a400_sci_read_data(void); +static void lh7a400_sci_rx_to(void); +static int lh7a400_sci_init(void); +static void lh7a400_sci_exit(void); + +/***************************************************************************** +* FUNC: vdprintk_status +* NOTE: DEBUG Only +*****************************************************************************/ +#if defined(VERBOSE) && defined(DEBUG) +static void +vdprintk_status(const uint32_t status) +{ + printk("\t\tstatus:"); + if (status & SCI_STATUS_CARDPRESENT) printk(" cardPresent"); + if (status & SCI_STATUS_nSCIDATA_EN) printk(" nDATAEN"); + if (status & SCI_STATUS_nSCIDATAOUT_EN) printk(" nDATAOUTEN"); + if (status & SCI_STATUS_SCICLOCK_OUT) printk(" CLKOUT"); + if (status & SCI_STATUS_nSCICLOCK_EN) printk(" nCLKEN"); + if (status & SCI_STATUS_nSCICLOCKOUT_EN)printk(" nCLKOUTEN"); + if (status & SCI_STATUS_DATA_EN) printk(" DATAEN"); + if (status & SCI_STATUS_CLK_EN) printk(" CLKEN"); + if (status & SCI_STATUS_CRESET) printk(" CRESET"); + if (status & SCI_STATUS_POWER) printk(" POWER"); + printk("\n"); + + return; +} +#else /* defined(VERBOSE) && defined(DEBUG) */ +#define vdprintk_status(status) +#endif /* defined(VERBOSE) && defined(DEBUG) */ + +/***************************************************************************** +* FUNC: vdprintk_fifostatus +* NOTE: DEBUG Only +*****************************************************************************/ +#if defined(VERBOSE) && defined(DEBUG) +static void +vdprintk_fifostatus(const uint32_t status) +{ + printk("\t\tfifoStatus:"); + if (status & SCI_FIFOSTAT_RXFE) printk(" RX-empty"); + if (status & SCI_FIFOSTAT_RXFF) printk(" RX-full"); + if (status & SCI_FIFOSTAT_TXFE) printk(" TX-empty"); + if (status & SCI_FIFOSTAT_TXFF) printk(" TX-full"); + printk("\n"); + + return; +} +#else /* defined(VERBOSE) && defined(DEBUG) */ +#define vdprintk_fifostatus(status) +#endif /* defined(VERBOSE) && defined(DEBUG) */ + +/***************************************************************************** +* FUNC: dprintk_regs +* NOTE: DEBUG Only +*****************************************************************************/ +#if defined(DEBUG) +static void +dprintk_regs(const char *prefix) +{ + sciRegs_t *sci = (sciRegs_t *)IO_ADDRESS(SCI_PHYS); + uint32_t status = sci->Status; + + dprintk("regs(%s):\n", prefix); + printk("\tStatus=%08x\n", status); +#if defined(VERBOSE) + vdprintk_status(status); +#endif /* VERBOSE */ + printk("\tData=%08x\n", sci->Data); + printk("\tCR0=%08x\n", sci->Ctrl0); + printk("\tCR1=%08x\n", sci->Ctrl1); + printk("\tCR2=%08x\n", sci->Ctrl2); + printk("\tInterruptEnable=%08x\n", sci->InterruptEnable); + printk("\tRetry=%08x\n", sci->Retry); + printk("\tTideMark=%08x\n", sci->TideMark); + printk("\tTxCount=%08x\n", sci->TxCount); + printk("\tRxCount=%08x\n", sci->RxCount); + printk("\tFifoStatus=%08x\n", sci->FifoStatus); +#if defined(VERBOSE) + vdprintk_fifostatus(sci->FifoStatus); +#endif /* VERBOSE */ + printk("\tRxTimeout=%08x\n", sci->RxTimeout); + printk("\tStatus=%08x\n", sci->Status); + printk("\tStable=%08x\n", sci->Stable); + printk("\tActivationTime=%08x\n", sci->ActivationTime); + printk("\tDeactivationTime=%08x\n", sci->DeactivationTime); + printk("\tATRStartTimeout=%08x\n", sci->ATRStartTimeout); + printk("\tATRDurationTimeout=%08x\n", sci->ATRDurationTimeout); + printk("\tBlockTimeout=%08x\n", sci->BlockTimeout); + printk("\tCharTimeout=%08x\n", sci->CharTimeout); + printk("\tClockICC=%08x\n", sci->ClockICC); + printk("\tBaud=%08x\n", sci->Baud); + printk("\tValue=%08x\n", sci->Value); + printk("\tCharGuardTime=%08x\n", sci->CharGuardTime); + printk("\tBlockGuardTime=%08x\n", sci->BlockGuardTime); + printk("\tSyncCR=%08x\n", sci->SyncCR); + printk("\tSyncData=%08x\n", sci->SyncData); + printk("\tRawStatus=%08x\n", sci->RawStatus); + // IrqID_Clear (SCIICR) == (SCIIIR) */ + printk("\tIrqID_Clear=%08x\n", sci->IrqID_Clear); + printk("\tControl=%08x\n", sci->Control); + + return; +} +#else /* DEBUG */ +#define dprintk_regs(prefix) +#endif /* DEBUG */ + +/***************************************************************************** +* FUNC: dprintk_irq +* NOTE: DEBUG Only +*****************************************************************************/ +#if defined(DEBUG) +static void +dprintk_irq(uint32_t id) +{ + if (id & SCI_IRQ_TX_TIDE) printk(" tx-tide"); + if (id & SCI_IRQ_RX_TIDE) printk(" rx-tide"); + if (id & SCI_IRQ_RX_TIMEOUT) printk(" rx-timeout"); + if (id & SCI_IRQ_CHAR_TIMEOUT) printk(" char-timeout"); + if (id & SCI_IRQ_BLK_TIMEOUT) printk(" blk-timeout"); + if (id & SCI_IRQ_ATRD_TIMEOUT) printk(" atrd-timeout"); + if (id & SCI_IRQ_ATRS_TIMEOUT) printk(" atrs-timeout"); + if (id & SCI_IRQ_TX_ERROR) printk(" tx-error"); + if (id & SCI_IRQ_POWER_DOWN) printk(" power-down"); + if (id & SCI_IRQ_POWER_UP) printk(" power-up"); + if (id & SCI_IRQ_CARD_OUT) printk(" card-out"); + if (id & SCI_IRQ_CARD_IN) printk(" card-in"); + printk("\n"); + + return; +} +#else /* DEBUG */ +#define dprintk_irq(id) +#endif /* DEBUG */ + +/***************************************************************************** +* Type definitions for the IRQ code... +*****************************************************************************/ +typedef struct +{ + uint32_t bit; + void (*handler)(void); + int priority; +#ifdef DEBUG + char *description; +#endif /* DEBUG */ +} SCI_IRQ; + +#define MAX_SCI_IRQ 11 +static struct { + SCI_IRQ irq[MAX_SCI_IRQ + 1]; + int priority_index[MAX_SCI_IRQ + 1]; +} sci_irq_context; +static int sci_irq_context_initialized; + +#ifdef DEBUG +/***************************************************************************** +* FUNC: sci_irq_index_to_description +*****************************************************************************/ +static char * +sci_irq_index_to_description(int bit_index) +{ + static char *description[MAX_SCI_IRQ + 1] = + { + "INVALID", + "CARD_IN", + "CARD_OUT", + "POWER_UP", + "POWER_DOWN", + "TX_ERROR", + "ATRS_TIMEOUT", + "ATRD_TIMEOUT", + "BLK_TIMEOUT", + "CHAR_TIMEOUT", + "RX_TIMEOUT", + "RX_TIDE", + "TX_TIDE" + }; + + if ((bit_index < 0) || (bit_index > MAX_SCI_IRQ)) { + bit_index = -1; + } + bit_index++; /* Offset by one to account for "INVALID" */ + + return(description[bit_index]); +} +#else +#define sci_irq_index_to_description(n) "" +#endif /* DEBUG */ + +/***************************************************************************** +* FUNC: lh7a400_sci_irq_bit_to_index +*****************************************************************************/ +static int +lh7a400_sci_irq_bit_to_index(uint32_t bit) +{ + int bit_index = -1; + + vdprintk("ENTER: lh7a400_sci_irq_bit_to_index(0x%04X)\n", bit); + switch (bit) { + case SCI_IRQ_CARD_IN: bit_index = 0; break; + case SCI_IRQ_CARD_OUT: bit_index = 1; break; + case SCI_IRQ_POWER_UP: bit_index = 2; break; + case SCI_IRQ_POWER_DOWN: bit_index = 3; break; + case SCI_IRQ_TX_ERROR: bit_index = 4; break; + case SCI_IRQ_ATRS_TIMEOUT: bit_index = 5; break; + case SCI_IRQ_ATRD_TIMEOUT: bit_index = 6; break; + case SCI_IRQ_BLK_TIMEOUT: bit_index = 7; break; + case SCI_IRQ_CHAR_TIMEOUT: bit_index = 8; break; + case SCI_IRQ_RX_TIMEOUT: bit_index = 9; break; + case SCI_IRQ_RX_TIDE: bit_index = 10; break; + case SCI_IRQ_TX_TIDE: bit_index = 11; break; + } + vdprintk("LEAVE: lh7a400_sci_irq_bit_to_index(%d)\n", bit_index); + + return(bit_index); +} + +/***************************************************************************** +* FUNC: lh7a400_sci_install_int_handler +*****************************************************************************/ +static int +lh7a400_sci_install_int_handler (uint32_t bit, int priority, + void (*handler(void))) +{ + int sts = -1; + int bit_index; + int i; +#ifdef DEBUG + char *description; +#endif /* DEBUG */ + + /* Initialize hander information for all available interrupts */ + if (sci_irq_context_initialized == 0) { + sci_irq_context_initialized++; + vdprintk("INIT: lh7a400_sci_install_int_handler()\n"); + for (bit_index = 0; bit_index <= MAX_SCI_IRQ; bit_index++) { + sci_irq_context.irq[bit_index].bit = (1 << bit_index); + sci_irq_context.irq[bit_index].handler = NULL; + sci_irq_context.irq[bit_index].priority = 99999; + sci_irq_context.priority_index[bit_index] = bit_index; + } + } + + /* Install the specified handler information */ + bit_index = lh7a400_sci_irq_bit_to_index(bit); +#ifdef DEBUG + description = sci_irq_index_to_description(bit_index); + vdprintk("ENTER: lh7a400_sci_install_int_handler(b:0x%04X, bi:%d, p:%d, h:0x%08X, d:%s)\n", bit, bit_index, priority, handler, description); +#endif /* DEBUG */ + if ((bit_index >= 0) && (bit_index <= MAX_SCI_IRQ)) { + sci_irq_context.irq[bit_index].handler = handler; + sci_irq_context.irq[bit_index].priority = priority; + sts = 0; + } + /* + * Sort the handler priority list (a list of indexes to the handlers) + * NOTE: Because we always keep this list in order, we can optimize a + * bubble sort by only going UP the list once and DOWN the list once... + */ + for (i = 0; i < MAX_SCI_IRQ; i++) { + int ii = i + 1; + if (sci_irq_context.irq[sci_irq_context.priority_index[i]].priority + > sci_irq_context.irq[sci_irq_context.priority_index[ii]].priority) + { + /* Switch the priority_index(es) */ + int tmp_priority_index = sci_irq_context.priority_index[i]; + sci_irq_context.priority_index[i] = + sci_irq_context.priority_index[ii]; + sci_irq_context.priority_index[ii] = tmp_priority_index; + } + } + for (i = MAX_SCI_IRQ; i > 0; i--) { + int ii = i - 1; + if (sci_irq_context.irq[sci_irq_context.priority_index[i]].priority + < sci_irq_context.irq[sci_irq_context.priority_index[ii]].priority) + { + /* Switch the priority_index(es) */ + int tmp_priority_index = sci_irq_context.priority_index[i]; + sci_irq_context.priority_index[i] = + sci_irq_context.priority_index[ii]; + sci_irq_context.priority_index[ii] = tmp_priority_index; + } + } +#if (0) + dprintk("priority_index: "); + for (i = 0; i <= MAX_SCI_IRQ; i++) { + printk(" <%d:%d>", + sci_irq_context.priority_index[i], + sci_irq_context.irq[sci_irq_context.priority_index[i]].priority); + } + printk("\n"); +#endif /* (0) */ + vdprintk("LEAVE: lh7a400_sci_install_int_handler()\n"); + + return(sts); +} + +/***************************************************************************** +* FUNC: lh7a400_sci_interrupt +* +* *************************************** +* ***** IRQ Bit, Priority, Function ***** +* *************************************** +* +*****************************************************************************/ +static void +lh7a400_sci_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + uint32_t irq_bits = sci->IrqID_Clear; + int priority_index; + int bit_index; + uint32_t bit; + void (*handler)(void); + // int priority; +#ifdef DEBUG + char *description; +#endif /* DEBUG */ + +#ifdef VERBOSE + vdprintk("ENTER: lh7a400_sci_interrupt(0x%04X)", irq_bits); + dprintk_irq(irq_bits); +#if (0) + dprintk_regs("irq"); +#endif +#endif /* VERBOSE */ + + /* Make sure we have initialized */ + if (sci_irq_context_initialized == 0) { + lh7a400_sci_install_int_handler(-1, -1, NULL); + } + + for (priority_index = 0; priority_index <= MAX_SCI_IRQ; priority_index++) { + bit_index = sci_irq_context.priority_index[priority_index]; + bit = sci_irq_context.irq[bit_index].bit; + handler = sci_irq_context.irq[bit_index].handler; + // priority = sci_irq_context.irq[bit_index].priority; + if ((irq_bits & bit) && (handler)) { +#ifdef DEBUG + description = sci_irq_index_to_description(bit_index); + dprintk("IRQ: %s\n", description); +#endif /* DEBUG */ + handler(); + } + } + vdprintk("LEAVE: lh7a400_sci_interrupt()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_open +*****************************************************************************/ +static int +lh7a400_sci_open(struct inode *inode, struct file *file) +{ + dprintk("ENTER: lh7a400_sci_open()\n"); +#if NEVER + if (test_and_set_bit(1, &sci_status)) + return -EBUSY; + sci_irq_data = 0; +#endif // NEVER + dprintk("LEAVE: lh7a400_sci_open()\n"); + + return 0; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_release +*****************************************************************************/ +static int +lh7a400_sci_release(struct inode *inode, struct file *file) +{ + dprintk("ENTER: lh7a400_sci_release()\n"); +#if NEVER + spin_lock_irq(&sci_lock); + rtcregs->u.eoi = 1; + spin_unlock_irq(&sci_lock); + sci_status = 0; +#endif // NEVER + dprintk("LEAVE: lh7a400_sci_release()\n"); + + return 0; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_fasync +*****************************************************************************/ +static int +lh7a400_sci_fasync(int fd, struct file *filp, int on) +{ + dprintk("ENTER: lh7a400_sci_fasync()\n"); + dprintk("LEAVE: lh7a400_sci_fasync()\n"); + return fasync_helper(fd, filp, on, &sci_async_queue); +} + +/***************************************************************************** +* FUNC: lh7a400_sci_poll +*****************************************************************************/ +static unsigned int +lh7a400_sci_poll(struct file *file, poll_table *wait) +{ + unsigned int retval = 0; + + dprintk("ENTER: lh7a400_sci_poll()\n"); +#if NEVER + poll_wait(file, &sci_wait, wait); + retval = (sci_irq_data) ? 0 : POLLIN | POLLRDNORM; +#endif // NEVER + dprintk("LEAVE: lh7a400_sci_poll()\n"); + + return(retval); +} + +/***************************************************************************** +* FUNC: lh7a400_sci_llseek +*****************************************************************************/ +static loff_t +lh7a400_sci_llseek(struct file *file, loff_t offset, int origin) +{ + dprintk("ENTER: lh7a400_sci_llseek()\n"); + dprintk("LEAVE: lh7a400_sci_llseek()\n"); + return -ESPIPE; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_read +*****************************************************************************/ +static ssize_t +lh7a400_sci_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + ssize_t retval; + + dprintk("ENTER: lh7a400_sci_read(file=0x%p, buf=0x%p, count=%d, ppos=0x%p)\n", file, buf, count, ppos); + +#if NEVER + DECLARE_WAITQUEUE(wait, current); + unsigned long data; + ssize_t retval; + + if (count < sizeof(unsigned long)) + return -EINVAL; + + add_wait_queue(&sci_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + for (;;) { + spin_lock_irq(&sci_lock); + data = sci_irq_data; + if (data != 0) { + sci_irq_data = 0; + break; + } + spin_unlock_irq(&sci_lock); + + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + schedule(); + } + + spin_unlock_irq(&sci_lock); + + data -= 0x100; /* the first IRQ wasn't actually missed */ + + retval = put_user(data, (unsigned long *)buf); + if (!retval) + retval = sizeof(unsigned long); + +out: + set_current_state(TASK_RUNNING); + remove_wait_queue(&sci_wait, &wait); +#else + retval = 0; +#endif // NEVER + dprintk("LEAVE: lh7a400_sci_read()\n"); + return(retval); +} + +/***************************************************************************** +* FUNC: lh7a400_sci_ioctl +*****************************************************************************/ +static int +lh7a400_sci_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int retval; + + dprintk("ENTER: lh7a400_sci_ioctl()\n"); +#if NEVER + struct sci_time tm, tm2; + + switch (cmd) { + case RTC_AIE_OFF: + spin_lock_irq(&sci_lock); + rtcregs->u.stat = 0; + rtcregs->cr = ~RTCR_MIE; + sci_irq_data = 0; + spin_unlock_irq(&sci_lock); + return 0; + case RTC_AIE_ON: + spin_lock_irq(&sci_lock); + rtcregs->u.stat = 0; + rtcregs->cr = RTCR_MIE; + sci_irq_data = 0; + spin_unlock_irq(&sci_lock); + return 0; + case RTC_UIE_OFF: + case RTC_UIE_ON: + case RTC_PIE_OFF: + case RTC_PIE_ON: + return -EINVAL; + + case RTC_ALM_READ: + decodetime(rtcregs->mr, &tm); + break; + case RTC_ALM_SET: + if (copy_from_user(&tm2, (struct sci_time*)arg, sizeof(tm2))) + return -EFAULT; + decodetime(rtcregs->dr, &tm); + if ((unsigned)tm2.tm_hour < 24) + tm.tm_hour = tm2.tm_hour; + if ((unsigned)tm2.tm_min < 60) + tm.tm_min = tm2.tm_min; + if ((unsigned)tm2.tm_sec < 60) + tm.tm_sec = tm2.tm_sec; + rtcregs->mr = encodetime(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + return 0; + case RTC_RD_TIME: + decodetime(rtcregs->dr, &tm); + break; + case RTC_SET_TIME: + if (!capable(CAP_SYS_TIME)) + return -EACCES; + if (copy_from_user(&tm, (struct sci_time*)arg, sizeof (tm))) + return -EFAULT; + tm.tm_year += 1900; + if (tm.tm_year < 1970 || (unsigned)tm.tm_mon >= 12 || + tm.tm_mday < 1 || tm.tm_mday > (days_in_mo[tm.tm_mon] + + (tm.tm_mon == 1 && is_leap(tm.tm_year))) || + (unsigned)tm.tm_hour >= 24 || + (unsigned)tm.tm_min >= 60 || + (unsigned)tm.tm_sec >= 60) + return -EINVAL; + rtcregs->clr = encodetime(tm.tm_year, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + return 0; + case RTC_IRQP_READ: + case RTC_IRQP_SET: + return -EINVAL; + case RTC_EPOCH_READ: + return put_user(epoch, (unsigned long *)arg); + default: + return -EINVAL; + } + retval = copy_to_user((void *)arg, &tm, sizeof (tm)) ? -EFAULT : 0; +#else + retval = 0; +#endif // NEVER + dprintk("LEAVE: lh7a400_sci_ioctl()\n"); + return(retval); +} + +/***************************************************************************** +* DATA: lh7a400_sci_fops +*****************************************************************************/ +static struct file_operations lh7a400_sci_fops = { + owner: THIS_MODULE, + llseek: lh7a400_sci_llseek, + read: lh7a400_sci_read, + poll: lh7a400_sci_poll, + ioctl: lh7a400_sci_ioctl, + open: lh7a400_sci_open, + release: lh7a400_sci_release, + fasync: lh7a400_sci_fasync, +}; + +/***************************************************************************** +* DATA: lh7a400_sci_miscdev +*****************************************************************************/ +static struct miscdevice lh7a400_sci_miscdev = { + LH7A400_SCI_MINOR, + "SmartCard(sci)", + &lh7a400_sci_fops +}; + +/***************************************************************************** +* FUNC: lh7a400_sci_read_proc +*****************************************************************************/ +static int +lh7a400_sci_read_proc(char *page, char **start, off_t off, int count, + int *eof, void *data) +{ + int retval; +#if NEVER + char *p = page; + int len; + struct sci_time tm; +#endif // NEVER + + dprintk("ENTER: lh7a400_sci_read_proc(page=0x%p, start=0x%p, " + "off=%d, count=%d, ...)\n", page, start, (int)off, count); + +#if NEVER + decodetime(rtcregs->dr, &tm); + p += sprintf(p, "dr\t\t: %d\n" + "rtc_time\t: %02d:%02d:%02d\n" + "rtc_date\t: %04d-%02d-%02d\n" + "rtc_epoch\t: %04d\n", + rtcregs->dr, + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, epoch); + decodetime(rtcregs->mr, &tm); + p += sprintf(p, "alrm_time\t: %02d:%02d:%02d\n" + "alrm_date\t: %04d-%02d-%02d\n", + tm.tm_hour, tm.tm_min, tm.tm_sec, + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday); + p += sprintf(p, "update_IRQ\t: %s\n", (rtcregs->u.stat) ? "yes" : "no"); + p += sprintf(p, "periodic_freq\t: %ld\n", sci_freq); + + len = (p - page) - off; + if (len < 0) + len = 0; + + *eof = (len <= count) ? 1 : 0; + *start = page + off; + + retval = len; +#else + retval = 0; +#endif // NEVER + dprintk("LEAVE: lh7a400_sci_read_proc()\n"); + return(retval); +} + +/***************************************************************************** +* FUNC: sci_session_if_config +* +* Purpose: Reconfigures the SCI for normal communication based on +* parameter returned during ATR sequence. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: Need to finish this function!!! +*****************************************************************************/ +static void +sci_session_if_config(void) +{ + vdprintk("ENTER: sci_session_if_config()\n"); + sci->TideMark = SCI_TIDE_RX(7); + lh7a400_sci_install_int_handler(SCI_IRQ_RX_TIDE, 2, lh7a400_sci_read_data); + sci->InterruptEnable &= ~(SCI_IRQ_ATRS_TIMEOUT | SCI_IRQ_ATRD_TIMEOUT); + vdprintk("LEAVE: sci_session_if_config()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_activate +* +* Purpose: To activate the SCI interface when a Smart card is inserted. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: None +*****************************************************************************/ +static void +lh7a400_sci_activate(void) +{ + vdprintk("ENTER: lh7a400_sci_activate()\n"); + /* Disable SCI_IRQ_CARD_IN, and Enable SCI_IRQ_CARD_OUT */ + sci->InterruptEnable &= ~SCI_IRQ_CARD_IN; + sci->InterruptEnable |= SCI_IRQ_CARD_OUT; + /* + * Clear SCI_IRQ_CARD_IN. + * SCI_IRQ_CARD_IN doesn't clear by just doing + * "sci->IrqID_Clear = SCI_IRQ_CARD_IN;" + * it also needs the card "activated". + */ + sci->IrqID_Clear = SCI_IRQ_CARD_IN; + /* Clear direction mode (enable RECEIVE) */ + sci->Ctrl1 &= ~SCI_CR1_MODE_TX; + sci->Ctrl2 = SCI_CR2_STARTUP; + sci->TideMark = (SCI_TIDE_TX(0) | SCI_TIDE_RX(0)); + sci->InterruptEnable |= SCI_IRQ_RX_TIDE; + lh7a400_sci_init_state = SCI_INIT_STATE_CARD_INSERTED; + vdprintk("LEAVE: lh7a400_sci_activate()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_deactivate +* +* Purpose: When the SCI card removed interrupt goes active, or when a +* user requests that the card be deactivated, initiate the +* deactivation sequence, and disable the card removed +* interrupt. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: The deactivation sequence must complete within one millisecond +* of card removal detection, or damage to the card may result. +*****************************************************************************/ +static void +lh7a400_sci_deactivate(void) +{ + vdprintk("ENTER: lh7a400_sci_deactivate()\n"); + /* Disable SCI_IRQ_CARD_OUT, and Enable SCI_IRQ_CARD_IN */ + sci->InterruptEnable &= ~SCI_IRQ_CARD_OUT; + sci->InterruptEnable |= SCI_IRQ_CARD_IN; + /* + * Clear SCI_IRQ_CARD_OUT. + * SCI_IRQ_CARD_OUT doesn't clear by just doing + * "sci->IrqID_Clear = SCI_IRQ_CARD_OUT;" + * it also needs the card "deactivated". + */ + sci->IrqID_Clear = SCI_IRQ_CARD_OUT; +#ifdef SHARP_STUFF + sci->Ctrl2 = SCI_CR2_FINISH; + //sci->InterruptEnable &= ~(SCI_IRQ_CARD_OUT); + lh7a400_sci_init_state = SCI_INIT_STATE_INITIALIZED; + mdelay(1); + lh7a400_sci_init(); +#endif /* SHARP_STUFF */ + vdprintk("LEAVE: lh7a400_sci_deactivate()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_card_up +* +* Purpose: To configure the SCI interface when a Smart card has been +* activated. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: Enables the Card Out interrupt. +*****************************************************************************/ +static void +lh7a400_sci_card_up(void) +{ + vdprintk("ENTER: lh7a400_sci_card_up()\n"); + sci->IrqID_Clear = SCI_IRQ_POWER_UP; + sci->InterruptEnable |= SCI_IRQ_CARD_OUT; + lh7a400_sci_init_state = SCI_INIT_STATE_ATR_COMPLETE; + vdprintk("LEAVE: lh7a400_sci_card_up()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_atr_timeout +* +* Purpose: +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: +*****************************************************************************/ +static void +lh7a400_sci_atr_timeout(void) +{ + vdprintk("ENTER: lh7a400_sci_atr_timeout()\n"); + sci->IrqID_Clear = SCI_IRQ_ATRD_TIMEOUT; + sci->InterruptEnable &= ~(SCI_IRQ_ATRS_TIMEOUT); + lh7a400_sci_deactivate(); + vdprintk("LEAVE: lh7a400_sci_atr_timeout()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_atr_start_to +* +* Purpose: +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: +*****************************************************************************/ +static void +lh7a400_sci_atr_start_to(void) +{ + vdprintk("ENTER: lh7a400_sci_atr_start_to()\n"); + sci->IrqID_Clear = SCI_IRQ_ATRD_TIMEOUT; + sci->InterruptEnable &= ~(SCI_IRQ_ATRS_TIMEOUT); + lh7a400_sci_deactivate(); + vdprintk("LEAVE: lh7a400_sci_atr_start_to()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_read_atr_ts +* +* Purpose: To check the TS character received from the SCI interface +* to determine what data mode the Smart card uses. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: Reads the TS char, and if a correct char is read, set the +* correct data mode, increase the FIFO watermark, and replace +* the ISR with the next stage handler. +*****************************************************************************/ +static void +lh7a400_sci_read_atr_ts(void) +{ + uint32_t ts_char; + + vdprintk("ENTER: lh7a400_sci_read_atr_ts()\n"); + dprintk_regs("read_atr_ts"); + if (sci->RxCount > 0) { + vdprintk("RxCount = %d\n", sci->RxCount); + ts_char = (uint8_t) sci->Data; + if (ts_char == DIRECT_MODE) { + // vdprintk("Using DIRECT Mode"); + sci->Ctrl0 = CR0_INIT; + } else if (ts_char == INVERSE_MODE) { + // vdprintk("Using INVERSE Mode"); + sci->Ctrl0 = (CR0_INIT | SCI_CR0_SENSE | SCI_CR0_ORDER); + } else { + /* This is a good place to add Sync mode init/id code*/ + // lh7a400_sci_deactivate(); --- Just ignore it - JMG + vdprintk("LEAVE: lh7a400_sci_read_atr_ts(UnknownMode:0x%02X)\n", + ts_char); + return; + } + lh7a400_sci_init_state = SCI_INIT_STATE_RECEIVED_TS; + lh7a400_sci_install_int_handler(SCI_IRQ_RX_TIDE, 2, + lh7a400_sci_read_atr_t0); + sci->InterruptEnable |= SCI_IRQ_ATRD_TIMEOUT; + vdprintk("LEAVE: lh7a400_sci_read_atr_ts(%s:0x%02X)\n", + ((ts_char == DIRECT_MODE) ? + "DirectMode":"InverseMode"), ts_char); + } else { + vdprintk("LEAVE: lh7a400_sci_read_atr_ts(Nothing read)\n"); + } + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_read_atr_t0 +* +* Purpose: To check the T0 character received from the SCI interface +* to determine the additional configuration for the interface. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: +*****************************************************************************/ +static void +lh7a400_sci_read_atr_t0(void) +{ + uint32_t temp; + + vdprintk("ENTER: lh7a400_sci_read_atr_t0()\n"); + SCI_CARD_PARAMS.char_T0 = (uint8_t) sci->Data; + SCI_CARD_PARAMS.char_TD[0] = (SCI_CARD_PARAMS.char_T0 & 0xF0); + lh7a400_sci_atr_chars = 0; + for (temp = 0x10; temp < 0x100; temp <<= 1) { + if (SCI_CARD_PARAMS.char_T0 & temp) { + lh7a400_sci_atr_chars++; + } + } + if (lh7a400_sci_atr_chars) { + lh7a400_sci_install_int_handler(SCI_IRQ_RX_TIDE, 2, + lh7a400_sci_read_atr_op); + } else { + lh7a400_sci_atr_chars = (SCI_CARD_PARAMS.char_T0 && 0xF); + lh7a400_sci_install_int_handler(SCI_IRQ_RX_TIDE, 2, + lh7a400_sci_read_atr_hc); + } + lh7a400_sci_init_state = SCI_INIT_STATE_RECEIVED_T0; + vdprintk("LEAVE: lh7a400_sci_read_atr_t0()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_read_atr_op +* +* Purpose: To check the T0 character received from the SCI interface +* to determine the additional configuration for the interface. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: +*****************************************************************************/ +static void +lh7a400_sci_read_atr_op(void) +{ + static uint32_t opt_chars; + uint32_t temp, data; + + vdprintk("ENTER: lh7a400_sci_read_atr_op()\n"); + data = sci->Data; + if (lh7a400_sci_init_state == SCI_INIT_STATE_RECEIVED_T0) { + opt_chars = 0; + } + if (lh7a400_sci_atr_chars) { + if (SCI_CARD_PARAMS.char_TD[opt_chars] & 0x10) { + SCI_CARD_PARAMS.char_TA[opt_chars] = (uint8_t) data; + SCI_CARD_PARAMS.char_TD[opt_chars] &= ~(0x10); + lh7a400_sci_atr_chars--; + } else if (SCI_CARD_PARAMS.char_TD[opt_chars] & 0x20) { + SCI_CARD_PARAMS.char_TB[opt_chars] = (uint8_t) data; + SCI_CARD_PARAMS.char_TD[opt_chars] &= ~(0x20); + lh7a400_sci_atr_chars--; + } else if (SCI_CARD_PARAMS.char_TD[opt_chars] & 0x40) { + SCI_CARD_PARAMS.char_TC[opt_chars] = (uint8_t) data; + SCI_CARD_PARAMS.char_TD[opt_chars] &= ~(0x40); + lh7a400_sci_atr_chars--; + } else if (SCI_CARD_PARAMS.char_TD[opt_chars] & 0x80) { + opt_chars++; + SCI_CARD_PARAMS.char_TD[opt_chars] = (uint8_t) data; + lh7a400_sci_atr_chars--; + for (temp = 0x10; temp < 0x100; temp <<= 1) { + if (SCI_CARD_PARAMS.char_TD[opt_chars] & temp) + { + lh7a400_sci_atr_chars++; + } + } + } + } + if (lh7a400_sci_atr_chars == 0) { + if (SCI_CARD_PARAMS.char_T0 && 0xF != 0) { + lh7a400_sci_atr_chars = SCI_CARD_PARAMS.char_T0 & 0xF; + lh7a400_sci_install_int_handler(SCI_IRQ_RX_TIDE, 2, + lh7a400_sci_read_atr_hc); + } else { + sci_session_if_config(); + } + } + lh7a400_sci_init_state = SCI_INIT_STATE_RECEIVED_ALL; + vdprintk("LEAVE: lh7a400_sci_read_atr_op()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_read_atr_hc +* +* Purpose: To handle the optional "Historical Characters received +* from the SCI interface. Currently these chars are ignored. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: +*****************************************************************************/ +static void +lh7a400_sci_read_atr_hc(void) +{ + static uint32_t hist_chars = 0; + + vdprintk("ENTER: lh7a400_sci_read_atr_hc()\n"); + SCI_CARD_PARAMS.char_HC[hist_chars++] = (uint8_t) sci->Data; + lh7a400_sci_atr_chars--; + if (lh7a400_sci_atr_chars == 0) { + sci_session_if_config(); + } + vdprintk("LEAVE: lh7a400_sci_read_atr_hc()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_read_data +* +* Purpose: +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: +*****************************************************************************/ +static void +lh7a400_sci_read_data(void) +{ + uint32_t idx; + + vdprintk("ENTER: lh7a400_sci_read_data()\n"); + for (idx = 0; idx < 8; idx++) { + lh7a400_sci_data_from_card[idx] = (uint8_t) sci->Data; + } + vdprintk("LEAVE: lh7a400_sci_read_data()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_rx_to +* +* Purpose: +* +* Parameters: none +* +* Outputs: nothing +* +* Returns: nothing +* +* Notes: None +*****************************************************************************/ +static void +lh7a400_sci_rx_to(void) +{ + uint32_t idx; + + vdprintk("ENTER: lh7a400_sci_rx_to()\n"); + for (idx = 0; idx < sci->RxCount; idx++) { + lh7a400_sci_data_from_card[idx] = (uint8_t) sci->Data; + } + vdprintk("LEAVE: lh7a400_sci_rx_to()\n"); + + return; +} + +/***************************************************************************** +* FUNC: lh7a400_sci_init +* +* Purpose: Configures the SCI for initial communication. Initializes +* the interrupt handler, and instals ISR's to prepare for +* card insertion. +* +* Parameters: None +* +* Outputs: Nothing +* +* Returns: Nothing +* +* Notes: +*****************************************************************************/ +static int __init +lh7a400_sci_init(void) +{ + int sts = 0; + int refclk; + int sciclk; + int baudPlusOne; + int value; + + dprintk("ENTER: lh7a400_sci_init()\n"); + + lh7a400_sci_init_state = SCI_INIT_STATE_NOT_INITIALIZED; + + /* If we start out and there is already power, reset & wait a moment */ + if (sci->Status & SCI_STATUS_POWER) + { + sci->Ctrl2 = SCI_CR2_WRESET; /* SCI_CR2_FINISH; */ + mdelay(1); + } + + /* + * SCIREFCLK is either HCLK or HCLK/2, + * depending on the SCI_CTL_PREDIV bit + */ + refclk = hclkfreq_get() * 1000; + sci->Control = 0; /* Start out in a known state */ + sci->Control = SCI_CTL_MUX_DETECT /* Enable card detection */ + | SCI_CTL_MUX_VCCEN; /* Enable power */ + if ((clksc->clkset & CLKSET_PCLKDIV4) /* | (refclk > 50000000) */ ) + { + refclk /= 2; + sci->Control |= SCI_CTL_PREDIV; /* Use (HCLK / 2) */ + } + sci->Control |= SCI_CTL_EN; /* Enable the SCI */ + + /* + * Frequency = (SCIREFCLK / ((SCICLKICC + 1) * 2)) + * -so- + * ((SCICLKICC + 1) * 2) = (SCIREFCLK / Frequency) + * -so- + * (SCICLKICC + 1) = ((SCIREFCLK / Frequency) / 2) + * -so- + * SCICLKICC = (((SCIREFCLK / Frequency) / 2) - 1) + */ + sciclk = (((refclk / SCI_CLOCK_FREQUENCY) / 2) - 1); + sci->ClockICC = SCI_CLKDIV(sciclk); + dprintk("SCI_CLK(freq:%d, refclk:%d, clkicc:%d)Hz.\n", + SCI_CLOCK_FREQUENCY, refclk, sciclk); + + sci->Ctrl0 = CR0_INIT; + sci->Ctrl1 = CR1_INIT; + sci->Ctrl2 = CR2_INIT; + sci->InterruptEnable = IER_INIT; + sci->Stable = SCI_STABLE(((refclk / (CARD_DEBOUNCE * 0xFFFF)) - 1)); + + /* + * The pulse width of an etu is one refclk. + * 1 etu = ((baud + 1) * value) / refclk + * 5 <= value <= 0xFF + * 0 <= baud <= 0xFFFF + * + * NOTE: I (JMG) assumed refclk was / 1000 as otherwise the resulting + * "Value" is too large for the register which is only 8-bits in size. + */ + baudPlusOne = SCI_BAUD_RATE + 1; + value = (refclk / 1000) / baudPlusOne; + if (value < 0x05) value = 0x05; + if (value > 0xFF) value = 0xFF; + baudPlusOne = (refclk / 1000) / value; + sci->Baud = SCI_BAUD((baudPlusOne - 1)); + sci->Value = SCI_VALUE(value); + + /* + * SCI_CLOCK derived from SCIREFCLK + * SCIDATA transmit (tx) FIFO drives SCI_IO + */ + sci->SyncCR = 0; + sci->SyncData = SCI_SYNCDR_WCLKEN | SCI_SYNCDR_WDATAEN; + + sci->DeactivationTime = ((refclk / DTIME_MAX) / 3); + sci->ActivationTime = ATIME_INIT; + sci->ATRStartTimeout = (SCI_ATRSTIME(ATRS_INIT)); + sci->ATRDurationTimeout = (SCI_ATRDTIME(ATRD_INIT)); + sci->CharTimeout = SCI_CHTIME(CHTIME_MAX); + sci->RxTimeout = SCI_RXTIME(0xFFFF); + sci->Retry = (SCI_TXRETRY(0) | SCI_RXRETRY(0)); + sci->TxCount = SCI_TXCOUNTCLR; + sci->RxCount = SCI_RXCOUNTCLR; + sci->CharGuardTime = SCI_CHGUARD(1); + sci->Status = DSTAT_INIT; + sci->IrqID_Clear = SCI_IRQ_ALL; + sci->BlockTimeout = SCI_BLKTIME(0); /* ??? JMG ??? */ + sci->BlockGuardTime = SCI_BLKGUARD(0); + sci->TideMark = (SCI_TIDE_TX(0) | SCI_TIDE_RX(0)); + + { + int idx; + SCI_CARD_PARAMS.char_T0 = 0; + SCI_CARD_PARAMS.char_TA[0] = 0x11; + for (idx = 1; idx < 4; idx++) + { + SCI_CARD_PARAMS.char_TA[idx] = 0; + } + for (idx = 0; idx < 4; idx++) + { + SCI_CARD_PARAMS.char_TB[idx] = 0; + } + for (idx = 0; idx < 4; idx++) + { + SCI_CARD_PARAMS.char_TC[idx] = 0; + } + for (idx = 0; idx < 3; idx++) + { + SCI_CARD_PARAMS.char_TD[idx] = 0; + } + for (idx = 0; idx < 16; idx++) + { + SCI_CARD_PARAMS.char_HC[idx] = 0; + } + } + + /******************************************************************** + * The remainder of the init function is for registering as a MISC + * driver, initializing the interrupt handler, and to parse the ATR + * sequence. If a user wants to use a polling method for the ATR parsing, + * the interrupt code below would not be needed. + ********************************************************************/ + + misc_register(&lh7a400_sci_miscdev); + create_proc_read_entry("driver/sci", 0, 0, lh7a400_sci_read_proc, NULL); + + /************************************** + ***** IRQ Bit, Priority, Function ***** + **************************************/ + lh7a400_sci_install_int_handler(SCI_IRQ_CARD_OUT, 0, + lh7a400_sci_deactivate); + lh7a400_sci_install_int_handler(SCI_IRQ_RX_TIDE, 1, + lh7a400_sci_read_atr_ts); + lh7a400_sci_install_int_handler(SCI_IRQ_CARD_IN, 2, + lh7a400_sci_activate); + lh7a400_sci_install_int_handler(SCI_IRQ_ATRD_TIMEOUT, 3, + lh7a400_sci_atr_timeout); + lh7a400_sci_install_int_handler(SCI_IRQ_ATRS_TIMEOUT, 4, + lh7a400_sci_atr_start_to); + lh7a400_sci_install_int_handler(SCI_IRQ_RX_TIMEOUT, 5, + lh7a400_sci_rx_to); +#if (0) + lh7a400_sci_install_int_handler(SCI_IRQ_CHAR_TIMEOUT, 6, + XXXXX); + lh7a400_sci_install_int_handler(SCI_IRQ_POWER_UP, 3, + lh7a400_sci_card_up); +#endif + + if (sci->Status & SCI_STATUS_CARDPRESENT) { + sci->InterruptEnable = + (SCI_IRQ_CARD_OUT | SCI_IRQ_ATRS_TIMEOUT); + } else { + sci->InterruptEnable = + (SCI_IRQ_CARD_IN | SCI_IRQ_ATRS_TIMEOUT); + } + + dprintk_regs("init"); + + sts = request_irq(IRQ_SCI, lh7a400_sci_interrupt, SA_INTERRUPT, + "LH7A400 SCI", NULL); + if(sts) { + printk(KERN_ERR "sci: request_irq failed, sts=0x%x.\n", sts); + remove_proc_entry("driver/sci", NULL); + misc_deregister(&lh7a400_sci_miscdev); + return(sts); + } + + if (sci->Status & SCI_STATUS_CARDPRESENT) { + lh7a400_sci_activate(); + } + + printk(KERN_INFO "LH7A400 Smart Card Interface driver v%s\n", + DRIVER_VERSION); + + dprintk("LEAVE: lh7a400_sci_init()\n"); + + return(sts); +} + +/***************************************************************************** +* FUNC: lh7a400_sci_exit +*****************************************************************************/ +static void __exit +lh7a400_sci_exit(void) +{ + dprintk("ENTER: lh7a400_sci_exit()\n"); + free_irq(IRQ_SCI, NULL); + remove_proc_entry("driver/sci", NULL); + misc_deregister(&lh7a400_sci_miscdev); + dprintk("LEAVE: lh7a400_sci_exit()\n"); + + return; +} + +module_init(lh7a400_sci_init); +module_exit(lh7a400_sci_exit); + +MODULE_AUTHOR("Jim Gleason "); +MODULE_DESCRIPTION("Sharp LH7A400 Smart Card Driver (SCI)"); +EXPORT_NO_SYMBOLS; + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/misc/ssp-lh7a400.c linux-2.4.21-rmk1-lh7a400/drivers/misc/ssp-lh7a400.c --- linux-2.4.21-rmk1/drivers/misc/ssp-lh7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/misc/ssp-lh7a400.c Sat Oct 18 13:30:10 2003 @@ -0,0 +1,1471 @@ +/* + * linux/drivers/misc/ssp-lh7x.c + * + * Provide SSP (synchronous Serial Port) functionality for LH7x EVB boards + * + * Copyright (C) 2002 Lineo, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License (GPL) version 2 + * as published by the Free Software Foundation. + * + */ + +/* + * I think this could be made generic for any LH7A400 or LH79520, but + * right now it's specific to the two eval boards... + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#undef VERBOSE +#define DRVNAME "ssp_lh7x" + +#include + +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +#endif /* MODULE */ + +#include +#include + +#ifdef CONFIG_MACH_KEV79520 +#include +#include +#include +#include +#define IRQ_SSP IRQ_CPLD +#endif + +#ifdef CONFIG_MACH_KEV7A400 +#include +#include +// DDD #include + +#define IRQ_SSP IRQ_KEV7A400_TS + +static int initted = 0; /* set iff init routine has run */ +#endif + +#ifdef CONFIG_CPU_FREQ +#include +#endif + +#include + +#include "ssp.h" + +#define vdprintk if (0) printk +#define dprintk if (0) printk + +static int ssp_lh7x_get_speed(void); +static void ssp_lh7x_write16(sspContext_t *sspContext, unsigned int data); +static unsigned int ssp_lh7x_read16(sspContext_t *sspContext); +static int __init ssp_lh7x_init(void); + +#ifdef CONFIG_MACH_KEV79520 +static gpioARegs_t *gpioa = (gpioARegs_t *)GPIO0_PHYS; +static ioconRegs_t *iocon = (ioconRegs_t *)IOCON_PHYS; +static rcpcRegs_t *rcpc = (rcpcRegs_t *)RCPC_PHYS; +static cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; +#endif + +#ifdef CONFIG_MACH_KEV7A400 +static gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); +#endif + +static sspRegs_t *ssp = (sspRegs_t *)IO_ADDRESS(SSP_BASE); + +/* +* hclk_freq: +* The frequency of the clock that feeds the SSP clock prescaler in the RCPC +* The frequency is in Hz +*/ +static unsigned int hclk_freq = 0; + +#ifdef CONFIG_MACH_KEV79520 +/********************************************************************** +* Additional RCPC defines +**********************************************************************/ +#define rcpc_sspClkControl spareClkCtrl +#define rcpc_sspClkPrescale spare1Prescale + +#define RCPC_LOCK 1 +#define RCPC_LOCKED RCPC_LOCK +#define RCPC_UNLOCK 0 +#define RCPC_UNLOCKED RCPC_UNLOCK +#endif + +/********************************************************************** +* Function: ssp_busy_wait +* Function: ssp_tx_full_wait +* +* Purpose: +* Wait until the state of the SSP busy bit from the status register +* indicates the SSP is no longer busy. +* +* Returns: +* N/A +**********************************************************************/ +static void ssp_busy_wait(void) +{ + while ( ssp->sr & SSP_SR_BSY ) { + barrier(); + } + return; +} + +static void ssp_tx_full_wait(void) +{ + while ( (ssp->sr & SSP_SR_TNF) == 0 ) { + barrier(); + } + return; +} + +/********************************************************************** +* Function: ssp_flush_tx_fifo +* Function: ssp_flush_rx_fifo +* +* Purpose: +* Flush the transmit (tx) and receive (rx) fifo buffer +* +* Returns: +* N/A +**********************************************************************/ +static void ssp_flush_tx_fifo(sspContext_t *sspContext) +{ + int i; + + for (i = sspContext->ts_txTimeout; ((i > 0) && (ssp->sr & SSP_SR_TFE)); i--) + { + barrier(); + } + return; +} + +static void ssp_flush_rx_fifo(sspContext_t *sspContext) +{ + int i; + unsigned int junk; + + for (i = sspContext->ts_rxTimeout; ((i > 0) && (ssp->sr & SSP_SR_RNE)); i--) + { + barrier(); + junk = ssp->dr; + //printk("ssp_flush_rx_fifo(0x%04X)\n", junk); + } + return; +} + +#if defined(CONFIG_MACH_KEV79520) +/********************************************************************** +* Function: ssp_chipselect_enable +* Function: ssp_chipselect_disable +* Function: ssp_chipselect_manual +* Function: ssp_chipselect_automatic +* +* Purpose: +* Controls the chipselect pin associated with the SSP +* +* Returns: +* N/A +* +**********************************************************************/ +static void ssp_chipselect_enable(void) +{ + /* Make the SSPFRM signal (ChipSelect) high (enabled) */ + /* Note: This must have had ssp_chipselect_manual() called first */ + //printk("ssp_chipselect_enable()\n"); + gpioa->dr &= ~(SSPFRM_GPIO_BIT); /* LOW == Enabled */ +} + +static void ssp_chipselect_disable(void) +{ + /* Make the SSPFRM signal (ChipSelect) low (disabled) */ + /* Note: This must have had ssp_chipselect_manual() called first */ + //printk("ssp_chipselect_disable()\n"); + gpioa->dr |= SSPFRM_GPIO_BIT; /* HIGH == Disabled */ +} + +static void ssp_chipselect_manual(void) +{ + /* First, disable the ChipSelect */ + //JMG ssp_chipselect_disable(); + /* Set up muxing so that we manually control the ChipSelect pin */ + /* via GPIO port A bit 2 */ + gpioa->ddr |= SSPFRM_GPIO_BIT; /* Make GPIO an output */ + iocon->SSIMux &= ~SSIMUX_SSPFRM; +} + +static void ssp_chipselect_automatic(void) +{ + /* First, disable the ChipSelect */ + ssp_chipselect_disable(); + /* Set up muxing so the SSP automatically controls the ChipSelect pin */ + iocon->SSIMux |= SSIMUX_SSPFRM; +} +#endif + +#if defined(CONFIG_MACH_KEV7A400) +/********************************************************************** +* Function: ssp_eeprom_busy_poll +* +* Purpose: +* Following a write or erase, wait for the EEPROM busy signal to go high. +* We control the EEPROM chipselect pin by keeping the SSP busy until the +* associated EEPROM BSY signal is no longer asserted. +* +* Processing: +* Following an erase or write command, the EEPROM will signal that the +* write or erase operation is complete by transitioning its data output +* from a 0 to a 1 provided that its chip select is desserted after the +* write command completes and reasserted 500 ns after the chip select +* has been deasserted. SSPFRM cannot be directly controlled as GPIO pin. +* +* This relatively complex algorithm results: +* Convert timeout_ms to units of the time it takes to +* send a single word. Wait for the last SSP transaction +* to complete. Flush the receive FIFO. Wait +* approximately 500 ns. This time is not really +* critical. It can be longer. Write a 0 to the +* transmit FIFO and then keep writing 0 to the transmit +* FIFO until the data read back from the EEPROM is not +* 0. This keeps the EEPROM's chip select asserted while +* we wait for the EEPROM data output to transition from +* 0 to 1. +* +* NOTE: +* BUSY_POLL_METHOD_1 follows the above method as closely as possible +* BUSY_POLL_METHOD_2 does a generic busy wait of timeout_ms +* +* Parameters: +* timeout_ms: number of milliseconds before +* aborting the busy poll operation +* +* Returns: +* 0 if timed out +* 1 otherwise +* +**********************************************************************/ +#undef BUSY_POLL_METHOD_1 /* DOESN'T WORK --- JimG */ +#define BUSY_POLL_METHOD_2 +static int ssp_eeprom_busy_poll(sspContext_t *sspContext, int timeout_ms) +{ + int i; + int timeout_in_words; +#define EEPROM_BITS_PER_SSP_WORD 16 + + // !!! WARNING !!! Printouts mess up the timing + + timeout_in_words = (ssp_lh7x_get_speed() * timeout_ms) + / (EEPROM_BITS_PER_SSP_WORD * 1000); + +#if defined(BUSY_POLL_METHOD_1) + /* wait for SSP to be not busy */ + ssp_busy_wait(); + + /* flush the receive FIFO */ + ssp_flush_rx_fifo(sspContext); + + /* + ** assume 10 ns bus speed. Wait at least 500 ns before + ** checking if write is complete + */ + for (i = 0; i < 50; i++) continue; +#endif /* BUSY_POLL_METHOD_1 */ + + /* keep CS active by keeping data in the transmit buffer */ + ssp_tx_full_wait(); + ssp_lh7x_write16(sspContext, 0); + do + { +#if defined(BUSY_POLL_METHOD_2) + ssp_flush_rx_fifo(sspContext); +#endif /* BUSY_POLL_METHOD_2 */ + ssp_tx_full_wait(); + ssp_lh7x_write16(sspContext, 0); + } +#if defined(BUSY_POLL_METHOD_1) + while (timeout_in_words-- && ssp_lh7x_read16(sspContext) == 0); +#elif defined(BUSY_POLL_METHOD_2) + while (timeout_in_words--); +#endif + + /* wait for SSP to be not busy */ + ssp_busy_wait(); + + /* flush the receive FIFO */ + ssp_flush_rx_fifo(sspContext); + + /* Give the rest of the system a chance to work */ + schedule(); + + /* return success or timeout */ + return (timeout_in_words != 0); +} +#endif + +#ifdef CONFIG_MACH_KEV79520 +/********************************************************************** +* Function: rcpc_lh7x_locked +* +* Purpose: +* Determine write access to the RCPC +* +* Returns: +* The lock state of the RCPC +* +**********************************************************************/ +static int rcpc_lh7x_locked(void) +{ + int lockState; + + vdprintk("ENTER: rcpc_lh7x_locked()\n"); + if (rcpc->control & RCPC_CTRL_WRTLOCK_ENABLED) { + lockState = RCPC_LOCKED; + } else { + lockState = RCPC_UNLOCKED; + } + vdprintk("LEAVE: rcpc_lh7x_locked(%s)\n", + (lockState==RCPC_LOCKED)?"Locked":"UnLocked"); + + return(lockState); +} + +/********************************************************************** +* Function: rcpc_lh7x_lock +* +* Purpose: +* Control write access to the RCPC +* +* Parameters: +* action: RCPC_UNLOCK == can write to RCPC +* RCPC_LOCK == cannot write to RCPC +* +* Returns: +* The previous lock state of the RCPC +* +**********************************************************************/ +static int rcpc_lh7x_lock(int action) +{ + int priorState; + + vdprintk("ENTER: rcpc_lh7x_lock(%s)\n", + (action==RCPC_LOCK)?"Lock":"UnLock"); + priorState = rcpc_lh7x_locked(); + if (action == RCPC_UNLOCK) { + rcpc->control |= RCPC_CTRL_WRTLOCK_ENABLED; + } else /* (action == RCPC_LOCK) */ { + rcpc->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + } + vdprintk("LEAVE: rcpc_lh7x_lock(%s)\n", + (action==RCPC_LOCK)?"Lock":"UnLock"); + + return(priorState); +} +#endif + + + +/********************************************************************** +* Function: ssp_lh7x_get_speed +* +* Purpose: +* Get the SSP speed in bits per second +**********************************************************************/ +static int ssp_lh7x_get_speed(void) +{ + int bps; +#ifdef CONFIG_MACH_KEV79520 + int rcpc_prescale; +#endif + int ssp_prescale; + int ssp_divider; + + vdprintk("ENTER: ssp_lh7x_get_speed()\n"); +#if defined(CONFIG_MACH_KEV79520) + rcpc_prescale = rcpc->rcpc_sspClkPrescale; + if (rcpc_prescale == 0) rcpc_prescale = 1; + else rcpc_prescale <<= 1; + ssp_prescale = ssp->cpsr; + ssp_divider = (ssp->cr0 & _SBF(8,_BITMASK(8) ) ) >> 8; + bps = hclk_freq / (rcpc_prescale * (ssp_prescale) * (ssp_divider + 1) ); +#elif defined(CONFIG_MACH_KEV7A400) + ssp_prescale = ssp->cpsr; + ssp_divider = (ssp->cr0 & 0xff00) >> 8; + + bps = CLKSC_SSP_CLK / (ssp_prescale * (ssp_divider + 1) ); +#endif + vdprintk("LEAVE: ssp_lh7x_get_speed(%d bps)\n", bps); + + return(bps); +} + +#ifdef CONFIG_MACH_KEV7A400 +/********************************************************************** +* Function: ssp_lh7x_set_speed +* +* Purpose: +* set the SSPCLK frequency as close to the requested bits per second +* as possible and return the actual bits per second. +* +* Processing: +* If the requested bits per second is greater than or equal to +* the maximum possible SSPCLK frequency, set the divider and +* the prescaler to the minimum values. +* +* If not too fast, compute the closest integer result of dividing the +* base sspclk frequency (approximately 7.4 MHz) by the requested +* bits per second. If this quotient is larger than the result +* of multiplying the maximum possible prescaler by the maximum +* possible divider, then the requested clock is too slow. Use +* the maximum possible divider and prescaler to get the slowest +* SSPCLK speed. +* +* If the clock frequency is neither too fast nor too slow, then +* step through all possible prescaler values to determine which +* combination of prescaler and divider values give the SSPCLK +* value closest to the requested bits per second. +* +* Set the SSP clock prescaler register to the prescaler value +* determined above. Clear out the old divider value from SSP +* control register 0 and OR in the new divider value - 1. Return +* the value returned by ssp_get_speed(). +* +* Parameters: +* requested_bits_per_second: the desired frequency of the SSPCLK +* pin in bits per second. +* +* Outputs: None +* +* Returns: +* 0 if the requested frequency is illegal. Otherwise, return +* the actual clock speed. +* +* Notes: +* +**********************************************************************/ + +#define MAX_SSP_FREQ (CLKSC_SSP_CLK / SSP_PRESCALE_MIN) + +static int ssp_lh7x_set_speed(int bps) +{ + int ssp_prescale; + int ssp_divider; + int new_prescale; + int new_divider; + int quotient; + int delta1; + int delta2; + int min_error; + int new_error; + + vdprintk("ENTER: ssp_lh7x_set_speed(%d bps)\n", bps); + + if (bps <= 0) + /* requested frequency is illegal. Return 0 */ + return 0; + + /* get the dividers as close to the requested freq as possible */ + if (bps >= MAX_SSP_FREQ) { + /* requested clock frequency is too fast. Set to max freq */ + ssp_prescale = SSP_PRESCALE_MIN; + ssp_divider = 1; + } else { + /* compute the required divider as close as possible */ + quotient = CLKSC_SSP_CLK / bps; + + /* round the quotient */ + delta1 = bps - (CLKSC_SSP_CLK / quotient ); + if (delta1 < 0) + delta1 = - delta1; + delta2 = bps - (CLKSC_SSP_CLK / (quotient + 1) ); + if (delta2 < 0) + delta2 = - delta2; + if (delta1 > delta2) + quotient++; + + if (quotient >= (SSP_PRESCALE_MAX * SSP_DIVIDER_MAX) ) { + /* + Then requested clock frequency is <= minimum possible. + Make it as slow as possible. + */ + ssp_prescale = SSP_PRESCALE_MAX; + ssp_divider = SSP_DIVIDER_MAX; + } else { + /* + The computed quotient is in range. + quotient is the target clock divide frequency; + get as close as possible + */ + + /* + * factor the quotient into the divider and + * prescaler combo that minimizes the error in + * the quotient by exhaustively searching all + * legal ssp prescaler values. + */ + ssp_prescale = SSP_PRESCALE_MIN; + ssp_divider = (quotient / ssp_prescale); + ssp_divider = (ssp_divider > SSP_DIVIDER_MAX) ? + SSP_DIVIDER_MAX : + ssp_divider; + min_error = quotient - (ssp_divider * ssp_prescale); + min_error = (min_error < 0) ? -min_error : min_error; + for (new_prescale = SSP_PRESCALE_MIN + 2; + new_prescale < SSP_PRESCALE_MAX; + new_prescale += 2) + { + new_divider = (quotient / new_prescale); + new_divider = (new_divider > SSP_DIVIDER_MAX) ? + SSP_DIVIDER_MAX : new_divider; + new_error = quotient - (new_divider * + new_prescale); + new_error = (new_error < 0) ? + -new_error : new_error; + if (new_error < min_error) { + min_error = new_error; + ssp_prescale = new_prescale; + ssp_divider = new_divider; + } + } + + } /* end if quotient is greater than max */ + + } /* end if requested frequency is too large */ + + ssp->cpsr = ssp_prescale; + + /* clear old divider value */ + ssp->cr0 &= ~SSP_CR0_SCR(SSP_DIVIDER_MAX - 1); + ssp->cr0 |= SSP_CR0_SCR(ssp_divider - 1); + + vdprintk("LEAVE: ssp_lh7x_set_speed(%d bps)\n", bps); + + return ssp_lh7x_get_speed(); +} +#endif /* CONFIG_MACH_KEV7A400 */ + + + +#if defined(CONFIG_MACH_KEV79520) +/********************************************************************** +* Function: ssp_lh7x_set_speed +* +* Purpose: +* Set the SSP speed in bits per second +* +* Processing: +* If the requested_bits_per_second is negaitve, return 0 +* If the requested_bits_per_second is too fast, set the bit rate +* as fast as possible. +* If the requested_bits_per_second is too slow, set the bit rate as +* slow as possible. +* If the requested_bits_per_second is in range, set the RCPC +* SSP clock prescaler register, SSP prescaler, and SSP divider +* to obtain the clock as close as possible. +* +* Parameters: +* bps: The desired bits per second +* +* Returns: +* The actual bps obtained or 0 if the requested bps is not obtainable. +* +* Notes: +* The mode (SPI/uWire/TI) must be set first for this function to work! +* +**********************************************************************/ +static int ssp_lh7x_set_speed(int bps) +{ + int rcpcLockState; + int32_t ssp_prescale; + int32_t ssp_divider; + int32_t rcpc_prescale; + int32_t new_prescale; + int32_t new_divider; + int32_t quotient; + int32_t delta1; + int32_t delta2; + int32_t min_error; + int32_t new_error; +#define MAX_SSP_FREQ (hclk_freq / SSP_PRESCALE_MIN) + + vdprintk("ENTER: ssp_lh7x_set_speed(%d bps)\n", bps); + + /* Ensure we are dealing with a legal BPS */ + if (bps <= 0) { + printk("%s: requested ssp speed (%d bps) is too slow\n", + DRVNAME, bps); + printk("%s: making ssp speed as slow as possible\n", DRVNAME); + /* The request bps is slower than the minimum possible */ + /* ... make it as slow as possible */ + /* Don't bother calculating the divider values as we know them */ + rcpc_prescale = RCPC_SSP_PRESCALE_MAX; + ssp_prescale = SSP_PRESCALE_MAX; + ssp_divider = SSP_DIVIDER_MAX; + } else if (bps >= MAX_SSP_FREQ) { + printk("%s: requested ssp speed (%d bps) is to fast\n", + DRVNAME, bps); + printk("%s: making ssp speed as fast as possible\n", DRVNAME); + /* Don't bother calculating the divider values as we know them */ + bps = MAX_SSP_FREQ; + ssp_prescale = SSP_PRESCALE_MIN; + ssp_divider = 1; + rcpc_prescale = 1; + } else { + /* Calculate the divider values as close as we can */ + quotient = hclk_freq / bps; + if (quotient <= 0) + quotient = 1; + /* round the quotient */ + delta1 = bps - (hclk_freq / quotient ); + if (delta1 < 0) + delta1 = -delta1; + delta2 = bps - (hclk_freq / (quotient + 1)); + if (delta2 < 0) + delta2 = -delta2; + if (delta1 > delta2) + quotient++; + if (quotient >= (SSP_PRESCALE_MAX * + RCPC_SSP_PRESCALE_MAX * SSP_DIVIDER_MAX)) + { + printk("%s: requested ssp speed (%d bps) is to slow\n", + DRVNAME, bps); + printk("%s: making ssp speed as slow as possible\n", + DRVNAME); + /* The request bps is slower than the minimum + * possible ... make it as slow as possible + * Don't bother calculating the divider values + * as we know them + */ + rcpc_prescale = RCPC_SSP_PRESCALE_MAX; + ssp_prescale = SSP_PRESCALE_MAX; + ssp_divider = SSP_DIVIDER_MAX; + } else { + /* + * The computed quotient is in range. + * Quotient is the target clock divide frequency. + * Get as close as possible. + */ + rcpc_prescale = 1; + /* + * Try to reduce power by using RCPC prescaler. + * Note that the ssp prescaler minimum is two + * so can only prescale and maintain accuracy + * if quotient is divisible by 4. + */ + while ( ((quotient & 0x3) == 0) && + (rcpc_prescale < RCPC_SSP_PRESCALE_MAX) ) + { + quotient >>= 1; + rcpc_prescale <<= 1; + } + /* + * Make sure the requested frequency is within range + * of the SPP's prescaler and divider. + * Hopefully, this loop never executes. + * If it does, accuracy suffers. + */ + while (quotient > + (SSP_PRESCALE_MAX * SSP_DIVIDER_MAX) ) + { + rcpc_prescale <<= 1; + quotient >>= 1; + } + /* + * Factor the quotient into the divider and + * prescaler combo that minimizes the error in + * the quotient by exhaustively searching all + * legal ssp prescaler values. + */ + ssp_prescale = SSP_PRESCALE_MIN; + ssp_divider = (quotient / ssp_prescale); + ssp_divider = (ssp_divider > SSP_DIVIDER_MAX) + ? SSP_DIVIDER_MAX : ssp_divider; + min_error = quotient - (ssp_divider * ssp_prescale); + min_error = (min_error < 0) ? -min_error : min_error; + for (new_prescale = SSP_PRESCALE_MIN + 2; + new_prescale < SSP_PRESCALE_MAX; + new_prescale += 2) + { + new_divider = (quotient / new_prescale); + new_divider = (new_divider > SSP_DIVIDER_MAX) + ? SSP_DIVIDER_MAX : new_divider; + new_error = quotient - (new_divider * new_prescale); + new_error = (new_error < 0) ? -new_error : new_error; + if (new_error < min_error) { + min_error = new_error; + ssp_prescale = new_prescale; + ssp_divider = new_divider; + } + } + } + } + /* Set up the necessary registers to get the desired BSP */ + rcpcLockState = rcpc_lh7x_lock(RCPC_UNLOCK); + rcpc->rcpc_sspClkPrescale = rcpc_prescale >> 1; + (void) rcpc_lh7x_lock(rcpcLockState); + ssp->cpsr = ssp_prescale; + ssp->cr0 &= 0xff; /* clear old divider value */ + ssp->cr0 |= SSP_CR0_SCR(ssp_divider - 1); + + vdprintk("LEAVE: ssp_lh7x_set_speed(%d bps)\n", bps); + + return(ssp_lh7x_get_speed()); +} +#endif /* CONFIG_MACH_KEV79520 */ + + +/********************************************************************** +* Function: ssp_lh7x_write16 +* +* Purpose: +* Write the LH7x SSP data register +**********************************************************************/ +static void ssp_lh7x_write16(sspContext_t *sspContext, + unsigned int data) +{ + int i; + + vdprintk("ENTER: ssp_lh7x_write16(0x%04X)\n", (uint16_t)data); + //if (sspContext->ssp_dev_sel == SSP_EEPROM) { + //printk("ENTER: ssp_lh7x_write16(0x%04X)\n", (uint16_t)data); + //} + for (i=sspContext->ts_txTimeout; ((i>0) && ((ssp->sr&SSP_SR_TNF) == 0)); i--) { + barrier(); + } + if (ssp->sr & SSP_SR_TNF) { + ssp->dr = (uint16_t)data; + } else { + printk("%s: write timout\n", DRVNAME); + } + //vdprintk("LEAVE: ssp_lh7x_write16(0x%04X)\n", (uint16_t)data); + return; +} + +/********************************************************************** +* Function: ssp_lh7x_read16 +* +* Purpose: +* Read the LH7x SSP data register +**********************************************************************/ +static unsigned int ssp_lh7x_read16(sspContext_t *sspContext) +{ + int i; + unsigned int data = -1; + + //vdprintk("ENTER: ssp_lh7x_read16()\n"); + for (i=sspContext->ts_rxTimeout; + ((i>0) && ((ssp->sr&SSP_SR_RNE) == 0)); i--) + { + barrier(); + } + if (ssp->sr & SSP_SR_RNE) { + if (sspContext->ssp_dev_sel == SSP_EEPROM) { + /* EEPROM */ + data = (unsigned int)ssp->dr; + vdprintk("LEAVE: ssp_lh7x_read16(ee: 0x%04X)\n", data); + } else { + /* TOUCHSCREEN */ + data = (((unsigned int)ssp->dr) >> 4) & 0x0FFF; + vdprintk("LEAVE: ssp_lh7x_read16(ts: 0x%04X)\n", data); + } + } else { + vdprintk("%s: read timout sr=0x%x\n", DRVNAME, ssp->sr); + } + + return(data); +} + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down +**********************************************************************/ +static int ssp_lh7x_ts_pen_down(sspContext_t *sspContext) +{ +#if defined(CONFIG_MACH_KEV79520) + int pen_down = cpld->misc_stat & CPLD_MISCSTS_TS_IRQ; + dprintk("ssp_lh7x_ts_pen_down(%d)\n", pen_down); + return (pen_down); +#elif defined(CONFIG_MACH_KEV7A400) + int pen_down = gpio->rawIntStatus & GPIOF_INT_TS; + return (pen_down); +#endif +} + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down_irq_enable +**********************************************************************/ +static int ssp_lh7x_ts_pen_down_irq_enable(sspContext_t *sspContext) +{ +#if defined(CONFIG_MACH_KEV79520) + int lastState = (cpld->intr_mask & CPLD_TS_INTR_ENABLE); + dprintk("ssp_lh7x_ts_pen_down_irq_enable\n"); + cpld->intr_mask |= CPLD_TS_INTR_ENABLE; + sspContext->irq_state = 1; + return(lastState); +#elif defined(CONFIG_MACH_KEV7A400) + dprintk("ssp_lh7x_ts_pen_down_irq_enable\n"); + gpio->intEnable |= GPIOF_INT_TS; + return 1; +#endif +} + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down_irq_disable +**********************************************************************/ +static int ssp_lh7x_ts_pen_down_irq_disable( + sspContext_t *sspContext) +{ +#if defined(CONFIG_MACH_KEV79520) + int lastState = (cpld->intr_mask & CPLD_TS_INTR_ENABLE); + dprintk("ssp_lh7x_ts_pen_down_irq_disable\n"); + cpld->intr_mask &= ~CPLD_TS_INTR_ENABLE; + sspContext->irq_state = 0; + return(lastState); +#elif defined(CONFIG_MACH_KEV7A400) + gpio->intEnable &= ~(GPIOF_INT_TS); + dprintk("ssp_lh7x_ts_pen_down_irq_disable\n"); + return 1; +#endif +} + +/********************************************************************** +* Function: ssp_lh7x_ts_pen_down_irq +* +* We only detect touch screen _touches_ (pen down) with this interrupt +* handler, and even then we just schedule our task. +* +* Note: It has already been determined that this is our interrupt +* before we ever get it here so checking is minimal to non-existant. +**********************************************************************/ +static void ssp_lh7x_ts_pen_down_irq(int irq, sspContext_t *sspContext, + struct pt_regs * regs) +{ + /* + * Disable the touchscreen interrupts + * by disabling the touchscreen IRQ + * --- AND --- + * Enable regular polling of the touchscreen device + * (The touchscreen IRQ will be re-enabled and polling + * will be disabled when it is detected that the + * pen is no longer down.) + */ + /* Disable touch screen IRQ */ + dprintk("ENTER: ssp_lh7x_ts_pen_down_irq()\n"); + ssp_lh7x_ts_pen_down_irq_disable(sspContext); + dprintk("ENTER: wake_up()\n"); + wake_up(sspContext->irq_wait_ptr); + vdprintk("LEAVE: ssp_lh7x_ts_pen_down_irq()\n"); + return; +} + +/********************************************************************** +* Function: ssp_lh7x_irq_handler +* +* This interrupt handler only directs traffic for the interrupts +* by forwarding on the call to the appropriate interrupt handler. +**********************************************************************/ +static void ssp_lh7x_irq_handler(int irq, void *_sspContext, + struct pt_regs * regs) +{ + sspContext_t *sspContext = _sspContext; + dprintk("ENTER: ssp_lh7x_irq_handler()\n"); + + if ((sspContext) && (sspContext->irq_wait_ptr)) { +#ifdef CONFIG_MACH_KEV79520 + if (ssp_lh7x_ts_pen_down(sspContext)) { +#elif defined(CONFIG_MACH_KEV7A400) + if( 1) { +#endif + ssp_lh7x_ts_pen_down_irq(irq, sspContext, regs); + } +#if defined(VERBOSE) && defined(DEBUG) + else { + vdprintk("ssp_lh7x_irq_handler() --- Not our interrupt\n"); + } +#endif + } +#if defined(VERBOSE) && defined(DEBUG) + else { + vdprintk("ssp_lh7x_irq_handler( NO ACTION )\n"); + } +#endif + return; +} + + +#if defined(CONFIG_MACH_KEV79520) +/********************************************************************** +* Function: ssp_lh7x_lock +* Function: ssp_lh7x_unlock +* +* Purpose: +* Lock/UnLock the SSP for a particular device (ts/ee) +**********************************************************************/ +static int ssp_lh7x_lock(sspContext_t *sspContext, int device) +{ + int sts = -1; + int cr0; + + spin_lock_irq(&sspContext->sspLock); + if (device == SSP_DEV_TOUCHSCREEN) { + /* Select the touchscreen */ + sspContext->ssp_dev_sel = SSP_TOUCHSCREEN; + cr0 = ssp->cr0; + cr0 &= ~0x00F0; + /* National Microwire frame format --- SPI Polarity High */ + /* Don't mess with data size or clock rate */ + cr0 |= (SSP_CR0_FRF_NS | SSP_CR0_SPH); + ssp->cr0 = cr0; + vdprintk("ssp_lh7x_lock(SSP_DEV_TOUCHSCREEN)\n"); + // sts = 0; + } else if (device == SSP_DEV_EEPROM) { + /* Select the eeprom */ + sspContext->ssp_dev_sel = SSP_EEPROM; + cr0 = ssp->cr0; + cr0 &= ~0x00F0; + /* Motorola SPI frame --- w/SPH & w/SPO */ + /* Don't mess with data size or clock rate */ + cr0 |= (SSP_CR0_FRF_MOT | SSP_CR0_SPH | SSP_CR0_SPO); + ssp->cr0 = cr0; + vdprintk("ssp_lh7x_lock(SSP_DEV_EEPROM)\n"); + // sts = 0; + } + cpld->ssp_dev_sel = sspContext->ssp_dev_sel; + + return(sts); +} +#endif /* defined(CONFIG_MACH_KEV79520) */ + + +#if defined(CONFIG_MACH_KEV7A400) +/********************************************************************** +* Function: ssp_lh7x_lock +* Function: ssp_lh7x_unlock +* +* Purpose: +* Lock/UnLock the SSP for a particular device (ts/ee) +**********************************************************************/ +static int ssp_lh7x_lock(sspContext_t *sspContext, int device) +{ + int sts = -1; + int cr0; + + spin_lock_irq(&sspContext->sspLock); + if (device == SSP_DEV_TOUCHSCREEN) { + /* Select the touchscreen */ + sspContext->ssp_dev_sel = SSP_TOUCHSCREEN; + cr0 = ssp->cr0; + cr0 &= ~(SSP_CR0_FRF_ALL); + /* National Microwire frame format --- SPI Polarity High */ + /* Don't mess with data size or clock rate */ + cr0 |= SSP_CR0_FRF_NS; + ssp->cr1 &= ~(SSP_CR1_SPO); /* turn off SPO */ + ssp->cr1 |= SSP_CR1_SPH; /* turn on SPH */ + ssp->cr0 = cr0; + vdprintk("\nssp_lh7x_lock(SSP_DEV_TOUCHSCREEN)\n"); + // sts = 0; + } else if (device == SSP_DEV_EEPROM) { + /* Select the eeprom */ + sspContext->ssp_dev_sel = SSP_EEPROM; + cr0 = ssp->cr0; + cr0 &= ~(SSP_CR0_FRF_ALL); + /* Motorola SPI frame --- w/SPH & w/SPO & FIFO's enabled */ + /* Don't mess with data size or clock rate */ + cr0 |= SSP_CR0_FRF_MOT; + ssp->cr1 |= (SSP_CR1_SPH | SSP_CR1_SPO | SSP_CR1_FEN); + ssp->cr0 = cr0; + vdprintk("\nssp_lh7x_lock(SSP_DEV_EEPROM)\n"); + // sts = 0; + } + if( sspContext->ssp_dev_sel == SSP_TOUCHSCREEN) { + /* Make it so the TOUCHSCREEN chip select follows the SSP FRM line */ + gpio->padr &= ~(GPIOA_SSP_TOUCHEN_EEEN); + gpio->paddr |= (GPIOA_SSP_TOUCHEN_EEEN); + gpio->padr |= (GPIOA_SSP_K3); + gpio->paddr |= (GPIOA_SSP_K3); + } else { /* assume EEPROM */ + /* Make it so the EEPROM chip select follows the SSP FRM line */ + gpio->padr |= (GPIOA_SSP_TOUCHEN_EEEN); + gpio->paddr |= (GPIOA_SSP_TOUCHEN_EEEN); + gpio->padr &= ~(GPIOA_SSP_K3); + gpio->paddr |= (GPIOA_SSP_K3); + } + + return(sts); +} +#endif /* defined(CONFIG_MACH_KEV7A400) */ + +static int ssp_lh7x_unlock(sspContext_t *sspContext, int device) +{ + int sts = -1; +// #define SSP_DEFAULT_DEVICE SSP_TOUCHSCREEN +#define SSP_DEFAULT_DEVICE SSP_INVALID_DEVICE + + spin_unlock_irq(&sspContext->sspLock); + if (device == SSP_DEV_TOUCHSCREEN) { + /* Select the default device */ + sspContext->ssp_dev_sel = SSP_DEFAULT_DEVICE; + vdprintk("ssp_lh7x_unlock(SSP_DEV_TOUCHSCREEN)\n\n"); + // sts = 0; + } else if (device == SSP_DEV_EEPROM) { + /* Select the default device */ + sspContext->ssp_dev_sel = SSP_DEFAULT_DEVICE; + vdprintk("ssp_lh7x_unlock(SSP_DEV_EEPROM)\n\n"); + // sts = 0; + } +#if defined(CONFIG_MACH_KEV79520) + cpld->ssp_dev_sel = sspContext->ssp_dev_sel; +#endif +#if defined(CONFIG_MACH_KEV7A400) + /* Make it so neither chip select follows the SSP FRM line */ + gpio->padr |= (GPIOA_SSP_TOUCHEN_EEEN); + gpio->paddr |= (GPIOA_SSP_TOUCHEN_EEEN); + gpio->padr |= (GPIOA_SSP_K3); + gpio->paddr |= (GPIOA_SSP_K3); +#endif + + return(sts); +} + +/********************************************************************** +* Function: ssp_lh7x_disable +* +* Purpose: +* Disconnect I/O pins from the SSP module +* and disable the SSP peripheral and its clocks. +**********************************************************************/ +static void ssp_lh7x_disable(void) +{ +#ifdef CONFIG_MACH_KEV79520 + int rcpcLockState; +#endif + + vdprintk("ENTER: ssp_lh7x_disable()\n"); + +#ifdef CONFIG_MACH_KEV79520 + /* Switch all muxed I/O away from the SSP */ + iocon->SSIMux &= ~( + SSIMUX_SSPIN | + SSIMUX_SSPOUT | + SSIMUX_SSPCLK | + SSIMUX_SSPENB | + SSIMUX_SSPFRM + ); + + /* Disable ssp clock */ + rcpcLockState = rcpc_lh7x_lock(RCPC_UNLOCK); + rcpc->rcpc_sspClkControl |= RCPC_SCLKSEL_SSPCLK; + (void) rcpc_lh7x_lock(rcpcLockState); +#endif + + /* Set control register to their reset defaults */ + ssp->cr0 = 0; + ssp->cr1 = 0; + + /* clear any receive overruns */ + ssp->u.icr = SSP_IIR_RORIS; + + //JMG /* disable the ssp DMA streams */ + //JMG dmac->stream0.max = 0; + //JMG dmac->stream0.ctrl = 0; + //JMG dmac->stream1.max = 0; + //JMG dmac->stream1.ctrl = 0; + //JMG /* clear any previous SSP DMA completions */ + //JMG dmac->clear = DMAC_EOT0 | DMAC_EOT1; + + vdprintk("LEAVE: ssp_lh7x_disable()\n"); + + return; +} + +/********************************************************************** +* Function: ssp_lh7x_enable +* +* Purpose: +* Disconnect I/O pins from the SSP module +* and disable the SSP peripheral and its clocks. +**********************************************************************/ +static void ssp_lh7x_enable(void) +{ + + vdprintk("ENTER: ssp_lh7x_enable()\n"); + +#ifdef CONFIG_MACH_KEV79520 + /* Enable the SSP */ + ssp->cr1 |= SSP_CR1_SSE; /* Synchronous serial port enable */ + + /* Switch all muxed I/O to the SSP */ + /* Note that SSPENB is not required for spi */ + iocon->SSIMux = ( + SSIMUX_SSPIN | + SSIMUX_SSPOUT | + SSIMUX_SSPCLK | + SSIMUX_SSPENB | + SSIMUX_SSPFRM + ); +#elif defined(CONFIG_MACH_KEV7A400) + ssp->cr0 |= SSP_CR0_SSE; +#endif + + vdprintk("LEAVE: ssp_lh7x_enable()\n"); + + return; +} + +/********************************************************************** +* Fill in our context structures +**********************************************************************/ + +static sspContext_t sspContext_l = { + ts_txTimeout: 10000, + ts_rxTimeout: 10000, + ee_txTimeout: 10000, + ee_rxTimeout: 10000, + haveIrq: 0, +}; + +/********************************************************************** +* Function: ssp_request_pointer +* Function: ssp_provide_pointer +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +void *ssp_request_pointer(int device, char *request) +{ + sspContext_t *sspContext = &sspContext_l; + void *vp = NULL; + +#ifdef CONFIG_MACH_KEV7A400 // DDD do for both (?) + if( !initted) { + ssp_lh7x_init(); + } +#endif /* CONFIG_MACH_KEV7A400 */ + + dprintk("ENTER: ssp_request_pointer(\"%d\":\"%s\")\n", device, request); + if (device == SSP_DEV_TOUCHSCREEN) { + if (strcmp(request, "write") == 0) { + vp = ssp_lh7x_write16; + } else if (strcmp(request, "read") == 0) { + vp = ssp_lh7x_read16; + } else if (strcmp(request, "enable_pen_down_irq") == 0) { + vp = ssp_lh7x_ts_pen_down_irq_enable; + } else if (strcmp(request, "disable_pen_down_irq") == 0) { + vp = ssp_lh7x_ts_pen_down_irq_disable; + } else if (strcmp(request, "is_pen_down") == 0) { + vp = ssp_lh7x_ts_pen_down; + } else if (strcmp(request, "lock") == 0) { + vp = ssp_lh7x_lock; + } else if (strcmp(request, "unlock") == 0) { + vp = ssp_lh7x_unlock; + } else if (strcmp(request, "sspContext") == 0) { + vp = sspContext; + } else if (strcmp(request, "flush_tx_fifo") == 0) { + vp = ssp_flush_tx_fifo; + } else if (strcmp(request, "flush_rx_fifo") == 0) { + vp = ssp_flush_rx_fifo; + } else if (strcmp(request, "ssp_busy_wait") == 0) { + vp = ssp_busy_wait; + } + } else if (device == SSP_DEV_EEPROM) { + if (strcmp(request, "write") == 0) { + vp = ssp_lh7x_write16; + } else if (strcmp(request, "read") == 0) { + vp = ssp_lh7x_read16; + } else if (strcmp(request, "lock") == 0) { + vp = ssp_lh7x_lock; + } else if (strcmp(request, "unlock") == 0) { + vp = ssp_lh7x_unlock; + } else if (strcmp(request, "sspContext") == 0) { + vp = sspContext; +#if defined(CONFIG_MACH_KEV79520) + } else if (strcmp(request, "chipselect_enable") == 0) { + vp = ssp_chipselect_enable; + } else if (strcmp(request, "chipselect_disable") == 0) { + vp = ssp_chipselect_disable; + } else if (strcmp(request, "chipselect_manual") == 0) { + vp = ssp_chipselect_manual; + } else if (strcmp(request, "chipselect_automatic") == 0) { + vp = ssp_chipselect_automatic; +#elif defined(CONFIG_MACH_KEV7A400) + } else if (strcmp(request, "eeprom_busy_poll") == 0) { + vp = ssp_eeprom_busy_poll; +#endif + } else if (strcmp(request, "flush_tx_fifo") == 0) { + vp = ssp_flush_tx_fifo; + } else if (strcmp(request, "flush_rx_fifo") == 0) { + vp = ssp_flush_rx_fifo; + } else if (strcmp(request, "ssp_busy_wait") == 0) { + vp = ssp_busy_wait; + } + } + dprintk("LEAVE: ssp_request_pointer(0x%08X)\n", (unsigned int)vp); + + return(vp); +} + +void *ssp_provide_pointer(int device, char *request, void *vp) +{ + sspContext_t *sspContext = &sspContext_l; + + dprintk("ENTER: ssp_provide_pointer(\"%d\":\"%s\":0x%08X)\n", + device, request, (unsigned int)vp); + if (device == SSP_DEV_TOUCHSCREEN) { + if (strcmp(request, "irq_wait_ptr") == 0) { + sspContext->irq_wait_ptr = vp; + } else { + vp = NULL; + } + } else if (device == SSP_DEV_EEPROM) { + vp = NULL; + } else { + vp = NULL; + } + dprintk("LEAVE: ssp_provide_pointer(0x%08X)\n", (unsigned int)vp); + + return(vp); +} + + +#ifdef CONFIG_CPU_FREQ +/* + * This routine gets called before and after a change in the + * HCLK bus speed. We adjust the ssp clock after HCLK has + * changed. + */ +static int +ssp_clkchg_notifier( struct notifier_block *nb, unsigned long val, void *data) +{ + switch( val) { + case HCLKFREQ_PRECHANGE: + dprintk( __FUNCTION__ ": PRECHANGE\n"); + break; + + case HCLKFREQ_POSTCHANGE: + dprintk( __FUNCTION__ ": PRECHANGE\n"); + hclk_freq = hclkfreq_get() * 1000; + (void) ssp_lh7x_set_speed( LH7x_TS_BPS); + break; + } + return 0; +} + +static struct notifier_block ssp_hclk_nb = { + notifier_call: ssp_clkchg_notifier, +}; + +#endif // CONFIG_CPU_FREQ + + +/********************************************************************** +* Function: ssp_lh7x_init +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +static int __init ssp_lh7x_init(void) +{ + sspContext_t *sspContext = &sspContext_l; + int sts = 0; +#ifdef CONFIG_MACH_KEV79520 + int rcpcLockState; +#endif + int result; + + vdprintk("ENTER: ssp_lh7x_init()\n"); + vdprintk("ssp = 0x%08X\n", (unsigned int)ssp); + +#ifdef CONFIG_MACH_KEV7A400 // both boards? + if( initted) { + vdprintk("LEAVE: ssp_lh7x_init(): already initted\n"); + return 0; + } +#endif /* CONFIG_MACH_KEV7A400 */ + + /* Determine the HCLK (bus clock) frequency in Hz */ + hclk_freq = hclkfreq_get() * 1000; + + /* + * Disconnect I/O pins from the SSP module + * and disable the SSP peripheral and its clocks. + */ + ssp_lh7x_disable(); + +#ifdef CONFIG_MACH_KEV79520 + /* Initialize the RCPC SSP clock & prescaler */ + rcpcLockState = rcpc_lh7x_lock(RCPC_UNLOCK); + /* As fast as possible */ + rcpc->rcpc_sspClkPrescale = 0; + /* Enable SSP clock */ + rcpc->rcpc_sspClkControl &= ~RCPC_SCLKSEL_SSPCLK; + (void) rcpc_lh7x_lock(rcpcLockState); +#endif + + ssp->cpsr = SSP_CPSR_CPDVSR(SSP_PRESCALE_MIN); + +#ifdef CONFIG_MACH_KEV79520 + /* Initialize CR0 */ + ssp->cr0 = ( + SSP_CR0_DSS(16) /* 16-bit data */ + | SSP_CR0_FRF_NS /* National Microwire frame format */ + | SSP_CR0_SPH /* SPI Polarity */ + | SSP_CR0_SCR(1) /* Serial clock rate (~922kbps) */ + ); + + /* Initialize CR1 */ + ssp->cr1 = ( + SSP_CR1_SSE /* Synchronous serial port enable */ + ); +#elif defined(CONFIG_MACH_KEV7A400) + /* Initialize CR0 */ + ssp->cr0 = ( + SSP_CR0_DSS(16) /* 16-bit data */ + | SSP_CR0_FRF_NS /* National Microwire frame format */ + | SSP_CR0_SCR(1) /* Serial clock rate (~922kbps) */ + | SSP_CR0_SSE /* Synchronous serial port enable */ + ); + + /* Initialize CR1 */ + ssp->cr1 = ( + SSP_CR1_SPH /* SPI Polarity */ + | SSP_CR1_SPO /* Adjust offset */ + | SSP_CR1_FEN /* Enable fifos */ + ); +#endif + + /* Set the SSP speed in bits per second */ + /* Note this MUST be done after the SSP_CR0_FRF_xxx mode is set */ + (void) ssp_lh7x_set_speed(LH7x_TS_BPS); + + /* Select the touchscreen */ + sspContext->ssp_dev_sel = SSP_TOUCHSCREEN; +#ifdef CONFIG_MACH_KEV79520 + cpld->ssp_dev_sel = sspContext->ssp_dev_sel; +#elif defined(CONFIG_MACH_KEV7A400) + gpio->padr |= (GPIOA_SSP_TOUCHEN_EEEN); + gpio->paddr |= (GPIOA_SSP_TOUCHEN_EEEN); + gpio->padr |= (GPIOA_SSP_K3); + gpio->paddr |= (GPIOA_SSP_K3); +#endif + + /* Flush the transmit FIFO */ + ssp_flush_tx_fifo(sspContext); + + /* Flush the receive FIFO */ + ssp_flush_rx_fifo(sspContext); + + /* clear any receive overruns */ + ssp->u.icr = SSP_IIR_RORIS; + + // printk("ssp->cr0 = 0x%04X\n", ssp->cr0); + // printk("ssp->cr1 = 0x%04X\n", ssp->cr1); + // printk("ssp->sr = 0x%04X\n", ssp->sr); + // printk("ssp->cpsr = 0x%04X\n", ssp->cpsr); + // printk("ssp->u.icr | u.iir = 0x%04X\n", ssp->u.icr); + + /* + * Connect I/O pins from the SSP module + * and enable the SSP peripheral and its clocks. + */ + ssp_lh7x_enable(); + + /* + * Request our IRQ and attach it to the touchscreen pen_down + * line and enable it + */ + sspContext->haveIrq = 0; + result = request_irq(IRQ_SSP, ssp_lh7x_irq_handler, + SA_SHIRQ | SA_SAMPLE_RANDOM, DRVNAME, sspContext); + if (result < 0) { + printk("%s: cannot get requested IRQ(%d) rc=%d\n", + DRVNAME, IRQ_SSP, result); + } else { + sspContext->haveIrq = 1; + dprintk("%s: got requested IRQ (%d)\n", DRVNAME, IRQ_SSP); + } + + ssp_lh7x_ts_pen_down_irq_enable(sspContext); + +#ifdef CONFIG_MACH_KEV7A400 + initted = 1; +#endif /* CONFIG_MACH_KEV7A400 */ + +#ifdef CONFIG_CPU_FREQ + hclkfreq_register_notifier( &ssp_hclk_nb); +#endif + + vdprintk("LEAVE: ssp_lh7x_init()\n"); + return(sts); +} + +/********************************************************************** +* Function: ssp_lh7x_exit +* +* Purpose: +* Un-Register & Cleanup the module +**********************************************************************/ +static void ssp_lh7x_exit(void) +{ + sspContext_t *sspContext = &sspContext_l; +#ifdef CONFIG_MACH_KEV79520 + int rcpcLockState; +#endif + + vdprintk("ENTER: ssp_lh7x_exit()\n"); + + //printk("ssp->cr0 = 0x%04X\n", ssp->cr0); + //printk("ssp->cr1 = 0x%04X\n", ssp->cr1); + //printk("ssp->sr = 0x%04X\n", ssp->sr); + //printk("ssp->cpsr = 0x%04X\n", ssp->cpsr); + //printk("ssp->u.icr | u.iir = 0x%04X\n", ssp->u.icr); + +#ifdef CONFIG_CPU_FREQ + hclkfreq_unregister_notifier( &ssp_hclk_nb); +#endif + + /* + * Disable & Return our IRQ + */ + lock_kernel(); + ssp_lh7x_ts_pen_down_irq_disable(sspContext); + if (sspContext->haveIrq) { + free_irq(IRQ_SSP, sspContext); + sspContext->haveIrq = 0; + } + unlock_kernel(); + + ssp->cr0 = 0; + ssp->cr1 = 0; + ssp->u.icr = SSP_IIR_RORIS; /* clear any receive overruns */ + ssp->cpsr = SSP_CPSR_CPDVSR(SSP_PRESCALE_MIN); + +#ifdef CONFIG_MACH_KEV79520 + /* Turn off the RCPC SSP clock */ + rcpcLockState = rcpc_lh7x_lock(RCPC_UNLOCK); + /* Disable SSP clock */ + rcpc->rcpc_sspClkControl |= RCPC_SCLKSEL_SSPCLK; + (void) rcpc_lh7x_lock(rcpcLockState); +#endif + + vdprintk("LEAVE: ssp_lh7x_exit()\n"); + return; +} + +module_init(ssp_lh7x_init); +module_exit(ssp_lh7x_exit); + +MODULE_AUTHOR("Jim Gleason / Lineo, Inc."); +MODULE_DESCRIPTION("SSP Driver for Sharp LH7x EVB"); +MODULE_LICENSE("Copyright (c) 2002 Lineo, Inc."); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/misc/ssp.h linux-2.4.21-rmk1-lh7a400/drivers/misc/ssp.h --- linux-2.4.21-rmk1/drivers/misc/ssp.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/misc/ssp.h Thu Oct 16 17:16:29 2003 @@ -0,0 +1,27 @@ +/********************************************************************** +* linux/drivers/misc/ssp.h +* +* Copyright (C) 2002 Lineo, Inc. +* +* Provide SSP types & definitions +* +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License (GPL) version 2 +* as published by the Free Software Foundation. +* +**********************************************************************/ + +#ifndef _SSP_h +#define _SSP_h + +/********************************************************************* +* Global Function Declarations +*********************************************************************/ +extern void *ssp_request_pointer(int device, char *request); +extern void *ssp_provide_pointer(int device, char *request, void *vp); + +#define SSP_DEV_TOUCHSCREEN 1 +#define SSP_DEV_EEPROM 2 + +#endif /* _SSP_h */ + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mmc/Config.in linux-2.4.21-rmk1-lh7a400/drivers/mmc/Config.in --- linux-2.4.21-rmk1/drivers/mmc/Config.in Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mmc/Config.in Thu Oct 16 15:20:44 2003 @@ -0,0 +1,15 @@ +# +# MMC subsystem configuration +# +mainmenu_option next_comment +comment 'MMC/SD Card support' + +tristate 'MMC support' CONFIG_MMC +if [ "$CONFIG_MMC" = "y" -o "$CONFIG_MMC" = "m" ]; then + bool ' MMC debugging' CONFIG_MMC_DEBUG + if [ "$CONFIG_MMC_DEBUG" = "y" ]; then + int ' MMC debugging verbosity (0=quiet, 3=noisy)' CONFIG_MMC_DEBUG_VERBOSE 0 + fi +fi + +endmenu diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mmc/Makefile linux-2.4.21-rmk1-lh7a400/drivers/mmc/Makefile --- linux-2.4.21-rmk1/drivers/mmc/Makefile Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mmc/Makefile Thu Oct 16 15:20:44 2003 @@ -0,0 +1,20 @@ +# +# Makefile for the kernel mmc device drivers. +# + +O_TARGET := mmc.o + +export-objs := mmc_core.o + +obj-$(CONFIG_MMC) += mmc_base.o + +# Declare multi-part drivers. +list-multi := mmc_base.o +mmc_base-objs := mmc_protocol.o mmc_core.o mmc_media.o + +include $(TOPDIR)/Rules.make + +# Link rules for multi-part drivers. + +mmc_base.o: $(mmc_base-objs) + $(LD) -r -o $@ $(mmc_base-objs) diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mmc/mmc_core.c linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_core.c --- linux-2.4.21-rmk1/drivers/mmc/mmc_core.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_core.c Thu Oct 16 20:04:56 2003 @@ -0,0 +1,830 @@ +/* + * Core MMC driver functions + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Author: Andrew Christian + * 6 May 2002 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "mmc_core.h" + +#define STATE_CMD_ACTIVE (1<<0) +#define STATE_CMD_DONE (1<<1) +#define STATE_INSERT (1<<2) +#define STATE_EJECT (1<<3) + +static struct mmc_dev g_mmc_dev; +static struct proc_dir_entry *proc_mmc_dir; + +#ifndef CONFIG_MMC_DEBUG_VERBOSE +#define CONFIG_MMC_DEBUG_VERBOSE 3 +#endif +int g_mmc_debug = CONFIG_MMC_DEBUG_VERBOSE; +EXPORT_SYMBOL(g_mmc_debug); + +/************************************************************************** + * Debugging functions + **************************************************************************/ + +static char * mmc_result_strings[] = { + "NO_RESPONSE", + "NO_ERROR", + "ERROR_OUT_OF_RANGE", + "ERROR_ADDRESS", + "ERROR_BLOCK_LEN", + "ERROR_ERASE_SEQ", + "ERROR_ERASE_PARAM", + "ERROR_WP_VIOLATION", + "ERROR_CARD_IS_LOCKED", + "ERROR_LOCK_UNLOCK_FAILED", + "ERROR_COM_CRC", + "ERROR_ILLEGAL_COMMAND", + "ERROR_CARD_ECC_FAILED", + "ERROR_CC", + "ERROR_GENERAL", + "ERROR_UNDERRUN", + "ERROR_OVERRUN", + "ERROR_CID_CSD_OVERWRITE", + "ERROR_STATE_MISMATCH", + "ERROR_HEADER_MISMATCH", + "ERROR_TIMEOUT", + "ERROR_CRC", + "ERROR_DRIVER_FAILURE", +}; + +char * mmc_result_to_string( int i ) +{ + return mmc_result_strings[i+1]; +} + +static char * card_state_strings[] = { + "empty", + "idle", + "ready", + "ident", + "stby", + "tran", + "data", + "rcv", + "prg", + "dis", +}; + +static inline char * card_state_to_string( int i ) +{ + return card_state_strings[i+1]; +} + +/************************************************************************** + * Utility functions + **************************************************************************/ + +#define PARSE_U32(_buf,_index) \ + (((u32)_buf[_index]) << 24) | (((u32)_buf[_index+1]) << 16) | \ + (((u32)_buf[_index+2]) << 8) | ((u32)_buf[_index+3]); + +#define PARSE_U16(_buf,_index) \ + (((u16)_buf[_index]) << 8) | ((u16)_buf[_index+1]); + +int mmc_unpack_csd( struct mmc_request *request, struct mmc_csd *csd ) +{ + u8 *buf = request->response; + + if ( request->result ) return request->result; + + csd->csd_structure = (buf[1] & 0xc0) >> 6; + csd->spec_vers = (buf[1] & 0x3c) >> 2; + csd->taac = buf[2]; + csd->nsac = buf[3]; + csd->tran_speed = buf[4]; + csd->ccc = (((u16)buf[5]) << 4) | ((buf[6] & 0xf0) >> 4); + csd->read_bl_len = buf[6] & 0x0f; + csd->read_bl_partial = (buf[7] & 0x80) ? 1 : 0; + csd->write_blk_misalign = (buf[7] & 0x40) ? 1 : 0; + csd->read_blk_misalign = (buf[7] & 0x20) ? 1 : 0; + csd->dsr_imp = (buf[7] & 0x10) ? 1 : 0; + csd->c_size = ((((u16)buf[7]) & 0x03) << 10) | (((u16)buf[8]) << 2) | (((u16)buf[9]) & 0xc0) >> 6; + csd->vdd_r_curr_min = (buf[9] & 0x38) >> 3; + csd->vdd_r_curr_max = buf[9] & 0x07; + csd->vdd_w_curr_min = (buf[10] & 0xe0) >> 5; + csd->vdd_w_curr_max = (buf[10] & 0x1c) >> 2; + csd->c_size_mult = ((buf[10] & 0x03) << 1) | ((buf[11] & 0x80) >> 7); + switch ( csd->csd_structure ) { + case CSD_STRUCT_VER_1_0: + case CSD_STRUCT_VER_1_1: + csd->erase.v22.sector_size = (buf[11] & 0x7c) >> 2; + csd->erase.v22.erase_grp_size = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5); + break; + case CSD_STRUCT_VER_1_2: + default: + csd->erase.v31.erase_grp_size = (buf[11] & 0x7c) >> 2; + csd->erase.v31.erase_grp_mult = ((buf[11] & 0x03) << 3) | ((buf[12] & 0xe0) >> 5); + break; + } + csd->wp_grp_size = buf[12] & 0x1f; + csd->wp_grp_enable = (buf[13] & 0x80) ? 1 : 0; + csd->default_ecc = (buf[13] & 0x60) >> 5; + csd->r2w_factor = (buf[13] & 0x1c) >> 2; + csd->write_bl_len = ((buf[13] & 0x03) << 2) | ((buf[14] & 0xc0) >> 6); + csd->write_bl_partial = (buf[14] & 0x20) ? 1 : 0; + csd->file_format_grp = (buf[15] & 0x80) ? 1 : 0; + csd->copy = (buf[15] & 0x40) ? 1 : 0; + csd->perm_write_protect = (buf[15] & 0x20) ? 1 : 0; + csd->tmp_write_protect = (buf[15] & 0x10) ? 1 : 0; + csd->file_format = (buf[15] & 0x0c) >> 2; + csd->ecc = buf[15] & 0x03; + + DEBUG(2," csd_structure=%d spec_vers=%d taac=%02x nsac=%02x tran_speed=%02x\n" + " ccc=%04x read_bl_len=%d read_bl_partial=%d write_blk_misalign=%d\n" + " read_blk_misalign=%d dsr_imp=%d c_size=%d vdd_r_curr_min=%d\n" + " vdd_r_curr_max=%d vdd_w_curr_min=%d vdd_w_curr_max=%d c_size_mult=%d\n" + " wp_grp_size=%d wp_grp_enable=%d default_ecc=%d r2w_factor=%d\n" + " write_bl_len=%d write_bl_partial=%d file_format_grp=%d copy=%d\n" + " perm_write_protect=%d tmp_write_protect=%d file_format=%d ecc=%d\n", + csd->csd_structure, csd->spec_vers, + csd->taac, csd->nsac, csd->tran_speed, + csd->ccc, csd->read_bl_len, + csd->read_bl_partial, csd->write_blk_misalign, + csd->read_blk_misalign, csd->dsr_imp, + csd->c_size, csd->vdd_r_curr_min, + csd->vdd_r_curr_max, csd->vdd_w_curr_min, + csd->vdd_w_curr_max, csd->c_size_mult, + csd->wp_grp_size, csd->wp_grp_enable, + csd->default_ecc, csd->r2w_factor, + csd->write_bl_len, csd->write_bl_partial, + csd->file_format_grp, csd->copy, + csd->perm_write_protect, csd->tmp_write_protect, + csd->file_format, csd->ecc); + switch (csd->csd_structure) { + case CSD_STRUCT_VER_1_0: + case CSD_STRUCT_VER_1_1: + DEBUG(2," V22 sector_size=%d erase_grp_size=%d\n", + csd->erase.v22.sector_size, + csd->erase.v22.erase_grp_size); + break; + case CSD_STRUCT_VER_1_2: + default: + DEBUG(2," V31 erase_grp_size=%d erase_grp_mult=%d\n", + csd->erase.v31.erase_grp_size, + csd->erase.v31.erase_grp_mult); + break; + + } + + if ( buf[0] != 0x3f ) return MMC_ERROR_HEADER_MISMATCH; + + return 0; +} + +int mmc_unpack_r1( struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state ) +{ + u8 *buf = request->response; + + if ( request->result ) return request->result; + + r1->cmd = buf[0]; + r1->status = PARSE_U32(buf,1); + + DEBUG(2," cmd=%d status=%08x\n", r1->cmd, r1->status); + + if (R1_STATUS(r1->status)) { + if ( r1->status & R1_OUT_OF_RANGE ) return MMC_ERROR_OUT_OF_RANGE; + if ( r1->status & R1_ADDRESS_ERROR ) return MMC_ERROR_ADDRESS; + if ( r1->status & R1_BLOCK_LEN_ERROR ) return MMC_ERROR_BLOCK_LEN; + if ( r1->status & R1_ERASE_SEQ_ERROR ) return MMC_ERROR_ERASE_SEQ; + if ( r1->status & R1_ERASE_PARAM ) return MMC_ERROR_ERASE_PARAM; + if ( r1->status & R1_WP_VIOLATION ) return MMC_ERROR_WP_VIOLATION; + if ( r1->status & R1_CARD_IS_LOCKED ) return MMC_ERROR_CARD_IS_LOCKED; + if ( r1->status & R1_LOCK_UNLOCK_FAILED ) return MMC_ERROR_LOCK_UNLOCK_FAILED; + if ( r1->status & R1_COM_CRC_ERROR ) return MMC_ERROR_COM_CRC; + if ( r1->status & R1_ILLEGAL_COMMAND ) return MMC_ERROR_ILLEGAL_COMMAND; + if ( r1->status & R1_CARD_ECC_FAILED ) return MMC_ERROR_CARD_ECC_FAILED; + if ( r1->status & R1_CC_ERROR ) return MMC_ERROR_CC; + if ( r1->status & R1_ERROR ) return MMC_ERROR_GENERAL; + if ( r1->status & R1_UNDERRUN ) return MMC_ERROR_UNDERRUN; + if ( r1->status & R1_OVERRUN ) return MMC_ERROR_OVERRUN; + if ( r1->status & R1_CID_CSD_OVERWRITE ) return MMC_ERROR_CID_CSD_OVERWRITE; + } + + if ( buf[0] != request->cmd ) return MMC_ERROR_HEADER_MISMATCH; + + /* This should be last - it's the least dangerous error */ + if ( R1_CURRENT_STATE(r1->status) != state ) return MMC_ERROR_STATE_MISMATCH; + + return 0; +} + +int mmc_unpack_cid( struct mmc_request *request, struct mmc_cid *cid ) +{ + u8 *buf = request->response; + int i; + + if ( request->result ) return request->result; + + cid->mid = buf[1]; + cid->oid = PARSE_U16(buf,2); + for ( i = 0 ; i < 6 ; i++ ) + cid->pnm[i] = buf[4+i]; + cid->pnm[6] = 0; + cid->prv = buf[10]; + cid->psn = PARSE_U32(buf,11); + cid->mdt = buf[15]; + + DEBUG(2," mid=%d oid=%d pnm=%s prv=%d.%d psn=%08x mdt=%d/%d\n", + cid->mid, cid->oid, cid->pnm, + (cid->prv>>4), (cid->prv&0xf), + cid->psn, (cid->mdt>>4), (cid->mdt&0xf)+1997); + + if ( buf[0] != 0x3f ) return MMC_ERROR_HEADER_MISMATCH; + return 0; +} + +int mmc_unpack_r3( struct mmc_request *request, struct mmc_response_r3 *r3 ) +{ + u8 *buf = request->response; + + if ( request->result ) return request->result; + + r3->ocr = PARSE_U32(buf,1); + DEBUG(2," ocr=%08x\n", r3->ocr); + + if ( buf[0] != 0x3f ) return MMC_ERROR_HEADER_MISMATCH; + return 0; +} + +/**************************************************************************/ + +#define KBPS 1 +#define MBPS 1000 + +static u32 ts_exp[] = { 100*KBPS, 1*MBPS, 10*MBPS, 100*MBPS, 0, 0, 0, 0 }; +static u32 ts_mul[] = { 0, 1000, 1200, 1300, 1500, 2000, 2500, 3000, + 3500, 4000, 4500, 5000, 5500, 6000, 7000, 8000 }; + +u32 mmc_tran_speed( u8 ts ) +{ + u32 rate = ts_exp[(ts & 0x7)] * ts_mul[(ts & 0x78) >> 3]; + + if ( rate <= 0 ) { + DEBUG(0, ": error - unrecognized speed 0x%02x\n", ts); + return 1; + } + + return rate; +} + +/**************************************************************************/ + +void mmc_send_cmd( struct mmc_dev *dev, int cmd, u32 arg, + u16 nob, u16 block_len, enum mmc_rsp_t rtype ) +{ + dev->request.cmd = cmd; + dev->request.arg = arg; + dev->request.rtype = rtype; + dev->request.nob = nob; + dev->request.block_len = block_len; + dev->request.buffer = NULL; + if ( nob && dev->io_request ) + dev->request.buffer = dev->io_request->buffer; + + dev->state |= STATE_CMD_ACTIVE; + dev->sdrive->send_cmd(&dev->request); +} + +void mmc_finish_io_request( struct mmc_dev *dev, int result ) +{ + struct mmc_io_request *t = dev->io_request; + struct mmc_slot *slot = dev->slot + t->id; + + dev->io_request = NULL; // Remove the old request (the media driver may requeue) + if ( slot->media_driver ) + slot->media_driver->io_request_done( t, result ); +} + + +/* Only call this when there is no pending request - it unloads the media driver */ +int mmc_check_eject( struct mmc_dev *dev ) +{ + unsigned long flags; + int state; + int i; + + DEBUG(2," dev state=%x\n", dev->state); + + local_irq_save(flags); + state = dev->state; + dev->state = state & ~STATE_EJECT; + local_irq_restore(flags); + + if ( !(state & STATE_EJECT) ) + return 0; + + for ( i = 0 ; i < dev->num_slots ; i++ ) { + struct mmc_slot *slot = dev->slot + i; + + if ( slot->flags & MMC_SLOT_FLAG_EJECT ) { + slot->state = CARD_STATE_EMPTY; + if ( slot->media_driver ) { + slot->media_driver->unload( slot ); + slot->media_driver = NULL; + } + slot->flags &= ~MMC_SLOT_FLAG_EJECT; + run_sbin_mmc_hotplug(dev,i,0); + } + } + return 1; +} + +int mmc_check_insert( struct mmc_dev *dev ) +{ + unsigned long flags; + int state; + int i; + int card_count = 0; + + DEBUG(2," dev state=%x\n", dev->state); + + local_irq_save(flags); + state = dev->state; + dev->state = state & ~STATE_INSERT; + local_irq_restore(flags); + + if ( !(state & STATE_INSERT) ) + return 0; + + for ( i = 0 ; i < dev->num_slots ; i++ ) { + struct mmc_slot *slot = dev->slot + i; + + if ( slot->flags & MMC_SLOT_FLAG_INSERT ) { + if (!dev->sdrive->is_empty(i)) { + slot->state = CARD_STATE_IDLE; + card_count++; + } + slot->flags &= ~MMC_SLOT_FLAG_INSERT; + } + } + return card_count; +} + +/****************************************************************** + * + * Hotplug callback card insertion/removal + * + ******************************************************************/ + +#ifdef CONFIG_HOTPLUG + +extern char hotplug_path[]; +extern int call_usermodehelper(char *path, char **argv, char **envp); + +static void run_sbin_hotplug(struct mmc_dev *dev, int id, int insert) +{ + int i; + char *argv[3], *envp[8]; + char media[64], slotnum[16]; + + if (!hotplug_path[0]) + return; + + DEBUG(0,": hotplug_path=%s id=%d insert=%d\n", hotplug_path, id, insert); + + i = 0; + argv[i++] = hotplug_path; + argv[i++] = "mmc"; + argv[i] = 0; + + /* minimal command environment */ + i = 0; + envp[i++] = "HOME=/"; + envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + + /* other stuff we want to pass to /sbin/hotplug */ + sprintf(slotnum, "SLOT=%d", id ); + if ( dev->slot[id].media_driver && dev->slot[id].media_driver->name ) + sprintf(media, "MEDIA=%s", dev->slot[id].media_driver->name ); + else + sprintf(media, "MEDIA=unknown"); + + envp[i++] = slotnum; + envp[i++] = media; + + if (insert) + envp[i++] = "ACTION=add"; + else + envp[i++] = "ACTION=remove"; + envp[i] = 0; + + call_usermodehelper (argv [0], argv, envp); +} + +static void mmc_hotplug_task_handler( void *nr ) +{ + int insert = ((int) nr) & 0x01; + int id = ((int) nr) >> 1; + DEBUG(2," id=%d insert=%d\n", id, insert ); + run_sbin_hotplug(&g_mmc_dev, id, insert ); +} + +static struct tq_struct mmc_hotplug_task = { + routine: mmc_hotplug_task_handler +}; + +void run_sbin_mmc_hotplug(struct mmc_dev *dev, int id, int insert ) +{ + mmc_hotplug_task.data = (void *) ((id << 1) | insert); + schedule_task( &mmc_hotplug_task ); +} + +#else +void run_sbin_mmc_hotplug(struct sleeve_dev *sdev, int insert) { } +#endif /* CONFIG_HOTPLUG */ + + +/****************************************************************** + * Common processing tasklet + * Everything gets serialized through this + ******************************************************************/ + +static void mmc_tasklet_action(unsigned long data) +{ + struct mmc_dev *dev = (struct mmc_dev *)data; + unsigned long flags; + int state; + + DEBUG(2,": dev=%p flags=%02x\n", dev, dev->state); + + /* Grab the current working state */ + local_irq_save(flags); + state = dev->state; + if ( state & STATE_CMD_DONE ) + dev->state = state & ~(STATE_CMD_DONE | STATE_CMD_ACTIVE); + local_irq_restore(flags); + + /* If there is an active command, don't do anything */ + if ( (state & STATE_CMD_ACTIVE) && !(state & STATE_CMD_DONE) ) + return; + + if ( dev->protocol ) + dev->protocol(dev,state); +} + +/****************************************************************** + * Callbacks from low-level driver + * These run at interrupt time + ******************************************************************/ + +void mmc_cmd_complete(struct mmc_request *request) +{ + DEBUG(2,": request=%p retval=%d\n", request, request->result); + g_mmc_dev.state |= STATE_CMD_DONE; + if ( !g_mmc_dev.suspended ) + tasklet_schedule(&g_mmc_dev.task); +} + +void mmc_insert(int slot) +{ + DEBUG(2,": %d\n", slot); + g_mmc_dev.state |= STATE_INSERT; + g_mmc_dev.slot[slot].flags |= MMC_SLOT_FLAG_INSERT; + if ( !g_mmc_dev.suspended && g_mmc_dev.task.func ) + tasklet_schedule(&g_mmc_dev.task); +} + +void mmc_eject(int slot) +{ + DEBUG(2,": %d\n", slot); + g_mmc_dev.state |= STATE_EJECT; + g_mmc_dev.slot[slot].flags |= MMC_SLOT_FLAG_EJECT; + if ( !g_mmc_dev.suspended ) + tasklet_schedule(&g_mmc_dev.task); +} + +EXPORT_SYMBOL(mmc_cmd_complete); +EXPORT_SYMBOL(mmc_insert); +EXPORT_SYMBOL(mmc_eject); + +/****************************************************************** + * Called from the media handler + ******************************************************************/ + +void mmc_handle_io_request( struct mmc_io_request *t ) +{ + DEBUG(2," id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n", + t->id, t->cmd, t->sector, t->nr_sectors, t->block_len, t->buffer); + + if ( g_mmc_dev.io_request ) { + DEBUG(0,": error! io_request in progress\n"); + return; + } + + g_mmc_dev.io_request = t; + tasklet_schedule(&g_mmc_dev.task); +} + +EXPORT_SYMBOL(mmc_handle_io_request); + +/****************************************************************** + * Media handlers + * Allow different drivers to register a media handler + ******************************************************************/ + +static LIST_HEAD(mmc_media_drivers); + +int mmc_match_media_driver( struct mmc_slot *slot ) +{ + struct list_head *item; + + DEBUG(2,": slot=%p\n", slot); + + for ( item = mmc_media_drivers.next ; item != &mmc_media_drivers ; item = item->next ) { + struct mmc_media_driver *drv = list_entry(item, struct mmc_media_driver, node ); + if ( drv->probe(slot) ) { + slot->media_driver = drv; + drv->load(slot); + return 1; + } + } + return 0; +} + +int mmc_register_media_driver( struct mmc_media_driver *drv ) +{ + list_add_tail( &drv->node, &mmc_media_drivers ); + return 0; +} + +void mmc_unregister_media_driver( struct mmc_media_driver *drv ) +{ + list_del(&drv->node); +} + +EXPORT_SYMBOL(mmc_register_media_driver); +EXPORT_SYMBOL(mmc_unregister_media_driver); + +/******************************************************************/ + +int mmc_register_slot_driver( struct mmc_slot_driver *sdrive, int num_slots ) +{ + int i; + int retval; + + DEBUG(2," max=%d ocr=0x%08x\n", num_slots, sdrive->ocr); + + if ( num_slots > MMC_MAX_SLOTS ) { + printk(KERN_CRIT __FUNCTION__ ": illegal num of slots %d\n", num_slots ); + return -ENOMEM; + } + + if ( g_mmc_dev.sdrive ) { + printk(KERN_ALERT __FUNCTION__ ": slot in use\n"); + return -EBUSY; + } + + g_mmc_dev.sdrive = sdrive; + g_mmc_dev.num_slots = num_slots; + + for ( i = 0 ; i < num_slots ; i++ ) { + struct mmc_slot *slot = &g_mmc_dev.slot[i]; + memset(slot,0,sizeof(struct mmc_slot)); + slot->id = i; + slot->state = CARD_STATE_EMPTY; + } + retval = sdrive->init(); + if ( retval ) + return retval; + + /* Generate insert events for cards */ + for ( i = 0 ; i < num_slots ; i++ ) + if ( !sdrive->is_empty(i) ) + mmc_insert(i); + return 0; +} + +void mmc_unregister_slot_driver( struct mmc_slot_driver *sdrive ) +{ + int i; + DEBUG(2,"\n"); + + for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ ) + mmc_eject(i); + + if ( sdrive == g_mmc_dev.sdrive ) { + g_mmc_dev.sdrive->cleanup(); + g_mmc_dev.sdrive = NULL; + } +} + +EXPORT_SYMBOL(mmc_register_slot_driver); +EXPORT_SYMBOL(mmc_unregister_slot_driver); + +/******************************************************************/ + +static struct pm_dev *mmc_pm_dev; + +static int mmc_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + int i; + DEBUG(0,": pm callback %d\n", req ); + + switch (req) { + case PM_SUSPEND: /* Enter D1-D3 */ + g_mmc_dev.suspended = 1; + break; + case PM_RESUME: /* Enter D0 */ + if ( g_mmc_dev.suspended ) { + g_mmc_dev.suspended = 0; + for ( i = 0 ; i < g_mmc_dev.num_slots ; i++ ) { + mmc_eject(i); + if ( !g_mmc_dev.sdrive->is_empty(i) ) + mmc_insert(i); + } + } + break; + } + return 0; +} + +/****************************************************************** + * TODO: These would be better handled by driverfs + * For the moment, we'll just eject and insert everything + ******************************************************************/ + +int mmc_do_eject(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp) +{ + mmc_eject(0); + return 0; +} + +int mmc_do_insert(ctl_table *ctl, int write, struct file * filp, void *buffer, size_t *lenp) +{ + mmc_insert(0); + return 0; +} + + +static struct ctl_table mmc_sysctl_table[] = +{ + { 1, "debug", &g_mmc_debug, sizeof(int), 0666, NULL, &proc_dointvec }, + { 2, "eject", NULL, 0, 0600, NULL, &mmc_do_eject }, + { 3, "insert", NULL, 0, 0600, NULL, &mmc_do_insert }, + {0} +}; + +static struct ctl_table mmc_dir_table[] = +{ + {BUS_MMC, "mmc", NULL, 0, 0555, mmc_sysctl_table}, + {0} +}; + +static struct ctl_table bus_dir_table[] = +{ + {CTL_BUS, "bus", NULL, 0, 0555, mmc_dir_table}, + {0} +}; + +static struct ctl_table_header *mmc_sysctl_header; + +static int mmc_proc_read_device(char *page, char **start, off_t off, int count, int *eof, void *data) +{ + struct mmc_dev *dev = (struct mmc_dev *)data; + char *p = page; + int len = 0; + int i; + + if (!dev || !dev->sdrive) + return 0; + + for ( i = 0 ; i < dev->num_slots ; i++ ) { + struct mmc_slot *slot = &dev->slot[i]; + + p += sprintf(p, "Slot #%d\n", i); + p += sprintf(p, " State %s (%d)\n", card_state_to_string(slot->state), slot->state); + + if ( slot->state != CARD_STATE_EMPTY ) { + p += sprintf(p, " Media %s\n", (slot->media_driver ? slot->media_driver->name : "unknown")); + p += sprintf(p, " CID mid=%d\n", slot->cid.mid); + p += sprintf(p, " oid=%d\n", slot->cid.oid); + p += sprintf(p, " pnm=%s\n", slot->cid.pnm); + p += sprintf(p, " prv=%d.%d\n", slot->cid.prv>>4, slot->cid.prv&0xf); + p += sprintf(p, " psn=0x%08x\n", slot->cid.psn); + p += sprintf(p, " mdt=%d/%d\n", slot->cid.mdt>>4, (slot->cid.mdt&0xf)+1997); + + p += sprintf(p, " CSD csd_structure=%d\n", slot->csd.csd_structure); + p += sprintf(p, " spec_vers=%d\n", slot->csd.spec_vers); + p += sprintf(p, " taac=0x%02x\n", slot->csd.taac); + p += sprintf(p, " nsac=0x%02x\n", slot->csd.nsac); + p += sprintf(p, " tran_speed=0x%02x\n", slot->csd.tran_speed); + p += sprintf(p, " ccc=0x%04x\n", slot->csd.ccc); + p += sprintf(p, " read_bl_len=%d\n", slot->csd.read_bl_len); + p += sprintf(p, " read_bl_partial=%d\n", slot->csd.read_bl_partial); + p += sprintf(p, " write_blk_misalign=%d\n", slot->csd.write_blk_misalign); + p += sprintf(p, " read_blk_misalign=%d\n", slot->csd.read_blk_misalign); + p += sprintf(p, " dsr_imp=%d\n", slot->csd.dsr_imp); + p += sprintf(p, " c_size=%d\n", slot->csd.c_size); + p += sprintf(p, " vdd_r_curr_min=%d\n", slot->csd.vdd_r_curr_min); + p += sprintf(p, " vdd_r_curr_max=%d\n", slot->csd.vdd_r_curr_max); + p += sprintf(p, " vdd_w_curr_min=%d\n", slot->csd.vdd_w_curr_min); + p += sprintf(p, " vdd_w_curr_max=%d\n", slot->csd.vdd_w_curr_max); + p += sprintf(p, " c_size_mult=%d\n", slot->csd.c_size_mult); + p += sprintf(p, " wp_grp_size=%d\n", slot->csd.wp_grp_size); + p += sprintf(p, " wp_grp_enable=%d\n", slot->csd.wp_grp_enable); + p += sprintf(p, " default_ecc=%d\n", slot->csd.default_ecc); + p += sprintf(p, " r2w_factor=%d\n", slot->csd.r2w_factor); + p += sprintf(p, " write_bl_len=%d\n", slot->csd.write_bl_len); + p += sprintf(p, " write_bl_partial=%d\n", slot->csd.write_bl_partial); + p += sprintf(p, " file_format_grp=%d\n", slot->csd.file_format_grp); + p += sprintf(p, " copy=%d\n", slot->csd.copy); + p += sprintf(p, " perm_write_protect=%d\n", slot->csd.perm_write_protect); + p += sprintf(p, " tmp_write_protect=%d\n", slot->csd.tmp_write_protect); + p += sprintf(p, " file_format=%d\n", slot->csd.file_format); + p += sprintf(p, " ecc=%d\n", slot->csd.ecc); + switch (slot->csd.csd_structure) { + case CSD_STRUCT_VER_1_0: + case CSD_STRUCT_VER_1_1: + p += sprintf(p, " sector_size=%d\n", slot->csd.erase.v22.sector_size); + p += sprintf(p, " erase_grp_size=%d\n", slot->csd.erase.v22.erase_grp_size); + break; + case CSD_STRUCT_VER_1_2: + default: + p += sprintf(p, " erase_grp_size=%d\n", slot->csd.erase.v31.erase_grp_size); + p += sprintf(p, " erase_grp_mult=%d\n", slot->csd.erase.v31.erase_grp_mult); + break; + } + } + } + + len = (p - page) - off; + *start = page + off; + return len; +} + +/******************************************************************/ + +void mmc_protocol_single_card( struct mmc_dev *dev, int state_flags ); +extern struct mmc_media_module media_module; + +static int __init mmc_init(void) +{ + DEBUG(1,"\n"); + + mmc_sysctl_header = register_sysctl_table(bus_dir_table, 0 ); + + tasklet_init(&g_mmc_dev.task,mmc_tasklet_action,(unsigned long)&g_mmc_dev); + g_mmc_dev.protocol = mmc_protocol_single_card; + + proc_mmc_dir = proc_mkdir("mmc", proc_bus); + if ( proc_mmc_dir ) + create_proc_read_entry("device", 0, proc_mmc_dir, mmc_proc_read_device, &g_mmc_dev); + + mmc_pm_dev = pm_register(PM_UNKNOWN_DEV, PM_SYS_UNKNOWN, mmc_pm_callback); + + media_module.init(); + return 0; +} + +static void __exit mmc_exit(void) +{ + DEBUG(1,"\n"); + + media_module.cleanup(); + + unregister_sysctl_table(mmc_sysctl_header); + + tasklet_kill(&g_mmc_dev.task); + + if ( proc_mmc_dir ) { + remove_proc_entry("device", proc_mmc_dir); + remove_proc_entry("mmc", proc_bus); + } + + pm_unregister(mmc_pm_dev); +} + +module_init(mmc_init); +module_exit(mmc_exit); + + + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mmc/mmc_core.h linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_core.h --- linux-2.4.21-rmk1/drivers/mmc/mmc_core.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_core.h Sun Feb 8 20:35:49 2004 @@ -0,0 +1,68 @@ +/* + * Header for MultiMediaCard (MMC) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Based strongly on code by: + * + * Author: Yong-iL Joh + * Date : $Date: 2003/02/17 18:56:27 $ + * + * Author: Andrew Christian + * 15 May 2002 + */ + +#ifndef MMC_MMC_CORE_H +#define MMC_MMC_CORE_H + +#include +#include "mmc_media.h" + +#define ID_TO_RCA(x) ((x)+1) + +struct mmc_dev { + struct mmc_slot_driver *sdrive; + struct mmc_slot slot[MMC_MAX_SLOTS]; + struct mmc_request request; // Active request to the low-level driver + struct mmc_io_request *io_request; // Active transfer request from the high-level media io + struct tasklet_struct task; + int num_slots; // Copied from the slot driver; used when slot driver shuts down + + /* State maintenance */ + int state; + int suspended; + void (*protocol)(struct mmc_dev *, int); +}; + +char * mmc_result_to_string( int ); +int mmc_unpack_csd( struct mmc_request *request, struct mmc_csd *csd ); +int mmc_unpack_r1( struct mmc_request *request, struct mmc_response_r1 *r1, enum card_state state ); +int mmc_unpack_cid( struct mmc_request *request, struct mmc_cid *cid ); +int mmc_unpack_r3( struct mmc_request *request, struct mmc_response_r3 *r3 ); + +void mmc_send_cmd( struct mmc_dev *dev, int cmd, u32 arg, + u16 nob, u16 block_len, enum mmc_rsp_t rtype ); +void mmc_finish_io_request( struct mmc_dev *dev, int result ); +int mmc_check_eject( struct mmc_dev *dev ); +int mmc_check_insert( struct mmc_dev *dev ); +u32 mmc_tran_speed( u8 ts ); +int mmc_match_media_driver( struct mmc_slot *slot ); +void run_sbin_mmc_hotplug(struct mmc_dev *dev, int id, int insert); + +static inline void mmc_simple_cmd( struct mmc_dev *dev, int cmd, u32 arg, enum mmc_rsp_t rtype ) +{ + mmc_send_cmd( dev, cmd, arg, 0, 0, rtype ); +} + +#endif /* MMC_MMC_CORE_H */ + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mmc/mmc_media.c linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_media.c --- linux-2.4.21-rmk1/drivers/mmc/mmc_media.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_media.c Thu Oct 16 20:04:07 2003 @@ -0,0 +1,527 @@ +/* + * Block driver for media (i.e., flash cards) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Author: Andrew Christian + * 28 May 2002 + */ + +#include +#include + +#include +#include /* printk() */ +#include /* everything... */ +#include /* error codes */ +#include /* size_t */ +#include /* O_ACCMODE */ +#include /* HDIO_GETGEO */ +#include +#include + +#include +#include + +#include "mmc_media.h" + +#define MAJOR_NR mmc_major /* force definitions on in blk.h */ +#ifdef CONFIG_DEVFS_FS +static int mmc_major; /* must be declared before including blk.h */ +#else +static int mmc_major = 250; /* must be declared before including blk.h */ +#endif + +#define MMC_SHIFT 3 /* max 8 partitions per card */ + +#define DEVICE_NR(device) (MINOR(device)>>MMC_SHIFT) +#define DEVICE_NAME "mmc" /* name for messaging */ +#define DEVICE_INTR mmc_intrptr /* pointer to the bottom half */ +#define DEVICE_NO_RANDOM /* no entropy to contribute */ +#define DEVICE_REQUEST mmc_media_request +#define DEVICE_OFF(d) /* do-nothing */ + +#include +#include + +static int rahead = 8; +static int maxsectors = 4; + +MODULE_PARM(maxsectors,"i"); +MODULE_PARM_DESC(maxsectors,"Maximum number of sectors for a single request"); +MODULE_PARM(rahead,"i"); +MODULE_PARM_DESC(rahead,"Default sector read ahead"); + +#define MMC_NDISK (MMC_MAX_SLOTS << MMC_SHIFT) + +/* + Don't bother messing with blksize_size....it gets changed by various filesystems. + You're better off dealing with arbitrary blksize's +*/ +static int mmc_blk[MMC_NDISK]; /* Used for hardsect_size - should be 512 bytes */ +static int mmc_max[MMC_NDISK]; /* Used for max_sectors[] - limit size of individual request */ + +static int mmc_sizes[MMC_NDISK]; /* Used in gendisk - gives whole size of partition */ +static struct hd_struct mmc_partitions[MMC_NDISK]; /* Used in gendisk - gives particular partition information */ + +static char mmc_gendisk_flags; +#ifdef CONFIG_DEVFS_FS +static devfs_handle_t mmc_devfs_handle; +#endif + +// There is one mmc_media_dev per inserted card +struct mmc_media_dev { + int usage; + struct mmc_slot *slot; + spinlock_t lock; + int changed; + long nr_sects; // In total number of sectors + + int read_block_len; // Valid read block length + int write_block_len; // Valid write block length +}; + +static struct mmc_media_dev g_media_dev[MMC_MAX_SLOTS]; +static struct mmc_io_request g_io_request; +static int g_busy; + +static struct gendisk mmc_gendisk = { + major: 0, /* major number dynamically assigned */ + major_name: DEVICE_NAME, + minor_shift: MMC_SHIFT, /* shift to get device number */ + max_p: 1 << MMC_SHIFT, /* Number of partiions */ + /* The remainder will be filled in dynamically */ +}; + +/*************************************************************************/ +/* TODO: O_EXCL, O_NDELAY, invalidate_buffers */ +static int mmc_media_open( struct inode *inode, struct file *filp ) +{ + struct mmc_media_dev *dev; + int num = DEVICE_NR(inode->i_rdev); + + DEBUG(1,": num=%d\n", num); + + if ( num >= MMC_MAX_SLOTS) + return -ENODEV; + + dev = &g_media_dev[num]; + if ( !dev->slot ) + return -ENODEV; + + spin_lock(&dev->lock); + if (!dev->usage) + check_disk_change(inode->i_rdev); + dev->usage++; + MOD_INC_USE_COUNT; + spin_unlock(&dev->lock); + return 0; +} + +static int mmc_media_release( struct inode *inode, struct file *filep ) +{ + struct mmc_media_dev *dev = &g_media_dev[DEVICE_NR(inode->i_rdev)]; + + DEBUG(1,": num=%d\n", DEVICE_NR(inode->i_rdev)); + + spin_lock(&dev->lock); + dev->usage--; + /* Is this worth doing? */ + if (!dev->usage) { + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + } + MOD_DEC_USE_COUNT; + spin_unlock(&dev->lock); + return 0; +} + +static int mmc_media_revalidate(kdev_t i_rdev) +{ + int index, max_p, start, i; + struct mmc_media_dev *dev; + + index = DEVICE_NR(i_rdev); + DEBUG(2,": index=%d\n", index); + + max_p = mmc_gendisk.max_p; + start = index << MMC_SHIFT; + dev = &g_media_dev[index]; + + for ( i = max_p - 1 ; i >= 0 ; i-- ) { + int item = start + i; + invalidate_device(MKDEV(mmc_major,item),1); + mmc_gendisk.part[item].start_sect = 0; + mmc_gendisk.part[item].nr_sects = 0; + /* TODO: Fix the blocksize? */ + } + + register_disk(&mmc_gendisk, i_rdev, 1 << MMC_SHIFT, mmc_gendisk.fops, dev->nr_sects); + return 0; +} + +static int mmc_media_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int num = DEVICE_NR(inode->i_rdev); + int size; + struct hd_geometry geo; + + DEBUG(1," ioctl 0x%x 0x%lx\n", cmd, arg); + + switch(cmd) { + case BLKGETSIZE: + /* Return the device size, expressed in sectors */ + /* Not really necessary, but this is faster than walking the gendisk list */ + if (!access_ok(VERIFY_WRITE, arg, sizeof(long))) + return -EFAULT; + return put_user(mmc_partitions[MINOR(inode->i_rdev)].nr_sects, (long *)arg); + + case BLKRRPART: /* re-read partition table */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return mmc_media_revalidate(inode->i_rdev); + + case HDIO_GETGEO: + if (!access_ok(VERIFY_WRITE, arg, sizeof(geo))) + return -EFAULT; + /* Grab the size from the 0 partition for this minor */ + /* TODO: is this the right thing? Or should we do it by partition??? */ + size = mmc_sizes[num << MMC_SHIFT] / mmc_blk[num << MMC_SHIFT]; + geo.cylinders = (size & ~0x3f) >> 6; + geo.heads = 4; + geo.sectors = 16; + geo.start = mmc_partitions[MINOR(inode->i_rdev)].start_sect; + if (copy_to_user((void *) arg, &geo, sizeof(geo))) + return -EFAULT; + return 0; + + default: + return blk_ioctl(inode->i_rdev, cmd, arg); + } + + return -ENOTTY; /* should never get here */ +} + +static int mmc_media_check_change(kdev_t i_rdev) +{ + int index, retval; + struct mmc_media_dev *dev; + unsigned long flags; + + index = DEVICE_NR(i_rdev); + DEBUG(2," device=%d\n", index); + if (index >= MMC_MAX_SLOTS) + return 0; + + dev = &g_media_dev[index]; + + spin_lock_irqsave(&dev->lock, flags); + retval = (dev->changed ? 1 : 0); + dev->changed = 0; + spin_unlock_irqrestore(&dev->lock, flags); + + return retval; +} + +static struct mmc_media_dev * mmc_media_locate_device(const struct request *req) +{ + int num = DEVICE_NR(req->rq_dev); + if ( num >= MMC_MAX_SLOTS) { + static int count = 0; + if (count++ < 5) /* print the message at most five times */ + printk(KERN_WARNING "mmc: request for unknown device\n"); + return NULL; + } + return &g_media_dev[num]; +} + +static int mmc_media_transfer( struct mmc_media_dev *dev, const struct request *req ) +{ + int minor = MINOR(req->rq_dev); + unsigned long flags; + + DEBUG(2,": minor=%d\n", minor); + + if ( req->sector + req->current_nr_sectors > mmc_partitions[minor].nr_sects ) { + static int count = 0; + if (count++ < 5) + printk(KERN_WARNING __FUNCTION__ ": request past end of partition\n"); + return 0; + } + + spin_lock_irqsave(&dev->lock, flags); + + g_io_request.id = DEVICE_NR(req->rq_dev); + g_io_request.cmd = req->cmd; + g_io_request.sector = mmc_partitions[minor].start_sect + req->sector; + g_io_request.nr_sectors = req->current_nr_sectors; + g_io_request.block_len = mmc_blk[minor]; + g_io_request.buffer = req->buffer; + + DEBUG(2,": id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n", + g_io_request.id, g_io_request.cmd, g_io_request.sector, g_io_request.nr_sectors, + g_io_request.block_len, g_io_request.buffer ); + + mmc_handle_io_request(&g_io_request); + spin_unlock_irqrestore(&dev->lock, flags); + return 1; +} + +static void mmc_media_request( request_queue_t *q ) +{ + struct mmc_media_dev *dev; + + if ( g_busy ) + return; + + while(1) { + INIT_REQUEST; /* returns when queue is empty */ + dev = mmc_media_locate_device(CURRENT); + if ( !dev ) { + end_request(0); + continue; + } + + DEBUG(2," (%p): cmd %i sec %li (nr. %li)\n", CURRENT, + CURRENT->cmd, CURRENT->sector, CURRENT->current_nr_sectors); + + if ( mmc_media_transfer(dev,CURRENT) ) { + g_busy = 1; + return; + } + end_request(0); /* There was a problem with the request */ + } +} + +static void mmc_media_transfer_done( struct mmc_io_request *trans, int result ) +{ + unsigned long flags; + DEBUG(3,": result=%d\n", result); + spin_lock_irqsave(&io_request_lock, flags); + end_request(result); + g_busy = 0; + if (!QUEUE_EMPTY) + mmc_media_request(NULL); // Start the next transfer + spin_unlock_irqrestore(&io_request_lock, flags); +} + + +static struct block_device_operations mmc_bdops = { + open: mmc_media_open, + release: mmc_media_release, + ioctl: mmc_media_ioctl, + check_media_change: mmc_media_check_change, + revalidate: mmc_media_revalidate +}; + +/******************************************************************/ +/* TODO: + We have a race condition if two slots need to be revalidated at the same + time. Perhaps we should walk the list of devices and look for change + flags? +*/ + +static void mmc_media_load_task_handler( void *nr ) +{ + int slot_id = (int) nr; + DEBUG(2," slot_id=%d\n", slot_id ); + mmc_media_revalidate(MKDEV(mmc_major,(slot_id<id]; + int i; + + long nr_sects; + int write_block_len; + int read_block_len; + + spin_lock_irqsave(&dev->lock, flags); + + nr_sects = (1 + slot->csd.c_size) * (1 << (slot->csd.c_size_mult + 2)); + write_block_len = 1 << slot->csd.write_bl_len; + read_block_len = 1 << slot->csd.read_bl_len; + + MOD_INC_USE_COUNT; + DEBUG(1, " slot=%p nr_sect=%ld write_block_length=%d read_block_len=%d\n", + slot, nr_sects, write_block_len, read_block_len ); + + dev->slot = slot; + dev->nr_sects = nr_sects; + dev->read_block_len = read_block_len; + dev->write_block_len = write_block_len; + dev->changed = 1; + mmc_gendisk.nr_real++; + + /* Fix up the block size to match read_block_len */ + /* TODO: can we really do this? Right now we're affecting blksize_size and hardsect_size */ + for ( i = 0 ; i < (1 << MMC_SHIFT) ; i++ ) + mmc_blk[(slot->id << MMC_SHIFT) + i] = read_block_len; + + mmc_media_load_task.data = (void *) slot->id; + schedule_task( &mmc_media_load_task ); + + spin_unlock_irqrestore(&dev->lock, flags); +} + +/* TODO: This is a problem area. We've lost our card, so we'd like + to flush all outstanding buffers and requests, remove the partitions from + the file system, and generally shut everything down. +*/ + +static void mmc_media_unload( struct mmc_slot *slot ) +{ + unsigned long flags; + struct mmc_media_dev *dev = &g_media_dev[slot->id]; + + spin_lock_irqsave(&dev->lock, flags); + +// for ( i = 0 ; i < MMC_SHIFT ; i++ ) +// fsync_dev(MKDEV(mmc_major,slot->id,i)); + + MOD_DEC_USE_COUNT; + DEBUG(1," slot=%p id=%d\n", slot, slot->id); + + dev->slot = NULL; + dev->nr_sects = 0; + dev->changed = 1; + mmc_gendisk.nr_real--; + + mmc_media_load_task.data = (void *) slot->id; + schedule_task( &mmc_media_load_task ); + + spin_unlock_irqrestore(&dev->lock, flags); +} + +/* + Called once the device has a valid CSD structure + In the future this should determine what type of card we have + For the moment, everything is a memory card +*/ + +static int mmc_media_probe( struct mmc_slot *slot ) +{ + return 1; +} + +static struct mmc_media_driver mmc_driver = { + name: "flash", + load: mmc_media_load, + unload: mmc_media_unload, + probe: mmc_media_probe, + io_request_done: mmc_media_transfer_done, +}; + +/******************************************************************/ + +static int __init mmc_media_init( void ) +{ + int i, result; + DEBUG(0,"\n"); + +#ifdef CONFIG_DEVFS_FS + mmc_devfs_handle = devfs_mk_dir(NULL, DEVICE_NAME, NULL); + if (!mmc_devfs_handle) { + DEBUG(0,"devfs_mk_dir failed\n"); + return -EBUSY; + } + + result = devfs_register_blkdev(mmc_major, DEVICE_NAME, &mmc_bdops); + if (result < 0) { + printk(KERN_WARNING "Unable to get major %d for MMC media\n", mmc_major); + return result; + } +#else + result = register_blkdev( mmc_major, DEVICE_NAME, &mmc_bdops); + if( result < 0) { + printk(KERN_WARNING "Unable to get major %d for MMC media.", mmc_major); + return result; + } + +#endif + + if ( !mmc_major ) mmc_major = result; + DEBUG(0,"mmc_major=%d\n", mmc_major); // DDD + + /* Set up global block arrays */ + read_ahead[mmc_major] = rahead; + for(i=0 ; i < MMC_NDISK; i++) + mmc_blk[i] = 512; + hardsect_size[mmc_major] = mmc_blk; + for(i=0; i < MMC_NDISK; i++) + mmc_max[i] = maxsectors; + max_sectors[mmc_major] = mmc_max; + + /* Start with zero-sized partitions : we'll fix this later */ + memset(mmc_sizes, 0, sizeof(int) * MMC_NDISK); + blk_size[mmc_major] = mmc_sizes; + + /* Fix up the gendisk structure */ + mmc_gendisk.part = mmc_partitions; + mmc_gendisk.sizes = mmc_sizes; + mmc_gendisk.nr_real = 0; +#ifdef CONFIG_DEVFS_FS + mmc_gendisk.de_arr = &mmc_devfs_handle; +#else + mmc_gendisk.de_arr = NULL; +#endif + mmc_gendisk.flags = &mmc_gendisk_flags; + mmc_gendisk.fops = &mmc_bdops; + + /* Add ourselves to the global list */ + mmc_gendisk.major = mmc_major; + add_gendisk(&mmc_gendisk); + + blk_init_queue(BLK_DEFAULT_QUEUE(mmc_major), DEVICE_REQUEST); + return mmc_register_media_driver(&mmc_driver); +} + +static void /*__exit*/ mmc_media_cleanup( void ) +{ + int i; + DEBUG(0,"\n"); + + flush_scheduled_tasks(); + unregister_blkdev(mmc_major, DEVICE_NAME); + + for ( i = 0 ; i < MMC_NDISK; i++ ) + fsync_dev(MKDEV(mmc_major,i)); + + mmc_unregister_media_driver(&mmc_driver); + + blk_cleanup_queue(BLK_DEFAULT_QUEUE(mmc_major)); + + blk_size[mmc_major] = NULL; + hardsect_size[mmc_major] = NULL; + max_sectors[mmc_major] = NULL; + + del_gendisk(&mmc_gendisk); + +#ifdef CONFIG_DEVFS_FS + devfs_unregister(mmc_devfs_handle); +#else + unregister_blkdev( mmc_major, DEVICE_NAME ); +#endif +} + +struct mmc_media_module media_module = { + init: mmc_media_init, + cleanup: mmc_media_cleanup +}; diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mmc/mmc_media.h linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_media.h --- linux-2.4.21-rmk1/drivers/mmc/mmc_media.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_media.h Sun Feb 8 20:35:49 2004 @@ -0,0 +1,85 @@ +/* + * Header for MultiMediaCard (MMC) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Based strongly on code by: + * + * Author: Yong-iL Joh + * Date : $Date: 2003/02/17 18:56:27 $ + * + * Author: Andrew Christian + * 15 May 2002 + */ + +#ifndef MMC_MMC_MEDIA_H +#define MMC_MMC_MEDIA_H + +#include +#include + +#include + +/* Set an upper bound for how many cards we'll support */ +/* This is used only for static array initialization */ +#define MMC_MAX_SLOTS 2 + +#define MMC_SLOT_FLAG_INSERT (1<<0) +#define MMC_SLOT_FLAG_EJECT (1<<1) + +struct mmc_media_driver; + +struct mmc_slot { + int id; /* Card index */ + /* Card specific information */ + struct mmc_cid cid; + struct mmc_csd csd; + + enum card_state state; /* empty, ident, ready, whatever */ + int flags; /* Ejected, inserted */ + + /* Assigned media driver */ + struct mmc_media_driver *media_driver; +}; + +struct mmc_io_request { + int id; /* Card index */ + int cmd; /* READ or WRITE */ + unsigned long sector; /* Start address */ + unsigned long nr_sectors; /* Length of read */ + unsigned long block_len; /* Size of sector (sanity check) */ + char *buffer; /* Data buffer */ +}; + +/* Media driver (e.g., Flash card, I/O card...) */ +struct mmc_media_driver { + struct list_head node; + char *name; + void (*load)(struct mmc_slot *); + void (*unload)(struct mmc_slot *); + int (*probe)(struct mmc_slot *); + void (*io_request_done)(struct mmc_io_request *, int result); +}; + +struct mmc_media_module { + int (*init)(void); + void (*cleanup)(void); +}; + +/* Calls made by the media driver */ +extern int mmc_register_media_driver( struct mmc_media_driver * ); +extern void mmc_unregister_media_driver( struct mmc_media_driver * ); +extern void mmc_handle_io_request( struct mmc_io_request * ); + +#endif /* MMC_MMC_MEDIA_H */ + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mmc/mmc_protocol.c linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_protocol.c --- linux-2.4.21-rmk1/drivers/mmc/mmc_protocol.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_protocol.c Thu Oct 16 19:56:16 2003 @@ -0,0 +1,433 @@ +/* + * MMC State machine functions + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * This part of the code is separated from mmc_core.o so we can + * plug in different state machines (e.g., SPI, SD) + * + * This code assumes that you have exactly one card slot, no more. + * + * Author: Andrew Christian + * 6 May 2002 + */ + +#include +#include + +#include +#include + +#include "mmc_core.h" + +static void * mmc_cim_default_state( struct mmc_dev *dev, int first ); + +/****************************************************************** + * + * Useful utility functions + * + ******************************************************************/ + +static int mmc_has_valid_request( struct mmc_dev *dev ) +{ + struct mmc_io_request *request = dev->io_request; + struct mmc_slot *slot; + + DEBUG(2," (%p)\n", request); + + if ( !request ) return 0; + + slot = dev->slot + request->id; + + if ( !slot->media_driver ) { + DEBUG(0,": card doesn't have media driver\n"); + return 0; + } + + return 1; +} + +static void mmc_configure_card( struct mmc_dev *dev, int slot ) +{ + u32 rate; + DEBUG(2,": slot=%d\n", slot); + + /* Fix the clock rate */ + rate = mmc_tran_speed(dev->slot[slot].csd.tran_speed); + if ( rate < MMC_CLOCK_SLOW ) + rate = MMC_CLOCK_SLOW; + if ( rate > MMC_CLOCK_FAST ) + rate = MMC_CLOCK_FAST; + + dev->sdrive->set_clock(rate); + + /* Match the drive media */ + mmc_match_media_driver(&dev->slot[slot]); + run_sbin_mmc_hotplug(dev, slot, 1); +} + +/* The blocks requested by the kernel may or may not + match what we can do. Unfortunately, filesystems play + fast and loose with block sizes, so we're stuck with this */ + +static void mmc_fix_request_block_size( struct mmc_dev *dev ) +{ + struct mmc_io_request *t = dev->io_request; + struct mmc_slot *slot = dev->slot + t->id; + u16 block_len; + + DEBUG(1, ": io_request id=%d cmd=%d sector=%ld nr_sectors=%ld block_len=%ld buf=%p\n", + t->id, t->cmd, t->sector, t->nr_sectors, t->block_len, t->buffer); + + switch( t->cmd ) { + case READ: + block_len = 1 << slot->csd.read_bl_len; + break; + case WRITE: + block_len = 1 << slot->csd.write_bl_len; + break; + default: + DEBUG(0,": unrecognized command %d\n", t->cmd); + return; + } + + if ( block_len < t->block_len ) { + int scale = t->block_len / block_len; + DEBUG(1,": scaling by %d from block_len=%d to %ld\n", + scale, block_len, t->block_len); + t->block_len = block_len; + t->sector *= scale; + t->nr_sectors *= scale; + } +} + + +/****************************************************************** + * State machine routines to read and write data + * + * SET_BLOCKLEN only needs to be done once for each card. + * SET_BLOCK_COUNT is only valid in MMC 3.1; most cards don't support this, + * so we don't use it. + * + * In the 2.x cards we have a choice between STREAMING mode and + * SINGLE mode. There's an obvious performance possibility in + * using streaming mode, but at this time we're just using the SINGLE + * mode. + ******************************************************************/ + +static void * mmc_cim_read_write_block( struct mmc_dev *dev, int first ) +{ + struct mmc_io_request *t = dev->io_request; + struct mmc_response_r1 r1; + struct mmc_slot *slot = dev->slot + t->id; + int retval = 0; + int i; + + DEBUG(2," first=%d\n",first); + + if ( first ) { + mmc_fix_request_block_size( dev ); + + switch ( slot->state ) { + case CARD_STATE_STBY: + mmc_simple_cmd(dev, MMC_SELECT_CARD, ID_TO_RCA(slot->id) << 16, RESPONSE_R1B ); + break; + case CARD_STATE_TRAN: + mmc_simple_cmd(dev, MMC_SET_BLOCKLEN, t->block_len, RESPONSE_R1 ); + break; + default: + DEBUG(0,": invalid card state %d\n", slot->state); + goto read_block_error; + break; + } + return NULL; + } + + switch (dev->request.cmd) { + case MMC_SELECT_CARD: + if ( (retval = mmc_unpack_r1( &dev->request, &r1, slot->state )) ) + goto read_block_error; + + for ( i = 0 ; i < dev->num_slots ; i++ ) + dev->slot[i].state = ( i == t->id ? CARD_STATE_TRAN : CARD_STATE_STBY ); + + mmc_simple_cmd(dev, MMC_SET_BLOCKLEN, t->block_len, RESPONSE_R1 ); + break; + + case MMC_SET_BLOCKLEN: + if ( (retval = mmc_unpack_r1( &dev->request, &r1, slot->state )) ) + goto read_block_error; + + mmc_send_cmd(dev, (t->cmd == READ ? MMC_READ_SINGLE_BLOCK : MMC_WRITE_BLOCK), + t->sector * t->block_len, 1, t->block_len, RESPONSE_R1 ); + break; + + case MMC_READ_SINGLE_BLOCK: + case MMC_WRITE_BLOCK: + if ( (retval = mmc_unpack_r1( &dev->request, &r1, slot->state )) ) + goto read_block_error; + + t->nr_sectors--; + t->sector++; + t->buffer += t->block_len; + + if ( t->nr_sectors ) { + mmc_send_cmd( dev, + t->cmd == READ ? + MMC_READ_SINGLE_BLOCK : + MMC_WRITE_BLOCK, + t->sector * t->block_len, 1, + t->block_len, RESPONSE_R1 ); + } + else { + mmc_finish_io_request( dev, 1 ); + if ( mmc_has_valid_request(dev) ) + return mmc_cim_read_write_block; + return mmc_cim_default_state; + } + break; + + default: + goto read_block_error; + break; + } + return NULL; + +read_block_error: + DEBUG(0,": failure during cmd %d, error %d (%s)\n", + dev->request.cmd, retval, mmc_result_to_string(retval)); + mmc_finish_io_request( dev, 0 ); // Failure + return mmc_cim_default_state; +} + +/* Update the card's status information in preparation to running a read/write cycle */ + +static void * mmc_cim_get_status( struct mmc_dev *dev, int first ) +{ + struct mmc_slot *slot = dev->slot + dev->io_request->id; + struct mmc_response_r1 r1; + int retval = MMC_NO_ERROR; + + DEBUG(2," first=%d\n",first); + + if ( first ) { + mmc_simple_cmd(dev, MMC_SEND_STATUS, ID_TO_RCA(slot->id) << 16, RESPONSE_R1 ); + return NULL; + } + + switch (dev->request.cmd) { + case MMC_SEND_STATUS: + retval = mmc_unpack_r1(&dev->request,&r1,slot->state); + if ( !retval || retval == MMC_ERROR_STATE_MISMATCH ) { + slot->state = R1_CURRENT_STATE(r1.status); + return mmc_cim_read_write_block; + } + break; + + default: + break; + } + + DEBUG(0, ": failure during cmd %d, error=%d (%s)\n", dev->request.cmd, + retval, mmc_result_to_string(retval)); + mmc_finish_io_request(dev,0); + return mmc_cim_default_state; +} + +static void * mmc_cim_handle_request( struct mmc_dev *dev, int first ) +{ + DEBUG(2," first=%d\n",first); + + if ( !first && !mmc_has_valid_request(dev)) { + DEBUG(0, ": invalid request\n"); + mmc_finish_io_request(dev,0); + return mmc_cim_default_state; + } + + if ( first ) + return mmc_cim_get_status; + + return mmc_cim_read_write_block; +} + +/****************************************************************** + * + * State machine routines to initialize card(s) + * + ******************************************************************/ + +/* + CIM_SINGLE_CARD_ACQ (frequency at 400 kHz) + --- Must enter from GO_IDLE_STATE --- + + 1. SEND_OP_COND (Full Range) [CMD1] {optional} + 2. SEND_OP_COND (Set Range ) [CMD1] + If busy, delay and repeat step 2 + 3. ALL_SEND_CID [CMD2] + If timeout, set an error (no cards found) + 4. SET_RELATIVE_ADDR [CMD3] + 5. SEND_CSD [CMD9] + 6. SET_DSR [CMD4] Only call this if (csd.dsr_imp). + 7. Set clock frequency (check available in csd.tran_speed) + */ + +static void * mmc_cim_single_card_acq( struct mmc_dev *dev, int first ) +{ + struct mmc_response_r3 r3; + struct mmc_response_r1 r1; + struct mmc_slot *slot = dev->slot; /* Must be slot 0 */ + int retval; + + DEBUG(2,"\n"); + + if ( first ) { + mmc_simple_cmd(dev, MMC_GO_IDLE_STATE, 0, RESPONSE_NONE); + return NULL; + } + + switch (dev->request.cmd) { + case MMC_GO_IDLE_STATE: /* No response to parse */ + if ( (dev->sdrive->flags & MMC_SDFLAG_VOLTAGE )) + DEBUG(0,": error - current driver doesn't do OCR\n"); + mmc_simple_cmd(dev, MMC_SEND_OP_COND, dev->sdrive->ocr, RESPONSE_R3); + break; + + case MMC_SEND_OP_COND: + retval = mmc_unpack_r3(&dev->request, &r3); + if ( retval ) { + DEBUG(0,": failed SEND_OP_COND error=%d (%s) - could be SD card\n", + retval, mmc_result_to_string(retval)); + return mmc_cim_default_state; + } + + DEBUG(2,": read ocr value = 0x%08x\n", r3.ocr); + if (!(r3.ocr & MMC_CARD_BUSY)) { + mmc_simple_cmd(dev, MMC_SEND_OP_COND, dev->sdrive->ocr, RESPONSE_R3); + } + else { + slot->state = CARD_STATE_READY; + mmc_simple_cmd(dev, MMC_ALL_SEND_CID, 0, RESPONSE_R2_CID); + } + break; + + case MMC_ALL_SEND_CID: + retval = mmc_unpack_cid( &dev->request, &slot->cid ); + if ( retval ) { + DEBUG(0,": unable to ALL_SEND_CID error=%d (%s)\n", + retval, mmc_result_to_string(retval)); + return mmc_cim_default_state; + } + slot->state = CARD_STATE_IDENT; + mmc_simple_cmd(dev, MMC_SET_RELATIVE_ADDR, ID_TO_RCA(slot->id) << 16, RESPONSE_R1); + break; + + case MMC_SET_RELATIVE_ADDR: + retval = mmc_unpack_r1(&dev->request,&r1,slot->state); + if ( retval ) { + DEBUG(0, ": unable to SET_RELATIVE_ADDR error=%d (%s)\n", + retval, mmc_result_to_string(retval)); + return mmc_cim_default_state; + } + slot->state = CARD_STATE_STBY; + mmc_simple_cmd(dev, MMC_SEND_CSD, ID_TO_RCA(slot->id) << 16, RESPONSE_R2_CSD); + break; + + case MMC_SEND_CSD: + retval = mmc_unpack_csd(&dev->request, &slot->csd); + if ( retval ) { + DEBUG(0, ": unable to SEND_CSD error=%d (%s)\n", + retval, mmc_result_to_string(retval)); + return mmc_cim_default_state; + } + if ( slot->csd.dsr_imp ) { + DEBUG(0, ": driver doesn't support setting DSR\n"); + // mmc_simple_cmd(dev, MMC_SET_DSR, 0, RESPONSE_NONE); + } + mmc_configure_card( dev, 0 ); + return mmc_cim_default_state; + + default: + DEBUG(0, ": error! Illegal last cmd %d\n", dev->request.cmd); + return mmc_cim_default_state; + } + return NULL; +} + +/* + CIM_INIT_STACK (frequency at 400 kHz) + + 1. GO_IDLE_STATE (CMD0) + 2. Do CIM_SINGLE_CARD_ACQ +*/ + +static void * mmc_cim_init_stack( struct mmc_dev *dev, int first ) +{ + DEBUG(2,"\n"); + + if ( first ) { + mmc_simple_cmd(dev, MMC_CIM_RESET, 0, RESPONSE_NONE); + return NULL; + } + + switch (dev->request.cmd) { + case MMC_CIM_RESET: + if ( dev->slot[0].state == CARD_STATE_EMPTY ) + return mmc_cim_default_state; + + dev->slot[0].state = CARD_STATE_IDLE; + return mmc_cim_single_card_acq; + + default: + DEBUG(0,": invalid state %d\n", dev->request.cmd); + break; + } + + return NULL; +} + +/****************************************************************** + * Default state - start here + ******************************************************************/ + +static void * mmc_cim_default_state( struct mmc_dev *dev, int first ) +{ + DEBUG(2,"\n"); + + mmc_check_eject(dev); + + if (mmc_check_insert(dev)) + return mmc_cim_init_stack; + else if (mmc_has_valid_request(dev)) + return mmc_cim_handle_request; + + return NULL; +} + + +/****************************************************************** + * State function handler + ******************************************************************/ + +typedef void *(*state_func_t)(struct mmc_dev *, int); +static state_func_t g_single_card = &mmc_cim_default_state; + +void mmc_protocol_single_card( struct mmc_dev *dev, int state_flags ) +{ + state_func_t sf; + + sf = g_single_card(dev,0); + while ( sf ) { + g_single_card = sf; + sf = g_single_card(dev,1); + } +} diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mmc/mmc_protocol.h linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_protocol.h --- linux-2.4.21-rmk1/drivers/mmc/mmc_protocol.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mmc/mmc_protocol.h Thu Oct 16 15:20:44 2003 @@ -0,0 +1,255 @@ +/* + * Header for MultiMediaCard (MMC) + * + * Copyright 2002 Hewlett-Packard Company + * + * Use consistent with the GNU GPL is permitted, + * provided that this copyright notice is + * preserved in its entirety in all copies and derived works. + * + * HEWLETT-PACKARD COMPANY MAKES NO WARRANTIES, EXPRESSED OR IMPLIED, + * AS TO THE USEFULNESS OR CORRECTNESS OF THIS CODE OR ITS + * FITNESS FOR ANY PARTICULAR PURPOSE. + * + * Many thanks to Alessandro Rubini and Jonathan Corbet! + * + * Based strongly on code by: + * + * Author: Yong-iL Joh + * Date : $Date: 2003/02/17 18:56:27 $ + * + * Author: Andrew Christian + * 15 May 2002 + */ + +#ifndef MMC_MMC_PROTOCOL_H +#define MMC_MMC_PROTOCOL_H + +#include + +/* Standard MMC clock speeds */ +#define MMC_CLOCK_SLOW 400000 /* 400 kHz for initial setup */ +#define MMC_CLOCK_FAST 20000000 /* 20 MHz for maximum for normal operation */ + +/* Extra MMC commands for state control */ +/* Use negative numbers to disambiguate */ +#define MMC_CIM_RESET -1 + +/* Standard MMC commands (3.1) type argument response */ + /* class 1 */ +#define MMC_GO_IDLE_STATE 0 /* bc */ +#define MMC_SEND_OP_COND 1 /* bcr [31:0] OCR R3 */ +#define MMC_ALL_SEND_CID 2 /* bcr R2 */ +#define MMC_SET_RELATIVE_ADDR 3 /* ac [31:16] RCA R1 */ +#define MMC_SET_DSR 4 /* bc [31:16] RCA */ +#define MMC_SELECT_CARD 7 /* ac [31:16] RCA R1 */ +#define MMC_SEND_CSD 9 /* ac [31:16] RCA R2 */ +#define MMC_SEND_CID 10 /* ac [31:16] RCA R2 */ +#define MMC_READ_DAT_UNTIL_STOP 11 /* adtc [31:0] dadr R1 */ +#define MMC_STOP_TRANSMISSION 12 /* ac R1b */ +#define MMC_SEND_STATUS 13 /* ac [31:16] RCA R1 */ +#define MMC_GO_INACTIVE_STATE 15 /* ac [31:16] RCA */ + + /* class 2 */ +#define MMC_SET_BLOCKLEN 16 /* ac [31:0] block len R1 */ +#define MMC_READ_SINGLE_BLOCK 17 /* adtc [31:0] data addr R1 */ +#define MMC_READ_MULTIPLE_BLOCK 18 /* adtc [31:0] data addr R1 */ + + /* class 3 */ +#define MMC_WRITE_DAT_UNTIL_STOP 20 /* adtc [31:0] data addr R1 */ + + /* class 4 */ +#define MMC_SET_BLOCK_COUNT 23 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_BLOCK 24 /* adtc [31:0] data addr R1 */ +#define MMC_WRITE_MULTIPLE_BLOCK 25 /* adtc R1 */ +#define MMC_PROGRAM_CID 26 /* adtc R1 */ +#define MMC_PROGRAM_CSD 27 /* adtc R1 */ + + /* class 6 */ +#define MMC_SET_WRITE_PROT 28 /* ac [31:0] data addr R1b */ +#define MMC_CLR_WRITE_PROT 29 /* ac [31:0] data addr R1b */ +#define MMC_SEND_WRITE_PROT 30 /* adtc [31:0] wpdata addr R1 */ + + /* class 5 */ +#define MMC_ERASE_GROUP_START 35 /* ac [31:0] data addr R1 */ +#define MMC_ERASE_GROUP_END 36 /* ac [31:0] data addr R1 */ +#define MMC_ERASE 37 /* ac R1b */ + + /* class 9 */ +#define MMC_FAST_IO 39 /* ac R4 */ +#define MMC_GO_IRQ_STATE 40 /* bcr R5 */ + + /* class 7 */ +#define MMC_LOCK_UNLOCK 42 /* adtc R1b */ + + /* class 8 */ +#define MMC_APP_CMD 55 /* ac [31:16] RCA R1 */ +#define MMC_GEN_CMD 56 /* adtc [0] RD/WR R1b */ + +/* Don't change the order of these; they are used in dispatch tables */ +enum mmc_rsp_t { + RESPONSE_NONE = 0, + RESPONSE_R1 = 1, + RESPONSE_R1B = 2, + RESPONSE_R2_CID = 3, + RESPONSE_R2_CSD = 4, + RESPONSE_R3 = 5, + RESPONSE_R4 = 6, + RESPONSE_R5 = 7 +}; + + +/* + MMC status in R1 + Type + e : error bit + s : status bit + r : detected and set for the actual command response + x : detected and set during command execution. the host must poll + the card by sending status command in order to read these bits. + Clear condition + a : according to the card state + b : always related to the previous command. Reception of + a valid command will clear it (with a delay of one command) + c : clear by read + */ + +#define R1_OUT_OF_RANGE (1 << 31) /* er, c */ +#define R1_ADDRESS_ERROR (1 << 30) /* erx, c */ +#define R1_BLOCK_LEN_ERROR (1 << 29) /* er, c */ +#define R1_ERASE_SEQ_ERROR (1 << 28) /* er, c */ +#define R1_ERASE_PARAM (1 << 27) /* ex, c */ +#define R1_WP_VIOLATION (1 << 26) /* erx, c */ +#define R1_CARD_IS_LOCKED (1 << 25) /* sx, a */ +#define R1_LOCK_UNLOCK_FAILED (1 << 24) /* erx, c */ +#define R1_COM_CRC_ERROR (1 << 23) /* er, b */ +#define R1_ILLEGAL_COMMAND (1 << 22) /* er, b */ +#define R1_CARD_ECC_FAILED (1 << 21) /* ex, c */ +#define R1_CC_ERROR (1 << 20) /* erx, c */ +#define R1_ERROR (1 << 19) /* erx, c */ +#define R1_UNDERRUN (1 << 18) /* ex, c */ +#define R1_OVERRUN (1 << 17) /* ex, c */ +#define R1_CID_CSD_OVERWRITE (1 << 16) /* erx, c, CID/CSD overwrite */ +#define R1_WP_ERASE_SKIP (1 << 15) /* sx, c */ +#define R1_CARD_ECC_DISABLED (1 << 14) /* sx, a */ +#define R1_ERASE_RESET (1 << 13) /* sr, c */ +#define R1_STATUS(x) (x & 0xFFFFE000) +#define R1_CURRENT_STATE(x) ((x & 0x00001E00) >> 9) /* sx, b (4 bits) */ +#define R1_READY_FOR_DATA (1 << 8) /* sx, a */ +#define R1_APP_CMD (1 << 7) /* sr, c */ + +enum card_state { + CARD_STATE_EMPTY = -1, + CARD_STATE_IDLE = 0, + CARD_STATE_READY = 1, + CARD_STATE_IDENT = 2, + CARD_STATE_STBY = 3, + CARD_STATE_TRAN = 4, + CARD_STATE_DATA = 5, + CARD_STATE_RCV = 6, + CARD_STATE_PRG = 7, + CARD_STATE_DIS = 8, +}; + +/* These are unpacked versions of the actual responses */ + +struct mmc_response_r1 { + u8 cmd; + u32 status; +}; + +struct mmc_cid { + u8 mid; + u16 oid; + u8 pnm[7]; // Product name (we null-terminate) + u8 prv; + u32 psn; + u8 mdt; +}; + +struct mmc_csd { + u8 csd_structure; + u8 spec_vers; + u8 taac; + u8 nsac; + u8 tran_speed; + u16 ccc; + u8 read_bl_len; + u8 read_bl_partial; + u8 write_blk_misalign; + u8 read_blk_misalign; + u8 dsr_imp; + u16 c_size; + u8 vdd_r_curr_min; + u8 vdd_r_curr_max; + u8 vdd_w_curr_min; + u8 vdd_w_curr_max; + u8 c_size_mult; + union { + struct { /* MMC system specification version 3.1 */ + u8 erase_grp_size; + u8 erase_grp_mult; + } v31; + struct { /* MMC system specification version 2.2 */ + u8 sector_size; + u8 erase_grp_size; + } v22; + } erase; + u8 wp_grp_size; + u8 wp_grp_enable; + u8 default_ecc; + u8 r2w_factor; + u8 write_bl_len; + u8 write_bl_partial; + u8 file_format_grp; + u8 copy; + u8 perm_write_protect; + u8 tmp_write_protect; + u8 file_format; + u8 ecc; +}; + +struct mmc_response_r3 { + u32 ocr; +}; + +#define MMC_VDD_145_150 0x00000001 /* VDD voltage 1.45 - 1.50 */ +#define MMC_VDD_150_155 0x00000002 /* VDD voltage 1.50 - 1.55 */ +#define MMC_VDD_155_160 0x00000004 /* VDD voltage 1.55 - 1.60 */ +#define MMC_VDD_160_165 0x00000008 /* VDD voltage 1.60 - 1.65 */ +#define MMC_VDD_165_170 0x00000010 /* VDD voltage 1.65 - 1.70 */ +#define MMC_VDD_17_18 0x00000020 /* VDD voltage 1.7 - 1.8 */ +#define MMC_VDD_18_19 0x00000040 /* VDD voltage 1.8 - 1.9 */ +#define MMC_VDD_19_20 0x00000080 /* VDD voltage 1.9 - 2.0 */ +#define MMC_VDD_20_21 0x00000100 /* VDD voltage 2.0 ~ 2.1 */ +#define MMC_VDD_21_22 0x00000200 /* VDD voltage 2.1 ~ 2.2 */ +#define MMC_VDD_22_23 0x00000400 /* VDD voltage 2.2 ~ 2.3 */ +#define MMC_VDD_23_24 0x00000800 /* VDD voltage 2.3 ~ 2.4 */ +#define MMC_VDD_24_25 0x00001000 /* VDD voltage 2.4 ~ 2.5 */ +#define MMC_VDD_25_26 0x00002000 /* VDD voltage 2.5 ~ 2.6 */ +#define MMC_VDD_26_27 0x00004000 /* VDD voltage 2.6 ~ 2.7 */ +#define MMC_VDD_27_28 0x00008000 /* VDD voltage 2.7 ~ 2.8 */ +#define MMC_VDD_28_29 0x00010000 /* VDD voltage 2.8 ~ 2.9 */ +#define MMC_VDD_29_30 0x00020000 /* VDD voltage 2.9 ~ 3.0 */ +#define MMC_VDD_30_31 0x00040000 /* VDD voltage 3.0 ~ 3.1 */ +#define MMC_VDD_31_32 0x00080000 /* VDD voltage 3.1 ~ 3.2 */ +#define MMC_VDD_32_33 0x00100000 /* VDD voltage 3.2 ~ 3.3 */ +#define MMC_VDD_33_34 0x00200000 /* VDD voltage 3.3 ~ 3.4 */ +#define MMC_VDD_34_35 0x00400000 /* VDD voltage 3.4 ~ 3.5 */ +#define MMC_VDD_35_36 0x00800000 /* VDD voltage 3.5 ~ 3.6 */ +#define MMC_CARD_BUSY 0x80000000 /* Card Power up status bit */ + + +/* CSD field definitions */ + +#define CSD_STRUCT_VER_1_0 0 /* Valid for system specification 1.0 - 1.2 */ +#define CSD_STRUCT_VER_1_1 1 /* Valid for system specification 1.4 - 2.2 */ +#define CSD_STRUCT_VER_1_2 2 /* Valid for system specification 3.1 */ + +#define CSD_SPEC_VER_0 0 /* Implements system specification 1.0 - 1.2 */ +#define CSD_SPEC_VER_1 1 /* Implements system specification 1.4 */ +#define CSD_SPEC_VER_2 2 /* Implements system specification 2.0 - 2.2 */ +#define CSD_SPEC_VER_3 3 /* Implements system specification 3.1 */ + +#endif /* MMC_MMC_PROTOCOL_H */ + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mtd/chips/Config.in linux-2.4.21-rmk1-lh7a400/drivers/mtd/chips/Config.in --- linux-2.4.21-rmk1/drivers/mtd/chips/Config.in Fri Jun 13 10:51:34 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/mtd/chips/Config.in Thu Oct 16 16:36:49 2003 @@ -8,6 +8,7 @@ dep_tristate ' Detect flash chips by Common Flash Interface (CFI) probe' CONFIG_MTD_CFI $CONFIG_MTD dep_tristate ' Detect JEDEC JESD21c compatible flash chips' CONFIG_MTD_JEDECPROBE $CONFIG_MTD +dep_tristate ' Detect Micron SyncFlash flash chips' CONFIG_MTD_SYNCFLASH_PROBE $CONFIG_MTD if [ "$CONFIG_MTD_CFI" = "y" -o "$CONFIG_MTD_JEDECPROBE" = "y" ]; then define_bool CONFIG_MTD_GEN_PROBE y diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mtd/chips/Makefile linux-2.4.21-rmk1-lh7a400/drivers/mtd/chips/Makefile --- linux-2.4.21-rmk1/drivers/mtd/chips/Makefile Fri Jun 13 10:51:34 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/mtd/chips/Makefile Thu Oct 16 16:37:18 2003 @@ -21,6 +21,7 @@ obj-$(CONFIG_MTD_CFI_AMDSTD) += cfi_cmdset_0002.o obj-$(CONFIG_MTD_CFI_INTELEXT) += cfi_cmdset_0001.o obj-$(CONFIG_MTD_GEN_PROBE) += gen_probe.o +obj-$(CONFIG_MTD_SYNCFLASH_PROBE) += micron_syncflash_probe.o obj-$(CONFIG_MTD_JEDEC) += jedec.o obj-$(CONFIG_MTD_JEDECPROBE) += jedec_probe.o obj-$(CONFIG_MTD_RAM) += map_ram.o diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mtd/chips/jedec_probe.c linux-2.4.21-rmk1-lh7a400/drivers/mtd/chips/jedec_probe.c --- linux-2.4.21-rmk1/drivers/mtd/chips/jedec_probe.c Fri Jun 13 10:51:34 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/mtd/chips/jedec_probe.c Sun Feb 8 17:49:53 2004 @@ -29,6 +29,7 @@ #define MANUFACTURER_ST 0x0020 #define MANUFACTURER_SST 0x00BF #define MANUFACTURER_TOSHIBA 0x0098 +#define MANUFACTURER_SHARP 0x00B0 /* AMD */ @@ -122,6 +123,9 @@ #define TC58FVT641 0x0093 #define TC58FVB641 0x0095 +/* Sharp */ +#define LH28F320BFE_PTTL70 0x00B4 +#define LH28F320BJE_PBTL90 0x00B5 struct amd_flash_info { const __u16 mfr_id; @@ -900,6 +904,26 @@ NumEraseRegions: 1, regions: {ERASEINFO(0x01000,256), } + }, { + mfr_id: MANUFACTURER_SHARP, + dev_id: LH28F320BFE_PTTL70, + name: "Sharp LH28F320BFE_PTTL70", + DevSize: SIZE_4MiB, + CmdSet: P_ID_INTEL_STD, + NumEraseRegions: 2, + regions: {ERASEINFO(0x02000,8), + ERASEINFO(0x10000,63) + } + }, { + mfr_id: MANUFACTURER_SHARP, + dev_id: LH28F320BJE_PBTL90, + name: "Sharp LH28F320BJE-PBTL90", + DevSize: SIZE_4MiB, + CmdSet: P_ID_INTEL_STD, + NumEraseRegions: 2, + regions: {ERASEINFO(0x02000,8), + ERASEINFO(0x10000,63) + } } }; @@ -945,6 +969,20 @@ */ cfi_send_gen_cmd(0xFF, 0, base, map, cfi, cfi->device_type, NULL); + /* Fixup for sharp LH28F320BJE-PBTL90 found by trial and error; + * for some unkown reason if you send then 0xF0 they go into a + * bizzare state and they Need this sequence to actualy reset + * them (Boris Itkis 9-11-2002) + */ + if(cfi->mfr == MANUFACTURER_SHARP && + (cfi->id == LH28F320BJE_PBTL90 || cfi->id==LH28F320BFE_PTTL70)) + { + cfi_read(map, base); + cfi_send_gen_cmd(0xFF, 0, base, map, + cfi, cfi->device_type, NULL); + cfi_send_gen_cmd(0xFF, 0, base, map, + cfi, cfi->device_type, NULL); + } } static int cfi_jedec_setup(struct cfi_private *p_cfi, int index) { diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mtd/chips/micron_syncflash_probe.c linux-2.4.21-rmk1-lh7a400/drivers/mtd/chips/micron_syncflash_probe.c --- linux-2.4.21-rmk1/drivers/mtd/chips/micron_syncflash_probe.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mtd/chips/micron_syncflash_probe.c Thu Oct 16 16:47:22 2003 @@ -0,0 +1,695 @@ +/* + * MTD chip driver for Micron SyncFlash chips + * + * Copyright (C) 2002, Embedix, Inc. + * + * based on drivers/mtd/chips/sharp.c, which is + * Copyright 2000,2001 David A. Schleef + * 2000,2001 Lineo, Inc. + * + * + * Devices supported: + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * Debug macros + */ +#define MYDEBUG 0 +#if MYDEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + + +#define CMD_READ_ID 0x90 +#define CMD_READ_STATUS 0x70 +#define CMD_BLOCK_ERASE_1 0x20 +#define CMD_BLOCK_ERASE_2 0xD0 +#define CMD_CLEAR_BLOCK_LOCKS_1 0x60 +#define CMD_CLEAR_BLOCK_LOCKS_2 0xD0 +#define CMD_CLEAR_STATUS 0x50 +#define CMD_WRITE 0x40 + + +#define SR_READY 0x80 // 1 = ready +#define SR_ERROR_ERASE 0x20 // 1 = error in block erase or clear lock bits +#define SR_ERROR_WRITE 0x10 // 1 = error in byte write or set lock bit + + +#define SR_ERRORS (SR_ERROR_ERASE | SR_ERROR_WRITE) + + +#define MANUF_MICRON (0x2c) +#define ID_FOO (0x2c) + + +struct mtd_info *micronsf_probe(struct map_info *); + +static int micronsf_read(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, u_char *buf); +static int micronsf_write(struct mtd_info *mtd, loff_t from, size_t len, + size_t *retlen, const u_char *buf); +static int micronsf_erase(struct mtd_info *mtd, struct erase_info *instr); +static void micronsf_sync(struct mtd_info *mtd); +static int micronsf_suspend(struct mtd_info *mtd); +static void micronsf_resume(struct mtd_info *mtd); +static void micronsf_destroy(struct mtd_info *mtd); + +static int micronsf_write_oneword(struct map_info *map, struct flchip *chip, + unsigned long adr, __u16 datum); +static int micronsf_erase_oneblock(struct map_info *map, struct flchip *chip, + unsigned long adr); +static void micronsf_unlock_oneblock(struct map_info *map, struct flchip *chip, + u16 *adr); + +static int micronsf_do_wait_for_ready(struct map_info *map, struct flchip *chip, + u16 *addr); + +struct micronsf_info{ + struct flchip *chip; + int bogus; + int chipshift; + int numchips; + struct flchip chips[1]; +}; + +struct mtd_info *micronsf_probe(struct map_info *map); +static void micronsf_destroy(struct mtd_info *mtd); + +static struct mtd_chip_driver micronsf_chipdrv = { + probe: micronsf_probe, + destroy: micronsf_destroy, + name: "micronsf_probe", + module: THIS_MODULE +}; + + +#define SDRAM16_ROW_OFFSET 9 +#define MICRON_SECTOR_SIZE (512 * 1024) /* 512Kbyte blocks */ +#define ADDR_MASK (MICRON_SECTOR_SIZE - 1) + + +#ifdef CONFIG_FB_PL110 +extern void pl110_fast_disable( void); +extern void pl110_fast_enable( void); +#endif // CONFIG_FB_PL110 + + +static inline void stop_dma( void) +{ +#ifdef CONFIG_FB_PL110 + pl110_fast_disable(); +#endif +} + +static inline void restart_dma( void) +{ +#ifdef CONFIG_FB_PL110 + pl110_fast_enable(); +#endif +} + + + +/* + * send command 'cmd' to the flash block containing 'addr', + * then read data from 'addr' and return it. + */ +static void +sendCmd( u16 cmd, volatile u16* addr) +{ + sdramRegs_t *sdram = (sdramRegs_t *)IO_ADDRESS(SDRAM_REGS_PHYS); + unsigned long flags; + + u16 *blkCmd = (u16 *)( ((u32)addr & ~ADDR_MASK) | ( cmd << SDRAM16_ROW_OFFSET)); + + // DPRINTK( "cmd=0x%x addr=0x%p blkCmd=0x%p\n", cmd, addr, blkCmd); + + save_flags_cli( flags); + + // DDD stop_dma(); + + __asm__ __volatile__ ( " + ldr r0, [%3, #4] /* dummy sdram read */ + ldrh r0, [%0] /* dummy blkCmd read */ + mcr p15, 0, r0, c7, c10, 4 /* drain write buffer */ + b 1f + .align 5 /* align on a cache line */ +1: + str %1, [%3, #4] /* sdram->globalConfig = ENACMD */ + ldrh r0, [%0] /* dummy = *blkCmd */ + str %2, [%3, #4] /* sdram->globalConfig = NORMAL */ + " + : /* no outputs */ + : /* inputs: */ + "r" (blkCmd), /* %0 */ + "r" (SDRAM_GLOBAL_CKE | SDRAM_GLOBAL_ENACMD), /* %1 */ + "r" (SDRAM_GLOBAL_CKE | SDRAM_GLOBAL_NORMAL), /* %2 */ + "r" (sdram) /* %3 */ + : /* clobbered: */ + "r0" ); + + // DDD restart_dma(); + + restore_flags( flags); + +} + + + + + + + + + +static int +micronsf_probe_map( struct map_info *map, struct mtd_info *mtd) +{ + u16 *base = 0; + u16 manuf, id; + + DPRINTK( "\n"); + + stop_dma(); + + base = (__u16 *)map->map_priv_1; + + sendCmd( CMD_READ_ID, base); + manuf = *base; + + sendCmd( CMD_READ_ID, base); + id = *(base+1); + + restart_dma(); + + DPRINTK( "manuf=0x%x id=0x%x\n", manuf, id); + + if( (manuf == MANUF_MICRON) && (id == ID_FOO)) { + mtd->erasesize = 512 * 1024; + mtd->size = 8 * 1024 * 1024; + return 2; + } + + return 0; +} + + + +static int +micronsf_unlock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + struct map_info *map = mtd->priv; + struct micronsf_info *micron = map->fldrv_priv; + int chipnum; + u16 *addr; + + addr = (u16 *)(map->map_priv_1 + (u32)ofs); + + chipnum = ofs >> micron->chipshift; + + DPRINTK( "ofs=0x%x len=0x%x addr=0x%p chipnum=%d\n", (u32)ofs, len, addr, chipnum); + + stop_dma(); + + while( len) { + micronsf_unlock_oneblock( map, µn->chips[chipnum], addr); + + addr += mtd->erasesize; + len -= mtd->erasesize; + } + + restart_dma(); + + return 0; +} + + +static int +micronsf_lock(struct mtd_info *mtd, loff_t ofs, size_t len) +{ + DPRINTK( "ofs=0x%x len=0x%x\n", (u32)ofs, len); + return 0; +} + + + +struct mtd_info * +micronsf_probe(struct map_info *map) +{ + struct mtd_info *mtd = NULL; + struct micronsf_info *micron = NULL; + + mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); + if(!mtd) + return NULL; + + micron = kmalloc(sizeof(*micron), GFP_KERNEL); + if(!micron) + return NULL; + + memset(mtd, 0, sizeof(*mtd)); + + if( micronsf_probe_map( map, mtd) == 0) { + kfree(mtd); + kfree(micron); + return NULL; + } + + mtd->priv = map; + mtd->type = MTD_NORFLASH; + mtd->erase = micronsf_erase; + mtd->read = micronsf_read; + mtd->write = micronsf_write; + mtd->sync = micronsf_sync; + mtd->suspend = micronsf_suspend; + mtd->resume = micronsf_resume; + mtd->lock = micronsf_lock; + mtd->unlock = micronsf_unlock; + mtd->flags = MTD_CAP_NORFLASH; + mtd->name = map->name; + + memset(micron, 0, sizeof(*micron)); + micron->chipshift = 23; + micron->numchips = 1; + micron->chips[0].start = 0; + micron->chips[0].state = FL_READY; + micron->chips[0].mutex = µn->chips[0]._spinlock; + micron->chips[0].word_write_time = 0; + init_waitqueue_head(µn->chips[0].wq); + spin_lock_init(µn->chips[0]._spinlock); + + map->fldrv = µnsf_chipdrv; + map->fldrv_priv = micron; + + MOD_INC_USE_COUNT; + return mtd; +} + + +/* This function returns with the chip->mutex lock held. */ +static int +micronsf_wait(struct map_info *map, struct flchip *chip) +{ + unsigned long timeo = jiffies + HZ; + DECLARE_WAITQUEUE(wait, current); + + DPRINTK( "\n"); + +retry: + spin_lock_bh( chip->mutex); + + switch( chip->state){ + case FL_READY: + break; + + default: + DPRINTK( "Waiting for chip\n"); + + set_current_state( TASK_UNINTERRUPTIBLE); + add_wait_queue( &chip->wq, &wait); + + spin_unlock_bh(chip->mutex); + + schedule(); + remove_wait_queue( &chip->wq, &wait); + + if(signal_pending(current)) + return -EINTR; + + timeo = jiffies + HZ; + + goto retry; + } + + chip->state = FL_READY; + + return 0; +} + +static void +micronsf_release(struct flchip *chip) +{ + wake_up(&chip->wq); + spin_unlock_bh(chip->mutex); +} + +static int +micronsf_read(struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf) +{ + struct map_info *map = mtd->priv; + struct micronsf_info *micron = map->fldrv_priv; + int chipnum; + int ret = 0; + int ofs = 0; + + chipnum = (from >> micron->chipshift); + ofs = from & ((1 << micron->chipshift)-1); + + *retlen = 0; + + while( len){ + unsigned long thislen; + + if( chipnum >= micron->numchips) + break; + + thislen = len; + if( ofs+thislen >= (1 << micron->chipshift)) + thislen = (1 << micron->chipshift) - ofs; + + ret = micronsf_wait( map, µn->chips[chipnum]); + if( ret < 0) + break; + + map->copy_from( map, buf, ofs, thislen); + + micronsf_release( µn->chips[chipnum]); + + *retlen += thislen; + len -= thislen; + buf += thislen; + + ofs = 0; + chipnum++; + } + + return ret; +} + + +static int +micronsf_write(struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf) +{ + struct map_info *map = mtd->priv; + struct micronsf_info *micron = map->fldrv_priv; + int ret = 0; + int i,j; + int chipnum; + unsigned long ofs; + union { u16 w; unsigned char uc[2]; } tbuf; + + *retlen = 0; + + DPRINTK( "to=0x%x len=0x%x\n", (u32)to, len); + + stop_dma(); + + while(len){ + tbuf.w = 0xffff; + chipnum = to >> micron->chipshift; + ofs = to & ((1<chipshift)-1); + + j = 0; + for( i = ofs & 1; i < 2 && len; i++){ + tbuf.uc[i] = *buf; + buf++; + to++; + len--; + j++; + } + + ret = micronsf_write_oneword( map, µn->chips[chipnum], ofs & ~1, tbuf.w); + + if( ret < 0) { + restart_dma(); + return ret; + } + + (*retlen) += j; + } + + restart_dma(); + + return 0; +} + +static int +micronsf_write_oneword(struct map_info *map, struct flchip *chip, unsigned long ofs, __u16 datum) +{ + int ret; + int try; + int i; + int status = 0; + u16 *addr; + + addr = (u16 *)(map->map_priv_1 + ofs); + + /* + * if flash already contains this data, just return success + */ + if( *addr == datum) + return 0; + + DPRINTK( "ofs=0x%x data=0x%x\n", (u32)ofs, datum); + + ret = micronsf_wait( map, chip); + if( ret < 0) + return ret; + + chip->state = FL_WRITING; + + for( try=0; try < 2; try++){ + sendCmd( CMD_WRITE, (u16 *)addr); + *addr = datum; + + for( i=0; i < 100; i++){ + sendCmd( CMD_READ_STATUS, addr); + status = *addr; + + if( (status & SR_READY) == SR_READY) + break; + } + if( i == 100) { + printk("micron: timed out writing\n"); + } + + if( !(status & SR_ERRORS)) + break; + + printk( "micron: error writing byte at addr=%p status=%08x\n",addr,status); + + sendCmd( CMD_CLEAR_STATUS, addr); + ret = -EIO; + } + + chip->state = FL_READY; + + wake_up( &chip->wq); + spin_unlock_bh( chip->mutex); + + return ret; +} + + + +static int +micronsf_erase(struct mtd_info *mtd, struct erase_info *instr) +{ + struct map_info *map = mtd->priv; + struct micronsf_info *micron = map->fldrv_priv; + unsigned long adr,len; + int chipnum, ret=0; + + DPRINTK( ": addr=0x%x len=0x%x\n", instr->addr, instr->len); + + if(instr->addr & (mtd->erasesize - 1)) + return -EINVAL; + if(instr->len & (mtd->erasesize - 1)) + return -EINVAL; + if(instr->len + instr->addr > mtd->size) + return -EINVAL; + + chipnum = instr->addr >> micron->chipshift; + adr = instr->addr & ((1<chipshift)-1); + len = instr->len; + + DPRINTK( "chipnum=%d\n", chipnum); + + stop_dma(); + + while( len){ + ret = micronsf_erase_oneblock(map, µn->chips[chipnum], adr); + if(ret) { + restart_dma(); + return ret; + } + + adr += mtd->erasesize; + len -= mtd->erasesize; + } + + restart_dma(); + + instr->state = MTD_ERASE_DONE; + if( instr->callback) { + instr->callback(instr); + } + + DPRINTK( "returning 0\n"); + return 0; +} + +static int +micronsf_do_wait_for_ready(struct map_info *map, struct flchip *chip, u16 *addr) +{ + int ret; + int timeo; + int status; + + DPRINTK( "+\n"); + + timeo = jiffies + 150 * HZ; + + while( jiffies < timeo){ + sendCmd( CMD_READ_STATUS, addr); + status = *addr; + + if( (status & SR_READY) == SR_READY){ + ret = 0; + goto out; + } + + udelay( 1000); + } + ret = -ETIME; +out: + DPRINTK( "- ret=%d\n", ret); + return ret; +} + +static int +micronsf_erase_oneblock(struct map_info *map, struct flchip *chip, unsigned long ofs) +{ + int ret; + int status; + u16 *addr = (u16 *)(map->map_priv_1 + ofs); + + DPRINTK( "ofs=0x%x\n", (u32)ofs); + + sendCmd( CMD_BLOCK_ERASE_1, addr); + *addr = CMD_BLOCK_ERASE_2; + + chip->state = FL_ERASING; + + ret = micronsf_do_wait_for_ready( map, chip, addr); + if( ret < 0) + return ret; + + sendCmd( CMD_READ_STATUS, addr); + status = *addr; + + if( !(status & SR_ERRORS)){ + sendCmd( CMD_CLEAR_STATUS, addr); + chip->state = FL_READY; + //spin_unlock_bh(chip->mutex); + DPRINTK( "returning\n"); + return 0; + } + + printk("micron: error erasing block at addr=%p status=%08x\n", addr, status); + sendCmd( CMD_CLEAR_STATUS, addr); + + //spin_unlock_bh(chip->mutex); + + return -EIO; +} + +static void +micronsf_unlock_oneblock( struct map_info *map, struct flchip *chip, u16 *addr) +{ + int i; + int status=0; + + DPRINTK( "addr=0x%p\n", addr); + + sendCmd( CMD_CLEAR_BLOCK_LOCKS_1, addr); + *addr = CMD_CLEAR_BLOCK_LOCKS_2; + + udelay(100); + + for( i=0; i < 1000; i++){ + sendCmd( CMD_READ_STATUS, addr); + status = *addr; + if((status & SR_READY) == SR_READY) + break; + udelay(100); + } + if(i==1000){ + printk("micron: timed out unlocking block\n"); + } + + sendCmd( CMD_CLEAR_STATUS, addr); + if( status & SR_ERRORS) { + printk("micron: error unlocking block at addr=0x%p status=%08x\n", addr,status); + return; + } + + chip->state = FL_READY; +} + +static void +micronsf_sync(struct mtd_info *mtd) +{ + //printk("micronsf_sync()\n"); +} + +static int +micronsf_suspend(struct mtd_info *mtd) +{ + printk("micronsf_suspend()\n"); + return -EINVAL; +} + +static void +micronsf_resume(struct mtd_info *mtd) +{ + printk("micronsf_resume()\n"); + +} + +static void +micronsf_destroy(struct mtd_info *mtd) +{ + printk("micronsf_destroy()\n"); + +} + +int __init +micronsf_probe_init(void) +{ + printk("Micron MTD SyncFlash chip driver.\n"); + register_mtd_chip_driver( µnsf_chipdrv); + + return 0; +} + +static void __exit +micronsf_probe_exit(void) +{ + unregister_mtd_chip_driver( µnsf_chipdrv); +} + +module_init(micronsf_probe_init); +module_exit(micronsf_probe_exit); + + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Duck "); +MODULE_DESCRIPTION("MTD chip driver for Micron SyncFlash chips"); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mtd/maps/Config.in linux-2.4.21-rmk1-lh7a400/drivers/mtd/maps/Config.in --- linux-2.4.21-rmk1/drivers/mtd/maps/Config.in Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/mtd/maps/Config.in Fri Oct 17 11:25:37 2003 @@ -87,6 +87,8 @@ dep_tristate ' CFI Flash device mapped on EDB7312' CONFIG_MTD_EDB7312 $CONFIG_ARCH_EDB7212 $CONFIG_MTD_CFI dep_tristate ' JEDEC Flash device mapped on impA7' CONFIG_MTD_IMPA7 $CONFIG_MTD_JEDECPROBE dep_tristate ' JEDEC Flash device mapped on Ceiva/Polaroid PhotoMax Digital Picture Frame' CONFIG_MTD_CEIVA $CONFIG_MTD_JEDECPROBE $CONFIG_ARCH_CEIVA + dep_tristate ' CFI Flash mapped on KEV7A400 eval board' CONFIG_MTD_KEV7A400 $CONFIG_MTD_JEDECPROBE $CONFIG_MACH_KEV7A400 $CONFIG_MTD_PARTITIONS + dep_tristate ' Sync Flash mapped on KEV7A400 eval board' CONFIG_MTD_KEV7A400_SYNC $CONFIG_MTD_SYNCFLASH_PROBE $CONFIG_MACH_KEV7A400 fi if [ "$CONFIG_ALPHA" = "y" ]; then dep_tristate ' Flash chip mapping on TSUNAMI' CONFIG_MTD_TSUNAMI $CONFIG_MTD_GENPROBE diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mtd/maps/Makefile linux-2.4.21-rmk1-lh7a400/drivers/mtd/maps/Makefile --- linux-2.4.21-rmk1/drivers/mtd/maps/Makefile Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/mtd/maps/Makefile Thu Oct 16 16:48:05 2003 @@ -60,5 +60,7 @@ obj-$(CONFIG_MTD_UCLINUX) += uclinux.o obj-$(CONFIG_MTD_NETtel) += nettel.o obj-$(CONFIG_MTD_SCB2_FLASH) += scb2_flash.o +obj-$(CONFIG_MTD_KEV7A400) += kev7a400-flash.o +obj-$(CONFIG_MTD_KEV7A400_SYNC) += kev7a400-syncflash.o include $(TOPDIR)/Rules.make diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mtd/maps/kev7a400-flash.c linux-2.4.21-rmk1-lh7a400/drivers/mtd/maps/kev7a400-flash.c --- linux-2.4.21-rmk1/drivers/mtd/maps/kev7a400-flash.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mtd/maps/kev7a400-flash.c Thu Oct 16 16:47:22 2003 @@ -0,0 +1,152 @@ +/* + * lh7a400-flash.c AsyncFlash support for the Sharp LH7A400 EVB + * Copyright (C) 2002, Embedix, Inc. + * + * based on sa1100-flash.c, which is + * (C) 2000 Nicolas Pitre + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + + +#ifndef CONFIG_ARCH_LH7A400 +#error This is for LH7A400 architecture only +#endif + + + +static __u8 lh7a400af_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + +static __u16 lh7a400af_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + +static __u32 lh7a400af_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + +static void lh7a400af_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + +static void lh7a400af_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + writeb(d, map->map_priv_1 + adr); +} + +static void lh7a400af_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + writew(d, map->map_priv_1 + adr); +} + +static void lh7a400af_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + writel(d, map->map_priv_1 + adr); +} + +static void lh7a400af_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + memcpy((void *)(map->map_priv_1 + to), from, len); +} + + +static struct map_info lh7a400af_map = { + name: "LH7A400 AsyncFlash", + read8: lh7a400af_read8, + read16: lh7a400af_read16, + read32: lh7a400af_read32, + copy_from: lh7a400af_copy_from, + write8: lh7a400af_write8, + write16: lh7a400af_write16, + write32: lh7a400af_write32, + copy_to: lh7a400af_copy_to, + buswidth: 2, + + map_priv_1: FLASH_BASE, + size: FLASH_SIZE, +}; + + +/* + * Partition information for the LH7A400 AsyncFlash chip + * See include/linux/mtd/partitions.h for definition of the mtd_partition + * structure. + */ +static struct mtd_partition lh7a400af_partitions[] = { + { + name: "blob", + size: 0x00020000, + offset: 0, + }, { + name: "params", + size: 0x00010000, + offset: 0x00020000, + }, { + name: "zImage", + size: 0x000d0000, + offset: 0x00030000, + }, { + name: "ramdisk.gz", + size: 0x00300000, + offset: 0x00100000, + } +}; + + + +static struct mtd_info *mymtd; + +int __init lh7a400af_mtd_init(void) +{ + /* + * probe for the actual flash. + */ + printk(KERN_NOTICE "Sharp LH7A400 AsyncFlash: probing %d-bit AsyncFlash bus\n", + lh7a400af_map.buswidth * 8); + + mymtd = do_map_probe("jedec_probe", &lh7a400af_map); + if (!mymtd) { + printk( __FUNCTION__ ": probe failed\n"); + return -ENXIO; + } + mymtd->module = THIS_MODULE; + +#if 0 /* no partitions: use entire device */ + add_mtd_device( mymtd); +#else /* use partition table */ + add_mtd_partitions( mymtd, lh7a400af_partitions, ARRAY_SIZE(lh7a400af_partitions) ); +#endif + + return 0; +} + +static void __exit lh7a400af_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } +} + +module_init(lh7a400af_mtd_init); +module_exit(lh7a400af_mtd_cleanup); +MODULE_AUTHOR("Duck"); +MODULE_DESCRIPTION("LH7A400 AsyncFlash CFI map driver"); +MODULE_LICENSE("GPL"); diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/mtd/maps/kev7a400-syncflash.c linux-2.4.21-rmk1-lh7a400/drivers/mtd/maps/kev7a400-syncflash.c --- linux-2.4.21-rmk1/drivers/mtd/maps/kev7a400-syncflash.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/mtd/maps/kev7a400-syncflash.c Thu Oct 16 16:47:22 2003 @@ -0,0 +1,184 @@ +/* + * lh7a400-syncflash.c + * Copyright (C) 2002, Embedix, Inc. + * + * based on sa1100-flash.c, which is + * (C) 2000 Nicolas Pitre + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#ifndef CONFIG_ARCH_LH7A400 +#error This is for LH7A400 architecture only +#endif + +/* + * Debug macros + */ +#define MYDEBUG 1 +#if MYDEBUG +# define DPRINTK(fmt, args...) printk("%s: " fmt, __FUNCTION__ , ## args) +#else +# define DPRINTK(fmt, args...) +#endif + + +static __u8 +lh7a400sf_read8(struct map_info *map, unsigned long ofs) +{ + return readb(map->map_priv_1 + ofs); +} + + +static __u16 +lh7a400sf_read16(struct map_info *map, unsigned long ofs) +{ + return readw(map->map_priv_1 + ofs); +} + + +static __u32 +lh7a400sf_read32(struct map_info *map, unsigned long ofs) +{ + return readl(map->map_priv_1 + ofs); +} + + +static void +lh7a400sf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + memcpy(to, (void *)(map->map_priv_1 + from), len); +} + + +static void +lh7a400sf_write8(struct map_info *map, __u8 d, unsigned long adr) +{ + DPRINTK( "write8 0x%x to 0x%x\n", d, (u32)(map->map_priv_1 + adr)); + writeb(d, map->map_priv_1 + adr); +} + + +static void +lh7a400sf_write16(struct map_info *map, __u16 d, unsigned long adr) +{ + DPRINTK( "write16 0x%x to 0x%x\n", d, (u32)(map->map_priv_1 + adr)); + writew(d, map->map_priv_1 + adr); +} + + +static void +lh7a400sf_write32(struct map_info *map, __u32 d, unsigned long adr) +{ + DPRINTK( "write32 d=0x%x adr=0x%x\n", d, (u32)adr); + writel(d, map->map_priv_1 + adr); +} + + +static void +lh7a400sf_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + DPRINTK( " copy_to 0x%p len=0x%x\n", (void *)(map->map_priv_1 + to), len); + memcpy( (void *)(map->map_priv_1 + to), from, len); +} + + +static struct map_info lh7a400sf_map = { + name: "LH7A400 SyncFlash", + read8: lh7a400sf_read8, + read16: lh7a400sf_read16, + read32: lh7a400sf_read32, + copy_from: lh7a400sf_copy_from, + write8: lh7a400sf_write8, + write16: lh7a400sf_write16, + write32: lh7a400sf_write32, + copy_to: lh7a400sf_copy_to, + buswidth: 2, + + map_priv_1: SYNCFLASH_BASE, + size: SYNCFLASH_SIZE, +}; + + +/* + * Partition information for the LH7A400 SyncFlash chip + * See include/linux/mtd/partitions.h for definition of the mtd_partition + * structure. + */ +static struct mtd_partition lh7a400sf_partitions[] = { + { + name: "p1", + offset: 0, + size: 1*1024*1024, + } + , { + name: "p2", + offset: 1*1024*1024, + size: 7*1024*1024, + } +#if 0 + , { + name: "p3", + offset: 0x00030000, + size: 0x000d0000, + } + , { + name: "p4", + offset: 0x00100000, + size: 0x00300000, + } +#endif +}; + +static struct mtd_info *mymtd; + +int __init lh7a400sf_mtd_init(void) +{ + /* + * probe for the actual flash. + */ + printk(KERN_NOTICE "LH7A400 SyncFlash: probing %d-bit flash bus\n", lh7a400sf_map.buswidth*8); + + mymtd = do_map_probe("micronsf_probe", &lh7a400sf_map); + if (!mymtd) { + DPRINTK( __FUNCTION__ ": probe failed\n"); + return -ENXIO; + } + mymtd->module = THIS_MODULE; + +#if 1 || WHOLE_DEVICE + add_mtd_device(mymtd); +#else + add_mtd_partitions( mymtd, lh7a400sf_partitions, ARRAY_SIZE(lh7a400sf_partitions) ); +#endif + + return 0; +} + +static void __exit lh7a400sf_mtd_cleanup(void) +{ + if (mymtd) { + del_mtd_partitions(mymtd); + map_destroy(mymtd); + } +} + +module_init(lh7a400sf_mtd_init); +module_exit(lh7a400sf_mtd_cleanup); +MODULE_AUTHOR("Duck"); +MODULE_DESCRIPTION("LH7A400 SyncFlash CFI map driver"); +MODULE_LICENSE("GPL"); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/net/Space.c linux-2.4.21-rmk1-lh7a400/drivers/net/Space.c --- linux-2.4.21-rmk1/drivers/net/Space.c Fri Aug 2 20:39:44 2002 +++ linux-2.4.21-rmk1-lh7a400/drivers/net/Space.c Fri Oct 17 12:40:54 2003 @@ -256,7 +256,7 @@ #ifdef CONFIG_AT1500 {at1500_probe, 0}, #endif -#ifdef CONFIG_CS89x0 +#if 1/*def CONFIG_CS89x0*/ {cs89x0_probe, 0}, #endif #ifdef CONFIG_AT1700 diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/net/cirrus.c linux-2.4.21-rmk1-lh7a400/drivers/net/cirrus.c --- linux-2.4.21-rmk1/drivers/net/cirrus.c Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/net/cirrus.c Mon Feb 9 11:11:40 2004 @@ -67,6 +67,10 @@ #elif CONFIG_ARCH_CDB89712 # define CIRRUS_DEFAULT_IO ETHER_BASE + 0x300 # define CIRRUS_DEFAULT_IRQ IRQ_EINT3 +#elif CONFIG_MACH_KEV7A400 +# define CIRRUS_DEFAULT_IO CS8900_BASE +# define CIRRUS_DEFAULT_IRQ IRQ_KEV7A400_ETHERNET +//#include #else # define CIRRUS_DEFAULT_IO 0 # define CIRRUS_DEFAULT_IRQ 0 @@ -274,6 +278,7 @@ cirrus_t *priv; u16 status; +printk("cirrus_interrupt()\n"); if (dev->priv == NULL) { printk (KERN_WARNING "%s: irq %d for unknown device.\n",dev->name,irq); return; @@ -341,7 +346,7 @@ static int cirrus_start (struct net_device *dev) { - int result; + int result, irq_flags; /* valid ethernet address? */ if (!is_valid_ether_addr(dev->dev_addr)) { @@ -350,7 +355,9 @@ } /* install interrupt handler */ - if ((result = request_irq (dev->irq,&cirrus_interrupt,0,dev->name,dev)) < 0) { + irq_flags = 0; + + if ((result = request_irq (dev->irq,&cirrus_interrupt,irq_flags,dev->name,dev)) < 0) { printk (KERN_ERR "%s: could not register interrupt %d\n",dev->name,dev->irq); return (result); } @@ -362,7 +369,6 @@ cirrus_set (dev,PP_BufCFG,Rdy4TxiE | RxMissiE | TxUnderruniE | TxColOvfiE | MissOvfloiE); cirrus_set (dev,PP_LineCTL,SerRxON | SerTxON); cirrus_set (dev,PP_BusCTL,EnableRQ); - #ifdef FULL_DUPLEX cirrus_set (dev,PP_TestCTL,FDX); #endif /* #ifdef FULL_DUPLEX */ @@ -469,7 +475,7 @@ if (cirrus_eeprom_read (dev,buf,0) < 0) { read_timed_out: - printk (KERN_DEBUG "%s: EEPROM read timed out\n",dev->name); + printk (/*KERN_DEBUG */"%s: EEPROM read timed out\n",dev->name); return (-ETIMEDOUT); } @@ -523,6 +529,8 @@ if (cirrus_eeprom_read (dev,&offset,0x10) < 0) goto read_timed_out; +printk("%s: read eeprom; checksum %x\n", dev->name, checksum); + if ((offset >> 8) != (u8) (0x100 - checksum)) { printk (KERN_DEBUG "%s: Checksum mismatch (expected 0x%.2x, got 0x%.2x instead\n", dev->name, @@ -634,9 +642,20 @@ #endif /* #ifdef CONFIG_SA1100_FRODO */ /* if an EEPROM is present, use it's MAC address */ - if (!cirrus_eeprom (dev,&eeprom)) + if (!cirrus_eeprom (dev,&eeprom)) { for (i = 0; i < 6; i++) dev->dev_addr[i] = eeprom.mac[i]; + } +#ifdef CONFIG_MACH_KEV7A400 + else { + /* unprogrammed */ + printk("%s: unprogrammed eeprom; faking mac addresss\n", + dev->name); + for (i = 0; i < 6; i++) { + dev->dev_addr[i] = i; + } + } +#endif /* verify EISA registration number for Cirrus Logic */ if ((value = cirrus_read (dev,PP_ProductID)) != EISA_REG_CODE) { @@ -662,6 +681,11 @@ return (0); } +int __init cs89x0_probe(struct net_device *dev) +{ + return -ENODEV; +} + EXPORT_NO_SYMBOLS; static struct net_device dev; diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/net/cirrus.h linux-2.4.21-rmk1-lh7a400/drivers/net/cirrus.h --- linux-2.4.21-rmk1/drivers/net/cirrus.h Fri Jun 13 10:51:34 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/net/cirrus.h Sun Feb 8 20:36:08 2004 @@ -22,6 +22,13 @@ #define PP_Address 0x0a /* PacketPage Pointer Port (Section 4.10.10) */ #define PP_Data 0x0c /* PacketPage Data Port (Section 4.10.10) */ +#ifdef CONFIG_MACH_KEV7A400 +#undef PP_Address +#undef PP_Data +#define PP_Address (0x0a<<1) +#define PP_Data (0x0c<<1) +#endif + /* * Registers */ diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/net/cs89x0.c linux-2.4.21-rmk1-lh7a400/drivers/net/cs89x0.c --- linux-2.4.21-rmk1/drivers/net/cs89x0.c Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/net/cs89x0.c Mon Feb 9 10:50:40 2004 @@ -142,6 +142,22 @@ #include "cs89x0.h" +#ifdef CONFIG_MACH_KEV79520 +#include +#include +#include +#undef ALLOW_DMA +#define ALLOW_DMA 0 +#endif + +#ifdef CONFIG_MACH_KEV7A400 +#include +#include +#undef ALLOW_DMA +#define ALLOW_DMA 0 +#endif + + static char version[] __initdata = "cs89x0.c: v2.4.3-pre1 Russell Nelson , Andrew Morton \n"; @@ -164,6 +180,10 @@ static unsigned int netcard_portlist[] __initdata = { 0x0300, 0}; static unsigned int cs8900_irq_map[] = {1,0,0,0}; +#elif defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) +static unsigned int netcard_portlist[] __initdata = + { CS8900_BASE, 0}; /* only one place to look */ +static unsigned int cs8900_irq_map[] = {IRQ_KEV7A400_ETHERNET,0,0,0}; #else static unsigned int netcard_portlist[] __initdata = { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; @@ -363,6 +383,32 @@ { int i, cksum; +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) + /* first try an 8 bit checksum */ + cksum = 0; + for (i = 0; i < len; i++) { + cksum += buffer[i] & 0xff; + cksum += buffer[i] >> 8; + } + cksum &= 0xff; + if (cksum == 0) { + printk( "cs89x0.c: 8 bit eeprom checksum OK\n"); + return 0; + } else { + printk( "cs89x0.c: 8 bit eeprom checksum failed\n"); + /* try a 16 bit checksum */ + cksum = 0; + for (i = 0; i < len; i++) + cksum += buffer[i]; + cksum &= 0xffff; + if (cksum == 0) { + printk( "cs89x0.c: 16 bit eeprom checksum OK\n"); + return 0; + } + } + printk( "cs89x0.c: 16 bit eeprom checksum failed\n"); + return -1; +#else cksum = 0; for (i = 0; i < len; i++) cksum += buffer[i]; @@ -370,6 +416,7 @@ if (cksum == 0) return 0; return -1; +#endif } /* This is the real probe routine. Linux has a history of friendly device @@ -442,7 +489,6 @@ ioaddr &= ~3; outw(PP_ChipID, ioaddr + ADD_PORT); } -printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) { printk(KERN_ERR "%s: incorrect signature 0x%x\n", @@ -586,11 +632,25 @@ if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) != (EEPROM_OK|EEPROM_PRESENT)) printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n"); + +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) + lp->auto_neg_cnf = (AUTO_NEG_ENABLE | IMM_BIT); + lp->adapter_cnf = A_CNF_10B_T; + lp->isa_config = 0x0; + for (i = 0; i < 6; i++) + dev->dev_addr[i] = i; +#endif } else { /* This reads an extended EEPROM that is not documented in the CS8900 datasheet. */ - + +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) + /* hardcode these since they're not in eeprom */ + lp->auto_neg_cnf = (AUTO_NEG_ENABLE | IMM_BIT); + lp->adapter_cnf = A_CNF_10B_T; + lp->isa_config = 0x0; +#else /* get transmission control word but keep the autonegotiation bits */ if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; /* Store adapter configuration */ @@ -598,12 +658,19 @@ /* Store ISA configuration */ lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2]; dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8; +#endif /* eeprom_buff has 32-bit ints, so we can't just memcpy it */ /* store the initial memory base address */ for (i = 0; i < ETH_ALEN/2; i++) { +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) + /* these are in eeprom, but in a different place */ + dev->dev_addr[i*2] = eeprom_buff[2+i]; + dev->dev_addr[i*2+1] = eeprom_buff[2+i] >> 8; +#else dev->dev_addr[i*2] = eeprom_buff[i]; dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8; +#endif } if (net_debug > 1) printk(KERN_DEBUG "%s: new adapter_cnf: 0x%x\n", @@ -1115,7 +1182,19 @@ int i; int ret; -#ifndef CONFIG_SH_HICOSH4 /* uses irq#1, so this wont work */ +#if defined(CONFIG_MACH_KEV7A400) || defined(CONFIG_MACH_KEV79520) + ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev); + + if (ret) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed. ret=0x%x\n", + dev->irq, ret); + goto bad_out; + } + writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); + writereg(dev, PP_CS8900_ISAINT, 0); /* use INTRQ0 pin */ +#else +#if !defined(CONFIG_SH_HICOSH4) /* uses irq#1, so this wont work */ if (dev->irq < 2) { /* Allow interrupts to be generated by the chip */ /* Cirrus' release had this: */ @@ -1166,6 +1245,7 @@ goto bad_out; } } +#endif /* CONFIG_MACH_KEV7A400) || CONFIG_MACH_KEV79520 */ #if ALLOW_DMA if (lp->use_dma) { diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/net/cs89x0.h linux-2.4.21-rmk1-lh7a400/drivers/net/cs89x0.h --- linux-2.4.21-rmk1/drivers/net/cs89x0.h Thu Nov 28 18:53:13 2002 +++ linux-2.4.21-rmk1-lh7a400/drivers/net/cs89x0.h Mon Feb 9 10:32:04 2004 @@ -324,16 +324,28 @@ #define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ #define PKT_START PP_TxFrame /* Start of packet RAM */ +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) || defined(CONFIG_MACH_EFRAME) +/* ports are 32-bit aligned */ +#define RX_FRAME_PORT (0x00 << 1) +#define TX_CMD_PORT (0x04 << 1) +#define TX_LEN_PORT (0x06 << 1) +#define ISQ_PORT (0x08 << 1) +#define ADD_PORT (0x0A << 1) +#define DATA_PORT (0x0C << 1) +#else #define RX_FRAME_PORT 0x0000 -#define TX_FRAME_PORT RX_FRAME_PORT #define TX_CMD_PORT 0x0004 -#define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ -#define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ -#define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ #define TX_LEN_PORT 0x0006 #define ISQ_PORT 0x0008 #define ADD_PORT 0x000A #define DATA_PORT 0x000C +#endif + +#define TX_FRAME_PORT RX_FRAME_PORT +#define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ +#define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ +#define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ + #define EEPROM_WRITE_EN 0x00F0 #define EEPROM_WRITE_DIS 0x0000 @@ -431,14 +443,24 @@ #define CS8920M 0x6000 #define REVISON_BITS 0x1F00 #define EEVER_NUMBER 0x12 -#define CHKSUM_LEN 0x14 #define CHKSUM_VAL 0x0000 + +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) || defined(CONFIG_MACH_EFRAME) +#define CHKSUM_LEN 0x6 +#define START_EEPROM_DATA 0x0000 /* Offset into eeprom for start of data */ +#else +#define CHKSUM_LEN 0x14 #define START_EEPROM_DATA 0x001c /* Offset into eeprom for start of data */ +#endif + #define IRQ_MAP_EEPROM_DATA 0x0046 /* Offset into eeprom for the IRQ map */ #define IRQ_MAP_LEN 0x0004 /* No of bytes to read for the IRQ map */ #define PNP_IRQ_FRMT 0x0022 /* PNP small item IRQ format */ + #ifdef CONFIG_SH_HICOSH4 #define CS8900_IRQ_MAP 0x0002 /* HiCO-SH4 board has its IRQ on #1 */ +#elif defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) || defined(CONFIG_MACH_EFRAME) +#define CS8900_IRQ_MAP 0x1 /* This IRQ map is fixed (IRQ 0 only)*/ #else #define CS8900_IRQ_MAP 0x1c20 /* This IRQ map is fixed */ #endif diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/net/cs89x0_kev7a400.c linux-2.4.21-rmk1-lh7a400/drivers/net/cs89x0_kev7a400.c --- linux-2.4.21-rmk1/drivers/net/cs89x0_kev7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/net/cs89x0_kev7a400.c Fri Feb 6 16:05:15 2004 @@ -0,0 +1,1878 @@ +/* cs89x0.c: A Crystal Semiconductor (Now Cirrus Logic) CS89[02]0 + * driver for linux. + */ + +/* + Written 1996 by Russell Nelson, with reference to skeleton.c + written 1993-1994 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + The author may be reached at nelson@crynwr.com, Crynwr + Software, 521 Pleasant Valley Rd., Potsdam, NY 13676 + + Changelog: + + Mike Cruse : mcruse@cti-ltd.com + : Changes for Linux 2.0 compatibility. + : Added dev_id parameter in net_interrupt(), + : request_irq() and free_irq(). Just NULL for now. + + Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros + : in net_open() and net_close() so kerneld would know + : that the module is in use and wouldn't eject the + : driver prematurely. + + Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c + : as an example. Disabled autoprobing in init_module(), + : not a good thing to do to other devices while Linux + : is running from all accounts. + + Russ Nelson : Jul 13 1998. Added RxOnly DMA support. + + Melody Lee : Aug 10 1999. Changes for Linux 2.2.5 compatibility. + : email: ethernet@crystal.cirrus.com + + Alan Cox : Removed 1.2 support, added 2.1 extra counters. + + Andrew Morton : andrewm@uow.edu.au + : Kernel 2.3.48 + : Handle kmalloc() failures + : Other resource allocation fixes + : Add SMP locks + : Integrate Russ Nelson's ALLOW_DMA functionality back in. + : If ALLOW_DMA is true, make DMA runtime selectable + : Folded in changes from Cirrus (Melody Lee + : ) + : Don't call netif_wake_queue() in net_send_packet() + : Fixed an out-of-mem bug in dma_rx() + : Updated Documentation/cs89x0.txt + + Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre1 + : Use skb_reserve to longword align IP header (two places) + : Remove a delay loop from dma_rx() + : Replace '100' with HZ + : Clean up a couple of skb API abuses + : Added 'cs89x0_dma=N' kernel boot option + : Correctly initialise lp->lock in non-module compile + + Andrew Morton : andrewm@uow.edu.au / Kernel 2.3.99-pre4-1 + : MOD_INC/DEC race fix (see + : http://www.uwsg.indiana.edu/hypermail/linux/kernel/0003.3/1532.html) + + Andrew Morton : andrewm@uow.edu.au / Kernel 2.4.0-test7-pre2 + : Enhanced EEPROM support to cover more devices, + : abstracted IRQ mapping to support CONFIG_ARCH_CLPS7500 arch + : (Jason Gunthorpe ) + + Andrew Morton : Kernel 2.4.0-test11-pre4 + : Use dev->name in request_*() (Andrey Panin) + : Fix an error-path memleak in init_module() + : Preserve return value from request_irq() + : Fix type of `media' module parm (Keith Owens) + : Use SET_MODULE_OWNER() + : Tidied up strange request_irq() abuse in net_open(). + + Andrew Morton : Kernel 2.4.3-pre1 + : Request correct number of pages for DMA (Hugh Dickens) + : Select PP_ChipID _after_ unregister_netdev in cleanup_module() + : because unregister_netdev() calls get_stats. + : Make `version[]' __initdata + : Uninlined the read/write reg/word functions. + + Oskar Schirmer : oskar@scara.com + : HiCO.SH4 (superh) support added (irq#1, cs89x0_media=) + +*/ + +/* Always include 'config.h' first in case the user wants to turn on + or override something. */ +#include +#include +#include + +/* + * Set this to zero to disable DMA code + * + * Note that even if DMA is turned off we still support the 'dma' and 'use_dma' + * module options so we don't break any startup scripts. + */ +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) +#define ALLOW_DMA 0 +#else +#define ALLOW_DMA 1 +#endif + +/* + * Set this to zero to remove all the debug statements via + * dead code elimination + */ +#define DEBUGGING 0 + +/* + Sources: + + Crynwr packet driver epktisa. + + Crystal Semiconductor data sheets. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#if ALLOW_DMA +#include +#endif +#include +#include + +#include +#include +#include + +#include "cs89x0_kev7a400.h" + +#include + + +static char version[] __initdata = +"cs89x0.c: v2.4.3-pre1 Russell Nelson , Andrew Morton \n"; + +/* First, a few definitions that the brave might change. + A zero-terminated list of I/O addresses to be probed. Some special flags.. + Addr & 1 = Read back the address port, look for signature and reset + the page window before probing + Addr & 3 = Reset the page window and probe + The CLPS eval board has the Cirrus chip at 0x80090300, in ARM IO space, + but it is possible that a Cirrus board could be plugged into the ISA + slots. */ +/* The cs8900 has 4 IRQ pins, software selectable. cs8900_irq_map maps + them to system IRQ numbers. This mapping is card specific and is set to + the configuration of the Cirrus Eval board for this chip. */ +#ifdef CONFIG_ARCH_CLPS7500 +static unsigned int netcard_portlist[] __initdata = + { 0x80090303, 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; +static unsigned int cs8900_irq_map[] = {12,0,0,0}; +#elif defined(CONFIG_SH_HICOSH4) +static unsigned int netcard_portlist[] __initdata = + { 0x0300, 0}; +static unsigned int cs8900_irq_map[] = {1,0,0,0}; +#elif defined(CONFIG_MACH_KEV7A400) + static unsigned int netcard_portlist[] __initdata = + { CS8900_BASE, 0}; /* only one place to look */ + static unsigned int cs8900_irq_map[] = {IRQ_KEV7A400_ETHERNET,0,0,0}; +#else +static unsigned int netcard_portlist[] __initdata = + { 0x300, 0x320, 0x340, 0x360, 0x200, 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x2e0, 0}; +static unsigned int cs8900_irq_map[] = {10,11,12,5}; +#endif + +#if DEBUGGING +static unsigned int net_debug = DEBUGGING; +#else +#define net_debug 0 /* gcc will remove all the debug code for us */ +#endif + +/* The number of low I/O ports used by the ethercard. */ +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) +#define NETCARD_IO_EXTENT 32 +#else +#define NETCARD_IO_EXTENT 16 +#endif + +/* we allow the user to override various values normally set in the EEPROM */ +#define FORCE_RJ45 0x0001 /* pick one of these three */ +#define FORCE_AUI 0x0002 +#define FORCE_BNC 0x0004 + +#define FORCE_AUTO 0x0010 /* pick one of these three */ +#define FORCE_HALF 0x0020 +#define FORCE_FULL 0x0030 + +/* Information that need to be kept for each board. */ +struct net_local { + struct net_device_stats stats; + int chip_type; /* one of: CS8900, CS8920, CS8920M */ + char chip_revision; /* revision letter of the chip ('A'...) */ + int send_cmd; /* the proper send command: TX_NOW, TX_AFTER_381, or TX_AFTER_ALL */ + int auto_neg_cnf; /* auto-negotiation word from EEPROM */ + int adapter_cnf; /* adapter configuration from EEPROM */ + int isa_config; /* ISA configuration from EEPROM */ + int irq_map; /* IRQ map from EEPROM */ + int rx_mode; /* what mode are we in? 0, RX_MULTCAST_ACCEPT, or RX_ALL_ACCEPT */ + int curr_rx_cfg; /* a copy of PP_RxCFG */ + int linectl; /* either 0 or LOW_RX_SQUELCH, depending on configuration. */ + int send_underrun; /* keep track of how many underruns in a row we get */ + int force; /* force various values; see FORCE* above. */ + spinlock_t lock; +#if ALLOW_DMA + int use_dma; /* Flag: we're using dma */ + int dma; /* DMA channel */ + int dmasize; /* 16 or 64 */ + unsigned char *dma_buff; /* points to the beginning of the buffer */ + unsigned char *end_dma_buff; /* points to the end of the buffer */ + unsigned char *rx_dma_ptr; /* points to the next packet */ +#endif +}; + +/* Index to functions, as function prototypes. */ + +extern int cs89x0_probe(struct net_device *dev); + +static int cs89x0_probe1(struct net_device *dev, int ioaddr); +static int net_open(struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs); +static void set_multicast_list(struct net_device *dev); +static void net_timeout(struct net_device *dev); +static void net_rx(struct net_device *dev); +static int net_close(struct net_device *dev); +static struct net_device_stats *net_get_stats(struct net_device *dev); +static void reset_chip(struct net_device *dev); +static int get_eeprom_data(struct net_device *dev, int off, int len, int *buffer); +static int get_eeprom_cksum(int off, int len, int *buffer); +static int set_mac_address(struct net_device *dev, void *addr); +static void count_rx_errors(int status, struct net_local *lp); +#if ALLOW_DMA +static void get_dma_channel(struct net_device *dev); +static void release_dma_buff(struct net_local *lp); +#endif + +/* Example routines you must write ;->. */ +#define tx_done(dev) 1 + +/* + * Permit 'cs89x0_dma=N' in the kernel boot environment + */ +#if !defined(MODULE) && (ALLOW_DMA != 0) +static int g_cs89x0_dma; + +static int __init dma_fn(char *str) +{ + g_cs89x0_dma = simple_strtol(str,NULL,0); + return 1; +} + +__setup("cs89x0_dma=", dma_fn); +#endif /* !defined(MODULE) && (ALLOW_DMA != 0) */ + +#ifndef MODULE +static int g_cs89x0_media__force; + +static int __init media_fn(char *str) +{ + if (!strcmp(str, "rj45")) g_cs89x0_media__force = FORCE_RJ45; + else if (!strcmp(str, "aui")) g_cs89x0_media__force = FORCE_AUI; + else if (!strcmp(str, "bnc")) g_cs89x0_media__force = FORCE_BNC; + return 1; +} + +__setup("cs89x0_media=", media_fn); +#endif + + +/* Check for a network adaptor of this type, and return '0' iff one exists. + If dev->base_addr == 0, probe all likely locations. + If dev->base_addr == 1, always return failure. + If dev->base_addr == 2, allocate space for the device and return success + (detachable devices only). + Return 0 on success. + */ + +int __init cs89x0_probe(struct net_device *dev) +{ + int i; + int base_addr = dev ? dev->base_addr : 0; + + SET_MODULE_OWNER(dev); + + if (net_debug) + printk("cs89x0:cs89x0_probe(0x%x)\n", base_addr); + + if (base_addr > 0x1ff) /* Check a single specified location. */ + return cs89x0_probe1(dev, base_addr); + else if (base_addr != 0) /* Don't probe at all. */ + return -ENXIO; + + for (i = 0; netcard_portlist[i]; i++) { + if (cs89x0_probe1(dev, netcard_portlist[i]) == 0) + return 0; + } + printk(KERN_WARNING "cs89x0: no cs8900 or cs8920 detected. Be sure to disable PnP with SETUP\n"); + return -ENODEV; +} + +static int +readreg(struct net_device *dev, int portno) +{ + outw(portno, dev->base_addr + ADD_PORT); + return inw(dev->base_addr + DATA_PORT); +} + +static void +writereg(struct net_device *dev, int portno, int value) +{ + outw(portno, dev->base_addr + ADD_PORT); + outw(value, dev->base_addr + DATA_PORT); +} + +static int +readword(struct net_device *dev, int portno) +{ + return inw(dev->base_addr + portno); +} + +static void +writeword(struct net_device *dev, int portno, int value) +{ + outw(value, dev->base_addr + portno); +} + +static int __init +wait_eeprom_ready(struct net_device *dev) +{ + int timeout = jiffies; + /* check to see if the EEPROM is ready, a timeout is used - + just in case EEPROM is ready when SI_BUSY in the + PP_SelfST is clear */ + while(readreg(dev, PP_SelfST) & SI_BUSY) + if (jiffies - timeout >= 40) + return -1; + return 0; +} + +static int __init +get_eeprom_data(struct net_device *dev, int off, int len, int *buffer) +{ + int i; + + if (net_debug > 3) printk("EEPROM data from %x for %x:\n",off,len); + for (i = 0; i < len; i++) { + if (wait_eeprom_ready(dev) < 0) return -1; + /* Now send the EEPROM read command and EEPROM location to read */ + writereg(dev, PP_EECMD, (off + i) | EEPROM_READ_CMD); + if (wait_eeprom_ready(dev) < 0) return -1; + buffer[i] = readreg(dev, PP_EEData); + if (net_debug > 3) printk("%04x ", buffer[i]); + } + if (net_debug > 3) printk("\n"); + return 0; +} + +static int __init +get_eeprom_cksum(int off, int len, int *buffer) +{ + int i, cksum; + +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) + /* first try an 8 bit checksum */ + cksum = 0; + for (i = 0; i < len; i++) { + cksum += buffer[i] & 0xff; + cksum += buffer[i] >> 8; + } + cksum &= 0xff; + if (cksum == 0) { + printk( "cs89x0.c: 8 bit eeprom checksum OK\n"); + return 0; + } else { + printk( "cs89x0.c: 8 bit eeprom checksum failed\n"); + /* try a 16 bit checksum */ + cksum = 0; + for (i = 0; i < len; i++) + cksum += buffer[i]; + cksum &= 0xffff; + if (cksum == 0) { + printk( "cs89x0.c: 16 bit eeprom checksum OK\n"); + return 0; + } + } + printk( "cs89x0.c: 16 bit eeprom checksum failed\n"); + return -1; +#else + cksum = 0; + for (i = 0; i < len; i++) + cksum += buffer[i]; + cksum &= 0xffff; + if (cksum == 0) + return 0; + return -1; +#endif +} + +/* This is the real probe routine. Linux has a history of friendly device + probes on the ISA bus. A good device probes avoids doing writes, and + verifies that the correct device exists and functions. + Return 0 on success. + */ + +static int __init +cs89x0_probe1(struct net_device *dev, int ioaddr) +{ + struct net_local *lp; + static unsigned version_printed; + int i; + unsigned rev_type = 0; + int eeprom_buff[CHKSUM_LEN]; + int retval; + + /* Initialize the device structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev->priv == 0) { + retval = -ENOMEM; + goto out; + } + lp = (struct net_local *)dev->priv; + memset(lp, 0, sizeof(*lp)); + spin_lock_init(&lp->lock); +#if !defined(MODULE) && (ALLOW_DMA != 0) + if (g_cs89x0_dma) { + lp->use_dma = 1; + lp->dma = g_cs89x0_dma; + lp->dmasize = 16; /* Could make this an option... */ + } +#endif +#ifndef MODULE + lp->force = g_cs89x0_media__force; +#endif + } + lp = (struct net_local *)dev->priv; + + /* Grab the region so we can find another board if autoIRQ fails. */ + if (!request_region(ioaddr & ~3, NETCARD_IO_EXTENT, dev->name)) { + printk(KERN_ERR "%s: request_region(0x%x, 0x%x) failed\n", + dev->name, ioaddr, NETCARD_IO_EXTENT); + retval = -EBUSY; + goto out1; + } + +#ifdef CONFIG_SH_HICOSH4 + /* truely reset the chip */ + outw(0x0114, ioaddr + ADD_PORT); + outw(0x0040, ioaddr + DATA_PORT); +#endif + + /* if they give us an odd I/O address, then do ONE write to + the address port, to get it back to address zero, where we + expect to find the EISA signature word. An IO with a base of 0x3 + will skip the test for the ADD_PORT. */ + if (ioaddr & 1) { + if (net_debug > 1) + printk(KERN_INFO "%s: odd ioaddr 0x%x\n", dev->name, ioaddr); + if ((ioaddr & 2) != 2) + if ((inw((ioaddr & ~3)+ ADD_PORT) & ADD_MASK) != ADD_SIG) { + printk(KERN_ERR "%s: bad signature 0x%x\n", + dev->name, inw((ioaddr & ~3)+ ADD_PORT)); + retval = -ENODEV; + goto out2; + } + ioaddr &= ~3; + outw(PP_ChipID, ioaddr + ADD_PORT); + } +//printk("PP_addr=0x%x\n", inw(ioaddr + ADD_PORT)); + + if (inw(ioaddr + DATA_PORT) != CHIP_EISA_ID_SIG) { + printk(KERN_ERR "%s: incorrect signature 0x%x\n", + dev->name, inw(ioaddr + DATA_PORT)); + retval = -ENODEV; + goto out2; + } + + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; + + /* get the chip type */ + rev_type = readreg(dev, PRODUCT_ID_ADD); + lp->chip_type = rev_type &~ REVISON_BITS; + lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; + + /* Check the chip type and revision in order to set the correct send command + CS8920 revision C and CS8900 revision F can use the faster send. */ + lp->send_cmd = TX_AFTER_381; + if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') + lp->send_cmd = TX_NOW; + if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') + lp->send_cmd = TX_NOW; + + if (net_debug && version_printed++ == 0) + printk(version); + + printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#3lx ", + dev->name, + lp->chip_type==CS8900?'0':'2', + lp->chip_type==CS8920M?"M":"", + lp->chip_revision, + dev->base_addr); + + reset_chip(dev); + + /* Here we read the current configuration of the chip. If there + is no Extended EEPROM then the idea is to not disturb the chip + configuration, it should have been correctly setup by automatic + EEPROM read on reset. So, if the chip says it read the EEPROM + the driver will always do *something* instead of complain that + adapter_cnf is 0. */ + +#ifdef CONFIG_SH_HICOSH4 + if (1) { + /* For the HiCO.SH4 board, things are different: we don't + have EEPROM, but there is some data in flash, so we go + get it there directly (MAC). */ + __u16 *confd; + short cnt; + if (((* (volatile __u32 *) 0xa0013ff0) & 0x00ffffff) + == 0x006c3000) { + confd = (__u16*) 0xa0013fc0; + } else { + confd = (__u16*) 0xa001ffc0; + } + cnt = (*confd++ & 0x00ff) >> 1; + while (--cnt > 0) { + __u16 j = *confd++; + + switch (j & 0x0fff) { + case PP_IA: + for (i = 0; i < ETH_ALEN/2; i++) { + dev->dev_addr[i*2] = confd[i] & 0xFF; + dev->dev_addr[i*2+1] = confd[i] >> 8; + } + break; + } + j = (j >> 12) + 1; + confd += j; + cnt -= j; + } + } else +#endif + + if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) == + (EEPROM_OK|EEPROM_PRESENT)) { + /* Load the MAC. */ + for (i=0; i < ETH_ALEN/2; i++) { + unsigned int Addr; + Addr = readreg(dev, PP_IA+i*2); + dev->dev_addr[i*2] = Addr & 0xFF; + dev->dev_addr[i*2+1] = Addr >> 8; + } + + /* Load the Adapter Configuration. + Note: Barring any more specific information from some + other source (ie EEPROM+Schematics), we would not know + how to operate a 10Base2 interface on the AUI port. + However, since we do read the status of HCB1 and use + settings that always result in calls to control_dc_dc(dev,0) + a BNC interface should work if the enable pin + (dc/dc converter) is on HCB1. It will be called AUI + however. */ + + lp->adapter_cnf = 0; + i = readreg(dev, PP_LineCTL); + /* Preserve the setting of the HCB1 pin. */ + if ((i & (HCB1 | HCB1_ENBL)) == (HCB1 | HCB1_ENBL)) + lp->adapter_cnf |= A_CNF_DC_DC_POLARITY; + /* Save the sqelch bit */ + if ((i & LOW_RX_SQUELCH) == LOW_RX_SQUELCH) + lp->adapter_cnf |= A_CNF_EXTND_10B_2 | A_CNF_LOW_RX_SQUELCH; + /* Check if the card is in 10Base-t only mode */ + if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == 0) + lp->adapter_cnf |= A_CNF_10B_T | A_CNF_MEDIA_10B_T; + /* Check if the card is in AUI only mode */ + if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUI_ONLY) + lp->adapter_cnf |= A_CNF_AUI | A_CNF_MEDIA_AUI; + /* Check if the card is in Auto mode. */ + if ((i & (AUI_ONLY | AUTO_AUI_10BASET)) == AUTO_AUI_10BASET) + lp->adapter_cnf |= A_CNF_AUI | A_CNF_10B_T | + A_CNF_MEDIA_AUI | A_CNF_MEDIA_10B_T | A_CNF_MEDIA_AUTO; + + if (net_debug > 1) + printk(KERN_INFO "%s: PP_LineCTL=0x%x, adapter_cnf=0x%x\n", + dev->name, i, lp->adapter_cnf); + + /* IRQ. Other chips already probe, see below. */ + if (lp->chip_type == CS8900) + lp->isa_config = readreg(dev, PP_CS8900_ISAINT) & INT_NO_MASK; + + printk( "[Cirrus EEPROM] "); + } + + printk("\n"); + + /* First check to see if an EEPROM is attached. */ +#ifdef CONFIG_SH_HICOSH4 /* no EEPROM on HiCO, don't hazzle with it here */ + if (1) { + printk(KERN_NOTICE "cs89x0: No EEPROM on HiCO.SH4\n"); + } else +#endif + if ((readreg(dev, PP_SelfST) & EEPROM_PRESENT) == 0) + printk(KERN_WARNING "cs89x0: No EEPROM, relying on command line....\n"); + else if (get_eeprom_data(dev, START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { + printk(KERN_WARNING "\ncs89x0: EEPROM read failed, relying on command line.\n"); + } else if (get_eeprom_cksum(START_EEPROM_DATA,CHKSUM_LEN,eeprom_buff) < 0) { + /* Check if the chip was able to read its own configuration starting + at 0 in the EEPROM*/ + if ((readreg(dev, PP_SelfST) & (EEPROM_OK | EEPROM_PRESENT)) != + (EEPROM_OK|EEPROM_PRESENT)) + printk(KERN_WARNING "cs89x0: Extended EEPROM checksum bad and no Cirrus EEPROM, relying on command line\n"); + +#ifdef CONFIG_MACH_KEV7A400 + lp->auto_neg_cnf = (AUTO_NEG_ENABLE | IMM_BIT); + lp->adapter_cnf = A_CNF_10B_T; + lp->isa_config = 0x0; + for (i = 0; i < 6; i++) + dev->dev_addr[i] = i; +#endif + + } else { + /* This reads an extended EEPROM that is not documented + in the CS8900 datasheet. */ + +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) + /* hardcode these since they're not in eeprom */ + lp->auto_neg_cnf = (AUTO_NEG_ENABLE | IMM_BIT); + lp->adapter_cnf = A_CNF_10B_T; + lp->isa_config = 0x0; +#else + /* get transmission control word but keep the autonegotiation bits */ + if (!lp->auto_neg_cnf) lp->auto_neg_cnf = eeprom_buff[AUTO_NEG_CNF_OFFSET/2]; + /* Store adapter configuration */ + if (!lp->adapter_cnf) lp->adapter_cnf = eeprom_buff[ADAPTER_CNF_OFFSET/2]; + /* Store ISA configuration */ + lp->isa_config = eeprom_buff[ISA_CNF_OFFSET/2]; +#endif + dev->mem_start = eeprom_buff[PACKET_PAGE_OFFSET/2] << 8; + + /* eeprom_buff has 32-bit ints, so we can't just memcpy it */ + /* store the initial memory base address */ + for (i = 0; i < ETH_ALEN/2; i++) { +#if defined(CONFIG_MACH_KEV79520) || defined(CONFIG_MACH_KEV7A400) + /* these are in eeprom, but in a different place */ + dev->dev_addr[i*2] = eeprom_buff[2+i]; + dev->dev_addr[i*2+1] = eeprom_buff[2+i] >> 8; +#else + dev->dev_addr[i*2] = eeprom_buff[i]; + dev->dev_addr[i*2+1] = eeprom_buff[i] >> 8; +#endif + } + if (net_debug > 1) + printk(KERN_DEBUG "%s: new adapter_cnf: 0x%x\n", + dev->name, lp->adapter_cnf); + } + + /* allow them to force multiple transceivers. If they force multiple, autosense */ + { + int count = 0; + if (lp->force & FORCE_RJ45) {lp->adapter_cnf |= A_CNF_10B_T; count++; } + if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_AUI; count++; } + if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_10B_2; count++; } + if (count > 1) {lp->adapter_cnf |= A_CNF_MEDIA_AUTO; } + else if (lp->force & FORCE_RJ45){lp->adapter_cnf |= A_CNF_MEDIA_10B_T; } + else if (lp->force & FORCE_AUI) {lp->adapter_cnf |= A_CNF_MEDIA_AUI; } + else if (lp->force & FORCE_BNC) {lp->adapter_cnf |= A_CNF_MEDIA_10B_2; } + } + + if (net_debug > 1) + printk(KERN_DEBUG "%s: after force 0x%x, adapter_cnf=0x%x\n", + dev->name, lp->force, lp->adapter_cnf); + + /* FIXME: We don't let you set dc-dc polarity or low RX squelch from the command line: add it here */ + + /* FIXME: We don't let you set the IMM bit from the command line: add it to lp->auto_neg_cnf here */ + + /* FIXME: we don't set the Ethernet address on the command line. Use + ifconfig IFACE hw ether AABBCCDDEEFF */ + + printk(KERN_INFO "cs89x0 media %s%s%s", + (lp->adapter_cnf & A_CNF_10B_T)?"RJ-45,":"", + (lp->adapter_cnf & A_CNF_AUI)?"AUI,":"", + (lp->adapter_cnf & A_CNF_10B_2)?"BNC,":""); + + lp->irq_map = 0xffff; + + /* If this is a CS8900 then no pnp soft */ + if (lp->chip_type != CS8900 && + /* Check if the ISA IRQ has been set */ + (i = readreg(dev, PP_CS8920_ISAINT) & 0xff, + (i != 0 && i < CS8920_NO_INTS))) { + if (!dev->irq) + dev->irq = i; + } else { + i = lp->isa_config & INT_NO_MASK; + if (lp->chip_type == CS8900) { + /* Translate the IRQ using the IRQ mapping table. */ + if (i >= sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) + printk("\ncs89x0: invalid ISA interrupt number %d\n", i); + else + i = cs8900_irq_map[i]; + + lp->irq_map = CS8900_IRQ_MAP; /* fixed IRQ map for CS8900 */ + } else { + int irq_map_buff[IRQ_MAP_LEN/2]; + + if (get_eeprom_data(dev, IRQ_MAP_EEPROM_DATA, + IRQ_MAP_LEN/2, + irq_map_buff) >= 0) { + if ((irq_map_buff[0] & 0xff) == PNP_IRQ_FRMT) + lp->irq_map = (irq_map_buff[0]>>8) | (irq_map_buff[1] << 8); + } + } + if (!dev->irq) + dev->irq = i; + } + + printk(" IRQ %d", dev->irq); + +#if ALLOW_DMA + if (lp->use_dma) { + get_dma_channel(dev); + printk(", DMA %d", dev->dma); + } + else +#endif + { + printk(", programmed I/O"); + } + + /* print the ethernet address. */ + printk(", MAC"); + for (i = 0; i < ETH_ALEN; i++) + { + printk("%c%02x", i ? ':' : ' ', dev->dev_addr[i]); + } + + dev->open = net_open; + dev->stop = net_close; + dev->tx_timeout = net_timeout; + dev->watchdog_timeo = HZ; + dev->hard_start_xmit = net_send_packet; + dev->get_stats = net_get_stats; + dev->set_multicast_list = set_multicast_list; + dev->set_mac_address = set_mac_address; + + /* Fill in the fields of the device structure with ethernet values. */ + ether_setup(dev); + + printk("\n"); + if (net_debug) + printk("cs89x0_probe1() successful\n"); + return 0; +out2: + release_region(ioaddr & ~3, NETCARD_IO_EXTENT); +out1: + kfree(dev->priv); + dev->priv = 0; +out: + return retval; +} + + +/********************************* + * This page contains DMA routines +**********************************/ + +#if ALLOW_DMA + +#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17) + +static void +get_dma_channel(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (lp->dma) { + dev->dma = lp->dma; + lp->isa_config |= ISA_RxDMA; + } else { + if ((lp->isa_config & ANY_ISA_DMA) == 0) + return; + dev->dma = lp->isa_config & DMA_NO_MASK; + if (lp->chip_type == CS8900) + dev->dma += 5; + if (dev->dma < 5 || dev->dma > 7) { + lp->isa_config &= ~ANY_ISA_DMA; + return; + } + } + return; +} + +static void +write_dma(struct net_device *dev, int chip_type, int dma) +{ + struct net_local *lp = (struct net_local *)dev->priv; + if ((lp->isa_config & ANY_ISA_DMA) == 0) + return; + if (chip_type == CS8900) { + writereg(dev, PP_CS8900_ISADMA, dma-5); + } else { + writereg(dev, PP_CS8920_ISADMA, dma); + } +} + +static void +set_dma_cfg(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (lp->use_dma) { + if ((lp->isa_config & ANY_ISA_DMA) == 0) { + if (net_debug > 3) + printk("set_dma_cfg(): no DMA\n"); + return; + } + if (lp->isa_config & ISA_RxDMA) { + lp->curr_rx_cfg |= RX_DMA_ONLY; + if (net_debug > 3) + printk("set_dma_cfg(): RX_DMA_ONLY\n"); + } else { + lp->curr_rx_cfg |= AUTO_RX_DMA; /* not that we support it... */ + if (net_debug > 3) + printk("set_dma_cfg(): AUTO_RX_DMA\n"); + } + } +} + +static int +dma_bufcfg(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + if (lp->use_dma) + return (lp->isa_config & ANY_ISA_DMA)? RX_DMA_ENBL : 0; + else + return 0; +} + +static int +dma_busctl(struct net_device *dev) +{ + int retval = 0; + struct net_local *lp = (struct net_local *)dev->priv; + if (lp->use_dma) { + if (lp->isa_config & ANY_ISA_DMA) + retval |= RESET_RX_DMA; /* Reset the DMA pointer */ + if (lp->isa_config & DMA_BURST) + retval |= DMA_BURST_MODE; /* Does ISA config specify DMA burst ? */ + if (lp->dmasize == 64) + retval |= RX_DMA_SIZE_64K; /* did they ask for 64K? */ + retval |= MEMORY_ON; /* we need memory enabled to use DMA. */ + } + return retval; +} + +static void +dma_rx(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + struct sk_buff *skb; + int status, length; + unsigned char *bp = lp->rx_dma_ptr; + + status = bp[0] + (bp[1]<<8); + length = bp[2] + (bp[3]<<8); + bp += 4; + if (net_debug > 5) { + printk( "%s: receiving DMA packet at %lx, status %x, length %x\n", + dev->name, (unsigned long)bp, status, length); + } + if ((status & RX_OK) == 0) { + count_rx_errors(status, lp); + goto skip_this_frame; + } + + /* Malloc up new buffer. */ + skb = dev_alloc_skb(length + 2); + if (skb == NULL) { + if (net_debug) /* I don't think we want to do this to a stressed system */ + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + + /* AKPM: advance bp to the next frame */ +skip_this_frame: + bp += (length + 3) & ~3; + if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024; + lp->rx_dma_ptr = bp; + return; + } + skb_reserve(skb, 2); /* longword align L3 header */ + skb->dev = dev; + + if (bp + length > lp->end_dma_buff) { + int semi_cnt = lp->end_dma_buff - bp; + memcpy(skb_put(skb,semi_cnt), bp, semi_cnt); + memcpy(skb_put(skb,length - semi_cnt), lp->dma_buff, + length - semi_cnt); + } else { + memcpy(skb_put(skb,length), bp, length); + } + bp += (length + 3) & ~3; + if (bp >= lp->end_dma_buff) bp -= lp->dmasize*1024; + lp->rx_dma_ptr = bp; + + if (net_debug > 3) { + printk( "%s: received %d byte DMA packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += length; +} + +#endif /* ALLOW_DMA */ + +void __init reset_chip(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + int reset_start_time; + + writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); + + /* wait 30 ms */ + current->state = TASK_INTERRUPTIBLE; + schedule_timeout(30*HZ/1000); + + if (lp->chip_type != CS8900) { + /* Hardware problem requires PNP registers to be reconfigured after a reset */ + outw(PP_CS8920_ISAINT, ioaddr + ADD_PORT); + outb(dev->irq, ioaddr + DATA_PORT); + outb(0, ioaddr + DATA_PORT + 1); + + outw(PP_CS8920_ISAMemB, ioaddr + ADD_PORT); + outb((dev->mem_start >> 16) & 0xff, ioaddr + DATA_PORT); + outb((dev->mem_start >> 8) & 0xff, ioaddr + DATA_PORT + 1); + } + /* Wait until the chip is reset */ + reset_start_time = jiffies; + while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) + ; +} + + +static void +control_dc_dc(struct net_device *dev, int on_not_off) +{ + struct net_local *lp = (struct net_local *)dev->priv; + unsigned int selfcontrol; + int timenow = jiffies; + /* control the DC to DC convertor in the SelfControl register. + Note: This is hooked up to a general purpose pin, might not + always be a DC to DC convertor. */ + + selfcontrol = HCB1_ENBL; /* Enable the HCB1 bit as an output */ + if (((lp->adapter_cnf & A_CNF_DC_DC_POLARITY) != 0) ^ on_not_off) + selfcontrol |= HCB1; + else + selfcontrol &= ~HCB1; + writereg(dev, PP_SelfCTL, selfcontrol); + + /* Wait for the DC/DC converter to power up - 500ms */ + while (jiffies - timenow < HZ) + ; +} + +#define DETECTED_NONE 0 +#define DETECTED_RJ45H 1 +#define DETECTED_RJ45F 2 +#define DETECTED_AUI 3 +#define DETECTED_BNC 4 + +static int +detect_tp(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int timenow = jiffies; + int fdx; + + if (net_debug > 1) printk("%s: Attempting TP\n", dev->name); + + /* If connected to another full duplex capable 10-Base-T card the link pulses + seem to be lost when the auto detect bit in the LineCTL is set. + To overcome this the auto detect bit will be cleared whilst testing the + 10-Base-T interface. This would not be necessary for the sparrow chip but + is simpler to do it anyway. */ + writereg(dev, PP_LineCTL, lp->linectl &~ AUI_ONLY); + control_dc_dc(dev, 0); + + /* Delay for the hardware to work out if the TP cable is present - 150ms */ + for (timenow = jiffies; jiffies - timenow < 15; ) + ; + if ((readreg(dev, PP_LineST) & LINK_OK) == 0) + return DETECTED_NONE; + + if (lp->chip_type == CS8900) { + switch (lp->force & 0xf0) { +#if 0 + case FORCE_AUTO: + printk("%s: cs8900 doesn't autonegotiate\n",dev->name); + return DETECTED_NONE; +#endif + /* CS8900 doesn't support AUTO, change to HALF*/ + case FORCE_AUTO: + lp->force &= ~FORCE_AUTO; + lp->force |= FORCE_HALF; + break; + case FORCE_HALF: + break; + case FORCE_FULL: + writereg(dev, PP_TestCTL, readreg(dev, PP_TestCTL) | FDX_8900); + break; + } + fdx = readreg(dev, PP_TestCTL) & FDX_8900; + } else { + switch (lp->force & 0xf0) { + case FORCE_AUTO: + lp->auto_neg_cnf = AUTO_NEG_ENABLE; + break; + case FORCE_HALF: + lp->auto_neg_cnf = 0; + break; + case FORCE_FULL: + lp->auto_neg_cnf = RE_NEG_NOW | ALLOW_FDX; + break; + } + + writereg(dev, PP_AutoNegCTL, lp->auto_neg_cnf & AUTO_NEG_MASK); + + if ((lp->auto_neg_cnf & AUTO_NEG_BITS) == AUTO_NEG_ENABLE) { + printk(KERN_INFO "%s: negotiating duplex...\n",dev->name); + while (readreg(dev, PP_AutoNegST) & AUTO_NEG_BUSY) { + if (jiffies - timenow > 4000) { + printk(KERN_ERR "**** Full / half duplex auto-negotiation timed out ****\n"); + break; + } + } + } + fdx = readreg(dev, PP_AutoNegST) & FDX_ACTIVE; + } + if (fdx) + return DETECTED_RJ45F; + else + return DETECTED_RJ45H; +} + +/* send a test packet - return true if carrier bits are ok */ +static int +send_test_pkt(struct net_device *dev) +{ + char test_packet[] = { 0,0,0,0,0,0, 0,0,0,0,0,0, + 0, 46, /* A 46 in network order */ + 0, 0, /* DSAP=0 & SSAP=0 fields */ + 0xf3, 0 /* Control (Test Req + P bit set) */ }; + long timenow = jiffies; + + writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_TX_ON); + + memcpy(test_packet, dev->dev_addr, ETH_ALEN); + memcpy(test_packet+ETH_ALEN, dev->dev_addr, ETH_ALEN); + + writeword(dev, TX_CMD_PORT, TX_AFTER_ALL); + writeword(dev, TX_LEN_PORT, ETH_ZLEN); + + /* Test to see if the chip has allocated memory for the packet */ + while (jiffies - timenow < 5) + if (readreg(dev, PP_BusST) & READY_FOR_TX_NOW) + break; + if (jiffies - timenow >= 5) + return 0; /* this shouldn't happen */ + + /* Write the contents of the packet */ + outsw(dev->base_addr + TX_FRAME_PORT,test_packet,(ETH_ZLEN+1) >>1); + + if (net_debug > 1) printk("Sending test packet "); + /* wait a couple of jiffies for packet to be received */ + for (timenow = jiffies; jiffies - timenow < 3; ) + ; + if ((readreg(dev, PP_TxEvent) & TX_SEND_OK_BITS) == TX_OK) { + if (net_debug > 1) printk("succeeded\n"); + return 1; + } + if (net_debug > 1) printk("failed\n"); + return 0; +} + + +static int +detect_aui(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (net_debug > 1) printk("%s: Attempting AUI\n", dev->name); + control_dc_dc(dev, 0); + + writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY); + + if (send_test_pkt(dev)) + return DETECTED_AUI; + else + return DETECTED_NONE; +} + +static int +detect_bnc(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (net_debug > 1) printk("%s: Attempting BNC\n", dev->name); + control_dc_dc(dev, 1); + + writereg(dev, PP_LineCTL, (lp->linectl &~ AUTO_AUI_10BASET) | AUI_ONLY); + + if (send_test_pkt(dev)) + return DETECTED_BNC; + else + return DETECTED_NONE; +} + + +static void +write_irq(struct net_device *dev, int chip_type, int irq) +{ + int i; + + if (chip_type == CS8900) { + /* Search the mapping table for the corresponding IRQ pin. */ + for (i = 0; i != sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0]); i++) + if (cs8900_irq_map[i] == irq) + break; + /* Not found */ + if (i == sizeof(cs8900_irq_map)/sizeof(cs8900_irq_map[0])) + i = 3; + writereg(dev, PP_CS8900_ISAINT, i); + } else { + writereg(dev, PP_CS8920_ISAINT, irq); + } +} + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine should set everything up anew at each open, even + registers that "should" only need to be set once at boot, so that + there is non-reboot way to recover if something goes wrong. + */ + +/* AKPM: do we need to do any locking here? */ + +static int +net_open(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int result = 0; + int i; + int ret; + +#if defined(CONFIG_MACH_KEV7A400) + /* we're hardwired to the shared CPLD IRQ */ + ret = request_irq(dev->irq, &net_interrupt, SA_SHIRQ, dev->name, dev); + + if (ret) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed. ret=0x%x\n", dev->irq, ret); + goto bad_out; + } + writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); + writereg(dev, PP_CS8900_ISAINT, 0); /* use INTRQ0 pin */ +#elif defined(CONFIG_MACH_KEV79520) + /* we're hardwired to IRQ 0 */ + ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev); + + if (ret) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed. ret=0x%x\n", dev->irq, ret); + goto bad_out; + } + writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); + writereg(dev, PP_CS8900_ISAINT, 0); /* use INTRQ0 pin */ +#elif defined(CONFIG_MACH_EFRAME) + /* we're hardwired to the shared CPLD IRQ */ + ret = request_irq(dev->irq, &net_interrupt, 0, dev->name, dev); + + if (ret) { + if (net_debug) + printk(KERN_DEBUG "cs89x0: request_irq(%d) failed. ret=0x%x\n", dev->irq, ret); + goto bad_out; + } +// writereg(dev, PP_BusCTL, ENABLE_IRQ | MEMORY_ON); + writereg(dev, PP_BusCTL, ENABLE_IRQ); + writereg(dev, PP_CS8900_ISAINT, 0); /* use INTRQ0 pin */ +#endif /* CONFIG_MACH_KEV79520 || CONFIG_MACH_KEV7A400 */ + +#if ALLOW_DMA + if (lp->use_dma) { + if (lp->isa_config & ANY_ISA_DMA) { + unsigned long flags; + lp->dma_buff = (unsigned char *)__get_dma_pages(GFP_KERNEL, + get_order(lp->dmasize * 1024)); + + if (!lp->dma_buff) { + printk(KERN_ERR "%s: cannot get %dK memory for DMA\n", dev->name, lp->dmasize); + goto release_irq; + } + if (net_debug > 1) { + printk( "%s: dma %lx %lx\n", + dev->name, + (unsigned long)lp->dma_buff, + (unsigned long)virt_to_bus(lp->dma_buff)); + } + if ((unsigned long) lp->dma_buff >= MAX_DMA_ADDRESS || + !dma_page_eq(lp->dma_buff, lp->dma_buff+lp->dmasize*1024-1)) { + printk(KERN_ERR "%s: not usable as DMA buffer\n", dev->name); + goto release_irq; + } + memset(lp->dma_buff, 0, lp->dmasize * 1024); /* Why? */ + if (request_dma(dev->dma, dev->name)) { + printk(KERN_ERR "%s: cannot get dma channel %d\n", dev->name, dev->dma); + goto release_irq; + } + write_dma(dev, lp->chip_type, dev->dma); + lp->rx_dma_ptr = lp->dma_buff; + lp->end_dma_buff = lp->dma_buff + lp->dmasize*1024; + spin_lock_irqsave(&lp->lock, flags); + disable_dma(dev->dma); + clear_dma_ff(dev->dma); + set_dma_mode(dev->dma, 0x14); /* auto_init as well */ + set_dma_addr(dev->dma, virt_to_bus(lp->dma_buff)); + set_dma_count(dev->dma, lp->dmasize*1024); + enable_dma(dev->dma); + spin_unlock_irqrestore(&lp->lock, flags); + } + } +#endif /* ALLOW_DMA */ + + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + /* while we're testing the interface, leave interrupts disabled */ + writereg(dev, PP_BusCTL, MEMORY_ON); + + /* Set the LineCTL quintuplet based on adapter configuration read from EEPROM */ + if ((lp->adapter_cnf & A_CNF_EXTND_10B_2) && (lp->adapter_cnf & A_CNF_LOW_RX_SQUELCH)) + lp->linectl = LOW_RX_SQUELCH; + else + lp->linectl = 0; + + /* check to make sure that they have the "right" hardware available */ + switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) { + case A_CNF_MEDIA_10B_T: result = lp->adapter_cnf & A_CNF_10B_T; break; + case A_CNF_MEDIA_AUI: result = lp->adapter_cnf & A_CNF_AUI; break; + case A_CNF_MEDIA_10B_2: result = lp->adapter_cnf & A_CNF_10B_2; break; + default: result = lp->adapter_cnf & (A_CNF_10B_T | A_CNF_AUI | A_CNF_10B_2); + } + if (!result) { + printk(KERN_ERR "%s: EEPROM is configured for unavailable media\n", dev->name); + release_irq: +#if ALLOW_DMA + release_dma_buff(lp); +#endif + writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) & ~(SERIAL_TX_ON | SERIAL_RX_ON)); + free_irq(dev->irq, dev); + ret = -EAGAIN; + goto bad_out; + } + + /* set the hardware to the configured choice */ + switch(lp->adapter_cnf & A_CNF_MEDIA_TYPE) { + case A_CNF_MEDIA_10B_T: + result = detect_tp(dev); + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-T (RJ-45) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_RJ45H; /* Yes! I don't care if I see a link pulse */ + } + break; + case A_CNF_MEDIA_AUI: + result = detect_aui(dev); + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-5 (AUI) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_AUI; /* Yes! I don't care if I see a carrrier */ + } + break; + case A_CNF_MEDIA_10B_2: + result = detect_bnc(dev); + if (result==DETECTED_NONE) { + printk(KERN_WARNING "%s: 10Base-2 (BNC) has no cable\n", dev->name); + if (lp->auto_neg_cnf & IMM_BIT) /* check "ignore missing media" bit */ + result = DETECTED_BNC; /* Yes! I don't care if I can xmit a packet */ + } + break; + case A_CNF_MEDIA_AUTO: + writereg(dev, PP_LineCTL, lp->linectl | AUTO_AUI_10BASET); + if (lp->adapter_cnf & A_CNF_10B_T) + if ((result = detect_tp(dev)) != DETECTED_NONE) + break; + if (lp->adapter_cnf & A_CNF_AUI) + if ((result = detect_aui(dev)) != DETECTED_NONE) + break; + if (lp->adapter_cnf & A_CNF_10B_2) + if ((result = detect_bnc(dev)) != DETECTED_NONE) + break; + printk(KERN_ERR "%s: no media detected\n", dev->name); + goto release_irq; + } + switch(result) { + case DETECTED_NONE: + printk(KERN_ERR "%s: no network cable attached to configured media\n", dev->name); + goto release_irq; + case DETECTED_RJ45H: + printk(KERN_INFO "%s: using half-duplex 10Base-T (RJ-45)\n", dev->name); + break; + case DETECTED_RJ45F: + printk(KERN_INFO "%s: using full-duplex 10Base-T (RJ-45)\n", dev->name); + break; + case DETECTED_AUI: + printk(KERN_INFO "%s: using 10Base-5 (AUI)\n", dev->name); + break; + case DETECTED_BNC: + printk(KERN_INFO "%s: using 10Base-2 (BNC)\n", dev->name); + break; + } + + /* Turn on both receive and transmit operations */ + writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); + + /* Receive only error free packets addressed to this card */ + lp->rx_mode = 0; + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); + + lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; + + if (lp->isa_config & STREAM_TRANSFER) + lp->curr_rx_cfg |= RX_STREAM_ENBL; +#if ALLOW_DMA + set_dma_cfg(dev); +#endif + writereg(dev, PP_RxCFG, lp->curr_rx_cfg); + + writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | + TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); + + writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | +#if ALLOW_DMA + dma_bufcfg(dev) | +#endif + TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); + + /* now that we've got our act together, enable everything */ + writereg(dev, PP_BusCTL, ENABLE_IRQ + | (dev->mem_start?MEMORY_ON : 0) /* turn memory on */ +#if ALLOW_DMA + | dma_busctl(dev) +#endif + ); + netif_start_queue(dev); + if (net_debug > 1) + printk("cs89x0: net_open() succeeded\n"); + return 0; +bad_out: + return ret; +} + +static void net_timeout(struct net_device *dev) +{ + /* If we get here, some higher level has decided we are broken. + There should really be a "kick me" function call instead. */ + if (net_debug > 0) printk("%s: transmit timed out, %s?\n", dev->name, + tx_done(dev) ? "IRQ conflict ?" : "network cable problem"); + /* Try to restart the adaptor. */ + netif_wake_queue(dev); +} + +static int net_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + if (net_debug > 3) { + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } + + /* keep the upload from being interrupted, since we + ask the chip to start transmitting before the + whole packet has been completely uploaded. */ + + spin_lock_irq(&lp->lock); + netif_stop_queue(dev); + + /* initiate a transmit sequence */ + writeword(dev, TX_CMD_PORT, lp->send_cmd); + writeword(dev, TX_LEN_PORT, skb->len); + + /* Test to see if the chip has allocated memory for the packet */ + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { + /* + * Gasp! It hasn't. But that shouldn't happen since + * we're waiting for TxOk, so return 1 and requeue this packet. + */ + + spin_unlock_irq(&lp->lock); + if (net_debug) printk("cs89x0: Tx buffer not free!\n"); + return 1; + } + /* Write the contents of the packet */ + outsw(dev->base_addr + TX_FRAME_PORT,skb->data,(skb->len+1) >>1); + spin_unlock_irq(&lp->lock); + dev->trans_start = jiffies; + dev_kfree_skb (skb); + + /* + * We DO NOT call netif_wake_queue() here. + * We also DO NOT call netif_start_queue(). + * + * Either of these would cause another bottom half run through + * net_send_packet() before this packet has fully gone out. That causes + * us to hit the "Gasp!" above and the send is rescheduled. it runs like + * a dog. We just return and wait for the Tx completion interrupt handler + * to restart the netdevice layer + */ + + return 0; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ + +static void net_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct net_device *dev = dev_id; + struct net_local *lp; + int ioaddr, status; + + ioaddr = dev->base_addr; + lp = (struct net_local *)dev->priv; + + /* we MUST read all the events out of the ISQ, otherwise we'll never + get interrupted again. As a consequence, we can't have any limit + on the number of times we loop in the interrupt handler. The + hardware guarantees that eventually we'll run out of events. Of + course, if you're on a slow machine, and packets are arriving + faster than you can read them off, you're screwed. Hasta la + vista, baby! */ + while ((status = readword(dev, ISQ_PORT))) { + if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status); + switch(status & ISQ_EVENT_MASK) { + case ISQ_RECEIVER_EVENT: + /* Got a packet(s). */ + net_rx(dev); + break; + case ISQ_TRANSMITTER_EVENT: + lp->stats.tx_packets++; + netif_wake_queue(dev); /* Inform upper layers. */ + if ((status & ( TX_OK | + TX_LOST_CRS | + TX_SQE_ERROR | + TX_LATE_COL | + TX_16_COL)) != TX_OK) { + if ((status & TX_OK) == 0) lp->stats.tx_errors++; + if (status & TX_LOST_CRS) lp->stats.tx_carrier_errors++; + if (status & TX_SQE_ERROR) lp->stats.tx_heartbeat_errors++; + if (status & TX_LATE_COL) lp->stats.tx_window_errors++; + if (status & TX_16_COL) lp->stats.tx_aborted_errors++; + } + break; + case ISQ_BUFFER_EVENT: + if (status & READY_FOR_TX) { + /* we tried to transmit a packet earlier, + but inexplicably ran out of buffers. + That shouldn't happen since we only ever + load one packet. Shrug. Do the right + thing anyway. */ + netif_wake_queue(dev); /* Inform upper layers. */ + } + if (status & TX_UNDERRUN) { + if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); + lp->send_underrun++; + if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; + else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; + /* transmit cycle is done, although + frame wasn't transmitted - this + avoids having to wait for the upper + layers to timeout on us, in the + event of a tx underrun */ + netif_wake_queue(dev); /* Inform upper layers. */ + } +#if ALLOW_DMA + if (lp->use_dma && (status & RX_DMA)) { + int count = readreg(dev, PP_DmaFrameCnt); + while(count) { + if (net_debug > 5) + printk("%s: receiving %d DMA frames\n", dev->name, count); + if (net_debug > 2 && count >1) + printk("%s: receiving %d DMA frames\n", dev->name, count); + dma_rx(dev); + if (--count == 0) + count = readreg(dev, PP_DmaFrameCnt); + if (net_debug > 2 && count > 0) + printk("%s: continuing with %d DMA frames\n", dev->name, count); + } + } +#endif + break; + case ISQ_RX_MISS_EVENT: + lp->stats.rx_missed_errors += (status >>6); + break; + case ISQ_TX_COL_EVENT: + lp->stats.collisions += (status >>6); + break; + } + } +} + +static void +count_rx_errors(int status, struct net_local *lp) +{ + lp->stats.rx_errors++; + if (status & RX_RUNT) lp->stats.rx_length_errors++; + if (status & RX_EXTRA_DATA) lp->stats.rx_length_errors++; + if (status & RX_CRC_ERROR) if (!(status & (RX_EXTRA_DATA|RX_RUNT))) + /* per str 172 */ + lp->stats.rx_crc_errors++; + if (status & RX_DRIBBLE) lp->stats.rx_frame_errors++; + return; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +net_rx(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + struct sk_buff *skb; + int status, length; + + int ioaddr = dev->base_addr; + status = inw(ioaddr + RX_FRAME_PORT); + length = inw(ioaddr + RX_FRAME_PORT); + + if ((status & RX_OK) == 0) { + count_rx_errors(status, lp); + return; + } + + /* Malloc up new buffer. */ + skb = dev_alloc_skb(length + 2); + if (skb == NULL) { +#if 0 /* Again, this seems a cruel thing to do */ + printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); +#endif + lp->stats.rx_dropped++; + return; + } + skb_reserve(skb, 2); /* longword align L3 header */ + skb->dev = dev; + + insw(ioaddr + RX_FRAME_PORT, skb_put(skb, length), length >> 1); + if (length & 1) + skb->data[length-1] = inw(ioaddr + RX_FRAME_PORT); + + if (net_debug > 3) { + printk( "%s: received %d byte packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) | skb->data[ETH_ALEN+ETH_ALEN+1]); + } + + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + dev->last_rx = jiffies; + lp->stats.rx_packets++; + lp->stats.rx_bytes += length; +} + +#if ALLOW_DMA +static void release_dma_buff(struct net_local *lp) +{ + if (lp->dma_buff) { + free_pages((unsigned long)(lp->dma_buff), get_order(lp->dmasize * 1024)); + lp->dma_buff = 0; + } +} +#endif + +/* The inverse routine to net_open(). */ +static int +net_close(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + netif_stop_queue(dev); + + writereg(dev, PP_RxCFG, 0); + writereg(dev, PP_TxCFG, 0); + writereg(dev, PP_BufCFG, 0); + writereg(dev, PP_BusCTL, 0); + + free_irq(dev->irq, dev); + +#if ALLOW_DMA + if (lp->use_dma && lp->dma) { + free_dma(dev->dma); + release_dma_buff(lp); + } +#endif + + /* Update the statistics here. */ + return 0; +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct net_device_stats * +net_get_stats(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + + spin_lock_irqsave(&lp->lock, flags); + /* Update the statistics from the device registers. */ + lp->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); + lp->stats.collisions += (readreg(dev, PP_TxCol) >> 6); + spin_unlock_irqrestore(&lp->lock, flags); + + return &lp->stats; +} + +static void set_multicast_list(struct net_device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + unsigned long flags; + + spin_lock_irqsave(&lp->lock, flags); + if(dev->flags&IFF_PROMISC) + { + lp->rx_mode = RX_ALL_ACCEPT; + } + else if((dev->flags&IFF_ALLMULTI)||dev->mc_list) + { + /* The multicast-accept list is initialized to accept-all, and we + rely on higher-level filtering for now. */ + lp->rx_mode = RX_MULTCAST_ACCEPT; + } + else + lp->rx_mode = 0; + + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); + + /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */ + writereg(dev, PP_RxCFG, lp->curr_rx_cfg | + (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0)); + spin_unlock_irqrestore(&lp->lock, flags); +} + + +static int set_mac_address(struct net_device *dev, void *addr) +{ + int i; + + if (netif_running(dev)) + return -EBUSY; + if (net_debug) { + printk("%s: Setting MAC address to ", dev->name); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); + printk(".\n"); + } + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + return 0; +} + +#ifdef MODULE + +static struct net_device dev_cs89x0 = { + "", + 0, 0, 0, 0, + 0, 0, + 0, 0, 0, NULL, NULL }; + +/* + * Support the 'debug' module parm even if we're compiled for non-debug to + * avoid breaking someone's startup scripts + */ + +static int io; +static int irq; +static int debug; +static char media[8]; +static int duplex=-1; + +static int use_dma; /* These generate unused var warnings if ALLOW_DMA = 0 */ +static int dma; +static int dmasize=16; /* or 64 */ + +MODULE_PARM(io, "i"); +MODULE_PARM(irq, "i"); +MODULE_PARM(debug, "i"); +MODULE_PARM(media, "c8"); +MODULE_PARM(duplex, "i"); +MODULE_PARM(dma , "i"); +MODULE_PARM(dmasize , "i"); +MODULE_PARM(use_dma , "i"); +MODULE_PARM_DESC(io, "cs89x0 I/O base address"); +MODULE_PARM_DESC(irq, "cs89x0 IRQ number"); +#if DEBUGGING +MODULE_PARM_DESC(debug, "cs89x0 debug level (0-6)"); +#else +MODULE_PARM_DESC(debug, "(ignored)"); +#endif +MODULE_PARM_DESC(media, "Set cs89x0 adapter(s) media type(s) (rj45,bnc,aui)"); +/* No other value than -1 for duplex seems to be currently interpreted */ +MODULE_PARM_DESC(duplex, "(ignored)"); +#if ALLOW_DMA +MODULE_PARM_DESC(dma , "cs89x0 ISA DMA channel; ignored if use_dma=0"); +MODULE_PARM_DESC(dmasize , "cs89x0 DMA size in kB (16,64); ignored if use_dma=0"); +MODULE_PARM_DESC(use_dma , "cs89x0 using DMA (0-1)"); +#else +MODULE_PARM_DESC(dma , "(ignored)"); +MODULE_PARM_DESC(dmasize , "(ignored)"); +MODULE_PARM_DESC(use_dma , "(ignored)"); +#endif + +MODULE_AUTHOR("Mike Cruse, Russwll Nelson , Andrew Morton "); +MODULE_LICENSE("GPL"); + + +EXPORT_NO_SYMBOLS; + +/* +* media=t - specify media type + or media=2 + or media=aui + or medai=auto +* duplex=0 - specify forced half/full/autonegotiate duplex +* debug=# - debug level + + +* Default Chip Configuration: + * DMA Burst = enabled + * IOCHRDY Enabled = enabled + * UseSA = enabled + * CS8900 defaults to half-duplex if not specified on command-line + * CS8920 defaults to autoneg if not specified on command-line + * Use reset defaults for other config parameters + +* Assumptions: + * media type specified is supported (circuitry is present) + * if memory address is > 1MB, then required mem decode hw is present + * if 10B-2, then agent other than driver will enable DC/DC converter + (hw or software util) + + +*/ + +int +init_module(void) +{ + struct net_local *lp; + int ret = 0; + +#if DEBUGGING + net_debug = debug; +#else + debug = 0; +#endif + + dev_cs89x0.irq = irq; + dev_cs89x0.base_addr = io; + + dev_cs89x0.init = cs89x0_probe; + dev_cs89x0.priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + if (dev_cs89x0.priv == 0) { + printk(KERN_ERR "cs89x0.c: Out of memory.\n"); + return -ENOMEM; + } + memset(dev_cs89x0.priv, 0, sizeof(struct net_local)); + lp = (struct net_local *)dev_cs89x0.priv; + +#if ALLOW_DMA + if (use_dma) { + lp->use_dma = use_dma; + lp->dma = dma; + lp->dmasize = dmasize; + } +#endif + + spin_lock_init(&lp->lock); + + /* boy, they'd better get these right */ + if (!strcmp(media, "rj45")) + lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; + else if (!strcmp(media, "aui")) + lp->adapter_cnf = A_CNF_MEDIA_AUI | A_CNF_AUI; + else if (!strcmp(media, "bnc")) + lp->adapter_cnf = A_CNF_MEDIA_10B_2 | A_CNF_10B_2; + else + lp->adapter_cnf = A_CNF_MEDIA_10B_T | A_CNF_10B_T; + + if (duplex==-1) + lp->auto_neg_cnf = AUTO_NEG_ENABLE; + + if (io == 0) { + printk(KERN_ERR "cs89x0.c: Module autoprobing not allowed.\n"); + printk(KERN_ERR "cs89x0.c: Append io=0xNNN\n"); + ret = -EPERM; + goto out; + } + +#if ALLOW_DMA + if (use_dma && dmasize != 16 && dmasize != 64) { + printk(KERN_ERR "cs89x0.c: dma size must be either 16K or 64K, not %dK\n", dmasize); + ret = -EPERM; + goto out; + } +#endif + + if (register_netdev(&dev_cs89x0) != 0) { + printk(KERN_ERR "cs89x0.c: No card found at 0x%x\n", io); + ret = -ENXIO; + goto out; + } +out: + if (ret) + kfree(dev_cs89x0.priv); + return ret; +} + +void +cleanup_module(void) +{ + if (dev_cs89x0.priv != NULL) { + /* Free up the private structure, or leak memory :-) */ + unregister_netdev(&dev_cs89x0); + outw(PP_ChipID, dev_cs89x0.base_addr + ADD_PORT); + kfree(dev_cs89x0.priv); + dev_cs89x0.priv = NULL; /* gets re-allocated by cs89x0_probe1 */ + /* If we don't do this, we can't re-insmod it later. */ + release_region(dev_cs89x0.base_addr, NETCARD_IO_EXTENT); + } +} +#endif /* MODULE */ + +/* + * Local variables: + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 8 + * tab-width: 8 + * End: + * + */ diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/net/cs89x0_kev7a400.h linux-2.4.21-rmk1-lh7a400/drivers/net/cs89x0_kev7a400.h --- linux-2.4.21-rmk1/drivers/net/cs89x0_kev7a400.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/net/cs89x0_kev7a400.h Sun Oct 19 07:43:13 2003 @@ -0,0 +1,488 @@ +/* Copyright, 1988-1992, Russell Nelson, Crynwr Software + + 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, version 1. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include + +#define PP_ChipID 0x0000 /* offset 0h -> Corp -ID */ + /* offset 2h -> Model/Product Number */ + /* offset 3h -> Chip Revision Number */ + +#define PP_ISAIOB 0x0020 /* IO base address */ +#define PP_CS8900_ISAINT 0x0022 /* ISA interrupt select */ +#define PP_CS8920_ISAINT 0x0370 /* ISA interrupt select */ +#define PP_CS8900_ISADMA 0x0024 /* ISA Rec DMA channel */ +#define PP_CS8920_ISADMA 0x0374 /* ISA Rec DMA channel */ +#define PP_ISASOF 0x0026 /* ISA DMA offset */ +#define PP_DmaFrameCnt 0x0028 /* ISA DMA Frame count */ +#define PP_DmaByteCnt 0x002A /* ISA DMA Byte count */ +#define PP_CS8900_ISAMemB 0x002C /* Memory base */ +#define PP_CS8920_ISAMemB 0x0348 /* */ + +#define PP_ISABootBase 0x0030 /* Boot Prom base */ +#define PP_ISABootMask 0x0034 /* Boot Prom Mask */ + +/* EEPROM data and command registers */ +#define PP_EECMD 0x0040 /* NVR Interface Command register */ +#define PP_EEData 0x0042 /* NVR Interface Data Register */ +#define PP_DebugReg 0x0044 /* Debug Register */ + +#define PP_RxCFG 0x0102 /* Rx Bus config */ +#define PP_RxCTL 0x0104 /* Receive Control Register */ +#define PP_TxCFG 0x0106 /* Transmit Config Register */ +#define PP_TxCMD 0x0108 /* Transmit Command Register */ +#define PP_BufCFG 0x010A /* Bus configuration Register */ +#define PP_LineCTL 0x0112 /* Line Config Register */ +#define PP_SelfCTL 0x0114 /* Self Command Register */ +#define PP_BusCTL 0x0116 /* ISA bus control Register */ +#define PP_TestCTL 0x0118 /* Test Register */ +#define PP_AutoNegCTL 0x011C /* Auto Negotiation Ctrl */ + +#define PP_ISQ 0x0120 /* Interrupt Status */ +#define PP_RxEvent 0x0124 /* Rx Event Register */ +#define PP_TxEvent 0x0128 /* Tx Event Register */ +#define PP_BufEvent 0x012C /* Bus Event Register */ +#define PP_RxMiss 0x0130 /* Receive Miss Count */ +#define PP_TxCol 0x0132 /* Transmit Collision Count */ +#define PP_LineST 0x0134 /* Line State Register */ +#define PP_SelfST 0x0136 /* Self State register */ +#define PP_BusST 0x0138 /* Bus Status */ +#define PP_TDR 0x013C /* Time Domain Reflectometry */ +#define PP_AutoNegST 0x013E /* Auto Neg Status */ +#define PP_TxCommand 0x0144 /* Tx Command */ +#define PP_TxLength 0x0146 /* Tx Length */ +#define PP_LAF 0x0150 /* Hash Table */ +#define PP_IA 0x0158 /* Physical Address Register */ + +#define PP_RxStatus 0x0400 /* Receive start of frame */ +#define PP_RxLength 0x0402 /* Receive Length of frame */ +#define PP_RxFrame 0x0404 /* Receive frame pointer */ +#define PP_TxFrame 0x0A00 /* Transmit frame pointer */ + +/* Primary I/O Base Address. If no I/O base is supplied by the user, then this */ +/* can be used as the default I/O base to access the PacketPage Area. */ +#define DEFAULTIOBASE 0x0300 +#define FIRST_IO 0x020C /* First I/O port to check */ +#define LAST_IO 0x037C /* Last I/O port to check (+10h) */ +#define ADD_MASK 0x3000 /* Mask it use of the ADD_PORT register */ +#define ADD_SIG 0x3000 /* Expected ID signature */ + +/* On Macs, we only need use the ISA I/O stuff until we do MEMORY_ON */ +#ifdef CONFIG_MAC +#define LCSLOTBASE 0xfee00000 +#define MMIOBASE 0x40000 +#endif + +#define CHIP_EISA_ID_SIG 0x630E /* Product ID Code for Crystal Chip (CS8900 spec 4.3) */ + +#ifdef IBMEIPKT +#define EISA_ID_SIG 0x4D24 /* IBM */ +#define PART_NO_SIG 0x1010 /* IBM */ +#define MONGOOSE_BIT 0x0000 /* IBM */ +#else +#define EISA_ID_SIG 0x630E /* PnP Vendor ID (same as chip id for Crystal board) */ +#define PART_NO_SIG 0x4000 /* ID code CS8920 board (PnP Vendor Product code) */ +#define MONGOOSE_BIT 0x2000 /* PART_NO_SIG + MONGOOSE_BUT => ID of mongoose */ +#endif + +#define PRODUCT_ID_ADD 0x0002 /* Address of product ID */ + +/* Mask to find out the types of registers */ +#define REG_TYPE_MASK 0x001F + +/* Eeprom Commands */ +#define ERSE_WR_ENBL 0x00F0 +#define ERSE_WR_DISABLE 0x0000 + +/* Defines Control/Config register quintuplet numbers */ +#define RX_BUF_CFG 0x0003 +#define RX_CONTROL 0x0005 +#define TX_CFG 0x0007 +#define TX_COMMAND 0x0009 +#define BUF_CFG 0x000B +#define LINE_CONTROL 0x0013 +#define SELF_CONTROL 0x0015 +#define BUS_CONTROL 0x0017 +#define TEST_CONTROL 0x0019 + +/* Defines Status/Count registers quintuplet numbers */ +#define RX_EVENT 0x0004 +#define TX_EVENT 0x0008 +#define BUF_EVENT 0x000C +#define RX_MISS_COUNT 0x0010 +#define TX_COL_COUNT 0x0012 +#define LINE_STATUS 0x0014 +#define SELF_STATUS 0x0016 +#define BUS_STATUS 0x0018 +#define TDR 0x001C + +/* PP_RxCFG - Receive Configuration and Interrupt Mask bit definition - Read/write */ +#define SKIP_1 0x0040 +#define RX_STREAM_ENBL 0x0080 +#define RX_OK_ENBL 0x0100 +#define RX_DMA_ONLY 0x0200 +#define AUTO_RX_DMA 0x0400 +#define BUFFER_CRC 0x0800 +#define RX_CRC_ERROR_ENBL 0x1000 +#define RX_RUNT_ENBL 0x2000 +#define RX_EXTRA_DATA_ENBL 0x4000 + +/* PP_RxCTL - Receive Control bit definition - Read/write */ +#define RX_IA_HASH_ACCEPT 0x0040 +#define RX_PROM_ACCEPT 0x0080 +#define RX_OK_ACCEPT 0x0100 +#define RX_MULTCAST_ACCEPT 0x0200 +#define RX_IA_ACCEPT 0x0400 +#define RX_BROADCAST_ACCEPT 0x0800 +#define RX_BAD_CRC_ACCEPT 0x1000 +#define RX_RUNT_ACCEPT 0x2000 +#define RX_EXTRA_DATA_ACCEPT 0x4000 +#define RX_ALL_ACCEPT (RX_PROM_ACCEPT|RX_BAD_CRC_ACCEPT|RX_RUNT_ACCEPT|RX_EXTRA_DATA_ACCEPT) +/* Default receive mode - individually addressed, broadcast, and error free */ +#define DEF_RX_ACCEPT (RX_IA_ACCEPT | RX_BROADCAST_ACCEPT | RX_OK_ACCEPT) + +/* PP_TxCFG - Transmit Configuration Interrupt Mask bit definition - Read/write */ +#define TX_LOST_CRS_ENBL 0x0040 +#define TX_SQE_ERROR_ENBL 0x0080 +#define TX_OK_ENBL 0x0100 +#define TX_LATE_COL_ENBL 0x0200 +#define TX_JBR_ENBL 0x0400 +#define TX_ANY_COL_ENBL 0x0800 +#define TX_16_COL_ENBL 0x8000 + +/* PP_TxCMD - Transmit Command bit definition - Read-only */ +#define TX_START_4_BYTES 0x0000 +#define TX_START_64_BYTES 0x0040 +#define TX_START_128_BYTES 0x0080 +#define TX_START_ALL_BYTES 0x00C0 +#define TX_FORCE 0x0100 +#define TX_ONE_COL 0x0200 +#define TX_TWO_PART_DEFF_DISABLE 0x0400 +#define TX_NO_CRC 0x1000 +#define TX_RUNT 0x2000 + +/* PP_BufCFG - Buffer Configuration Interrupt Mask bit definition - Read/write */ +#define GENERATE_SW_INTERRUPT 0x0040 +#define RX_DMA_ENBL 0x0080 +#define READY_FOR_TX_ENBL 0x0100 +#define TX_UNDERRUN_ENBL 0x0200 +#define RX_MISS_ENBL 0x0400 +#define RX_128_BYTE_ENBL 0x0800 +#define TX_COL_COUNT_OVRFLOW_ENBL 0x1000 +#define RX_MISS_COUNT_OVRFLOW_ENBL 0x2000 +#define RX_DEST_MATCH_ENBL 0x8000 + +/* PP_LineCTL - Line Control bit definition - Read/write */ +#define SERIAL_RX_ON 0x0040 +#define SERIAL_TX_ON 0x0080 +#define AUI_ONLY 0x0100 +#define AUTO_AUI_10BASET 0x0200 +#define MODIFIED_BACKOFF 0x0800 +#define NO_AUTO_POLARITY 0x1000 +#define TWO_PART_DEFDIS 0x2000 +#define LOW_RX_SQUELCH 0x4000 + +/* PP_SelfCTL - Software Self Control bit definition - Read/write */ +#define POWER_ON_RESET 0x0040 +#define SW_STOP 0x0100 +#define SLEEP_ON 0x0200 +#define AUTO_WAKEUP 0x0400 +#define HCB0_ENBL 0x1000 +#define HCB1_ENBL 0x2000 +#define HCB0 0x4000 +#define HCB1 0x8000 + +/* PP_BusCTL - ISA Bus Control bit definition - Read/write */ +#define RESET_RX_DMA 0x0040 +#define MEMORY_ON 0x0400 +#define DMA_BURST_MODE 0x0800 +#define IO_CHANNEL_READY_ON 0x1000 +#define RX_DMA_SIZE_64K 0x2000 +#define ENABLE_IRQ 0x8000 + +/* PP_TestCTL - Test Control bit definition - Read/write */ +#define LINK_OFF 0x0080 +#define ENDEC_LOOPBACK 0x0200 +#define AUI_LOOPBACK 0x0400 +#define BACKOFF_OFF 0x0800 +#define FDX_8900 0x4000 +#define FAST_TEST 0x8000 + +/* PP_RxEvent - Receive Event Bit definition - Read-only */ +#define RX_IA_HASHED 0x0040 +#define RX_DRIBBLE 0x0080 +#define RX_OK 0x0100 +#define RX_HASHED 0x0200 +#define RX_IA 0x0400 +#define RX_BROADCAST 0x0800 +#define RX_CRC_ERROR 0x1000 +#define RX_RUNT 0x2000 +#define RX_EXTRA_DATA 0x4000 + +#define HASH_INDEX_MASK 0x0FC00 + +/* PP_TxEvent - Transmit Event Bit definition - Read-only */ +#define TX_LOST_CRS 0x0040 +#define TX_SQE_ERROR 0x0080 +#define TX_OK 0x0100 +#define TX_LATE_COL 0x0200 +#define TX_JBR 0x0400 +#define TX_16_COL 0x8000 +#define TX_SEND_OK_BITS (TX_OK|TX_LOST_CRS) +#define TX_COL_COUNT_MASK 0x7800 + +/* PP_BufEvent - Buffer Event Bit definition - Read-only */ +#define SW_INTERRUPT 0x0040 +#define RX_DMA 0x0080 +#define READY_FOR_TX 0x0100 +#define TX_UNDERRUN 0x0200 +#define RX_MISS 0x0400 +#define RX_128_BYTE 0x0800 +#define TX_COL_OVRFLW 0x1000 +#define RX_MISS_OVRFLW 0x2000 +#define RX_DEST_MATCH 0x8000 + +/* PP_LineST - Ethernet Line Status bit definition - Read-only */ +#define LINK_OK 0x0080 +#define AUI_ON 0x0100 +#define TENBASET_ON 0x0200 +#define POLARITY_OK 0x1000 +#define CRS_OK 0x4000 + +/* PP_SelfST - Chip Software Status bit definition */ +#define ACTIVE_33V 0x0040 +#define INIT_DONE 0x0080 +#define SI_BUSY 0x0100 +#define EEPROM_PRESENT 0x0200 +#define EEPROM_OK 0x0400 +#define EL_PRESENT 0x0800 +#define EE_SIZE_64 0x1000 + +/* PP_BusST - ISA Bus Status bit definition */ +#define TX_BID_ERROR 0x0080 +#define READY_FOR_TX_NOW 0x0100 + +/* PP_AutoNegCTL - Auto Negotiation Control bit definition */ +#define RE_NEG_NOW 0x0040 +#define ALLOW_FDX 0x0080 +#define AUTO_NEG_ENABLE 0x0100 +#define NLP_ENABLE 0x0200 +#define FORCE_FDX 0x8000 +#define AUTO_NEG_BITS (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE) +#define AUTO_NEG_MASK (FORCE_FDX|NLP_ENABLE|AUTO_NEG_ENABLE|ALLOW_FDX|RE_NEG_NOW) + +/* PP_AutoNegST - Auto Negotiation Status bit definition */ +#define AUTO_NEG_BUSY 0x0080 +#define FLP_LINK 0x0100 +#define FLP_LINK_GOOD 0x0800 +#define LINK_FAULT 0x1000 +#define HDX_ACTIVE 0x4000 +#define FDX_ACTIVE 0x8000 + +/* The following block defines the ISQ event types */ +#define ISQ_RECEIVER_EVENT 0x04 +#define ISQ_TRANSMITTER_EVENT 0x08 +#define ISQ_BUFFER_EVENT 0x0c +#define ISQ_RX_MISS_EVENT 0x10 +#define ISQ_TX_COL_EVENT 0x12 + +#define ISQ_EVENT_MASK 0x003F /* ISQ mask to find out type of event */ +#define ISQ_HIST 16 /* small history buffer */ +#define AUTOINCREMENT 0x8000 /* Bit mask to set bit-15 for autoincrement */ + +#define TXRXBUFSIZE 0x0600 +#define RXDMABUFSIZE 0x8000 +#define RXDMASIZE 0x4000 +#define TXRX_LENGTH_MASK 0x07FF + +/* rx options bits */ +#define RCV_WITH_RXON 1 /* Set SerRx ON */ +#define RCV_COUNTS 2 /* Use Framecnt1 */ +#define RCV_PONG 4 /* Pong respondent */ +#define RCV_DONG 8 /* Dong operation */ +#define RCV_POLLING 0x10 /* Poll RxEvent */ +#define RCV_ISQ 0x20 /* Use ISQ, int */ +#define RCV_AUTO_DMA 0x100 /* Set AutoRxDMAE */ +#define RCV_DMA 0x200 /* Set RxDMA only */ +#define RCV_DMA_ALL 0x400 /* Copy all DMA'ed */ +#define RCV_FIXED_DATA 0x800 /* Every frame same */ +#define RCV_IO 0x1000 /* Use ISA IO only */ +#define RCV_MEMORY 0x2000 /* Use ISA Memory */ + +#define RAM_SIZE 0x1000 /* The card has 4k bytes or RAM */ +#define PKT_START PP_TxFrame /* Start of packet RAM */ + +#if defined(CONFIG_MACH_KEV7A400) +/* ports are 32-bit aligned */ +#define RX_FRAME_PORT (0x00 << 1) +#define TX_CMD_PORT (0x04 << 1) +#define TX_LEN_PORT (0x06 << 1) +#define ISQ_PORT (0x08 << 1) +#define ADD_PORT (0x0A << 1) +#define DATA_PORT (0x0C << 1) +#else +#define RX_FRAME_PORT 0x0000 +#define TX_CMD_PORT 0x0004 +#define TX_LEN_PORT 0x0006 +#define ISQ_PORT 0x0008 +#define ADD_PORT 0x000A +#define DATA_PORT 0x000C +#endif + +#define TX_FRAME_PORT RX_FRAME_PORT +#define TX_NOW 0x0000 /* Tx packet after 5 bytes copied */ +#define TX_AFTER_381 0x0040 /* Tx packet after 381 bytes copied */ +#define TX_AFTER_ALL 0x00c0 /* Tx packet after all bytes copied */ + +#define EEPROM_WRITE_EN 0x00F0 +#define EEPROM_WRITE_DIS 0x0000 +#define EEPROM_WRITE_CMD 0x0100 +#define EEPROM_READ_CMD 0x0200 + +/* Receive Header */ +/* Description of header of each packet in receive area of memory */ +#define RBUF_EVENT_LOW 0 /* Low byte of RxEvent - status of received frame */ +#define RBUF_EVENT_HIGH 1 /* High byte of RxEvent - status of received frame */ +#define RBUF_LEN_LOW 2 /* Length of received data - low byte */ +#define RBUF_LEN_HI 3 /* Length of received data - high byte */ +#define RBUF_HEAD_LEN 4 /* Length of this header */ + +#define CHIP_READ 0x1 /* Used to mark state of the repins code (chip or dma) */ +#define DMA_READ 0x2 /* Used to mark state of the repins code (chip or dma) */ + +/* for bios scan */ +/* */ +#ifdef CSDEBUG +/* use these values for debugging bios scan */ +#define BIOS_START_SEG 0x00000 +#define BIOS_OFFSET_INC 0x0010 +#else +#define BIOS_START_SEG 0x0c000 +#define BIOS_OFFSET_INC 0x0200 +#endif + +#define BIOS_LAST_OFFSET 0x0fc00 + +/* Byte offsets into the EEPROM configuration buffer */ +#define ISA_CNF_OFFSET 0x6 +#define TX_CTL_OFFSET (ISA_CNF_OFFSET + 8) /* 8900 eeprom */ +#define AUTO_NEG_CNF_OFFSET (ISA_CNF_OFFSET + 8) /* 8920 eeprom */ + + /* the assumption here is that the bits in the eeprom are generally */ + /* in the same position as those in the autonegctl register. */ + /* Of course the IMM bit is not in that register so it must be */ + /* masked out */ +#define EE_FORCE_FDX 0x8000 +#define EE_NLP_ENABLE 0x0200 +#define EE_AUTO_NEG_ENABLE 0x0100 +#define EE_ALLOW_FDX 0x0080 +#define EE_AUTO_NEG_CNF_MASK (EE_FORCE_FDX|EE_NLP_ENABLE|EE_AUTO_NEG_ENABLE|EE_ALLOW_FDX) + +#define IMM_BIT 0x0040 /* ignore missing media */ + +#define ADAPTER_CNF_OFFSET (AUTO_NEG_CNF_OFFSET + 2) +#define A_CNF_10B_T 0x0001 +#define A_CNF_AUI 0x0002 +#define A_CNF_10B_2 0x0004 +#define A_CNF_MEDIA_TYPE 0x0070 +#define A_CNF_MEDIA_AUTO 0x0070 +#define A_CNF_MEDIA_10B_T 0x0020 +#define A_CNF_MEDIA_AUI 0x0040 +#define A_CNF_MEDIA_10B_2 0x0010 +#define A_CNF_DC_DC_POLARITY 0x0080 +#define A_CNF_NO_AUTO_POLARITY 0x2000 +#define A_CNF_LOW_RX_SQUELCH 0x4000 +#define A_CNF_EXTND_10B_2 0x8000 + +#define PACKET_PAGE_OFFSET 0x8 + +/* Bit definitions for the ISA configuration word from the EEPROM */ +#define INT_NO_MASK 0x000F +#define DMA_NO_MASK 0x0070 +#define ISA_DMA_SIZE 0x0200 +#define ISA_AUTO_RxDMA 0x0400 +#define ISA_RxDMA 0x0800 +#define DMA_BURST 0x1000 +#define STREAM_TRANSFER 0x2000 +#define ANY_ISA_DMA (ISA_AUTO_RxDMA | ISA_RxDMA) + +/* DMA controller registers */ +#define DMA_BASE 0x00 /* DMA controller base */ +#define DMA_BASE_2 0x0C0 /* DMA controller base */ + +#define DMA_STAT 0x0D0 /* DMA controller status register */ +#define DMA_MASK 0x0D4 /* DMA controller mask register */ +#define DMA_MODE 0x0D6 /* DMA controller mode register */ +#define DMA_RESETFF 0x0D8 /* DMA controller first/last flip flop */ + +/* DMA data */ +#define DMA_DISABLE 0x04 /* Disable channel n */ +#define DMA_ENABLE 0x00 /* Enable channel n */ +/* Demand transfers, incr. address, auto init, writes, ch. n */ +#define DMA_RX_MODE 0x14 +/* Demand transfers, incr. address, auto init, reads, ch. n */ +#define DMA_TX_MODE 0x18 + +#define DMA_SIZE (16*1024) /* Size of dma buffer - 16k */ + +#define CS8900 0x0000 +#define CS8920 0x4000 +#define CS8920M 0x6000 +#define REVISON_BITS 0x1F00 +#define EEVER_NUMBER 0x12 +#define CHKSUM_VAL 0x0000 + +#if defined(CONFIG_MACH_KEV7A400) +#define CHKSUM_LEN 0x6 +#define START_EEPROM_DATA 0x0000 /* Offset into eeprom for start of data */ +#define CS8900_IRQ_MAP 0x1 /* This IRQ map is fixed (IRQ 0 only)*/ +#else +#define CHKSUM_LEN 0x14 +#define START_EEPROM_DATA 0x001c /* Offset into eeprom for start of data */ +#ifdef CONFIG_SH_HICOSH4 +#define CS8900_IRQ_MAP 0x0002 /* HiCO-SH4 board has its IRQ on #1 */ +#else +#define CS8900_IRQ_MAP 0x1c20 /* This IRQ map is fixed */ +#endif +#endif + +#define IRQ_MAP_EEPROM_DATA 0x0046 /* Offset into eeprom for the IRQ map */ +#define IRQ_MAP_LEN 0x0004 /* No of bytes to read for the IRQ map */ +#define PNP_IRQ_FRMT 0x0022 /* PNP small item IRQ format */ + +#define CS8920_NO_INTS 0x0F /* Max CS8920 interrupt select # */ + +#define PNP_ADD_PORT 0x0279 +#define PNP_WRITE_PORT 0x0A79 + +#define GET_PNP_ISA_STRUCT 0x40 +#define PNP_ISA_STRUCT_LEN 0x06 +#define PNP_CSN_CNT_OFF 0x01 +#define PNP_RD_PORT_OFF 0x02 +#define PNP_FUNCTION_OK 0x00 +#define PNP_WAKE 0x03 +#define PNP_RSRC_DATA 0x04 +#define PNP_RSRC_READY 0x01 +#define PNP_STATUS 0x05 +#define PNP_ACTIVATE 0x30 +#define PNP_CNF_IO_H 0x60 +#define PNP_CNF_IO_L 0x61 +#define PNP_CNF_INT 0x70 +#define PNP_CNF_DMA 0x74 +#define PNP_CNF_MEM 0x48 + +#define BIT0 1 +#define BIT15 0x8000 + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/pcmcia/Config.in linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/Config.in --- linux-2.4.21-rmk1/drivers/pcmcia/Config.in Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/Config.in Thu Oct 16 16:49:37 2003 @@ -31,6 +31,7 @@ if [ "$CONFIG_ARM" = "y" ]; then dep_tristate ' CLPS6700 support' CONFIG_PCMCIA_CLPS6700 $CONFIG_ARCH_CLPS711X $CONFIG_PCMCIA dep_tristate ' SA1100 support' CONFIG_PCMCIA_SA1100 $CONFIG_ARCH_SA1100 $CONFIG_PCMCIA + dep_tristate ' LH7A400 support' CONFIG_PCMCIA_LH7A400 $CONFIG_ARCH_LH7A400 $CONFIG_PCMCIA fi endmenu diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/pcmcia/Makefile linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/Makefile --- linux-2.4.21-rmk1/drivers/pcmcia/Makefile Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/Makefile Sat Oct 18 09:07:38 2003 @@ -85,6 +85,14 @@ sa1100_cs-objs-$(CONFIG_SA1100_XP860) += sa1100_xp860.o sa1111_generic.o sa1100_cs-objs-$(CONFIG_SA1100_YOPY) += sa1100_yopy.o +ifeq ($(CONFIG_PCMCIA_LH7A400),y) +obj-y += lh7a400_generic.o +obj-$(CONFIG_MACH_KEV7A400) += lh7a400_kev7a400.o +obj-$(CONFIG_MACH_EFRAME) += lh7a400_eframe.o +endif + +obj-$(CONFIG_PCMCIA_LH7A400) += lh7a400_generic.o + include $(TOPDIR)/Rules.make pcmcia_core.o: $(pcmcia_core-objs) diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/pcmcia/lh7a400_cs.h linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/lh7a400_cs.h --- linux-2.4.21-rmk1/drivers/pcmcia/lh7a400_cs.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/lh7a400_cs.h Sun Feb 8 20:36:14 2004 @@ -0,0 +1,237 @@ +/*====================================================================== + + Device driver for the PCMCIA control functionality of Sharp + LH7A400 microprocessors. + + The contents of this file are subject to the Mozilla Public + License Version 1.1 (the "License"); you may not use this file + except in compliance with the License. You may obtain a copy of + the License at http://www.mozilla.org/MPL/ + + Software distributed under the License is distributed on an "AS + IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + implied. See the License for the specific language governing + rights and limitations under the License. + + The initial developer of the original code is John G. Dorsey + . Portions created by John G. Dorsey are + Copyright (C) 1999 John G. Dorsey. All Rights Reserved. + + Alternatively, the contents of this file may be used under the + terms of the GNU Public License version 2 (the "GPL"), in which + case the provisions of the GPL are applicable instead of the + above. If you wish to allow the use of your version of this file + only under the terms of the GPL and not to allow others to use + your version of this file under the MPL, indicate your decision + by deleting the provisions above and replace them with the notice + and other provisions required by the GPL. If you do not delete + the provisions above, a recipient may use your version of this + file under either the MPL or the GPL. + +======================================================================*/ + +#if !defined(_PCMCIA_LH7A400_H) +#define _PCMCIA_LH7A400_H + +#include +#include +#include +#include +#include "cs_internal.h" + +#include +#include + +/* + * PCMCIA status word bit definitions + */ +#define PCMCIA_STATUS_PC1_BVD1 _BIT(0) /* slot 1 battery voltage detect 1 */ +#define PCMCIA_STATUS_PC1_BVD2 _BIT(1) /* slot 1 battery voltage detect 2 */ +#define PCMCIA_STATUS_PC1_nVS1 _BIT(2) /* slot 1 voltage select 1 */ +#define PCMCIA_STATUS_PC1_nVS2 _BIT(3) /* slot 1 voltage select 2 */ + +#define PCMCIA_STATUS_PC2_BVD1 _BIT(4) /* slot 2 battery voltage detect 1 */ +#define PCMCIA_STATUS_PC2_BVD2 _BIT(5) /* slot 2 battery voltage detect 2 */ +#define PCMCIA_STATUS_PC2_nVS1 _BIT(6) /* slot 2 voltage select 1 */ +#define PCMCIA_STATUS_PC2_nVS2 _BIT(7) /* slot 2 voltage select 2 */ + +#define PCMCIA_STATUS_PC1_CD _BIT(8) /* slot 1 card detect */ +#define PCMCIA_STATUS_PC2_CD _BIT(9) /* slot 1 card detect */ + + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +/* + * Modify a PCMCIA configuration register. + * + * 'reg' points to the right register + * {attribute, common, io} for the right slot {0,1}. + */ +static inline void +pcmcia_register_set( volatile u32 *reg, int pcmcia_cycle_ns, int hclk_khz) +{ + int cycle_ns = 1000000 / hclk_khz; + int accessTime, holdTime, preChargeTime; + int access_ns, hold_ns, preCharge_ns; + + access_ns = MAX(pcmcia_cycle_ns + cycle_ns, 165); + hold_ns = MAX((access_ns + cycle_ns) / 3, 20); + preCharge_ns = MAX((access_ns + cycle_ns) / 2, 70); + +#if 0 // DDD try these timings + hold_ns = access_ns; + preCharge_ns = access_ns; +#endif + + accessTime = (access_ns * hclk_khz ) / 1000000; + holdTime = (hold_ns * hclk_khz ) / 1000000; + preChargeTime = (preCharge_ns * hclk_khz ) / 1000000; + holdTime = MIN( holdTime, 15); + +#if 0 // DDD + printk( " ns: precharge=%d access=%d hold=%d\n", preCharge_ns, access_ns, hold_ns); + printk( "time: precharge=%d access=%d hold=%d\n\n", preChargeTime, accessTime, holdTime); +#endif + + *reg = PCMCIA_CFG_W16 | + PCMCIA_CFG_AC( accessTime -1) | + PCMCIA_CFG_HT( holdTime) | + PCMCIA_CFG_PC( preChargeTime -1); +} + +#define PCMCIA_ATTRIB_SET( sock, speed, clock) \ + pcmcia_register_set( &((smcRegs_t *)IO_ADDRESS(SMC_REGS_PHYS))->slot[sock].attribute, (speed), (clock)) + +#define PCMCIA_MEMORY_SET( sock, speed, clock) \ + pcmcia_register_set( &((smcRegs_t *)IO_ADDRESS(SMC_REGS_PHYS))->slot[sock].common, (speed), (clock)) + +#define PCMCIA_IO_SET( sock, speed, clock) \ + pcmcia_register_set( &((smcRegs_t *)IO_ADDRESS(SMC_REGS_PHYS))->slot[sock].io, (speed), (clock)) + +#define TIME2NS(val, clock) (((val) * 1000000) / (clock)) + +#define GET_AC(reg) ((((reg) >> PCMCIA_CFG_AC_SHIFT) & 0xFF) + 1 ) +#define GET_HT(reg) ((((reg) >> PCMCIA_CFG_HT_SHIFT) & 0x0F) + 0 ) +#define GET_PC(reg) ((((reg) >> PCMCIA_CFG_PC_SHIFT) & 0xFF) + 1 ) + + +/* + * The PC Card Standard, Release 7, section 4.13.4, says that twIORD + * has a minimum value of 165ns. Section 4.13.5 says that twIOWR has + * a minimum value of 165ns, as well. Section 4.7.2 (describing + * common and attribute memory write timing) says that twWE has a + * minimum value of 150ns for a 250ns cycle time (for 5V operation; + * see section 4.7.4), or 300ns for a 600ns cycle time (for 3.3V + * operation, also section 4.7.4). Section 4.7.3 says that taOE + * has a maximum value of 150ns for a 300ns cycle time (for 5V + * operation), or 300ns for a 600ns cycle time (for 3.3V operation). + * + * When configuring memory maps, Card Services appears to adopt the policy + * that a memory access time of "0" means "use the default." The default + * PCMCIA I/O command width time is 165ns. The default PCMCIA 5V attribute + * and memory command width time is 150ns; the PCMCIA 3.3V attribute and + * memory command width time is 300ns. + */ +#define LH7A400_PCMCIA_IO_ACCESS (165) +#define LH7A400_PCMCIA_5V_MEM_ACCESS (150) +#define LH7A400_PCMCIA_3V_MEM_ACCESS (300) + + +/* The socket driver actually works nicely in interrupt-driven form, + * so the (relatively infrequent) polling is "just to be sure." + */ +#define LH7A400_PCMCIA_POLL_PERIOD (2*HZ) + +struct pcmcia_init { + void (*handler)(int irq, void *dev, struct pt_regs *regs); +}; + +struct pcmcia_state { + unsigned detect: 1, + ready: 1, + bvd1: 1, + bvd2: 1, + wrprot: 1, + vs_3v: 1, + vs_Xv: 1; +}; + +struct pcmcia_state_array { + unsigned int size; + struct pcmcia_state *state; +}; + +struct pcmcia_configure { + unsigned sock: 8, + vcc: 8, + vpp: 8, + output: 1, + speaker: 1, + reset: 1, + irq: 1; +}; + +struct pcmcia_irq_info { + unsigned int sock; + unsigned int irq; +}; + +/* This structure encapsulates per-socket state which we might need to + * use when responding to a Card Services query of some kind. + */ +struct lh7a400_pcmcia_socket { + socket_state_t cs_state; + struct pcmcia_state k_state; + unsigned int irq; + void (*handler)(void *, unsigned int); + void *handler_info; + pccard_io_map io_map[MAX_IO_WIN]; + pccard_mem_map mem_map[MAX_WIN]; + ioaddr_t virt_io, phys_attr, phys_mem; + unsigned short speed_io, speed_attr, speed_mem; +}; + +struct pcmcia_low_level { + int (*init)(struct pcmcia_init *); + int (*shutdown)(void); + int (*socket_state)(struct pcmcia_state_array *); + int (*get_irq_info)(struct pcmcia_irq_info *); + int (*configure_socket)(const struct pcmcia_configure *); + +#if 0 + /* + * Enable card status IRQs on (re-)initialisation. This can + * be called at initialisation, power management event, or + * pcmcia event. + */ + int (*socket_init)(int sock); + + /* + * Disable card status IRQs and PCMCIA bus on suspend. + */ + int (*socket_suspend)(int sock); +#endif +}; + +extern struct pcmcia_low_level *pcmcia_low_level; + + +/* I/O pins replacing memory pins + * (PCMCIA System Architecture, 2nd ed., by Don Anderson, p.75) + * + * These signals change meaning when going from memory-only to + * memory-or-I/O interface: + */ +#define iostschg bvd1 +#define iospkr bvd2 + +#if defined(CONFIG_MACH_KEV7A400) +extern struct pcmcia_low_level kev7a400_pcmcia_ops; +#elif defined(CONFIG_MACH_EFRAME) +extern struct pcmcia_low_level eframe_pcmcia_ops; +#else +error unknown LH7A400 board +#endif + +#endif /* !defined(_PCMCIA_LH7A400_H) */ diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/pcmcia/lh7a400_eframe.c linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/lh7a400_eframe.c --- linux-2.4.21-rmk1/drivers/pcmcia/lh7a400_eframe.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/lh7a400_eframe.c Fri Nov 28 09:39:13 2003 @@ -0,0 +1,223 @@ +/* + * driver/pcmcia/lh7a400_eframe.c + * + * PCMCIA control functionality specific to the eframe + * + * Copyright (C) Brad Parker + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +#include +#include +#include + +#include + +static int +eframe_pcmcia_init(struct pcmcia_init *init) +{ + int irq, rc; + smcRegs_t *smc = (smcRegs_t *)IO_ADDRESS(SMC_REGS_PHYS); + + if (1) printk("eframe_pcmcia_init()\n"); + + /* enable one slot, enable wait states, and set Auto nPREG */ + smc->pcmciaCtl = PCMCIA_CTL_PC | PCMCIA_CTL_WEN1 | PCMCIA_CTL_AUTOPREG; + + /* # of sockets */ + return 1; +} + +static int +eframe_pcmcia_shutdown(void) +{ + if (1) printk("eframe_pcmcia_shutdown()\n"); + + return 0; +} + +static int +eframe_pcmcia_socket_state(struct pcmcia_state_array *state_array) +{ + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + u32 status; + + /* if no card is inserted, don't read status */ + if (gpio->pfdr & GPIOF_INT_PC_CD1) { + status = PCMCIA_STATUS_PC1_CD; + } else { + status = *(volatile u16 *)PCMCIA_IO_1_BASE+2; + status = *(volatile u32 *)PCMCIA_STATUS_BASE; + } + + if (1) printk("eframe_pcmcia_socket_state() status=0x%x\n", status); + + if (state_array->size < 2) + return -1; + +#define ASSERTS_LOW(mask) ( ((status & mask) == 0) ? 1 : 0 ) +#define ASSERTS_HIGH(mask) ( ((status & mask) != 0) ? 1 : 0 ) + + memset(state_array->state, 0, + (state_array->size)*sizeof(struct pcmcia_state)); + + state_array->state[0].detect = ASSERTS_LOW(PCMCIA_STATUS_PC1_CD); +#if 0 + state_array->state[0].ready = ASSERTS_LOW(PCMCIA_STATUS_PC1_CD); +#else + state_array->state[0].ready = + (gpio->pfdr & GPIOF_INT_PC_SLOT1) ? 1 : 0; +#endif + state_array->state[0].bvd1 = ASSERTS_HIGH(PCMCIA_STATUS_PC1_BVD1); + state_array->state[0].bvd2 = ASSERTS_HIGH(PCMCIA_STATUS_PC1_BVD2); + state_array->state[0].vs_3v = ASSERTS_LOW(PCMCIA_STATUS_PC1_nVS1); + state_array->state[0].vs_Xv = ASSERTS_LOW(PCMCIA_STATUS_PC1_nVS2); + state_array->state[0].wrprot = 0; + + return 1; +} + +static int +eframe_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + if (1) printk("eframe_pcmcia_get_irq_info() socket=%d\n", info->sock); + + if (info->sock > 1) + return -1; + + info->irq = info->sock == 0 ? IRQ_PCMCIA1 : IRQ_PCMCIA2; + + return 0; +} + +static int old_volts; + +static void +eframe_set_pcmcia_voltage(int volts) +{ + volatile u32 *cpld = (volatile u32 *)CPLD_BASE; + + if (volts && volts == old_volts) + return; + + switch (volts) { + case 0: + cpld[CPLD_CTRL_RESET] = + CPLD_CTRL_PCMCIA_PWR1 | CPLD_CTRL_PCMCIA_PWR2; + break; + case 1: + cpld[CPLD_CTRL_RESET] = + CPLD_CTRL_PCMCIA_PWR1 | CPLD_CTRL_PCMCIA_PWR2; + cpld[CPLD_CTRL_SET] = + CPLD_CTRL_PCMCIA_PWR1; + break; + case 2: + cpld[CPLD_CTRL_RESET] = + CPLD_CTRL_PCMCIA_PWR1 | CPLD_CTRL_PCMCIA_PWR2; + cpld[CPLD_CTRL_SET] = + CPLD_CTRL_PCMCIA_PWR2; + break; + } +} + +static int +eframe_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + unsigned long flags; + u16 clearVcc, setVcc; + + + if (configure->sock > 2) + return -1; + + if (1) printk("eframe_pcmcia_configure_socket()" + " socket=%d Vcc=%d reset=%d\n", + configure->sock, configure->vcc, configure->reset); + + save_flags_cli(flags); + + /* + * set socket voltage + */ + switch (configure->vcc) { + case 0: + eframe_set_pcmcia_voltage(0); + break; + + case 33: + eframe_set_pcmcia_voltage(1); + break; + + case 50: + eframe_set_pcmcia_voltage(2); + break; + + default: + printk("lh7a400: Attempt to set bad Vcc (%d) on socket %d\n", + configure->vcc, configure->sock); + restore_flags(flags); + return -1; + } + + + if (configure->reset) { + smcRegs_t *smc = (smcRegs_t *)IO_ADDRESS(SMC_REGS_PHYS); + u32 reset = configure->sock == 0 ? + PCMCIA_CTL_PC1RST : PCMCIA_CTL_PC2RST; + + smc->pcmciaCtl |= reset; + mdelay(10); + + smc->pcmciaCtl &= ~reset; + mdelay(10); + } + + /* Silently ignore Vpp, output enable, speaker enable */ + + restore_flags(flags); + + return 0; +} + +struct pcmcia_low_level eframe_pcmcia_ops = { + eframe_pcmcia_init, + eframe_pcmcia_shutdown, + eframe_pcmcia_socket_state, + eframe_pcmcia_get_irq_info, + eframe_pcmcia_configure_socket +}; + + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/pcmcia/lh7a400_generic.c linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/lh7a400_generic.c --- linux-2.4.21-rmk1/drivers/pcmcia/lh7a400_generic.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/lh7a400_generic.c Sat Oct 18 09:58:50 2003 @@ -0,0 +1,1094 @@ +/* + * drivers/pcmcia/lh7a400_generic.c + * + * Device driver for the PCMCIA control functionality of the Sharp + * LH7A400 SoC. + * + * Portions Copyright (C) 2003 Embedix Inc. + * + * Based on sa1100_generic.c, which is + * Copyright (C) 1999 John G. Dorsey. All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The initial developer of the original code is John G. Dorsey + * . Portions created by John G. Dorsey are + * Copyright (C) 1999 John G. Dorsey. All Rights Reserved. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU Public License version 2 (the "GPL"), in which + * case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use + * your version of this file under the MPL, indicate your decision + * by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL. If you do not delete + * the provisions above, a recipient may use your version of this + * file under either the MPL or the GPL. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifdef CONFIG_CPU_FREQ +#include +#endif + +#include "lh7a400_cs.h" + +#define PCMCIA_DEBUG 0 + +#ifdef PCMCIA_DEBUG +static int pc_debug = PCMCIA_DEBUG; +MODULE_PARM(pc_debug, "i"); +#undef DEBUG +#define DEBUG(n, args...) if (pc_debug > (n)) printk(args) +#endif + +MODULE_AUTHOR("Brad Parker, Heeltoe Consulting "); +MODULE_DESCRIPTION("Linux PCMCIA Card Services: Sharp LH7A400 Socket Controller"); + + +/* This structure maintains housekeeping state for each socket, such + * as the last known values of the card detect pins, or the Card Services + * callback value associated with the socket: + */ +#define LH7A400_PCMCIA_MAX_SOCK (2) + +static struct lh7a400_pcmcia_socket +lh7a400_pcmcia_socket[LH7A400_PCMCIA_MAX_SOCK]; + +static int lh7a400_pcmcia_socket_count; + + +/* Returned by the low-level PCMCIA interface: */ +static struct pcmcia_low_level *pcmcia_low_level; + +/* Event poll timer structure */ +static struct timer_list poll_timer; + + +/* Prototypes for routines which are used internally: */ + +static int lh7a400_pcmcia_driver_init(void); +static void lh7a400_pcmcia_driver_shutdown(void); +static void lh7a400_pcmcia_task_handler(void *data); +static void lh7a400_pcmcia_poll_event(unsigned long data); +static void lh7a400_pcmcia_interrupt(int irq, void *dev, + struct pt_regs *regs); +static struct tq_struct lh7a400_pcmcia_task; + +#ifdef CONFIG_PROC_FS +static int lh7a400_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data); +#endif + + +/* Prototypes for operations which are exported to the + * new-and-impr^H^H^H^H^H^H^H^H^H^H in-kernel PCMCIA core: + */ + +static int lh7a400_pcmcia_init(unsigned int sock); +static int lh7a400_pcmcia_suspend(unsigned int sock); +static int lh7a400_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), + void *info); +static int lh7a400_pcmcia_inquire_socket(unsigned int sock, + socket_cap_t *cap); +static int lh7a400_pcmcia_get_status(unsigned int sock, u_int *value); +static int lh7a400_pcmcia_get_socket(unsigned int sock, + socket_state_t *state); +static int lh7a400_pcmcia_set_socket(unsigned int sock, + socket_state_t *state); +static int lh7a400_pcmcia_get_io_map(unsigned int sock, + struct pccard_io_map *io); +static int lh7a400_pcmcia_set_io_map(unsigned int sock, + struct pccard_io_map *io); +static int lh7a400_pcmcia_get_mem_map(unsigned int sock, + struct pccard_mem_map *mem); +static int lh7a400_pcmcia_set_mem_map(unsigned int sock, + struct pccard_mem_map *mem); +#ifdef CONFIG_PROC_FS +static void lh7a400_pcmcia_proc_setup(unsigned int sock, + struct proc_dir_entry *base); +#endif + +static struct pccard_operations lh7a400_pcmcia_operations = { + lh7a400_pcmcia_init, + lh7a400_pcmcia_suspend, + lh7a400_pcmcia_register_callback, + lh7a400_pcmcia_inquire_socket, + lh7a400_pcmcia_get_status, + lh7a400_pcmcia_get_socket, + lh7a400_pcmcia_set_socket, + lh7a400_pcmcia_get_io_map, + lh7a400_pcmcia_set_io_map, + lh7a400_pcmcia_get_mem_map, + lh7a400_pcmcia_set_mem_map, +#ifdef CONFIG_PROC_FS + lh7a400_pcmcia_proc_setup +#endif +}; + +#ifdef CONFIG_CPU_FREQ +/* forward declaration */ +static struct notifier_block lh7a400_pcmcia_notifier_block; +#endif + + + + + + +/* lh7a400_pcmcia_driver_init() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * + * This routine performs a basic sanity check to ensure that this + * kernel has been built with the appropriate board-specific low-level + * PCMCIA support, performs low-level PCMCIA initialization, registers + * this socket driver with Card Services, and then spawns the daemon + * thread which is the real workhorse of the socket driver. + * + * Please see linux/Documentation/arm/SA1100/PCMCIA for more information + * on the low-level kernel interface. + * + * Returns: 0 on success, -1 on error + */ +static int __init +lh7a400_pcmcia_driver_init(void) +{ + servinfo_t info; + struct pcmcia_init pcmcia_init; + struct pcmcia_state state[LH7A400_PCMCIA_MAX_SOCK]; + struct pcmcia_state_array state_array; + unsigned int i, clock; + + printk(KERN_INFO "Sharp LH7A400 PCMCIA (CS release %s)\n", CS_RELEASE); + + CardServices(GetCardServicesInfo, &info); + + if (info.Revision != CS_RELEASE_CODE) { + printk(KERN_ERR "Card Services release codes do not match\n"); + return -1; + } + +#if defined(CONFIG_MACH_KEV7A400) + pcmcia_low_level = &kev7a400_pcmcia_ops; +#elif defined(CONFIG_MACH_EFRAME) + pcmcia_low_level = &eframe_pcmcia_ops; +#else +#error Unsupported LH7A400 board. +#endif + + if (!pcmcia_low_level) { + printk(KERN_ERR "This hardware is not supported by the " + "LH7A400 Card Service driver\n"); + return -ENODEV; + } + + pcmcia_init.handler = lh7a400_pcmcia_interrupt; + + lh7a400_pcmcia_socket_count = pcmcia_low_level->init(&pcmcia_init); + if (lh7a400_pcmcia_socket_count < 0) { + printk(KERN_ERR + "Unable to initialize kernel PCMCIA service.\n"); + return -EIO; + } + + state_array.size = lh7a400_pcmcia_socket_count; + state_array.state = state; + + if (pcmcia_low_level->socket_state(&state_array) < 0) { + printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + return -EIO; + } + + clock = hclkfreq_get(); + + for (i = 0; i < lh7a400_pcmcia_socket_count; ++i) { + struct lh7a400_pcmcia_socket *psock = + &lh7a400_pcmcia_socket[i]; + + psock->k_state = state[i]; + + /* + * This is an interim fix. Apparently, SetSocket is no longer + * called to initialize each socket (prior to the first detect + * event). For now, we'll just manually set up the mask. + */ + psock->cs_state.csc_mask = SS_DETECT; + + psock->virt_io = (i == 0) ? + PCMCIA_IO_0_BASE : PCMCIA_IO_1_BASE; + psock->phys_attr = (i == 0) ? + PCMCIA_ATTR_0_START : PCMCIA_ATTR_1_START; + psock->phys_mem = (i == 0) ? + PCMCIA_MEM_0_START : PCMCIA_MEM_1_START; + + PCMCIA_IO_SET(i, LH7A400_PCMCIA_IO_ACCESS, clock); + PCMCIA_ATTRIB_SET(i, LH7A400_PCMCIA_5V_MEM_ACCESS, clock); + PCMCIA_MEMORY_SET(i, LH7A400_PCMCIA_5V_MEM_ACCESS, clock); + + psock->speed_io = LH7A400_PCMCIA_IO_ACCESS; + psock->speed_attr = LH7A400_PCMCIA_5V_MEM_ACCESS; + psock->speed_mem = LH7A400_PCMCIA_5V_MEM_ACCESS; + } + +#ifdef CONFIG_CPU_FREQ + if (hclkfreq_register_notifier(&lh7a400_pcmcia_notifier_block) < 0) { + printk(KERN_ERR + "Unable to register HCLK frequency change notifier\n"); + return -ENXIO; + } +#endif + + /* Only advertise as many sockets as we can detect: */ + if (register_ss_entry(lh7a400_pcmcia_socket_count, + &lh7a400_pcmcia_operations) < 0) + { + printk(KERN_ERR "Unable to register socket service routine\n"); + return -ENXIO; + } + + /* Start the event poll timer. will reschedule by itself afterwards. */ + lh7a400_pcmcia_poll_event(0); + + DEBUG(1, "lh7a400_cs: initialization complete\n"); + + return 0; + +} /* lh7a400_pcmcia_driver_init() */ + + +/* lh7a400_pcmcia_driver_shutdown() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Invokes the low-level kernel service to free IRQs associated with this + * socket controller and reset GPIO edge detection. + */ +static void __exit +lh7a400_pcmcia_driver_shutdown(void) +{ + del_timer_sync(&poll_timer); + unregister_ss_entry(&lh7a400_pcmcia_operations); +#ifdef CONFIG_CPU_FREQ + hclkfreq_unregister_notifier(&lh7a400_pcmcia_notifier_block); +#endif + pcmcia_low_level->shutdown(); + flush_scheduled_tasks(); + + DEBUG(1, "lh7a400_cs: shutdown complete\n"); +} + +module_exit(lh7a400_pcmcia_driver_shutdown); + + +/* lh7a400_pcmcia_init() + * ^^^^^^^^^^^^^^^^^^^^ + * We perform all of the interesting initialization tasks in + * lh7a400_pcmcia_driver_init(). + * + * Returns: 0 + */ +static int +lh7a400_pcmcia_init(unsigned int sock) +{ + DEBUG(2, "%s(): initializing socket %u\n", __FUNCTION__, sock); + + return 0; +} + + +/* lh7a400_pcmcia_suspend() + * ^^^^^^^^^^^^^^^^^^^^^^^ + * We don't currently perform any actions on a suspend. + * + * Returns: 0 + */ +static int lh7a400_pcmcia_suspend(unsigned int sock) +{ + struct pcmcia_configure conf; + int ret; + + DEBUG(2, "%s(): suspending socket %u\n", __FUNCTION__, sock); + + conf.sock = sock; + conf.vcc = 0; + conf.vpp = 0; + conf.output = 0; + conf.speaker = 0; + conf.reset = 1; + + ret = pcmcia_low_level->configure_socket(&conf); + + if (ret == 0) + lh7a400_pcmcia_socket[sock].cs_state = dead_socket; + + return ret; +} + + +/* lh7a400_pcmcia_events() + * ^^^^^^^^^^^^^^^^^^^^^^ + * Helper routine to generate a Card Services event mask based on + * state information obtained from the kernel low-level PCMCIA layer + * in a recent (and previous) sampling. Updates `prev_state'. + * + * Returns: an event mask for the given socket state. + */ +static inline unsigned lh7a400_pcmcia_events(struct pcmcia_state *state, + struct pcmcia_state *prev_state, + unsigned int mask, + unsigned int flags) +{ + unsigned int events = 0; + + if (state->detect != prev_state->detect) { + DEBUG(2, "%s(): card detect value %u\n", + __FUNCTION__, state->detect); + events |= mask & SS_DETECT; + } + + if (state->ready != prev_state->ready) { + DEBUG(2, "%s(): card ready value %u\n", + __FUNCTION__, state->ready); + events |= mask & ((flags & SS_IOCARD) ? 0:SS_READY); + } + + if (state->bvd1 != prev_state->bvd1) { + DEBUG(2, "%s(): card BVD1 value %u\n", + __FUNCTION__, state->bvd1); + events |= mask & (flags & SS_IOCARD) ? SS_STSCHG:SS_BATDEAD; + } + + if (state->bvd2 != prev_state->bvd2) { + DEBUG(2, "%s(): card BVD2 value %u\n", + __FUNCTION__, state->bvd2); + events |= mask & (flags & SS_IOCARD) ? 0:SS_BATWARN; + } + + DEBUG(3, "events: %s%s%s%s%s%s\n", + (events == 0) ? "":"", + (events & SS_DETECT) ? "DETECT ":"", + (events & SS_READY) ? "READY ":"", + (events & SS_BATDEAD) ? "BATDEAD ":"", + (events & SS_BATWARN) ? "BATWARN ":"", + (events & SS_STSCHG) ? "STSCHG ":""); + + *prev_state = *state; + + return events; +} /* lh7a400_pcmcia_events() */ + + +/* lh7a400_pcmcia_task_handler() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Processes serviceable socket events using the "eventd" thread context. + * + * Event processing (specifically, the invocation of the Card Services event + * callback) occurs in this thread rather than in the actual interrupt + * handler due to the use of scheduling operations in the PCMCIA core. + */ +static void +lh7a400_pcmcia_task_handler(void *data) +{ + struct pcmcia_state state[LH7A400_PCMCIA_MAX_SOCK]; + struct pcmcia_state_array state_array; + int i, events, all_events, irq_status; + + DEBUG(4, "%s(): entering PCMCIA monitoring thread\n", __FUNCTION__); + + state_array.size = lh7a400_pcmcia_socket_count; + state_array.state = state; + + do { + + DEBUG(3, "%s(): interrogating low-level PCMCIA service\n", + __FUNCTION__); + + irq_status = pcmcia_low_level->socket_state(&state_array); + if (irq_status < 0) { + printk(KERN_ERR + "Error in kernel low-level PCMCIA service.\n"); + } + + all_events = 0; + + if (irq_status <= 0) + break; + + for (i = 0; i < state_array.size; ++i, all_events |= events) + { + struct lh7a400_pcmcia_socket *psock = + &lh7a400_pcmcia_socket[i]; + + if ((events = lh7a400_pcmcia_events( + &state[i], + &psock->k_state, + psock->cs_state.csc_mask, + psock->cs_state.flags))) + { + if (psock->handler != NULL) + psock->handler(psock->handler_info, + events); + } + } + } while (all_events); + +} /* lh7a400_pcmcia_task_handler() */ + +static struct tq_struct lh7a400_pcmcia_task = { + routine: lh7a400_pcmcia_task_handler +}; + + +/* lh7a400_pcmcia_poll_event() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Let's poll for events in addition to IRQs since IRQ only is unreliable... + */ +static void lh7a400_pcmcia_poll_event(unsigned long dummy) +{ + DEBUG(3, "%s(): polling for events\n", __FUNCTION__); + poll_timer.function = lh7a400_pcmcia_poll_event; + poll_timer.expires = jiffies + LH7A400_PCMCIA_POLL_PERIOD; + add_timer(&poll_timer); + schedule_task(&lh7a400_pcmcia_task); +} + + +/* lh7a400_pcmcia_interrupt() + * ^^^^^^^^^^^^^^^^^^^^^^^^^ + * Service routine for socket driver interrupts (requested by the + * low-level PCMCIA init() operation via lh7a400_pcmcia_thread()). + * The actual interrupt-servicing work is performed by + * lh7a400_pcmcia_thread(), largely because the Card Services event- + * handling code performs scheduling operations which cannot be + * executed from within an interrupt context. + */ +static void lh7a400_pcmcia_interrupt(int irq, void *dev, struct pt_regs *regs) { + DEBUG(3, "%s(): servicing IRQ %d\n", __FUNCTION__, irq); + schedule_task(&lh7a400_pcmcia_task); +} + + +/* lh7a400_pcmcia_register_callback() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the register_callback() operation for the in-kernel + * PCMCIA service (formerly SS_RegisterCallback in Card Services). If + * the function pointer `handler' is not NULL, remember the callback + * location in the state for `sock', and increment the usage counter + * for the driver module. (The callback is invoked from the interrupt + * service routine, lh7a400_pcmcia_interrupt(), to notify Card Services + * of interesting events.) Otherwise, clear the callback pointer in the + * socket state and decrement the module usage count. + * + * Returns: 0 + */ +static int +lh7a400_pcmcia_register_callback(unsigned int sock, + void (*handler)(void *, unsigned int), + void *info) +{ + if (handler == NULL) { + lh7a400_pcmcia_socket[sock].handler = NULL; + MOD_DEC_USE_COUNT; + } else { + MOD_INC_USE_COUNT; + lh7a400_pcmcia_socket[sock].handler = handler; + lh7a400_pcmcia_socket[sock].handler_info = info; + } + + return 0; +} + + +/* lh7a400_pcmcia_inquire_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the inquire_socket() operation for the in-kernel PCMCIA + * service (formerly SS_InquireSocket in Card Services). Of note is + * the setting of the SS_CAP_PAGE_REGS bit in the `features' field of + * `cap' to "trick" Card Services into tolerating large "I/O memory" + * addresses. Also set is SS_CAP_STATIC_MAP, which disables the memory + * resource database check. (Mapped memory is set up within the socket + * driver itself.) + * + * In conjunction with the STATIC_MAP capability is a new field, + * `io_offset', recommended by David Hinds. Rather than go through + * the SetIOMap interface (which is not quite suited for communicating + * window locations up from the socket driver), we just pass up + * an offset which is applied to client-requested base I/O addresses + * in alloc_io_space(). + * + * Returns: 0 on success, -1 if no pin has been configured for `sock' + */ +static int lh7a400_pcmcia_inquire_socket(unsigned int sock, + socket_cap_t *cap) +{ + struct pcmcia_irq_info irq_info; + + DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + + if (sock >= lh7a400_pcmcia_socket_count) { + printk(KERN_ERR "lh7a400: socket %u not configured\n", sock); + return -1; + } + + /* SS_CAP_PAGE_REGS: used by setup_cis_mem() in cistpl.c to set the + * force_low argument to validate_mem() in rsrc_mgr.c -- since in + * general, the mapped * addresses of the PCMCIA memory regions + * will not be within 0xffff, setting force_low would be + * undesirable. + * + * SS_CAP_STATIC_MAP: don't bother with the (user-configured) memory + * resource database; we instead pass up physical address ranges + * and allow other parts of Card Services to deal with remapping. + * + * SS_CAP_PCCARD: we can deal with 16-bit PCMCIA & CF cards, but + * not 32-bit CardBus devices. + */ + cap->features = (SS_CAP_PAGE_REGS | SS_CAP_STATIC_MAP | SS_CAP_PCCARD); + + irq_info.sock = sock; + irq_info.irq = -1; + + if (pcmcia_low_level->get_irq_info(&irq_info) < 0) { + printk(KERN_ERR "Error obtaining IRQ info from kernel for socket %u\n", sock); + return -1; + } + + cap->irq_mask = 0; + cap->map_size = PAGE_SIZE; + cap->pci_irq = irq_info.irq; + cap->io_offset = lh7a400_pcmcia_socket[sock].virt_io; + + return 0; + +} /* lh7a400_pcmcia_inquire_socket() */ + + +/* lh7a400_pcmcia_get_status() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_status() operation for the in-kernel PCMCIA + * service (formerly SS_GetStatus in Card Services). Essentially just + * fills in bits in `status' according to internal driver state or + * the value of the voltage detect chipselect register. + * + * As a debugging note, during card startup, the PCMCIA core issues + * three set_socket() commands in a row the first with RESET deasserted, + * the second with RESET asserted, and the last with RESET deasserted + * again. Following the third set_socket(), a get_status() command will + * be issued. The kernel is looking for the SS_READY flag (see + * setup_socket(), reset_socket(), and unreset_socket() in cs.c). + * + * Returns: 0 + */ +static int lh7a400_pcmcia_get_status(unsigned int sock, + unsigned int *status) +{ + struct pcmcia_state state[LH7A400_PCMCIA_MAX_SOCK]; + struct pcmcia_state_array state_array; + + DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + + state_array.size = lh7a400_pcmcia_socket_count; + state_array.state = state; + + if ((pcmcia_low_level->socket_state(&state_array)) < 0) { + printk(KERN_ERR "Unable to get PCMCIA status from kernel.\n"); + return -1; + } + + lh7a400_pcmcia_socket[sock].k_state = state[sock]; + + *status = state[sock].detect ? SS_DETECT:0; + + *status |= state[sock].ready ? SS_READY:0; + + /* The power status of individual sockets is not available + * explicitly from the hardware, so we just remember the state + * and regurgitate it upon request: + */ + *status |= lh7a400_pcmcia_socket[sock].cs_state.Vcc ? SS_POWERON:0; + + if (lh7a400_pcmcia_socket[sock].cs_state.flags & SS_IOCARD) { + *status |= state[sock].bvd1 ? SS_STSCHG:0; + }else { + if (state[sock].bvd1 == 0) + *status |= SS_BATDEAD; + else if (state[sock].bvd2 == 0) + *status |= SS_BATWARN; + } + + *status |= state[sock].vs_3v ? SS_3VCARD:0; + + *status |= state[sock].vs_Xv ? SS_XVCARD:0; + + DEBUG(1, "\tstatus: %s%s%s%s%s%s%s%s\n", + (*status & SS_DETECT) ? "DETECT ":"", + (*status & SS_READY) ? "READY ":"", + (*status & SS_BATDEAD) ? "BATDEAD ":"", + (*status & SS_BATWARN) ? "BATWARN ":"", + (*status & SS_POWERON) ? "POWERON ":"", + (*status & SS_STSCHG) ? "STSCHG ":"", + (*status & SS_3VCARD) ? "3VCARD ":"", + (*status & SS_XVCARD) ? "XVCARD ":""); + + return 0; + +} /* lh7a400_pcmcia_get_status() */ + + +/* lh7a400_pcmcia_get_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_socket() operation for the in-kernel PCMCIA + * service (formerly SS_GetSocket in Card Services). Not a very + * exciting routine. + * + * Returns: 0 + */ +static int lh7a400_pcmcia_get_socket(unsigned int sock, + socket_state_t *state) +{ + DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + + /* This information was given to us in an earlier call to set_socket(), + * so we're just regurgitating it here: + */ + *state = lh7a400_pcmcia_socket[sock].cs_state; + + return 0; +} + + +/* lh7a400_pcmcia_set_socket() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_socket() operation for the in-kernel PCMCIA + * service (formerly SS_SetSocket in Card Services). We more or + * less punt all of this work and let the kernel handle the details + * of power configuration, reset, &c. We also record the value of + * `state' in order to regurgitate it to the PCMCIA core later. + * + * Returns: 0 + */ +static int lh7a400_pcmcia_set_socket(unsigned int sock, + socket_state_t *state) +{ + struct pcmcia_configure configure; + + DEBUG(3, "%s() for sock %u\n", __FUNCTION__, sock); + + DEBUG(3, "\tmask: %s%s%s%s%s%s\n\tflags: %s%s%s%s%s%s\n" + "\tVcc %d Vpp %d irq %d\n", + (state->csc_mask == 0) ? "":"", + (state->csc_mask & SS_DETECT) ? "DETECT ":"", + (state->csc_mask & SS_READY) ? "READY ":"", + (state->csc_mask & SS_BATDEAD) ? "BATDEAD ":"", + (state->csc_mask & SS_BATWARN) ? "BATWARN ":"", + (state->csc_mask & SS_STSCHG) ? "STSCHG ":"", + (state->flags == 0) ? "":"", + (state->flags & SS_PWR_AUTO) ? "PWR_AUTO ":"", + (state->flags & SS_IOCARD) ? "IOCARD ":"", + (state->flags & SS_RESET) ? "RESET ":"", + (state->flags & SS_SPKR_ENA) ? "SPKR_ENA ":"", + (state->flags & SS_OUTPUT_ENA) ? "OUTPUT_ENA ":"", + state->Vcc, state->Vpp, state->io_irq); + + configure.sock = sock; + configure.vcc = state->Vcc; + configure.vpp = state->Vpp; + configure.output = (state->flags & SS_OUTPUT_ENA) ? 1:0; + configure.speaker = (state->flags & SS_SPKR_ENA) ? 1:0; + configure.reset = (state->flags & SS_RESET) ? 1:0; + + if (pcmcia_low_level->configure_socket(&configure) < 0) { + printk(KERN_ERR "Unable to configure socket %u\n", sock); + return -1; + } + + lh7a400_pcmcia_socket[sock].cs_state = *state; + + return 0; +} /* lh7a400_pcmcia_set_socket() */ + + +/* lh7a400_pcmcia_get_io_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_io_map() operation for the in-kernel PCMCIA + * service (formerly SS_GetIOMap in Card Services). Just returns an + * I/O map descriptor which was assigned earlier by a set_io_map(). + * + * Returns: 0 on success, -1 if the map index was out of range + */ +static int lh7a400_pcmcia_get_io_map(unsigned int sock, + struct pccard_io_map *map) +{ + DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + + if (map->map >= MAX_IO_WIN) { + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + *map = lh7a400_pcmcia_socket[sock].io_map[map->map]; + + return 0; +} + + +/* lh7a400_pcmcia_set_io_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_io_map() operation for the in-kernel PCMCIA + * service (formerly SS_SetIOMap in Card Services). We configure + * the map speed as requested, but override the address ranges + * supplied by Card Services. + * + * Returns: 0 on success, -1 on error + */ +static int +lh7a400_pcmcia_set_io_map(unsigned int sock, struct pccard_io_map *map) +{ + unsigned int clock, speed; + unsigned long start; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + DEBUG(2, "\tmap %u speed %u\n\tstart 0x%08x stop 0x%08x\n" + "\tflags: %s%s%s%s%s%s%s%s\n", + map->map, map->speed, (u32)map->start, (u32)map->stop, + (map->flags == 0) ? "" : "", + (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", + (map->flags & MAP_16BIT) ? "16BIT " : "", + (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", + (map->flags & MAP_0WS) ? "0WS " : "", + (map->flags & MAP_WRPROT) ? "WRPROT " : "", + (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : "", + (map->flags & MAP_PREFETCH) ? "PREFETCH " : ""); + + if (map->map >= MAX_IO_WIN) { + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + if (map->flags & MAP_ACTIVE) { + + speed = (map->speed > 0) ? map->speed : + LH7A400_PCMCIA_IO_ACCESS; + + clock = hclkfreq_get(); + + PCMCIA_IO_SET(sock, speed, clock); + + { + u32 reg; + pcmciaRegs_t *pc = (pcmciaRegs_t *) + (&((smcRegs_t *) + IO_ADDRESS(SMC_REGS_PHYS))->slot[sock]); + + DEBUG(2, "%s(): socket=%d speed=%d hclk=%d\n", + __FUNCTION__, sock, speed, 1000000/clock); + + reg = pc->io; + DEBUG(2, "%s(): I/O: AC=%d HT=%d PC=%d\n", + __FUNCTION__, + (((reg >> 16) & 0xff) + 1 ) * 1000000 / clock, + (((reg >> 8) & 0x0f) ) * 1000000 / clock, + (((reg) & 0xff) + 1 ) * 1000000 / clock); + } + + lh7a400_pcmcia_socket[sock].speed_io=speed; + } + + start = map->start; + + if (map->stop == 1) + map->stop = PAGE_SIZE-1; + + map->start = lh7a400_pcmcia_socket[sock].virt_io; + map->stop = map->start+(map->stop-start); + + lh7a400_pcmcia_socket[sock].io_map[map->map] = *map; + + return 0; + +} /* lh7a400_pcmcia_set_io_map() */ + + +/* lh7a400_pcmcia_get_mem_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the get_mem_map() operation for the in-kernel PCMCIA + * service (formerly SS_GetMemMap in Card Services). Just returns a + * memory map descriptor which was assigned earlier by a + * set_mem_map() request. + * + * Returns: 0 on success, -1 if the map index was out of range + */ +static int lh7a400_pcmcia_get_mem_map(unsigned int sock, + struct pccard_mem_map *map) +{ + DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + + if (map->map >= MAX_WIN) { + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + *map = lh7a400_pcmcia_socket[sock].mem_map[map->map]; + + return 0; +} + + +/* lh7a400_pcmcia_set_mem_map() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the set_mem_map() operation for the in-kernel PCMCIA + * service (formerly SS_SetMemMap in Card Services). We configure + * the map speed as requested, but override the address ranges + * supplied by Card Services. + * + * Returns: 0 on success, -1 on error + */ +static int +lh7a400_pcmcia_set_mem_map(unsigned int sock, struct pccard_mem_map *map) +{ + unsigned int clock, speed; + unsigned long start; + + DEBUG(2, "%s() for sock %u\n", __FUNCTION__, sock); + + DEBUG(2, "\tmap %u speed %u\n\tsys_start %#lx\n" + "\tsys_stop %#lx\n\tcard_start %#x\n" + "\tflags: %s%s%s%s%s%s%s%s\n", + map->map, map->speed, map->sys_start, map->sys_stop, + map->card_start, (map->flags == 0) ? "": "", + (map->flags & MAP_ACTIVE) ? "ACTIVE " : "", + (map->flags & MAP_16BIT) ? "16BIT " : "", + (map->flags & MAP_AUTOSZ) ? "AUTOSZ " : "", + (map->flags & MAP_0WS) ? "0WS " : "", + (map->flags & MAP_WRPROT) ? "WRPROT " : "", + (map->flags & MAP_ATTRIB) ? "ATTRIB " : "", + (map->flags & MAP_USE_WAIT) ? "USE_WAIT " : ""); + + if (map->map >= MAX_WIN) { + printk(KERN_ERR "%s(): map (%d) out of range\n", + __FUNCTION__, map->map); + return -1; + } + + if (map->flags & MAP_ACTIVE) { + + /* + * When clients issue RequestMap, the access speed is not + * always properly configured: + */ + if (map->speed > 0) { + speed = map->speed; + } else { + switch(lh7a400_pcmcia_socket[sock].cs_state.Vcc) { + case 33: + speed = LH7A400_PCMCIA_3V_MEM_ACCESS; + break; + default: + speed = LH7A400_PCMCIA_5V_MEM_ACCESS; + } + } + + clock = hclkfreq_get(); + + if (map->flags & MAP_ATTRIB) { + PCMCIA_ATTRIB_SET(sock, speed, clock); + lh7a400_pcmcia_socket[sock].speed_attr=speed; + } else { + PCMCIA_MEMORY_SET(sock, speed, clock); + lh7a400_pcmcia_socket[sock].speed_mem = speed; + } + + { + u32 reg; + pcmciaRegs_t *pc = (pcmciaRegs_t *) + (&((smcRegs_t *) + IO_ADDRESS(SMC_REGS_PHYS))->slot[sock]); + + DEBUG(2, "%s(): sock=%d speed=%dns hclk=%dns\n", + __FUNCTION__, sock, speed, 1000000/clock); + + reg = pc->attribute; + DEBUG(2, "%s(): ATTR: PC=%d AC=%d HT=%d\n", + __FUNCTION__, + TIME2NS(GET_PC(reg), clock), + TIME2NS(GET_AC(reg), clock), + TIME2NS(GET_HT(reg), clock)); + + reg = pc->common; + DEBUG(2, "%s(): MEM: PC=%d AC=%d HT=%d\n", + __FUNCTION__, + TIME2NS(GET_PC(reg), clock), + TIME2NS(GET_AC(reg), clock), + TIME2NS(GET_HT(reg), clock)); + } + } + + start = map->sys_start; + + if (map->sys_stop == 0) + map->sys_stop = PAGE_SIZE-1; + + map->sys_start = (map->flags & MAP_ATTRIB) ? + lh7a400_pcmcia_socket[sock].phys_attr : + lh7a400_pcmcia_socket[sock].phys_mem; + + map->sys_stop = map->sys_start + (map->sys_stop-start); + + lh7a400_pcmcia_socket[sock].mem_map[map->map] = *map; + + return 0; +} /* lh7a400_pcmcia_set_mem_map() */ + + +#if defined(CONFIG_PROC_FS) + +/* lh7a400_pcmcia_proc_setup() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the proc_setup() operation for the in-kernel PCMCIA + * service (formerly SS_ProcSetup in Card Services). + * + * Returns: 0 on success, -1 on error + */ +static void lh7a400_pcmcia_proc_setup(unsigned int sock, + struct proc_dir_entry *base) +{ + struct proc_dir_entry *entry; + + DEBUG(4, "%s() for sock %u\n", __FUNCTION__, sock); + + if ((entry = create_proc_entry("status", 0, base)) == NULL) { + printk(KERN_ERR "Unable to install \"status\" procfs entry\n"); + return; + } + + entry->read_proc = lh7a400_pcmcia_proc_status; + entry->data = (void *)sock; +} + + +/* lh7a400_pcmcia_proc_status() + * ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + * Implements the /proc/bus/pccard/??/status file. + * + * Returns: the number of characters added to the buffer + */ +static int lh7a400_pcmcia_proc_status(char *buf, char **start, off_t pos, + int count, int *eof, void *data) +{ + char *p = buf; + unsigned int sock = (unsigned int)data; + unsigned int clock = hclkfreq_get(); + u32 reg; + pcmciaRegs_t *pc = (pcmciaRegs_t *) + (&((smcRegs_t *)IO_ADDRESS(SMC_REGS_PHYS))->slot[sock]); + struct lh7a400_pcmcia_socket *psock; + + psock = &lh7a400_pcmcia_socket[sock]; + + p+=sprintf(p, "k_flags : %s%s%s%s%s%s%s\n", + psock->k_state.detect ? "detect ":"", + psock->k_state.ready ? "ready ":"", + psock->k_state.bvd1 ? "bvd1 ":"", + psock->k_state.bvd2 ? "bvd2 ":"", + psock->k_state.wrprot ? "wrprot ":"", + psock->k_state.vs_3v ? "vs_3v ":"", + psock->k_state.vs_Xv ? "vs_Xv ":""); + + p+=sprintf(p, "status : %s%s%s%s%s%s%s%s%s\n", + psock->k_state.detect ? "SS_DETECT ":"", + psock->k_state.ready ? "SS_READY ":"", + psock->cs_state.Vcc ? "SS_POWERON ":"", + psock->cs_state.flags & SS_IOCARD ? "SS_IOCARD ":"", + (psock->cs_state.flags & SS_IOCARD && + psock->k_state.bvd1) ? "SS_STSCHG ":"", + ((psock->cs_state.flags & SS_IOCARD)==0 && + (psock->k_state.bvd1==0)) ? "SS_BATDEAD ":"", + ((psock->cs_state.flags & SS_IOCARD)==0 && + (psock->k_state.bvd2==0)) ? "SS_BATWARN ":"", + psock->k_state.vs_3v ? "SS_3VCARD ":"", + psock->k_state.vs_Xv ? "SS_XVCARD ":""); + + p+=sprintf(p, "mask : %s%s%s%s%s\n", + psock->cs_state.csc_mask & SS_DETECT ? "SS_DETECT ":"", + psock->cs_state.csc_mask & SS_READY ? "SS_READY ":"", + psock->cs_state.csc_mask & SS_BATDEAD ? "SS_BATDEAD ":"", + psock->cs_state.csc_mask & SS_BATWARN ? "SS_BATWARN ":"", + psock->cs_state.csc_mask & SS_STSCHG ? "SS_STSCHG ":""); + + p+=sprintf(p, "cs_flags : %s%s%s%s%s\n", + psock->cs_state.flags & SS_PWR_AUTO ? "SS_PWR_AUTO ":"", + psock->cs_state.flags & SS_IOCARD ? "SS_IOCARD ":"", + psock->cs_state.flags & SS_RESET ? "SS_RESET ":"", + psock->cs_state.flags & SS_SPKR_ENA ? "SS_SPKR_ENA ":"", + psock->cs_state.flags & SS_OUTPUT_ENA ? "SS_OUTPUT_ENA ":""); + + p+=sprintf(p, "Vcc : %d\n", psock->cs_state.Vcc); + p+=sprintf(p, "Vpp : %d\n", psock->cs_state.Vpp); + p+=sprintf(p, "irq : %d\n", psock->cs_state.io_irq); + + reg = pc->io; + p+=sprintf(p, "I/O : %u PreCharge=%d Access=%d Hold=%d\n", + psock->speed_io, + TIME2NS(GET_PC(reg), clock), + TIME2NS(GET_AC(reg), clock), + TIME2NS(GET_HT(reg), clock)); + + reg = pc->attribute; + p+=sprintf(p, "attribute: %u PreCharge=%d Access=%d Hold=%d\n", + psock->speed_attr, + TIME2NS(GET_PC(reg), clock), + TIME2NS(GET_AC(reg), clock), + TIME2NS(GET_HT(reg), clock)); + + reg = pc->common; + p+=sprintf(p, "common : %u PreCharge=%d Access=%d Hold=%d\n", + psock->speed_mem, + TIME2NS(GET_PC(reg), clock), + TIME2NS(GET_AC(reg), clock), + TIME2NS(GET_HT(reg), clock)); + + return p-buf; +} + +#endif /* defined(CONFIG_PROC_FS) */ + +module_init(lh7a400_pcmcia_driver_init); + + + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/pcmcia/lh7a400_kev7a400.c linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/lh7a400_kev7a400.c --- linux-2.4.21-rmk1/drivers/pcmcia/lh7a400_kev7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/pcmcia/lh7a400_kev7a400.c Sat Oct 18 13:31:25 2003 @@ -0,0 +1,214 @@ +/* + * driver/pcmcia/lh7a400_kev7a400.c + * + * PCMCIA control functionality specific to the KEV7A400 board + * + * Portions Copyright (C) 2003 Embedix Inc. + * + * This program is free software; you can distribute it and/or modify it + * under the terms of the GNU General Public License (Version 2) as + * published by the Free Software Foundation. + * + * This program is distributed in the hope 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cs_internal.h" + +#include "lh7a400_cs.h" + +#include +#include +#include + +#include +#include +#include + +static int +kev7a400_pcmcia_init(struct pcmcia_init *init) +{ + int irq, rc; + smcRegs_t *smc = (smcRegs_t *)IO_ADDRESS(SMC_REGS_PHYS); + + DEBUG( 2, "kev7a400_pcmcia_init()\n"); + + /* + * enable both slots, enable wait states, and set Auto nPREG. + */ + smc->pcmciaCtl = + PCMCIA_CTL_CFPC | PCMCIA_CTL_WEN1 | + PCMCIA_CTL_WEN2 | PCMCIA_CTL_AUTOPREG; + +#if 0 // DDD + irq = IRQ_PCMCIA_CD1; + if ((rc = request_irq(irq, init->handler, SA_INTERRUPT, "PCMCIA 0 CD", NULL)) < 0) { + printk( KERN_ERR "Request for IRQ %d failed, rc=%d\n", irq, rc); + return -1; + } + + irq = IRQ_PCMCIA_CD2; + if ((rc = request_irq( irq, init->handler, SA_INTERRUPT, "PCMCIA 1 CD", NULL)) < 0) { + printk( KERN_ERR "Request for IRQ %d failed, rc=%d\n", irq, rc); + return -1; + } +#endif + + return 2; +} + +static int +kev7a400_pcmcia_shutdown(void) +{ + DEBUG( 3, "kev7a400_pcmcia_shutdown()\n"); + +#if 0 // DDD + free_irq( IRQ_PCMCIA_CD1, NULL); + free_irq( IRQ_PCMCIA_CD2, NULL); +#endif + return 0; +} + +static int +kev7a400_pcmcia_socket_state( struct pcmcia_state_array *state_array) +{ + u16 status = *(volatile u16 *)PCMCIA_STATUS_BASE; + + DEBUG( 1, "kev7a400_pcmcia_socket_state() status=0x%x\n", status); + + if( state_array->size < 2) + return -1; + + memset( state_array->state, 0, (state_array->size)*sizeof(struct pcmcia_state)); + + state_array->state[0].detect = (status & PCMCIA_STATUS_PC1_CD) ? 1 : 0; + state_array->state[0].ready = (status & PCMCIA_STATUS_PC1_CD) ? 1 : 0; // FIXME - use right signal + state_array->state[0].bvd1 = (status & PCMCIA_STATUS_PC1_BVD1) ? 1 : 0; + state_array->state[0].bvd2 = (status & PCMCIA_STATUS_PC1_BVD2) ? 1 : 0; + state_array->state[0].vs_3v = (status & PCMCIA_STATUS_PC1_nVS1) ? 0 : 1; + state_array->state[0].vs_Xv = (status & PCMCIA_STATUS_PC1_nVS2) ? 0 : 1; + state_array->state[0].wrprot = 0; + + state_array->state[1].detect = (status & PCMCIA_STATUS_PC2_CD) ? 1 : 0; + state_array->state[1].ready = (status & PCMCIA_STATUS_PC2_CD) ? 1 : 0; // FIXME - use right signal + state_array->state[1].bvd1 = (status & PCMCIA_STATUS_PC2_BVD1) ? 1 : 0; + state_array->state[1].bvd2 = (status & PCMCIA_STATUS_PC2_BVD2) ? 1 : 0; + state_array->state[1].vs_3v = (status & PCMCIA_STATUS_PC2_nVS1) ? 0 : 1; + state_array->state[1].vs_Xv = (status & PCMCIA_STATUS_PC2_nVS2) ? 0 : 1; + state_array->state[1].wrprot = 0; + + return 1; +} + +static int +kev7a400_pcmcia_get_irq_info(struct pcmcia_irq_info *info) +{ + DEBUG( 3, "kev7a400_pcmcia_get_irq_info() socket=%d\n", info->sock); + + if( info->sock > 1) + return -1; + + info->irq = info->sock == 0 ? IRQ_KEV7A400_PCMCIA1 : IRQ_KEV7A400_PCMCIA2; + + return 0; +} + +static int +kev7a400_pcmcia_configure_socket(const struct pcmcia_configure *configure) +{ + unsigned long flags; + u16 clearVcc, setVcc; + + + if( configure->sock > 2) + return -1; + + DEBUG( 3, "%s: socket=%d Vcc=%d reset=%d\n", + __FUNCTION__, configure->sock, configure->vcc, configure->reset); + + save_flags_cli( flags); + + /* + * set socket voltage + */ + clearVcc = configure->sock == 0 ? (CPLD_IOB_PC1_3V | CPLD_IOB_PC1_5V) : + (CPLD_IOB_PC2_3V | CPLD_IOB_PC2_5V); + + switch( configure->vcc) { + case 0: + clear_ioBrdCtl_bit( clearVcc); + break; + + case 33: + setVcc = configure->sock == 0 ? CPLD_IOB_PC1_3V : CPLD_IOB_PC2_3V; + clear_ioBrdCtl_bit( clearVcc); + set_ioBrdCtl_bit( setVcc); + break; + + case 50: + setVcc = configure->sock == 0 ? CPLD_IOB_PC1_5V : CPLD_IOB_PC2_5V; + clear_ioBrdCtl_bit( clearVcc); + set_ioBrdCtl_bit( setVcc); + break; + + default: + printk(KERN_ERR " lh7a400: Attempt to set bad Vcc (%d) on socket %d\n", + configure->vcc, configure->sock); + restore_flags( flags); + return -1; + } + + + if( configure->reset) { + smcRegs_t *smc = (smcRegs_t *)IO_ADDRESS(SMC_REGS_PHYS); + u32 reset = configure->sock == 0 ? + PCMCIA_CTL_PC1RST : PCMCIA_CTL_PC2RST; + + smc->pcmciaCtl |= reset; + mdelay( 10); + + smc->pcmciaCtl &= ~reset; + mdelay( 10); + } + + /* Silently ignore Vpp, output enable, speaker enable */ + + restore_flags( flags); + + return 0; +} + +struct pcmcia_low_level kev7a400_pcmcia_ops = { + kev7a400_pcmcia_init, + kev7a400_pcmcia_shutdown, + kev7a400_pcmcia_socket_state, + kev7a400_pcmcia_get_irq_info, + kev7a400_pcmcia_configure_socket +}; + + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/serial/Config.in linux-2.4.21-rmk1-lh7a400/drivers/serial/Config.in --- linux-2.4.21-rmk1/drivers/serial/Config.in Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/serial/Config.in Thu Oct 16 15:01:46 2003 @@ -15,11 +15,26 @@ fi dep_tristate 'ARM AMBA serial port support' CONFIG_SERIAL_AMBA $CONFIG_ARCH_INTEGRATOR - dep_bool ' Support for console on AMBA serial port' CONFIG_SERIAL_AMBA_CONSOLE $CONFIG_SERIAL_AMBA if [ "$CONFIG_SERIAL_AMBA" = "y" ]; then define_bool CONFIG_SERIAL_INTEGRATOR y fi + dep_tristate 'ARM PL011 PrimeCell serial port support' CONFIG_SERIAL_AMBA_PL011 $CONFIG_ARCH_LH79520 + + if [ "$CONFIG_SERIAL_AMBA" = "y" ]; then + bool ' Support for console on AMBA serial port' CONFIG_SERIAL_AMBA__CONSOLE + fi + + if [ "$CONFIG_SERIAL_AMBA_PL011" = "y" ]; then + bool ' Support for console on ARM PrimeCell PL011 serial port' CONFIG_SERIAL_AMBA_PL011_CONSOLE + fi + + dep_tristate 'Sharp LH7A400 serial port support' CONFIG_SERIAL_LH7A400 $CONFIG_ARCH_LH7A400 + + if [ "$CONFIG_SERIAL_LH7A400" = "y" ]; then + bool ' Support for console on LH7A400 serial port' CONFIG_SERIAL_LH7A400_CONSOLE + fi + dep_tristate 'CLPS711X serial port support' CONFIG_SERIAL_CLPS711X $CONFIG_ARCH_CLPS711X dep_bool ' Support for console on CLPS711X serial port' CONFIG_SERIAL_CLPS711X_CONSOLE $CONFIG_SERIAL_CLPS711X @@ -57,6 +72,8 @@ dep_bool ' Support Bell Technologies HUB6 card' CONFIG_SERIAL_8250_HUB6 $CONFIG_SERIAL_8250_EXTENDED if [ "$CONFIG_SERIAL_AMBA" = "y" -o \ + "$CONFIG_SERIAL_AMBA_PL011" = "y" -o \ + "$CONFIG_SERIAL_LH7A400" = "y" -o \ "$CONFIG_SERIAL_CLPS711X" = "y" -o \ "$CONFIG_SERIAL_SA1100" = "y" -o \ "$CONFIG_SERIAL_ANAKIN" = "y" -o \ @@ -67,6 +84,8 @@ define_bool CONFIG_SERIAL_CORE y else if [ "$CONFIG_SERIAL_AMBA" = "m" -o \ + "$CONFIG_SERIAL_AMBA_PL011" = "m" -o \ + "$CONFIG_SERIAL_LH7A400" = "m" -o \ "$CONFIG_SERIAL_CLPS711X" = "m" -o \ "$CONFIG_SERIAL_SA1100" = "m" -o \ "$CONFIG_SERIAL_ANAKIN" = "m" -o \ @@ -78,6 +97,8 @@ fi fi if [ "$CONFIG_SERIAL_AMBA_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_AMBA_PL011_CONSOLE" = "y" -o \ + "$CONFIG_SERIAL_LH7A400_CONSOLE" = "y" -o \ "$CONFIG_SERIAL_CLPS711X_CONSOLE" = "y" -o \ "$CONFIG_SERIAL_SA1100_CONSOLE" = "y" -o \ "$CONFIG_SERIAL_ANAKIN_CONSOLE" = "y" -o \ diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/serial/Makefile linux-2.4.21-rmk1-lh7a400/drivers/serial/Makefile --- linux-2.4.21-rmk1/drivers/serial/Makefile Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/serial/Makefile Thu Oct 16 17:37:58 2003 @@ -27,6 +27,8 @@ obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y) obj-$(CONFIG_SERIAL_ANAKIN) += anakin.o obj-$(CONFIG_SERIAL_AMBA) += amba.o +obj-$(CONFIG_SERIAL_AMBA_PL011) += amba_pl011.o +obj-$(CONFIG_SERIAL_LH7A400) += lh7a400.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_UART00) += uart00.o diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/serial/core.c linux-2.4.21-rmk1-lh7a400/drivers/serial/core.c --- linux-2.4.21-rmk1/drivers/serial/core.c Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/serial/core.c Thu Oct 16 15:01:46 2003 @@ -1934,6 +1934,7 @@ } extern void ambauart_console_init(void); +extern void amba11uart_console_init(void); extern void anakin_console_init(void); extern void clps711xuart_console_init(void); extern void sa1100_rs_console_init(void); @@ -1966,6 +1967,12 @@ #ifdef CONFIG_SERIAL_UART00_CONSOLE uart00_console_init(); #endif +#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE + amba11uart_console_init(); +#endif +#ifdef CONFIG_SERIAL_LH7A400_CONSOLE + lh7a400uart_console_init(); +#endif } #endif /* CONFIG_SERIAL_CORE_CONSOLE */ diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/serial/lh7a400.c linux-2.4.21-rmk1-lh7a400/drivers/serial/lh7a400.c --- linux-2.4.21-rmk1/drivers/serial/lh7a400.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/serial/lh7a400.c Fri Oct 17 21:41:52 2003 @@ -0,0 +1,938 @@ +/* + * linux/drivers/char/serial_lh7a400.c + * + * Driver for Sharp LH7A400 serial ports + * Copyright (C) 2002 Lineo, Inc. + * + * Based on drivers/char/serial_amba.c, which is: + * Copyright 1999 ARM Limited + * Copyright (C) 2000 Deep Blue Solutions Ltd. + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * 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 + * + * $Id: patch-2.4.17-rmk2-lineo-lh7a400-serial,v 1.5 2003/01/24 21:44:41 duck Exp $ + * + * This is a generic driver for Sharp LH7A400-type serial ports. They + * have a lot of 16550-like features, but are not register compatable. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#ifdef CONFIG_CPU_FREQ +#include +#include +#endif + +#if defined(CONFIG_SERIAL_LH7A400_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include +#include +#include + +#define UART_NR 3 + +#define SERIAL_AMBA_MAJOR 204 +#define SERIAL_AMBA_MINOR 16 +#define SERIAL_AMBA_NR UART_NR + +#define CALLOUT_AMBA_NAME "cuaam" +#define CALLOUT_AMBA_MAJOR 205 +#define CALLOUT_AMBA_MINOR 16 +#define CALLOUT_AMBA_NR UART_NR + +static struct tty_driver normal, callout; +static struct tty_struct *lh7a400_table[UART_NR]; +static struct termios *lh7a400_termios[UART_NR], *lh7a400_termios_locked[UART_NR]; +#ifdef SUPPORT_SYSRQ +static struct console lh7a400_console; +#endif +static void lh7a400uart_tx_chars(struct uart_port *port); + +#define AMBA_ISR_PASS_LIMIT 256 + +/* + * Access macros for the LH7A400 UARTs + */ +#define UART_GET_CHAR(p) readl(&((uartRegs_t *)(p)->membase)->dr) +#define UART_PUT_CHAR(p, c) writel((c), &((uartRegs_t *)(p)->membase)->dr) + +#define UART_GET_LCR(p) readb(&((uartRegs_t *)(p)->membase)->lcr) +#define UART_PUT_LCR(p,c) writel((c), &((uartRegs_t *)(p)->membase)->lcr) + +#define UART_GET_CR(p) readl(&((uartRegs_t *)(p)->membase)->cr) +#define UART_PUT_CR(p,c) writel((c), &((uartRegs_t *)(p)->membase)->cr) + +#define UART_GET_FR(p) readw(&((uartRegs_t *)(p)->membase)->fr) +#define UART_RX_DATA(s) (((s) & UART_FR_RXFE) == 0) +#define UART_TX_READY(s) (((s) & UART_FR_TXFF) == 0) +#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & UART_FR_TMSK) == 0) + +#define UART_GET_INT_STATUS(p) readw(&((uartRegs_t *)(p)->membase)->intres) + +#define UART_GET_INTMASK(p) readl(&((uartRegs_t *)(p)->membase)->intmask) +#define UART_PUT_INTMASK(p,c) writel((c), &((uartRegs_t *)(p)->membase)->intmask) + +#define UART_GET_BCR(p) readl(&((uartRegs_t *)(p)->membase)->bcr) +#define UART_PUT_BCR(p,c) writel((c), &((uartRegs_t *)(p)->membase)->bcr) + +#define UART_CLEAR_MODEM_INTR(p) writel( 1, &((uartRegs_t *)(p)->membase)->intraw) + +#define UART_DUMMY_RSR_RX 256 +#define UART_PORT_SIZE 64 + +/* + * Our private driver data mappings. + */ +#define drv_old_status driver_priv + +static void lh7a400uart_stop_tx(struct uart_port *port, u_int from_tty) +{ + unsigned int mask; + + mask = UART_GET_INTMASK( port); + mask &= ~UART_INT_TX; + UART_PUT_INTMASK( port, mask); /* disable Tx interrupts */ +} + + +static void lh7a400uart_start_tx(struct uart_port *port, unsigned int tty_start + /*u_int nonempty, u_int from_tty*/) +{ + unsigned int flags; + + save_flags_cli( flags); + + if (/*nonempty*/tty_start) { + unsigned int mask; + + mask = UART_GET_INTMASK(port); + if( (mask & UART_INT_TX) == 0) {/* not already enabled */ + mask |= UART_INT_TX; /* enable Tx interrupts */ + UART_PUT_INTMASK(port, mask); + + lh7a400uart_tx_chars(port); /* start transmiting */ + } + } + restore_flags( flags); +} + + +static void lh7a400uart_stop_rx(struct uart_port *port) +{ + unsigned int mask; + + mask = UART_GET_INTMASK(port); + mask &= ~(UART_INT_RX | UART_INT_RT); + UART_PUT_INTMASK(port, mask); /* disable Rx interrupts */ +} + + +static void lh7a400uart_enable_ms(struct uart_port *port) +{ + unsigned int mask; + + mask = UART_GET_INTMASK( port); + mask |= UART_INT_MI; + UART_PUT_INTMASK(port, mask); /* Disable modem interrupts */ +} + +static void +#ifdef SUPPORT_SYSRQ +lh7a400uart_rx_chars(struct uart_port *port, struct pt_regs *regs) +#else +lh7a400uart_rx_chars(struct uart_port *port) +#endif +{ + struct tty_struct *tty = port->info->tty; + unsigned int status, ch, err, max_count = 256; + + status = UART_GET_FR(port); + while (UART_RX_DATA(status) && max_count--) { + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + tty->flip.tqueue.routine((void *)tty); + if (tty->flip.count >= TTY_FLIPBUF_SIZE) { + printk(KERN_WARNING "TTY_DONT_FLIP set\n"); + return; + } + } + + ch = UART_GET_CHAR(port); + + *tty->flip.char_buf_ptr = ch & 0xff; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + err = ch & 0xf00; + if (err != 0) { + if (err & UART_DR_BE) { + err &= ~(UART_DR_FE | UART_DR_PE); + port->icount.brk++; + if (uart_handle_break(port)) + goto ignore_char; + } else if (err & UART_DR_PE) + port->icount.parity++; + else if (err & UART_DR_FE) + port->icount.frame++; + if (err & UART_DR_OE) + port->icount.overrun++; + + err &= port->read_status_mask; + + if (err & UART_DR_BE) + *tty->flip.flag_buf_ptr = TTY_BREAK; + else if (err & UART_DR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (err & UART_DR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch, regs)) + goto ignore_char; + + if ((err & port->ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((err & UART_DR_OE) && + tty->flip.count < TTY_FLIPBUF_SIZE) { + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + *tty->flip.char_buf_ptr++ = 0; + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + tty->flip.count++; + } + ignore_char: + status = UART_GET_FR(port); + } + tty_flip_buffer_push(tty); + return; +} + +static void lh7a400uart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + int status; + + if (port->x_char) { + UART_PUT_CHAR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (xmit->head == xmit->tail + || port->info->tty->stopped + || port->info->tty->hw_stopped) { + lh7a400uart_stop_tx(port, 0); + return; + } + + do { + UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + ++port->icount.tx; + status = UART_GET_FR(port); + } while (UART_TX_READY(status) && xmit->head != xmit->tail); + + if (CIRC_CNT(xmit->head, xmit->tail, UART_XMIT_SIZE) < WAKEUP_CHARS) + uart_write_wakeup(port); + + if (xmit->head == xmit->tail) + lh7a400uart_stop_tx(port, 0); +} + +static void lh7a400uart_modem_status(struct uart_port *port) +{ + unsigned int status, delta; + + UART_CLEAR_MODEM_INTR( port); + + status = UART_GET_FR(port) & UART_FR_MODEM_ANY; + + delta = status ^ port->info->drv_old_status; + port->info->drv_old_status = status; + + if (!delta) + return; + +#if 0 /* is this right ? */ + if (delta & UART_FR_DCD) + uart_handle_dcd_change(port->info, status & UART_FR_DCD); + + if (delta & UART_FR_DSR) + port->icount.dsr++; + + if (delta & UART_FR_CTS) + uart_handle_cts_change(port->info, status & UART_FR_CTS); +#endif + + wake_up_interruptible(&port->info->delta_msr_wait); +} + +static void lh7a400uart_int(int irq, void *dev_id, struct pt_regs *regs) +{ + struct uart_port *port = dev_id; + unsigned int status, pass_counter = AMBA_ISR_PASS_LIMIT; + + status = UART_GET_INT_STATUS(port); + do { + if (status & (UART_INT_RT | UART_INT_RX)) + +#ifdef SUPPORT_SYSRQ + lh7a400uart_rx_chars(port, regs); +#else + lh7a400uart_rx_chars(port); +#endif + + if (status & UART_INT_TX) + lh7a400uart_tx_chars(port); + + + if (status & UART_INT_MI) + lh7a400uart_modem_status(port); + + if (pass_counter-- == 0) + break; + + status = UART_GET_INT_STATUS(port); + } while (status & (UART_INT_RT | UART_INT_RX | UART_INT_TX)); +} + +static u_int lh7a400uart_tx_empty(struct uart_port *port) +{ + return UART_GET_FR(port) & UART_FR_BUSY ? 0 : TIOCSER_TEMT; +} + +static u_int lh7a400uart_get_mctrl(struct uart_port *port) +{ + unsigned int result = 0; + unsigned int status; + + status = UART_GET_FR(port); + if (status & UART_FR_DCD) + result |= TIOCM_CAR; + if (status & UART_FR_DSR) + result |= TIOCM_DSR; + if (status & UART_FR_CTS) + result |= TIOCM_CTS; + + return result; +} + +static void lh7a400uart_set_mctrl(struct uart_port *port, u_int mctrl) +{ + /* + * UART1 (the DTE port) has a programable RTS signal. + * It does not have a programable DCD. + * + * These signals are hard wired on UART2, and neither + * is programable. + */ + + if( port->mapbase == UART1_PHYS) { + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + if (mctrl & TIOCM_RTS) + gpio->pbdr &= ~GPIOB_UART1_RTS; + else + gpio->pbdr |= GPIOB_UART1_RTS; + } +} + + +static void lh7a400uart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned int lcr; + + lcr = UART_GET_LCR(port); + if (break_state == -1) + lcr |= UART_LCR_SENDBRK; + else + lcr &= ~UART_LCR_SENDBRK; + UART_PUT_LCR(port, lcr); +} + +static int lh7a400uart_startup(struct uart_port *port) +{ + int retval; + + /* + * Allocate the IRQ + */ + retval = request_irq(port->irq, lh7a400uart_int, 0, "lh7a400 UART", port); + if (retval) + return retval; + + /* + * initialise the old status of the modem signals + */ + port->info->drv_old_status = UART_GET_FR(port) & UART_FR_MODEM_ANY; + + /* + * Finally, enable interrupts + */ + + /* + * Use iobase to store a pointer to info. We need this to start a + * transmission as the tranmittr interrupt is only generated on + * the transition to the idle state + */ +// port->iobase=(u_int)info; + +#if defined(CONFIG_IRTTY_SIR) || defined(CONFIG_IRTTY_SIR_MODULE) + /* enable SIR on UART1, enable the uart */ + if( port->membase == (void *)IO_ADDRESS(UART1_PHYS)) { + // DDD printk( "\n\n IR open\n\n"); + UART_PUT_CR( port, UART_CR_SIRLP | UART_CR_EN); + } else { + UART_PUT_CR( port, UART_CR_SIRDIS | UART_CR_EN); + } +#else + /* disable SIR, enable the uart */ + UART_PUT_CR( port, UART_CR_SIRDIS | UART_CR_EN); +#endif + UART_PUT_INTMASK( port, (UART_INT_RX | UART_INT_RT) ); + + return 0; +} + +static void lh7a400uart_shutdown(struct uart_port *port) +{ + /* + * Free the interrupt + */ + free_irq(port->irq, port); + + /* disable break condition and fifos */ + UART_PUT_LCR(port, UART_GET_LCR(port) & + ~(UART_LCR_SENDBRK | UART_LCR_FEN)); + + /* + * disable all interrupts, disable the port + */ + UART_PUT_CR(port, 0); +} + +static void lh7a400uart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) +{ + u_int lcr; + unsigned long flags; + unsigned long old_mask; + +#if DEBUG + printk("lh7a400uart_change_speed(port=0x%x cflag=0x%x iflag=0x%x quot=%d)\n", + port, cflag, iflag, quot); +#endif + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: lcr = UART_LCR_WLEN5; break; + case CS6: lcr = UART_LCR_WLEN6; break; + case CS7: lcr = UART_LCR_WLEN7; break; + default: lcr = UART_LCR_WLEN8; break; // CS8 + } + if (cflag & CSTOPB) + lcr |= UART_LCR_STP2; + if (cflag & PARENB) { + lcr |= UART_LCR_PEN; + if (!(cflag & PARODD)) + lcr |= UART_LCR_EPS; + } + if (port->fifosize > 1) + lcr |= UART_LCR_FEN; + + port->read_status_mask = UART_DR_OE; + if (iflag & INPCK) + port->read_status_mask |= UART_DR_FE | UART_DR_PE; + if (iflag & (BRKINT | PARMRK)) + port->read_status_mask |= UART_DR_BE; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= UART_DR_FE | UART_DR_PE; + if (iflag & IGNBRK) { + port->ignore_status_mask |= UART_DR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + port->ignore_status_mask |= UART_DR_OE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_RSR_RX; + + /* first, disable everything */ + save_flags(flags); cli(); + old_mask = UART_GET_INTMASK( port) & ~UART_INT_MI; + + if ((port->flags & ASYNC_HARDPPS_CD) || + (cflag & CRTSCTS) || !(cflag & CLOCAL)) + old_mask |= UART_INT_MI; + + + /* Set baud rate */ + quot -= 1; + UART_PUT_BCR( port, quot); + + UART_PUT_LCR(port, lcr); + UART_PUT_INTMASK( port, old_mask); + + restore_flags(flags); +} + +static const char *lh7a400uart_type(struct uart_port *port) +{ + return port->type == PORT_LH7A400 ? "LH7A400 UART" : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void lh7a400uart_release_port(struct uart_port *port) +{ + release_mem_region(port->mapbase, UART_PORT_SIZE); +} + +/* + * Request the memory region(s) being used by 'port' + */ +static int lh7a400uart_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_lh7a400") + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void lh7a400uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_LH7A400; + lh7a400uart_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int lh7a400uart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_LH7A400) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops lh7a400_pops = { + tx_empty: lh7a400uart_tx_empty, + set_mctrl: lh7a400uart_set_mctrl, + get_mctrl: lh7a400uart_get_mctrl, + stop_tx: lh7a400uart_stop_tx, + start_tx: lh7a400uart_start_tx, + stop_rx: lh7a400uart_stop_rx, + enable_ms: lh7a400uart_enable_ms, + break_ctl: lh7a400uart_break_ctl, + startup: lh7a400uart_startup, + shutdown: lh7a400uart_shutdown, + change_speed: lh7a400uart_change_speed, + type: lh7a400uart_type, + release_port: lh7a400uart_release_port, + request_port: lh7a400uart_request_port, + config_port: lh7a400uart_config_port, + verify_port: lh7a400uart_verify_port, +}; + +static struct uart_port lh7a400_ports[UART_NR] = { + { + membase: (void *)IO_ADDRESS(UART1_PHYS), // VA + mapbase: UART1_PHYS, + iotype: SERIAL_IO_MEM, + irq: IRQ_UART1, + uartclk: (14745600 / 2), + fifosize: 16, + ops: &lh7a400_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 0 + }, + { + membase: (void *)IO_ADDRESS(UART2_PHYS), + mapbase: UART2_PHYS, + iotype: SERIAL_IO_MEM, + irq: IRQ_UART2, + uartclk: (14745600 / 2), + fifosize: 16, + ops: &lh7a400_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 1 + }, + { + membase: (void *)IO_ADDRESS(UART3_PHYS), + mapbase: UART3_PHYS, + iotype: SERIAL_IO_MEM, + irq: IRQ_UART3, + uartclk: (14745600 / 2), + fifosize: 16, + ops: &lh7a400_pops, + flags: ASYNC_BOOT_AUTOCONF, + line: 2 + } +}; + + +#ifdef CONFIG_SERIAL_LH7A400_CONSOLE +#ifdef used_and_not_const_char_pointer +static int lh7a400uart_console_read(struct uart_port *port, char *s, u_int count) +{ + unsigned int status; + int c; +#if DEBUG + printk("lh7a400uart_console_read() called\n"); +#endif + + c = 0; + while (c < count) { + status = UART_GET_FR(port); + if (UART_RX_DATA(status)) { + *s++ = UART_GET_CHAR(port); + c++; + } else { + // nothing more to get, return + return c; + } + } + // return the count + return c; +} +#endif + +static void lh7a400uart_console_write(struct console *co, const char *s, u_int count) +{ + struct uart_port *port = lh7a400_ports + co->index; + unsigned int status; + int i; + + /* + * First save the CR then disable the interrupts + */ + unsigned int old_mask; + old_mask = UART_GET_INTMASK( port); + UART_PUT_INTMASK( port, 0); + + /* + * Now, do each character + */ + for (i = 0; i < count; i++) { + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, s[i]); + if (s[i] == '\n') { + do { + status = UART_GET_FR(port); + } while (!UART_TX_READY(status)); + UART_PUT_CHAR(port, '\r'); + } + } + + /* + * Finally, wait for transmitter to become empty + * and restore the TCR + */ + do { + status = UART_GET_FR(port); + } while (status & UART_FR_BUSY); + UART_PUT_INTMASK( port, old_mask); +} + +static kdev_t lh7a400uart_console_device(struct console *co) +{ + return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + co->index); +} + +static void __init +lh7a400uart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +{ + if (UART_GET_CR(port) & UART_CR_EN) { + u_int lcr, quot; + lcr = UART_GET_LCR(port); + + *parity = 'n'; + if (lcr & UART_LCR_PEN) { + if (lcr & UART_LCR_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr & 0x60) == UART_LCR_WLEN7) + *bits = 7; + else + *bits = 8; + + quot = UART_GET_BCR(port); + *baud = port->uartclk / (16 * quot ); + } +} + +static int __init lh7a400uart_console_setup(struct console *co, char *options) +{ + struct uart_port *port; + int baud = 38400; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + /* + * Check whether an invalid uart number has been specified, and + * if so, search for the first available port that does have + * console support. + */ + port = uart_get_console(lh7a400_ports, UART_NR, co); + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + lh7a400uart_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console lh7a400_console = { + name: "ttyAM", + write: lh7a400uart_console_write, +#ifdef used_and_not_const_char_pointer + read: lh7a400uart_console_read, +#endif + device: lh7a400uart_console_device, + setup: lh7a400uart_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + + + +#ifdef CONFIG_CPU_FREQ + +typedef struct { + u32 lcr; + u32 bcr; +} saveRegs_t; + +static saveRegs_t saveRegs[UART_NR]; + +static inline void +save_regs( void) +{ + int i; + + for( i=0; i < UART_NR; i++) { + uartRegs_t *uart = lh7a400_ports[i].membase; + saveRegs_t *save = &saveRegs[i]; + + save->lcr = uart->lcr; + save->bcr = uart->bcr; + } +} + +static inline void +restore_regs( void) +{ + int i; + + for( i=0; i < UART_NR; i++) { + uartRegs_t *uart = lh7a400_ports[i].membase; + saveRegs_t *save = &saveRegs[i]; + + uart->lcr = save->lcr ; + uart->bcr = save->bcr ; + } +} + + +/* + * This routine gets called before and after a change in the + * CPU speed or in the HCLK bus speed. It's purpose is to get + * around an errata where lcr and bcr are lost when the CPU + * enters standby mode, which happens when the CLKSET register + * is written. + * + * We save lcr and bcr before CLKSET is written, and restore + * them afterwards. Note that if both the CPU and HCLK clocks + * change at the same time, we'll get called twice to save the + * regs, and twice to restore them. + */ +static int +uart_cpu_clkchg_notifier(struct notifier_block *nb, unsigned long val, void *data) +{ + switch (val) { + case CPUFREQ_PRECHANGE: + save_regs(); + break; + + case CPUFREQ_POSTCHANGE: + restore_regs(); + break; + } + return 0; +} + +static int +uart_hclk_clkchg_notifier(struct notifier_block *nb, unsigned long val, void *data) +{ + switch (val) { + case HCLKFREQ_PRECHANGE: + save_regs(); + break; + + case HCLKFREQ_POSTCHANGE: + restore_regs(); + break; + } + return 0; +} + +static struct notifier_block fclk_nb = { + notifier_call: uart_cpu_clkchg_notifier, +}; + +static struct notifier_block hclk_nb = { + notifier_call: uart_hclk_clkchg_notifier, +}; + +#endif // CONFIG_CPU_FREQ + + + + +void __init lh7a400uart_console_init(void) +{ + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + gpio->pbddr |= GPIOB_UART1_RTS; /* set as an output */ + + register_console(&lh7a400_console); +} + +#define AMBA_CONSOLE &lh7a400_console +#else +#define AMBA_CONSOLE NULL +#endif + +static struct uart_driver lh7a400_reg = { + owner: THIS_MODULE, + normal_major: SERIAL_AMBA_MAJOR, +#ifdef CONFIG_DEVFS_FS + normal_name: "ttyAM%d", + callout_name: "cuaam%d", +#else + normal_name: "ttyAM", + callout_name: "cuaam", +#endif + normal_driver: &normal, + callout_major: CALLOUT_AMBA_MAJOR, + callout_driver: &callout, + table: lh7a400_table, + termios: lh7a400_termios, + termios_locked: lh7a400_termios_locked, + minor: SERIAL_AMBA_MINOR, + nr: UART_NR, + cons: AMBA_CONSOLE, +}; + +static int __init lh7a400uart_init(void) +{ + int ret; + +#ifdef CONFIG_CPU_FREQ + cpufreq_register_notifier(&fclk_nb); + hclkfreq_register_notifier(&hclk_nb); +#endif + + ret = uart_register_driver(&lh7a400_reg); + if (ret == 0) { + int i; + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&lh7a400_reg, &lh7a400_ports[i]); + } + return ret; +} + +static void __exit lh7a400uart_exit(void) +{ +#ifdef CONFIG_CPU_FREQ + cpufreq_unregister_notifier( &fclk_nb); + hclkfreq_unregister_notifier( &hclk_nb); +#endif + int i; + + for (i = 0; i < UART_NR; i++) + uart_remove_one_port(&lh7a400_reg, &lh7a400_ports[i]); + + uart_unregister_driver(&lh7a400_reg); +} + +module_init(lh7a400uart_init); +module_exit(lh7a400uart_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("ARM Ltd/Deep Blue Solutions Ltd"); +MODULE_DESCRIPTION("ARM AMBA serial port driver"); +MODULE_LICENSE("GPL"); diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/sound/Config.in linux-2.4.21-rmk1-lh7a400/drivers/sound/Config.in --- linux-2.4.21-rmk1/drivers/sound/Config.in Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/sound/Config.in Thu Oct 16 15:22:29 2003 @@ -136,6 +136,10 @@ dep_tristate ' Generic DAC on the SA11x0 SSP port' CONFIG_SOUND_SA1100SSP $CONFIG_SOUND_SA1100 fi +if [ "$CONFIG_ARCH_LH7A400" = "y" ]; then + dep_tristate ' Sharp LH7A400 AAC/AC97 Sound Drivers' CONFIG_SOUND_LH7A400 $CONFIG_SOUND +fi + dep_tristate ' OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND if [ "$CONFIG_SOUND_OSS" = "y" -o "$CONFIG_SOUND_OSS" = "m" ]; then diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/sound/Makefile linux-2.4.21-rmk1-lh7a400/drivers/sound/Makefile --- linux-2.4.21-rmk1/drivers/sound/Makefile Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/sound/Makefile Thu Oct 16 16:02:24 2003 @@ -90,6 +90,7 @@ obj-$(CONFIG_SOUND_RME96XX) += rme96xx.o obj-$(CONFIG_SOUND_BT878) += btaudio.o obj-$(CONFIG_SOUND_IT8172) += ite8172.o ac97_codec.o +obj-$(CONFIG_SOUND_LH7A400) += lh7a400-aac.o ac97_codec.o ifeq ($(CONFIG_MIDI_EMU10K1),y) obj-$(CONFIG_SOUND_EMU10K1) += sound.o diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/sound/ac97_codec.c linux-2.4.21-rmk1-lh7a400/drivers/sound/ac97_codec.c --- linux-2.4.21-rmk1/drivers/sound/ac97_codec.c Fri Jun 13 10:51:36 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/sound/ac97_codec.c Fri Oct 17 21:22:45 2003 @@ -141,6 +141,8 @@ {0x43525931, "Cirrus Logic CS4299 rev A", &crystal_digital_ops}, {0x43525933, "Cirrus Logic CS4299 rev C", &crystal_digital_ops}, {0x43525934, "Cirrus Logic CS4299 rev D", &crystal_digital_ops}, + {0x4352594d, "Cirrus Logic CS4201", &crystal_digital_ops}, + {0x43525970, "Cirrus Logic CS4202", &crystal_digital_ops}, {0x43585442, "CXT66", &default_ops, AC97_DELUDED_MODEM }, {0x44543031, "Diamond Technology DT0893", &default_ops}, {0x45838308, "ESS Allegro ES1988", &null_ops}, diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/sound/lh7a400-aac.c linux-2.4.21-rmk1-lh7a400/drivers/sound/lh7a400-aac.c --- linux-2.4.21-rmk1/drivers/sound/lh7a400-aac.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/sound/lh7a400-aac.c Thu Oct 16 18:44:21 2003 @@ -0,0 +1,2564 @@ +/* + * drivers/sound/lh7a400-acc.c + * + * Driver for the Advanced Audio Codec Controller + * found on the Sharp LH7A400 SoC. + * + * Portions Copyright (C) 2002, Embedix, Inc. + * + * Mostly based on assabet-uda1341.c, which is + * Copyright (c) 2000 Nicolas Pitre + * + * Portions also based on cs46xx.c, which contains these copyrights: + * Copyright 1998-2001 Cirrus Logic Corporation + * + * Copyright 1999-2000 Jaroslav Kysela + * Copyright 2000 Alan Cox + * + * The core of this code is taken from the ALSA project driver by + * Jaroslav. Please send Jaroslav the credit for the driver and + * report bugs in this port to + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "lh7a400-aac.h" + + +#define POWER_UP_LOOP_COUNT 1024 +#define POLL_LOOP_COUNT 1024 + +#define CS_TRUE 1 +#define CS_FALSE 0 + +#define CS_INC_USE_COUNT(m) (atomic_inc(m)) +#define CS_DEC_USE_COUNT(m) (atomic_dec(m)) +#define CS_DEC_AND_TEST(m) (atomic_dec_and_test(m)) +#define CS_IN_USE(m) (atomic_read(m) != 0) + + +#if 0 +#define DEBUG 1 +#define DEBUG_INTERFACE 1 +#else +#undef DEBUG +#undef DEBUG_INTERFACE +#endif + + +#if DEBUG +#define DPRINTK( x... ) printk( ##x ) +#define DUMP_REGS(s) dump_regs(s) +#else +#define DPRINTK( x... ) +#define DUMP_REGS(s) +#endif + +/* + * Turn on/off debugging compilation by using 1/0 respectively for DEBUG + * + * DEBUG is usual mode is set to 1, then use the + * aac_debuglevel and aac_debugmask to turn on or off debugging. + * Debug level of 1 has been defined to be kernel errors and info + * that should be printed on any released driver. + */ +#if DEBUG +#define CS_DBGOUT(mask,level,x) if((aac_debuglevel >= (level)) && ((mask) & aac_debugmask)) {x;} +#else +#define CS_DBGOUT(mask,level,x) +#endif + + + +/* + * aac_debugmask bits + */ +#define CS_INIT 0x00000001 /* init and probe functions */ +#define CS_ERROR 0x00000002 /* tmp debugging bit placeholder */ +#define CS_INTERRUPT 0x00000004 /* int handler (separate from other) */ +#define CS_FUNCTION 0x00000008 /* enter/leave functions */ +#define CS_WAVE_WRITE 0x00000010 /* write information for wave */ +#define CS_WAVE_READ 0x00000020 /* read information for wave */ +#define CS_MIDI_WRITE 0x00000040 /* write information for midi */ +#define CS_MIDI_READ 0x00000080 /* read information for midi */ +#define CS_MPU401_WRITE 0x00000100 /* write information for mpu401 */ +#define CS_MPU401_READ 0x00000200 /* read information for mpu401 */ +#define CS_OPEN 0x00000400 /* all open functions in the driver */ +#define CS_RELEASE 0x00000800 /* all release funcs in the driver */ +#define CS_PARMS 0x00001000 /* functional and operational params */ +#define CS_IOCTL 0x00002000 /* ioctl (non-mixer) */ +#define CS_PM 0x00004000 /* PM */ +#define CS_POWER 0x00008000 /* Power up/down */ +#define CS_TMP 0x10000000 /* tmp debug mask bit */ + +#define CS_IOCTL_CMD_SUSPEND 0x1 /* suspend */ +#define CS_IOCTL_CMD_RESUME 0x2 /* resume */ + +#if DEBUG +static unsigned long aac_debuglevel=9; /* levels range from 1-9 */ +MODULE_PARM( aac_debuglevel, "i"); + +static unsigned long aac_debugmask=CS_INIT | CS_ERROR | CS_IOCTL | CS_POWER | CS_FUNCTION ; +MODULE_PARM( aac_debugmask, "i"); +#endif + +/* + * set the powerdown module parm to 0 to disable all + * powerdown. + */ +static unsigned long powerdown=-1; /* turn on/off powerdown processing in driver */ +MODULE_PARM( powerdown, "i"); + + +#define AAC_MAJOR_VERSION "1" +#define AAC_MINOR_VERSION "29" + +#define TX_CHANNEL 0 /* Use this AAC channel for output */ +#define RX_CHANNEL 0 /* Use this AAC channel for input */ + + + +/* + * Globals. + */ +static u16 g_ac97_features; +static int g_dev_audio = 0; +static struct aac_pm g_pm; +static atomic_t g_mixer_use_cnt; +static struct ac97_codec *g_codec = NULL; +static unsigned g_enablePowerdown=1; +static int audio_samplerate = 48000; + +static aacRegs_t *aac = (aacRegs_t *)IO_ADDRESS(AC97_PHYS); + + +static int lh7a400_audio_open(struct inode *inode, struct file *file); +static inline void wait_for_power_ready( void); + + +#if DEBUG +const char *reg2str[] = { +"Reset", /* AC97_RESET 0x0000 */ +"Master Vol Stereo", /* AC97_MASTER_VOL_STEREO 0x0002 */ +"Headphone Volume", /* AC97_HEADPHONE_VOL 0x0004 */ +"Master Volume Mono", /* AC97_MASTER_VOL_MONO 0x0006 */ +"Master Tone", /* AC97_MASTER_TONE 0x0008 */ +"PC Beep Volume", /* AC97_PCBEEP_VOL 0x000a */ +"Phone volume", /* AC97_PHONE_VOL 0x000c */ +"Mic Volume", /* AC97_MIC_VOL 0x000e */ +"LineIn Volume", /* AC97_LINEIN_VOL 0x0010 */ +"CD Volume", /* AC97_CD_VOL 0x0012 */ +"Video Volume", /* AC97_VIDEO_VOL 0x0014 */ +"AUX Volume", /* AC97_AUX_VOL 0x0016 */ +"PCM Out Volume", /* AC97_PCMOUT_VOL 0x0018 */ +"Record Select", /* AC97_RECORD_SELECT 0x001a */ +"Record Gain", /* AC97_RECORD_GAIN 0x001c */ +"Record Gain Mic", /* AC97_RECORD_GAIN_MIC 0x001e */ +"Gereral Purpose", /* AC97_GENERAL_PURPOSE 0x0020 */ +"3D Control", /* AC97_3D_CONTROL 0x0022 */ +"Modem Rate", /* AC97_MODEM_RATE 0x0024 */ +"Power Control", /* AC97_POWER_CONTROL 0x0026 */ +"Extended ID", /* AC97_EXTENDED_ID 0x0028 */ +"Extended Status", /* AC97_EXTENDED_STATUS 0x002A */ +"PCM Front DAC Rate", /* AC97_PCM_FRONT_DAC_RATE 0x002C */ +"PCM Surround DAC Rate", /* AC97_PCM_SURR_DAC_RATE 0x002E */ +"PCM LFE DAC Rate", /* AC97_PCM_LFE_DAC_RATE 0x0030 */ +"PCM LR DAC Rate", /* AC97_PCM_LR_ADC_RATE 0x0032 */ +"PCM Mic ADC Rate", /* AC97_PCM_MIC_ADC_RATE 0x0034 */ +"Center+LFE Master Volume", /* AC97_CENTER_LFE_MASTER 0x0036 */ +"Surround Master Volume", /* AC97_SURROUND_MASTER 0x0038 */ +"Reserved 3A", /* AC97_RESERVED_3A 0x003A */ +"Extended Modem ID", /* 0x003C */ +"Extended Modem Status", /* 0x003E */ +"Reserved 40", "Reserved 42", "Reserved 44", "Reserved 46", "Reserved 48", "Reserved 4A", +"GPIO Pin Config", /* 0x004C */ +"GPIO Pin Polarity", /* 0x004E */ +"GPIO Pin Sticky", /* 0x0050 */ +"GPIO Pin Wakeup Mask", /* 0x0052 */ +"GPIO Pin Status", /* 0x0054 */ +"Reserved 56", "Reserved 58", "Reserved 5A", "Reserved 5C", +"AC Mode Control", /* 0x005E */ +"Misc Crystal Control", /* 0x0060 */ +"Reserved 62", "Reserved 64", "Reserved 66", +"S/PDIF Control", /* 0x0068 */ +"Serial Port Control", /* 0x006A */ +"Reserved 6C", "Reserved 6E", +"Reserved 70", "Reserved 72", +"Reserved 74", "Reserved 77", "Reserved 78", "Reserved 7A", +"Vendor ID1", /* AC97_VENDOR_ID1 0x007c */ +"Vendor ID2", /* AC97_VENDOR_ID2 0x007e */ +}; + + + +static void decode_GlobalISR( u32 isr) +{ + if( isr & AAC_IRQ_CODEC_READY ) printk( "CodecReady "); + if( isr & AAC_IRQ_WAKEUP ) printk( "Wakeup "); + if( isr & AAC_IRQ_GPIO ) printk( "GPIO "); + if( isr & AAC_IRQ_GPIO_BUSY ) printk( "GPIO_BUSY "); + if( isr & AAC_IRQ_SLOT2_RX_VALID ) printk( "Slot2_Rx_Valid "); + if( isr & AAC_IRQ_SLOT1_TX_DONE ) printk( "Slot1_Tx_Done "); + printk( "\n"); +} + + +static void dump_channel( const char *prefix, int channel) +{ + aacChannel_t *c = &aac->chan[channel]; + + printk( "%s: C%d RxControl=%08x\n", prefix, channel, c->RxControl); + printk( "%s: C%d TxControl=%08x\n", prefix, channel, c->TxControl); + printk( "%s: C%d Status=%08x\n", prefix, channel, c->Status); + printk( "%s: C%d RawISR=%08x\n", prefix, channel, c->RawISR); + printk( "%s: C%d ISR=%08x\n", prefix, channel, c->ISR); + printk( "%s: C%d IE=%08x\n", prefix, channel, c->IE); +} + + +static void dump_regs( const char *prefix) +{ + u32 x; + + dump_channel( prefix, 0); + dump_channel( prefix, 1); + + x = aac->GlobalRawISR; + printk( "%s: GlobalRawISR=%08x ", prefix, x); + decode_GlobalISR( x); + + x = aac->GlobalISR; + printk( "%s: GlobalISR=%08x ", prefix, x); + decode_GlobalISR( x); + + x = aac->GlobalIE; + printk( "%s: GlobalIE=%08x ", prefix, x); + decode_GlobalISR( x); + + printk( "%s: Control=%08x\n", prefix, aac->Control); + printk( "%s: Reset=%08x\n", prefix, aac->Reset); + printk( "%s: Sync=%08x\n", prefix, aac->Sync); + printk( "%s: GlobalFifoISR=%08x\n", prefix, aac->GlobalFifoISR); +} + + + +/* DEBUG ROUTINES */ + +#define SOUND_MIXER_CS_GETDBGLEVEL _SIOWR('M',120, int) +#define SOUND_MIXER_CS_SETDBGLEVEL _SIOWR('M',121, int) +#define SOUND_MIXER_CS_GETDBGMASK _SIOWR('M',122, int) +#define SOUND_MIXER_CS_SETDBGMASK _SIOWR('M',123, int) +#define SOUND_MIXER_CS_APM _SIOWR('M',124, int) + +void printioctl(unsigned int x) +{ + unsigned int i; + unsigned char vidx; + + /* these values are incorrect for the ac97 driver, fix. + * Index of mixtable1[] member is Device ID + * and must be <= SOUND_MIXER_NRDEVICES. + * Value of array member is index into s->mix.vol[] + */ + static const unsigned char mixtable1[SOUND_MIXER_NRDEVICES] = { + [SOUND_MIXER_PCM] = 1, /* voice */ + [SOUND_MIXER_LINE1] = 2, /* AUX */ + [SOUND_MIXER_CD] = 3, /* CD */ + [SOUND_MIXER_LINE] = 4, /* Line */ + [SOUND_MIXER_SYNTH] = 5, /* FM */ + [SOUND_MIXER_MIC] = 6, /* Mic */ + [SOUND_MIXER_SPEAKER] = 7, /* Speaker */ + [SOUND_MIXER_RECLEV] = 8, /* Recording level */ + [SOUND_MIXER_VOLUME] = 9 /* Master Volume */ + }; + + switch(x) { + case SOUND_MIXER_CS_GETDBGMASK: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGMASK: ") ); + break; + case SOUND_MIXER_CS_GETDBGLEVEL: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_GETDBGLEVEL: ") ); + break; + case SOUND_MIXER_CS_SETDBGMASK: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGMASK: ") ); + break; + case SOUND_MIXER_CS_SETDBGLEVEL: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CS_SETDBGLEVEL: ") ); + break; + case OSS_GETVERSION: + CS_DBGOUT(CS_IOCTL, 4, printk("OSS_GETVERSION: ") ); + break; + case SNDCTL_DSP_SYNC: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SYNC: ") ); + break; + case SNDCTL_DSP_SETDUPLEX: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETDUPLEX: ") ); + break; + case SNDCTL_DSP_GETCAPS: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETCAPS: ") ); + break; + case SNDCTL_DSP_RESET: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_RESET: ") ); + break; + case SNDCTL_DSP_SPEED: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SPEED: ") ); + break; + case SNDCTL_DSP_STEREO: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_STEREO: ") ); + break; + case SNDCTL_DSP_CHANNELS: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_CHANNELS: ") ); + break; + case SNDCTL_DSP_GETFMTS: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETFMTS: ") ); + break; + case SNDCTL_DSP_SETFMT: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFMT: ") ); + break; + case SNDCTL_DSP_POST: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_POST: ") ); + break; + case SNDCTL_DSP_GETTRIGGER: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETTRIGGER: ") ); + break; + case SNDCTL_DSP_SETTRIGGER: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETTRIGGER: ") ); + break; + case SNDCTL_DSP_GETOSPACE: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOSPACE: ") ); + break; + case SNDCTL_DSP_GETISPACE: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETISPACE: ") ); + break; + case SNDCTL_DSP_NONBLOCK: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_NONBLOCK: ") ); + break; + case SNDCTL_DSP_GETODELAY: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETODELAY: ") ); + break; + case SNDCTL_DSP_GETIPTR: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETIPTR: ") ); + break; + case SNDCTL_DSP_GETOPTR: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETOPTR: ") ); + break; + case SNDCTL_DSP_GETBLKSIZE: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_GETBLKSIZE: ") ); + break; + case SNDCTL_DSP_SETFRAGMENT: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETFRAGMENT: ") ); + break; + case SNDCTL_DSP_SUBDIVIDE: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SUBDIVIDE: ") ); + break; + case SOUND_PCM_READ_RATE: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_RATE: ") ); + break; + case SOUND_PCM_READ_CHANNELS: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_CHANNELS: ") ); + break; + case SOUND_PCM_READ_BITS: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_BITS: ") ); + break; + case SOUND_PCM_WRITE_FILTER: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_WRITE_FILTER: ") ); + break; + case SNDCTL_DSP_SETSYNCRO: + CS_DBGOUT(CS_IOCTL, 4, printk("SNDCTL_DSP_SETSYNCRO: ") ); + break; + case SOUND_PCM_READ_FILTER: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_PCM_READ_FILTER: ") ); + break; + case SOUND_MIXER_PRIVATE1: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE1: ") ); + break; + case SOUND_MIXER_PRIVATE2: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE2: ") ); + break; + case SOUND_MIXER_PRIVATE3: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE3: ") ); + break; + case SOUND_MIXER_PRIVATE4: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE4: ") ); + break; + case SOUND_MIXER_PRIVATE5: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_PRIVATE5: ") ); + break; + case SOUND_MIXER_INFO: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_INFO: ") ); + break; + case SOUND_OLD_MIXER_INFO: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_OLD_MIXER_INFO: ") ); + break; + + default: + switch (_IOC_NR(x)) { + case SOUND_MIXER_VOLUME: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_VOLUME: ") ); + break; + case SOUND_MIXER_SPEAKER: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SPEAKER: ") ); + break; + case SOUND_MIXER_RECLEV: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECLEV: ") ); + break; + case SOUND_MIXER_MIC: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_MIC: ") ); + break; + case SOUND_MIXER_SYNTH: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_SYNTH: ") ); + break; + case SOUND_MIXER_RECSRC: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECSRC: ") ); + break; + case SOUND_MIXER_DEVMASK: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_DEVMASK: ") ); + break; + case SOUND_MIXER_RECMASK: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_RECMASK: ") ); + break; + case SOUND_MIXER_STEREODEVS: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_STEREODEVS: ") ); + break; + case SOUND_MIXER_CAPS: + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_CAPS:") ); + break; + default: + i = _IOC_NR(x); + if (i >= SOUND_MIXER_NRDEVICES || !(vidx = mixtable1[i])) { + CS_DBGOUT(CS_IOCTL, 4, printk("UNKNOWN IOCTL: 0x%.8x NR=%d ",x,i) ); + } else { + CS_DBGOUT(CS_IOCTL, 4, printk("SOUND_MIXER_IOCTL AC9x: 0x%.8x NR=%d ", + x,i) ); + } + break; + } + } + CS_DBGOUT(CS_IOCTL, 4, printk("command = 0x%x IOC_NR=%d\n",x, _IOC_NR(x)) ); +} +#endif /* DEBUG */ + + + + +#define AUDIO_NAME "lh7x-aac" +#define AUDIO_NBFRAGS_DEFAULT 4 +#define AUDIO_FRAGSIZE_DEFAULT 32768 + +#define NEXT_BUF(_s_,_b_) { \ + (_s_)->_b_##_idx++; \ + (_s_)->_b_##_idx %= (_s_)->nbfrags; \ + (_s_)->_b_ = (_s_)->buffers + (_s_)->_b_##_idx; } + +#define AUDIO_ACTIVE(state) ((state)->rd_ref || (state)->wr_ref) + + +/* Write AC97 codec registers */ +static u16 aac_ac97_get(struct ac97_codec *dev, u8 reg) +{ + int count; + u16 val; + u16 tmp; + u16 gisr; + + /* ensure AAC_IRQ_SLOT2_RX_VALID is clear */ + tmp = aac->slot2Data; + + /* send the register number */ + aac->slot1Data = reg; + + /* wait for Tx Complete */ + count = POLL_LOOP_COUNT; + do { + if( (gisr=aac->GlobalRawISR & AAC_IRQ_SLOT1_TX_DONE)) + break; + barrier(); + } while( count--); + + if( count == 0) + printk( KERN_ERR "aac: aac_ac97_get(): read reg %x Tx Complete count expired\n", reg); + + /* now wait for Rx valid */ + count = POLL_LOOP_COUNT; + do { + if( (gisr=aac->GlobalRawISR & AAC_IRQ_SLOT2_RX_VALID)) + break; + barrier(); + } while( count--); + + udelay( 100); + + if( count) { + val = aac->slot2Data; /* get the register value */ + } else { + printk( KERN_ERR "aac: aac_ac97_get(): read reg %x Rx Valid count expired\n", reg); + val = 0; + } + + CS_DBGOUT(CS_PARMS, 2, + printk("aac: " __FUNCTION__ "(%s<%02x>) = 0x%x\n", + reg2str[reg>>1], reg, val) ); + + return val; +} + + +static void aac_ac97_set(struct ac97_codec *dev, u8 reg, u16 val) +{ + int count; + + CS_DBGOUT( CS_FUNCTION, 2, + printk("\t\t\taac: " __FUNCTION__ "(%s<%02x> val=0x%x) \n", + reg2str[reg>>1], reg, val) ); + + aac->slot2Data = val; /* set the value first */ + aac->slot1Data = reg; /* then the register number */ + + udelay( 100); + + /* wait for Tx Complete */ + count = POLL_LOOP_COUNT; + do { + if( aac->GlobalRawISR & AAC_IRQ_SLOT1_TX_DONE) + break; + barrier(); + } while( count--); + + if( !count) /* TX didn't complete */ + printk( KERN_ERR "aac: aac_ac97_set(): didn't get TX_DONE\n"); + + /* + * if we just wrote to the reset register, + * wait till the chip's ready. + */ + if( reg == AC97_RESET) + wait_for_power_ready(); +} + + +static inline void wait_for_power_ready( void) +{ + int count = POWER_UP_LOOP_COUNT; + + do { + if( aac_ac97_get( NULL, AC97_POWER_CONTROL) == 0x0F) + break; + barrier(); + } while( count--); +} + + + +/* + * mute some of the more prevalent registers to avoid popping. + */ +static void aac_mute( int state) +{ + struct ac97_codec *dev = g_codec; + + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "aac: aac_mute()+ %s\n", + (state == CS_TRUE) ? "Muting" : "UnMuting") ); + + if(state == CS_TRUE) { + /* + * fix pops when powering up on thinkpads + */ + g_pm.u32AC97_master_volume = aac_ac97_get(dev, AC97_MASTER_VOL_STEREO); + g_pm.u32AC97_headphone_volume = aac_ac97_get(dev, AC97_HEADPHONE_VOL); + g_pm.u32AC97_master_volume_mono = aac_ac97_get(dev, AC97_MASTER_VOL_MONO); + g_pm.u32AC97_pcm_out_volume = aac_ac97_get(dev, AC97_PCMOUT_VOL); + + aac_ac97_set(dev, AC97_MASTER_VOL_STEREO, 0x8000); + aac_ac97_set(dev, AC97_HEADPHONE_VOL, 0x8000); + aac_ac97_set(dev, AC97_MASTER_VOL_MONO, 0x8000); + aac_ac97_set(dev, AC97_PCMOUT_VOL, 0x8000); + } else { + aac_ac97_set(dev, AC97_MASTER_VOL_STEREO, g_pm.u32AC97_master_volume); + aac_ac97_set(dev, AC97_HEADPHONE_VOL, g_pm.u32AC97_headphone_volume); + aac_ac97_set(dev, AC97_MASTER_VOL_MONO, g_pm.u32AC97_master_volume_mono); + aac_ac97_set(dev, AC97_PCMOUT_VOL, g_pm.u32AC97_pcm_out_volume); + } + CS_DBGOUT(CS_FUNCTION, 2, printk(KERN_INFO "aac: aac_mute()-\n")); +} + + +/* set playback sample rate */ +static unsigned int aac_set_dac_rate( unsigned int rate) +{ + struct ac97_codec *codec=g_codec; + u32 new_rate; + + CS_DBGOUT(CS_FUNCTION, 2, printk("aac: aac_set_dac_rate()+ rate=%d\n",rate) ); + + if( !(g_ac97_features & 0x01)) { +#if DEBUG + printk("Asked for %d Hz, but ac97_features says we only do 48Hz. Sorry!\n", rate); +#endif + audio_samplerate = 48000; + return 48000; + } + + if (rate > 48000) + rate = 48000; + if (rate < 8000) + rate = 8000; + + new_rate = ac97_set_dac_rate( codec, rate); + + CS_DBGOUT(CS_PARMS, 2, + printk("aac: called ac97_set_dac_rate: asked for %d, got %d\n", + rate, new_rate)); + + audio_samplerate = new_rate; + + CS_DBGOUT(CS_FUNCTION, 2, printk("aac: aac_set_dac_rate()- %d\n",audio_samplerate) ); + return audio_samplerate; +} + + +/* set recording sample rate */ +static unsigned int aac_set_adc_rate( unsigned int rate) +{ + struct ac97_codec *codec=g_codec; + u32 new_rate; + + CS_DBGOUT(CS_FUNCTION, 2, + printk("aac: aac_set_adc_rate()+ rate=%d\n",rate) ); + + if( !(g_ac97_features & 0x01)) { +#if DEBUG + printk("Asked for %d Hz, but ac97_features says we only do 48Hz. Sorry!\n", rate); +#endif + audio_samplerate = 48000; + return 48000;; + } + + if (rate > 48000) + rate = 48000; + if (rate < 8000) + rate = 8000; + + new_rate = ac97_set_adc_rate( codec, rate); + + CS_DBGOUT(CS_PARMS, 2, + printk("aac: called ac97_set_dac_rate : asked for %d, got %d\n", + rate, new_rate)); + + audio_samplerate = new_rate; + + CS_DBGOUT(CS_FUNCTION, 2, + printk("aac: aac_set_adc_rate()- %d\n", audio_samplerate) ); + + return audio_samplerate; +} + + +static int aac_powerdown( unsigned int type, int suspendflag) +{ + int count; + unsigned int tmp=0,muted=0; + + CS_DBGOUT( CS_FUNCTION | CS_POWER, 4, printk(KERN_INFO + "aac: aac_powerdown()+ type=0x%x\n",type)); + + if( !g_enablePowerdown && !suspendflag) { + CS_DBGOUT(CS_FUNCTION | CS_POWER, 8, printk(KERN_INFO + "aac: aac_powerdown() DISABLED exiting\n")); + return 0; + } + + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + + CS_DBGOUT(CS_FUNCTION | CS_POWER, 8, printk(KERN_INFO + "aac: aac_powerdown() AC97_POWER_CONTROL=0x%x\n",tmp)); + + /* + * if powering down only the VREF, and not powering down the DAC/ADC, + * then do not power down the VREF, UNLESS both the DAC and ADC are not + * currently powered down. If powering down DAC and ADC, then + * it is possible to power down the VREF (ON). + */ + if ( ((type & AAC_POWER_MIXVON) && + (!(type & AAC_POWER_ADC) || (!(type & AAC_POWER_DAC))) ) + && + ((tmp & AAC_AC97_POWER_CONTROL_ADC_ON) || + (tmp & AAC_AC97_POWER_CONTROL_DAC_ON) ) ) + { + CS_DBGOUT(CS_FUNCTION | CS_POWER, 8, printk(KERN_INFO + "aac: aac_powerdown()- 0 unable to powerdown. tmp=0x%x\n",tmp)); + return 0; + } + + /* + * for now, always keep power to the mixer block. + * not sure why it's a problem but it seems to be if we power off. + */ + type &= ~AAC_POWER_MIXVON; + type &= ~AAC_POWER_MIXVOFF; + + /* + * Power down indicated areas. + */ + if(type & AAC_POWER_MIXVOFF) { + + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, + printk(KERN_INFO "aac: aac_powerdown()+ MIXVOFF\n")); + /* + * Power down the MIXER (VREF ON) on the AC97 card. + */ + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + if (tmp & AAC_AC97_POWER_CONTROL_MIXVOFF_ON) { + if(!muted) { + aac_mute( CS_TRUE); + muted=1; + } + tmp |= AAC_AC97_POWER_CONTROL_MIXVOFF; + aac_ac97_set( g_codec, AC97_POWER_CONTROL, tmp ); + + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_MIXVOFF_ON)) + break; + } + + /* + * Check the status.. + */ + if (aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_MIXVOFF_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "aac: powerdown MIXVOFF failed\n")); + return 1; + } + } + } + + if(type & AAC_POWER_MIXVON) { + + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, + printk(KERN_INFO "aac: aac_powerdown()+ MIXVON\n")); + /* + * Power down the MIXER (VREF ON) on the AC97 card. + */ + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + if( tmp & AAC_AC97_POWER_CONTROL_MIXVON_ON) { + if( !muted) { + aac_mute( CS_TRUE); + muted=1; + } + tmp |= AAC_AC97_POWER_CONTROL_MIXVON; + aac_ac97_set( g_codec, AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for( count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_MIXVON_ON)) + break; + } + + /* + * Check the status.. + */ + if( aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_MIXVON_ON) + { + CS_DBGOUT(CS_ERROR | CS_POWER, 1, printk(KERN_WARNING + "aac: powerdown MIXVON failed\n")); + return 1; + } + } + } + + if( type & AAC_POWER_ADC) { + /* + * Power down the ADC on the AC97 card. + */ + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, printk(KERN_INFO "aac: aac_powerdown()+ ADC\n")); + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + if( tmp & AAC_AC97_POWER_CONTROL_ADC_ON) { + if( !muted) { + aac_mute( CS_TRUE); + muted=1; + } + tmp |= AAC_AC97_POWER_CONTROL_ADC; + aac_ac97_set( g_codec, AC97_POWER_CONTROL, tmp ); + + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_ADC_ON)) + break; + } + + /* + * Check the status.. + */ + if (aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_ADC_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "aac: powerdown ADC failed\n")); + return 1; + } + } + } + + if( type & AAC_POWER_DAC) { + /* + * Power down the DAC on the AC97 card. + */ + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, + printk(KERN_INFO "aac: aac_powerdown()+ DAC\n")); + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + if (tmp & AAC_AC97_POWER_CONTROL_DAC_ON) { + if(!muted) { + aac_mute( CS_TRUE); + muted=1; + } + tmp |= AAC_AC97_POWER_CONTROL_DAC; + aac_ac97_set( g_codec, AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (!(aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_DAC_ON)) + break; + } + + /* + * Check the status.. + */ + if (aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_DAC_ON) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "aac: powerdown DAC failed\n")); + return 1; + } + } + } + + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + + if(muted) + aac_mute( CS_FALSE); + + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, printk(KERN_INFO + "aac: aac_powerdown()- 0 AC97_POWER_CONTROL=0x%x\n",tmp)); + + return 0; +} + +static int aac_powerup( unsigned int type) +{ + int count; + unsigned int tmp=0,muted=0; + + CS_DBGOUT( CS_FUNCTION | CS_POWER, 8, printk(KERN_INFO + "aac: aac_powerup()+ type=0x%x\n",type)); + /* + * check for VREF and powerup if need to. + */ + if(type & AAC_POWER_MIXVON) + type |= AAC_POWER_MIXVOFF; + + if(type & (AAC_POWER_DAC | AAC_POWER_ADC)) + type |= AAC_POWER_MIXVON | AAC_POWER_MIXVOFF; + + /* + * Power up indicated areas. + */ + if(type & AAC_POWER_MIXVOFF) { + + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, + printk(KERN_INFO "aac: aac_powerup()+ MIXVOFF\n")); + /* + * Power up the MIXER (VREF ON) on the AC97 card. + */ + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + if (!(tmp & AAC_AC97_POWER_CONTROL_MIXVOFF_ON)) { + if(!muted) { + aac_mute( CS_TRUE); + muted=1; + } + tmp &= ~AAC_AC97_POWER_CONTROL_MIXVOFF; + aac_ac97_set( g_codec, AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_MIXVOFF_ON) + break; + } + + /* + * Check the status.. + */ + if (!(aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_MIXVOFF_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "aac: powerup MIXVOFF failed\n")); + return 1; + } + } + } + + if(type & AAC_POWER_MIXVON) { + + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, + printk(KERN_INFO "aac: aac_powerup()+ MIXVON\n")); + /* + * Power up the MIXER (VREF ON) on the AC97 card. + */ + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + if (!(tmp & AAC_AC97_POWER_CONTROL_MIXVON_ON)) { + if(!muted) { + aac_mute( CS_TRUE); + muted=1; + } + tmp &= ~AAC_AC97_POWER_CONTROL_MIXVON; + aac_ac97_set( g_codec, AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_MIXVON_ON) + break; + } + + /* + * Check the status.. + */ + if (!(aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_MIXVON_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "aac: powerup MIXVON failed\n")); + return 1; + } + } + } + + if( type & AAC_POWER_ADC) { + /* + * Power up the ADC on the AC97 card. + */ + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, printk(KERN_INFO "aac: aac_powerup()+ ADC\n")); + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + if ( !(tmp & AAC_AC97_POWER_CONTROL_ADC_ON)) { + if( !muted) { + aac_mute( CS_TRUE); + muted=1; + } + tmp &= ~AAC_AC97_POWER_CONTROL_ADC; + aac_ac97_set( g_codec, AC97_POWER_CONTROL, tmp ); + + /* + * Now, we wait until we sample a ready state. + */ + for( count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay( 500); + + /* + * Read the current state of the power control register. + */ + if( aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_ADC_ON) + break; + } + + /* + * Check the status.. + */ + if( !(aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_ADC_ON)) + { + CS_DBGOUT(CS_ERROR | CS_POWER, 1, printk(KERN_WARNING + "aac: powerup ADC failed\n")); + return 1; + } + } + } + + if( type & AAC_POWER_DAC) { + /* + * Power up the DAC on the AC97 card. + */ + + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, + printk(KERN_INFO "aac: aac_powerup()+ DAC\n")); + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + if (!(tmp & AAC_AC97_POWER_CONTROL_DAC_ON)) { + if(!muted) { + aac_mute( CS_TRUE); + muted=1; + } + tmp &= ~AAC_AC97_POWER_CONTROL_DAC; + aac_ac97_set( g_codec, AC97_POWER_CONTROL, tmp ); + /* + * Now, we wait until we sample a ready state. + */ + for (count = 0; count < 32; count++) { + /* + * First, lets wait a short while to let things settle out a + * bit, and to prevent retrying the read too quickly. + */ + udelay(500); + + /* + * Read the current state of the power control register. + */ + if (aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_DAC_ON) + break; + } + + /* + * Check the status.. + */ + if (!(aac_ac97_get( g_codec, AC97_POWER_CONTROL) & + AAC_AC97_POWER_CONTROL_DAC_ON)) + { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_WARNING + "aac: powerup DAC failed\n")); + return 1; + } + } + } + + tmp = aac_ac97_get( g_codec, AC97_POWER_CONTROL); + + if( muted) + aac_mute( CS_FALSE); + + CS_DBGOUT(CS_FUNCTION | CS_POWER, 4, printk(KERN_INFO + "aac: aac_powerup()- 0 AC97_POWER_CONTROL=0x%x\n",tmp)); + + return 0; +} + + + +/* OSS /dev/mixer file operation methods */ + +static int aac_open_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + unsigned int tmp; + + CS_DBGOUT(CS_FUNCTION | CS_OPEN, 4, + printk(KERN_INFO "aac: aac_open_mixdev()+\n")); + + if( g_codec == NULL || g_codec->dev_mixer != minor) { + CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, + printk(KERN_INFO "aac: aac_open_mixdev()- -ENODEV\n")); + return -ENODEV; + } + + file->private_data = g_codec; + + if( !CS_IN_USE( &g_mixer_use_cnt)) { + if( (tmp = aac_powerup( AAC_POWER_MIXVON )) ) { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "aac: aac_open_mixdev() powerup failure (0x%x)\n",tmp) ); + return -EIO; + } + } + + CS_INC_USE_COUNT( &g_mixer_use_cnt); + MOD_INC_USE_COUNT; /* for 2.2 */ + + CS_DBGOUT( CS_FUNCTION | CS_OPEN, 4, + printk(KERN_INFO "aac: aac_open_mixdev()- 0\n")); + + return 0; +} + + +static int aac_release_mixdev(struct inode *inode, struct file *file) +{ + int minor = MINOR(inode->i_rdev); + unsigned int tmp; + + CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4, + printk(KERN_INFO "aac: aac_release_mixdev()+\n")); + + if (!g_codec || g_codec->dev_mixer != minor) { + CS_DBGOUT(CS_FUNCTION | CS_OPEN | CS_ERROR, 2, + printk(KERN_INFO "aac: aac_release_mixdev()- -ENODEV\n")); + return -ENODEV; + } + + MOD_DEC_USE_COUNT; /* for 2.2 */ + + if( !CS_DEC_AND_TEST( &g_mixer_use_cnt)) { + CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4, + printk(KERN_INFO "aac: aac_release_mixdev()- no powerdown, usecnt>0\n")); + return 0; + } + + /* + * ok, no outstanding mixer opens, so powerdown. + */ + if( (tmp = aac_powerdown( AAC_POWER_MIXVON, CS_FALSE )) ) { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "aac: aac_release_mixdev() powerdown MIXVON failure (0x%x)\n",tmp) ); + return -EIO; + } + + CS_DBGOUT(CS_FUNCTION | CS_RELEASE, 4, + printk(KERN_INFO "aac: aac_release_mixdev()- 0\n")); + + return 0; +} + + + +static int aac_ioctl_mixdev(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct ac97_codec *codec = (struct ac97_codec *)file->private_data; + +#if DEBUG_INTERFACE + int val; + + if( (cmd == SOUND_MIXER_CS_GETDBGMASK) || + (cmd == SOUND_MIXER_CS_SETDBGMASK) || + (cmd == SOUND_MIXER_CS_GETDBGLEVEL) || + (cmd == SOUND_MIXER_CS_SETDBGLEVEL) || + (cmd == SOUND_MIXER_CS_APM)) + { + switch(cmd) + { + + case SOUND_MIXER_CS_GETDBGMASK: + return put_user(aac_debugmask, (unsigned long *)arg); + + case SOUND_MIXER_CS_GETDBGLEVEL: + return put_user(aac_debuglevel, (unsigned long *)arg); + + case SOUND_MIXER_CS_SETDBGMASK: + if (get_user(val, (unsigned long *)arg)) + return -EFAULT; + aac_debugmask = val; + return 0; + + case SOUND_MIXER_CS_SETDBGLEVEL: + if (get_user(val, (unsigned long *)arg)) + return -EFAULT; + aac_debuglevel = val; + return 0; + + default: + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "aac: mixer_ioctl(): ERROR unknown debug cmd\n") ); + return 0; + } + } +#endif + return codec->mixer_ioctl(codec, cmd, arg); +} + +static /*const*/ struct file_operations aac_mixer_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + ioctl: aac_ioctl_mixdev, + open: aac_open_mixdev, + release: aac_release_mixdev, +}; + + +static /*const*/ struct file_operations aac_fops = { + owner: THIS_MODULE, + open: lh7a400_audio_open, +}; + + + +/* + * This function frees all buffers + */ +static void audio_clear_buf(audio_stream_t * s) +{ + DPRINTK("audio_clear_buf\n"); + + /* ensure DMA won't run anymore */ + s->active = 0; + s->stopped = 0; + lh7a400_dma_flush_all(s->dma_ch); + + if (s->buffers) { + int frag; + for (frag = 0; frag < s->nbfrags; frag++) { + if (!s->buffers[frag].master) + continue; + consistent_free(s->buffers[frag].start, + s->buffers[frag].master, + s->buffers[frag].dma_addr); + } + kfree(s->buffers); + s->buffers = NULL; + } + + s->buf_idx = 0; + s->buf = NULL; +} + + +/* + * This function allocates the buffer structure array and buffer data space + * according to the current number of fragments and fragment size. + */ + +static int audio_setup_buf(audio_stream_t * s) +{ + int frag; + int dmasize = 0; + char *dmabuf = NULL; + dma_addr_t dmaphys = 0; + + if (s->buffers) + return -EBUSY; + + s->buffers = (audio_buf_t *) + kmalloc(sizeof(audio_buf_t) * s->nbfrags, GFP_KERNEL); + if (!s->buffers) + goto err; + memset(s->buffers, 0, sizeof(audio_buf_t) * s->nbfrags); + + for (frag = 0; frag < s->nbfrags; frag++) { + audio_buf_t *b = &s->buffers[frag]; + + /* + * Let's allocate non-cached memory for DMA buffers. + * We try to allocate all memory at once. + * If this fails (a common reason is memory fragmentation), + * then we allocate more smaller buffers. + */ + if (!dmasize) { + dmasize = (s->nbfrags - frag) * s->fragsize; + do { + dmabuf = consistent_alloc(GFP_KERNEL|GFP_DMA, + dmasize, + &dmaphys); + if (!dmabuf) + dmasize -= s->fragsize; + } while (!dmabuf && dmasize); + if (!dmabuf) + goto err; + b->master = dmasize; + memzero(dmabuf, dmasize); + } + + b->start = dmabuf; + b->dma_addr = dmaphys; + b->stream = s; + sema_init(&b->sem, 1); + DPRINTK( __FUNCTION__ ": buf %d: start %p dma %x size=%d\n", + frag, b->start, b->dma_addr, dmasize); + + dmabuf += s->fragsize; + dmaphys += s->fragsize; + dmasize -= s->fragsize; + } + + s->buf_idx = 0; + s->buf = &s->buffers[0]; + s->bytecount = 0; + s->fragcount = 0; + + return 0; + +err: + printk(AUDIO_NAME ": unable to allocate audio memory\n "); + audio_clear_buf(s); + return -ENOMEM; +} + + +/* + * This function yanks all buffers from the DMA code's control and + * resets them ready to be used again. + */ + +static void audio_reset_buf(audio_stream_t * s) +{ + int frag; + + s->active = 0; + s->stopped = 0; + lh7a400_dma_flush_all(s->dma_ch); + if (s->buffers) { + for (frag = 0; frag < s->nbfrags; frag++) { + audio_buf_t *b = &s->buffers[frag]; + b->size = 0; + sema_init(&b->sem, 1); + } + } + s->bytecount = 0; + s->fragcount = 0; +} + + +/* + * DMA callback functions + */ +static void audio_dmaout_done_callback(void *buf_id, int size) +{ + audio_buf_t *b = (audio_buf_t *) buf_id; + audio_stream_t *s = b->stream; + + DPRINTK( "audio_dmaout callback bid=0x%p\n", buf_id); + + /* Accounting */ + s->bytecount += size; + s->fragcount++; + + /* Recycle buffer */ + if (s->mapped) + lh7a400_dma_queue_buffer(s->dma_ch, buf_id, + b->dma_addr, s->fragsize); + else { + up(&b->sem); + } + + /* And any process polling on write. */ + wake_up(&s->wq); +} + + +static void audio_dmain_done_callback(void *buf_id, int size) +{ + audio_buf_t *b = (audio_buf_t *) buf_id; + audio_stream_t *s = b->stream; + + DPRINTK( "audio_dmain callback bid=0x%p size=%d\n", buf_id, size); + + /* Accounting */ + s->bytecount += size; + s->fragcount++; + + /* Recycle buffer */ + if (s->mapped) { + lh7a400_dma_queue_buffer(s->dma_ch, buf_id, + b->dma_addr, s->fragsize); + } else { + b->size = size; + up(&b->sem); + } + + /* And any process polling on write. */ + wake_up(&s->wq); +} + + +static int audio_sync(struct file *file) +{ + audio_state_t *state = (audio_state_t *)file->private_data; + audio_stream_t *s = state->output_stream; + audio_buf_t *b; + + DPRINTK("audio_sync file=%p\n", file); + + if (!(file->f_mode & FMODE_WRITE) || !s->buffers || s->mapped) + return 0; + + /* + * Send current buffer if it contains data. Be sure to send + * a full sample count. + */ + b = s->buf; + + if (b->size &= ~3) { + down(&b->sem); + lh7a400_dma_queue_buffer(s->dma_ch, (void *) b, + b->dma_addr, b->size); + b->size = 0; + NEXT_BUF(s, buf); + } + + /* + * Let's wait for the last buffer we sent i.e. the one before the + * current buf_idx. When we acquire the semaphore, this means either: + * - DMA on the buffer completed or + * - the buffer was already free thus nothing else to sync. + */ + b = s->buffers + ((s->nbfrags + s->buf_idx - 1) % s->nbfrags); + + if (down_interruptible(&b->sem)) + return -EINTR; + up(&b->sem); + return 0; +} + + +#define USE_DMA 1 + +static int audio_write(struct file *file, const char *buffer, + size_t count, loff_t * ppos) +{ + const char *buffer0 = buffer; + audio_state_t *state = (audio_state_t *)file->private_data; + audio_stream_t *s = state->output_stream; + int chunksize, ret = 0; + + DPRINTK("\naudio_write: called. jif=%ld count=%d\n", jiffies, count); + + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->mapped) + return -ENXIO; + if (!s->buffers && audio_setup_buf(s)) + return -ENOMEM; + + while (count > 0) { + audio_buf_t *b = s->buf; + + /* Wait for a buffer to become free */ + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + if (down_trylock(&b->sem)) + break; + } else { + ret = -ERESTARTSYS; + if (down_interruptible(&b->sem)) + break; + } + + /* Feed the current buffer */ + chunksize = s->fragsize - b->size; + if (chunksize > count) + chunksize = count; + DPRINTK("write %d to %d at 0x%p\n", chunksize, s->buf_idx, b->start+b->size); + if (copy_from_user(b->start + b->size, buffer, chunksize)) { + up(&b->sem); + return -EFAULT; + } + b->size += chunksize; + buffer += chunksize; + count -= chunksize; + if (b->size < s->fragsize) { + up(&b->sem); + break; + } + + /* Send current buffer to dma */ + s->active = 1; + +#if USE_DMA + + lh7a400_dma_queue_buffer(s->dma_ch, (void *) b, + b->dma_addr, b->size); + DPRINTK("\naudio_write: queue done\n"); + +#else /* test with programmed I/O */ + + { + aacChannel_t *chan = &aac->chan[0]; + u32 *data = (u32 *)b->start; + u32 *fifo = (u32 *)&chan->Data; + int i; + + printk( "*** writing %d bytes from %p to %p\n", b->size, data, fifo); + + for( i=0; i < ( b->size >> 2) ; i++) { + while( chan->Status & CH_STATUS_TXFF ) { + /* FIFO full, wait a bit */ + barrier(); + } + *fifo = *data++; + } + + s->bytecount += b->size; + s->fragcount++; + up(&b->sem); + } +#endif + b->size = 0; /* indicate that the buffer has been sent */ + NEXT_BUF(s, buf); + } + + if ((buffer - buffer0)) + ret = buffer - buffer0; + + DPRINTK("audio_write: return=%d\n\n", ret); + + return ret; +} + + +static void audio_prime_dma(audio_stream_t *s) +{ + int i; + + s->active = 1; + for (i = 0; i < s->nbfrags; i++) { + audio_buf_t *b = s->buf; + down(&b->sem); + lh7a400_dma_queue_buffer(s->dma_ch, (void *) b, + b->dma_addr, s->fragsize); + NEXT_BUF(s, buf); + } +} + + +static int audio_read(struct file *file, char *buffer, + size_t count, loff_t * ppos) +{ + char *buffer0 = buffer; + audio_state_t *state = (audio_state_t *)file->private_data; + audio_stream_t *s = state->input_stream; + int chunksize, ret = 0; + + DPRINTK("audio_read: count=%d\n", count); + + if (ppos != &file->f_pos) + return -ESPIPE; + if (s->mapped) + return -ENXIO; + + if (!s->active) { + if (!s->buffers && audio_setup_buf(s)) + return -ENOMEM; + audio_prime_dma(s); + } + + while (count > 0) { + audio_buf_t *b = s->buf; + + /* Wait for a buffer to become full */ + if (file->f_flags & O_NONBLOCK) { + ret = -EAGAIN; + if (down_trylock(&b->sem)) + break; + } else { + ret = -ERESTARTSYS; + if (down_interruptible(&b->sem)) + break; + } + + /* Grab data from the current buffer */ + chunksize = b->size; + if (chunksize > count) + chunksize = count; + DPRINTK("read %d from %d\n", chunksize, s->buf_idx); + if (copy_to_user(buffer, + b->start + s->fragsize - b->size, + chunksize)) { + up(&b->sem); + return -EFAULT; + } + b->size -= chunksize; + buffer += chunksize; + count -= chunksize; + if (b->size > 0) { + up(&b->sem); + break; + } + + /* Make current buffer available for DMA again */ + lh7a400_dma_queue_buffer(s->dma_ch, (void *) b, + b->dma_addr, s->fragsize); + NEXT_BUF(s, buf); + } + + if ((buffer - buffer0)) + ret = buffer - buffer0; + DPRINTK("audio_read: return=%d\n", ret); + return ret; +} + + +static int audio_mmap(struct file *file, struct vm_area_struct *vma) +{ + audio_state_t *state = (audio_state_t *)file->private_data; + audio_stream_t *s; + unsigned long size, vma_addr; + int i, ret; + + if (vma->vm_pgoff != 0) + return -EINVAL; + + if (vma->vm_flags & VM_WRITE) { + if (!state->wr_ref) + return -EINVAL;; + s = state->output_stream; + } else if (vma->vm_flags & VM_READ) { + if (!state->rd_ref) + return -EINVAL; + s = state->input_stream; + } else return -EINVAL; + + if (s->mapped) + return -EINVAL; + size = vma->vm_end - vma->vm_start; + if (size != s->fragsize * s->nbfrags) + return -EINVAL; + if (!s->buffers && audio_setup_buf(s)) + return -ENOMEM; + vma_addr = vma->vm_start; + for (i = 0; i < s->nbfrags; i++) { + audio_buf_t *buf = &s->buffers[i]; + if (!buf->master) + continue; + ret = remap_page_range(vma_addr, buf->dma_addr, buf->master, vma->vm_page_prot); + if (ret) + return ret; + vma_addr += buf->master; + } + s->mapped = 1; + + return 0; +} + + +static unsigned int audio_poll(struct file *file, + struct poll_table_struct *wait) +{ + audio_state_t *state = (audio_state_t *)file->private_data; + audio_stream_t *is = state->input_stream; + audio_stream_t *os = state->output_stream; + unsigned int mask = 0; + int i; + + DPRINTK("audio_poll(): mode=%s%s\n", + (file->f_mode & FMODE_READ) ? "r" : "", + (file->f_mode & FMODE_WRITE) ? "w" : ""); + + if (file->f_mode & FMODE_READ) { + /* Start audio input if not already active */ + if (!is->active) { + if (!is->buffers && audio_setup_buf(is)) + return -ENOMEM; + audio_prime_dma(is); + } + poll_wait(file, &is->wq, wait); + } + + if (file->f_mode & FMODE_WRITE) { + if (!os->buffers && audio_setup_buf(os)) + return -ENOMEM; + poll_wait(file, &os->wq, wait); + } + + if (file->f_mode & FMODE_READ) { + if (is->mapped) { + if (is->bytecount > 0) + mask |= POLLIN | POLLRDNORM; + } else { + for (i = 0; i < is->nbfrags; i++) { + if (atomic_read(&is->buffers[i].sem.count) > 0) { + mask |= POLLIN | POLLRDNORM; + break; + } + } + } + } + + if (file->f_mode & FMODE_WRITE) { + if (os->mapped) { + if (os->bytecount > 0) + mask |= POLLOUT | POLLWRNORM; + } else { + for (i = 0; i < os->nbfrags; i++) { + if (atomic_read(&os->buffers[i].sem.count) > 0) { + mask |= POLLOUT | POLLWRNORM; + break; + } + } + } + } + + DPRINTK("audio_poll() returned mask of %s%s\n", + (mask & POLLIN) ? "r" : "", + (mask & POLLOUT) ? "w" : ""); + + return mask; +} + + +static loff_t audio_llseek(struct file *file, loff_t offset, int origin) +{ + return -ESPIPE; +} + + +static int audio_set_fragments(audio_stream_t *s, int val) +{ + DPRINTK("audio_set_fragments: val=0x%x\n", val); + if (s->active) + return -EBUSY; + if (s->buffers) + audio_clear_buf(s); + s->nbfrags = (val >> 16) & 0x7FFF; + val &= 0xffff; + if (val < 4) + val = 4; + if (val > 15) + val = 15; + s->fragsize = 1 << val; + if (s->nbfrags < 2) + s->nbfrags = 2; + if (s->nbfrags * s->fragsize > 128 * 1024) + s->nbfrags = 128 * 1024 / s->fragsize; + if (audio_setup_buf(s)) + return -ENOMEM; + return val|(s->nbfrags << 16); +} + + +static int audio_ioctl(struct inode *inode, struct file *file, + uint cmd, ulong arg) +{ + audio_state_t *state = (audio_state_t *)file->private_data; + audio_stream_t *os = state->output_stream; + audio_stream_t *is = state->input_stream; + long val; + int ret = 0; + + DPRINTK("audio_ioctl: inode=%p cmd=0x%x arg=0x%x\n", inode, cmd, (u32)arg); + +#if DEBUG + printioctl(cmd); +#endif + + /* dispatch based on command */ + switch (cmd) { + case OSS_GETVERSION: + return put_user(SOUND_VERSION, (int *)arg); + + case SNDCTL_DSP_RESET: + if (file->f_mode & FMODE_READ) { + if (state->tx_spinning) { + lh7a400_dma_set_spin(os->dma_ch, 0, 0); + state->tx_spinning = 0; + } + audio_reset_buf(is); + } + if (file->f_mode & FMODE_WRITE) { + audio_reset_buf(os); + } + return 0; + + case SNDCTL_DSP_SYNC: + return audio_sync(file); + + case SNDCTL_DSP_SPEED: + ret = get_user(val, (long *) arg); + if (ret) + break; + + if (val >= 0) { + if (file->f_mode & FMODE_READ) { + aac_set_adc_rate( val); + } + if (file->f_mode & FMODE_WRITE) { + aac_set_dac_rate( val); + } + } + + return put_user(audio_samplerate, (long *) arg); + + case SNDCTL_DSP_STEREO: + ret = get_user(val, (int *) arg); + if (ret) + return ret; + /* the AC79 is stereo only */ + ret = (val == 0) ? -EINVAL : 1; + return put_user(ret, (int *) arg); + + case SNDCTL_DSP_GETBLKSIZE: + if (file->f_mode & FMODE_WRITE) + return put_user(os->fragsize, (int *)arg); + else + return put_user(is->fragsize, (int *)arg); + + case SNDCTL_DSP_SETFMT: + case SNDCTL_DSP_GETFMTS: + /* we can do signed 16-bit only */ + return put_user(AFMT_S16_LE, (long *) arg); + + case SNDCTL_DSP_CHANNELS: + case SOUND_PCM_READ_CHANNELS: + /* is stereo only */ + return put_user(2, (long *) arg); + + case SNDCTL_DSP_POST: + return 0; + + case SNDCTL_DSP_SUBDIVIDE: + return 0; + + case SNDCTL_DSP_SETFRAGMENT: + if (get_user(val, (long *) arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + int ret = audio_set_fragments(is, val); + if (ret < 0) + return ret; + ret = put_user(ret, (int *)arg); + if (ret) + return ret; + } + if (file->f_mode & FMODE_WRITE) { + int ret = audio_set_fragments(os, val); + if (ret < 0) + return ret; + ret = put_user(ret, (int *)arg); + if (ret) + return ret; + } + return 0; + + case SNDCTL_DSP_GETOSPACE: + { + audio_buf_info inf = { 0, }; + int i; + + if (!(file->f_mode & FMODE_WRITE)) + return -EINVAL; + if (!os->buffers && audio_setup_buf(os)) + return -ENOMEM; + for (i = 0; i < os->nbfrags; i++) { + if (atomic_read(&os->buffers[i].sem.count) > 0) { + if (os->buffers[i].size == 0) + inf.fragments++; + inf.bytes += os->fragsize - os->buffers[i].size; + } + } + inf.fragstotal = os->nbfrags; + inf.fragsize = os->fragsize; + return copy_to_user((void *)arg, &inf, sizeof(inf)); + } + + case SNDCTL_DSP_GETISPACE: + { + audio_buf_info inf = { 0, }; + int i; + + if (!(file->f_mode & FMODE_READ)) + return -EINVAL; + if (!is->buffers && audio_setup_buf(is)) + return -ENOMEM; + for (i = 0; i < is->nbfrags; i++) { + if (atomic_read(&is->buffers[i].sem.count) > 0) { + if (is->buffers[i].size == is->fragsize) + inf.fragments++; + inf.bytes += is->buffers[i].size; + } + } + inf.fragstotal = is->nbfrags; + inf.fragsize = is->fragsize; + return copy_to_user((void *)arg, &inf, sizeof(inf)); + } + + case SNDCTL_DSP_NONBLOCK: + file->f_flags |= O_NONBLOCK; + return 0; + + case SNDCTL_DSP_GETCAPS: + val = DSP_CAP_REALTIME|DSP_CAP_TRIGGER|DSP_CAP_MMAP; + if (is && os) + val |= DSP_CAP_DUPLEX; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_GETTRIGGER: + val = 0; + if (file->f_mode & FMODE_READ && is->active && !is->stopped) + val |= PCM_ENABLE_INPUT; + if (file->f_mode & FMODE_WRITE && os->active && !os->stopped) + val |= PCM_ENABLE_OUTPUT; + return put_user(val, (int *)arg); + + case SNDCTL_DSP_SETTRIGGER: + if (get_user(val, (int *)arg)) + return -EFAULT; + if (file->f_mode & FMODE_READ) { + if (val & PCM_ENABLE_INPUT) { + if (!is->active) { + if (!is->buffers && audio_setup_buf(is)) + return -ENOMEM; + audio_prime_dma(is); + } + if (is->stopped) { + is->stopped = 0; + lh7a400_dma_resume(is->dma_ch); + } + } else { + lh7a400_dma_stop(is->dma_ch); + is->stopped = 1; + } + } + if (file->f_mode & FMODE_WRITE) { + if (val & PCM_ENABLE_OUTPUT) { + if (!os->active) { + if (!os->buffers && audio_setup_buf(os)) + return -ENOMEM; + if (os->mapped) + audio_prime_dma(os); + } + if (os->stopped) { + os->stopped = 0; + lh7a400_dma_resume(os->dma_ch); + } + } else { + lh7a400_dma_stop(os->dma_ch); + os->stopped = 1; + } + } + return 0; + + case SNDCTL_DSP_GETOPTR: + case SNDCTL_DSP_GETIPTR: + { + count_info inf = { 0, }; + audio_stream_t *s = (cmd == SNDCTL_DSP_GETOPTR) ? os : is; + audio_buf_t *b; + dma_addr_t ptr; + int bytecount, offset, flags; + + if ((s == is && !(file->f_mode & FMODE_READ)) || + (s == os && !(file->f_mode & FMODE_WRITE))) + return -EINVAL; + if (s->active) { + save_flags_cli(flags); + if (lh7a400_dma_get_current(s->dma_ch, (void *)&b, &ptr) == 0) { + offset = ptr - b->dma_addr; + inf.ptr = (b - s->buffers) * s->fragsize + offset; + } else offset = 0; + bytecount = s->bytecount + offset; + s->bytecount = -offset; + inf.blocks = s->fragcount; + s->fragcount = 0; + restore_flags(flags); + if (bytecount < 0) + bytecount = 0; + inf.bytes = bytecount; + } + return copy_to_user((void *)arg, &inf, sizeof(inf)); + } + + case SNDCTL_DSP_SETDUPLEX: + return 0; + + case SNDCTL_DSP_GETODELAY: + val = 0; + return put_user(val, (int *)arg); + + case SOUND_PCM_READ_RATE: + return put_user(audio_samplerate, (long *) arg); + + case SOUND_PCM_READ_BITS: + return put_user( AFMT_S16_LE, (int *)arg); + + case SNDCTL_DSP_MAPINBUF: + case SNDCTL_DSP_MAPOUTBUF: + case SNDCTL_DSP_SETSYNCRO: + case SOUND_PCM_WRITE_FILTER: + case SOUND_PCM_READ_FILTER: + default: + return -EINVAL; + } + + return 0; +} + + +static int audio_release(struct inode *inode, struct file *file) +{ + audio_state_t *state = (audio_state_t *)file->private_data; + int rc; + + DPRINTK("audio_release\n"); + + down(&state->sem); + + if (file->f_mode & FMODE_READ) { + if (state->tx_spinning) { + lh7a400_dma_set_spin(state->output_stream->dma_ch, 0, 0); + state->tx_spinning = 0; + } + audio_clear_buf(state->input_stream); + if (!state->skip_dma_init) { + lh7a400_free_dma(state->input_stream->dma_ch); + if (state->need_tx_for_rx && !state->wr_ref) + lh7a400_free_dma(state->output_stream->dma_ch); + } + state->rd_ref = 0; + + if( (rc = aac_powerdown( AAC_POWER_ADC, CS_FALSE )) ) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "aac: " __FUNCTION__ "() powerdown ADC failure (0x%x)\n",rc) ); + } + + } + + if (file->f_mode & FMODE_WRITE) { + audio_sync(file); + audio_clear_buf(state->output_stream); + if (!state->skip_dma_init) + if (!state->need_tx_for_rx || !state->rd_ref) + lh7a400_free_dma(state->output_stream->dma_ch); + state->wr_ref = 0; + + if( (rc = aac_powerdown( AAC_POWER_DAC, CS_FALSE )) ) { + CS_DBGOUT(CS_ERROR, 1, printk(KERN_INFO + "aac: " __FUNCTION__ "() powerdown DAC failure (0x%x)\n",rc) ); + } + } + + if (!AUDIO_ACTIVE(state)) { + if (state->hw_shutdown) + state->hw_shutdown(state->data); +#ifdef CONFIG_PM + pm_unregister(state->pm_dev); +#endif + } + + up(&state->sem); + return 0; +} + + +#ifdef CONFIG_PM +static int audio_pm_callback(struct pm_dev *pm_dev, pm_request_t req, void *data) +{ + audio_state_t *state = (audio_state_t *)pm_dev->data; + + switch (req) { + case PM_SUSPEND: /* enter D1-D3 */ + if (state->output_stream) + lh7a400_dma_sleep(state->output_stream->dma_ch); + if (state->input_stream) + lh7a400_dma_sleep(state->input_stream->dma_ch); + if (AUDIO_ACTIVE(state) && state->hw_shutdown) + state->hw_shutdown(state->data); + break; + case PM_RESUME: /* enter D0 */ + if (AUDIO_ACTIVE(state) && state->hw_init) + state->hw_init(state->data); + if (state->input_stream) + lh7a400_dma_wakeup(state->input_stream->dma_ch); + if (state->output_stream) + lh7a400_dma_wakeup(state->output_stream->dma_ch); + break; + } + return 0; +} + +#endif + + +static int aac_audio_attach(struct inode *inode, struct file *file, + audio_state_t *state) +{ + int err, need_tx_dma, rc; + + DPRINTK( __FUNCTION__ "\n"); + + down(&state->sem); + + /* access control */ + err = -ENODEV; + if ((file->f_mode & FMODE_WRITE) && !state->output_stream) + goto out; + if ((file->f_mode & FMODE_READ) && !state->input_stream) + goto out; + err = -EBUSY; + if ((file->f_mode & FMODE_WRITE) && state->wr_ref) + goto out; + if ((file->f_mode & FMODE_READ) && state->rd_ref) + goto out; + err = -EINVAL; + if ((file->f_mode & FMODE_READ) && state->need_tx_for_rx && !state->output_stream) + goto out; + + /* request DMA channels */ + if (state->skip_dma_init) + goto skip_dma; + + need_tx_dma = ((file->f_mode & FMODE_WRITE) || + ((file->f_mode & FMODE_READ) && state->need_tx_for_rx)); + + if (state->wr_ref || (state->rd_ref && state->need_tx_for_rx)) + need_tx_dma = 0; + + if (need_tx_dma) { + err = lh7a400_request_dma(&state->output_stream->dma_ch, + state->output_id, + state->output_dma); + if (err) + goto out; + + if( (rc = aac_powerup( AAC_POWER_DAC))) { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "aac: aac_powerup of DAC failed (0x%x)\n",rc) ); + return -EIO; + } + + /* set up the Tx side */ + aac->chan[TX_CHANNEL].TxControl = CH_TXCTL_TSIZE_16 | + CH_TXCTL_SLOT_3 | + CH_TXCTL_SLOT_4 | + CH_TXCTL_TXEN; + aac->chan[TX_CHANNEL].TxControl |= CH_TXCTL_CM; + + } + + if (file->f_mode & FMODE_READ) { + err = lh7a400_request_dma(&state->input_stream->dma_ch, + state->input_id, + state->input_dma); + if (err) { + if (need_tx_dma) + lh7a400_free_dma(state->output_stream->dma_ch); + aac->chan[TX_CHANNEL].TxControl = 0; + goto out; + } + + if( (rc = aac_powerup( AAC_POWER_ADC))) { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "aac: aac_powerup of ADC failed (0x%x)\n",rc) ); + return -EIO; + } + + /* set up the Rx side */ + aac->chan[RX_CHANNEL].RxControl = CH_RXCTL_RSIZE_16 | + CH_RXCTL_SLOT_3 | + CH_RXCTL_SLOT_4 | + CH_RXCTL_RXEN; + aac->chan[RX_CHANNEL].RxControl |= CH_RXCTL_CM; + + DPRINTK( "LINEIN_VOL=0x%04x, RECORD_SELECT=0x%04x, RECORD_GAIN=0x%04x\n", + aac_ac97_get( NULL, AC97_LINEIN_VOL), + aac_ac97_get( NULL, AC97_RECORD_SELECT), + aac_ac97_get( NULL, AC97_RECORD_GAIN)); + } +skip_dma: + + /* now complete initialisation */ + if (!AUDIO_ACTIVE(state)) { + if (state->hw_init) + state->hw_init(state->data); +#ifdef CONFIG_PM + state->pm_dev = pm_register(PM_SYS_DEV, 0, audio_pm_callback); + if (state->pm_dev) + state->pm_dev->data = state; +#endif + } + + if ((file->f_mode & FMODE_WRITE)) { + state->wr_ref = 1; + audio_clear_buf(state->output_stream); + state->output_stream->fragsize = AUDIO_FRAGSIZE_DEFAULT; + state->output_stream->nbfrags = AUDIO_NBFRAGS_DEFAULT; + state->output_stream->mapped = 0; + lh7a400_dma_set_callback(state->output_stream->dma_ch, + audio_dmaout_done_callback); + init_waitqueue_head(&state->output_stream->wq); + } + if (file->f_mode & FMODE_READ) { + state->rd_ref = 1; + audio_clear_buf(state->input_stream); + state->input_stream->fragsize = AUDIO_FRAGSIZE_DEFAULT; + state->input_stream->nbfrags = AUDIO_NBFRAGS_DEFAULT; + state->input_stream->mapped = 0; + lh7a400_dma_set_callback(state->input_stream->dma_ch, + audio_dmain_done_callback); + init_waitqueue_head(&state->input_stream->wq); + } + + file->private_data = state; + file->f_op->release = audio_release; + file->f_op->write = audio_write; + file->f_op->read = audio_read; + file->f_op->mmap = audio_mmap; + file->f_op->poll = audio_poll; + file->f_op->ioctl = audio_ioctl; + file->f_op->llseek = audio_llseek; + err = 0; + +out: + up(&state->sem); + return err; +} + +static audio_stream_t output_stream, input_stream; + +static audio_state_t audio_state = { + output_stream: &output_stream, + output_dma: DMA_AAC_0_Tx, + output_id: "LH7A400 AC97 out", + input_stream: &input_stream, + input_dma: DMA_AAC_0_Rx, + input_id: "LH7A400 AC97 in", + need_tx_for_rx: 0, + sem: __MUTEX_INITIALIZER(audio_state.sem), +}; + + +static int lh7a400_audio_open(struct inode *inode, struct file *file) +{ + return aac_audio_attach(inode, file, &audio_state); +} + +static const char aac_banner[] = + KERN_INFO + "Sharp LH7x AAC + AC97 Audio, version " + AAC_MAJOR_VERSION "." AAC_MINOR_VERSION ", " + __TIME__ " " __DATE__ "\n"; + + +/* AC97 codec initialization. */ +static int __init aac_ac97_init( void) +{ + struct ac97_codec *codec; + u16 eid; + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "aac: aac_ac97_init()+\n") ); + + g_codec = NULL; + + if ((codec = kmalloc(sizeof(struct ac97_codec), GFP_KERNEL)) == NULL) + return -ENOMEM; + + memset(codec, 0, sizeof(struct ac97_codec)); + + /* + * initialize some basic codec information, + * other fields will be filled in ac97_probe_codec + */ + codec->private_data = NULL; + codec->id = 0; + + codec->codec_read = aac_ac97_get; + codec->codec_write = aac_ac97_set; + + if( ac97_probe_codec( codec) == 0) { + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "aac: aac_ac97_init()- codec number %d not found\n", + 0) ); + return 0; + } + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "aac: aac_ac97_init() found codec %d\n",0) ); + + eid = aac_ac97_get( codec, AC97_EXTENDED_ID); + + if( eid==0xFFFFFF) { + printk( KERN_WARNING "aac: codec %d not present\n",0); + kfree( codec); + return 0; + } + + g_ac97_features = eid; + + if( !proc_mkdir( "driver/aac", 0)) { + printk( KERN_ERR "aac: unable to create proc dir 'driver/aac'\n"); + kfree( codec); + return 0; + } + + if( !create_proc_read_entry( "driver/aac/ac97", 0, 0, ac97_read_proc, codec)) { + printk( KERN_ERR "aac: unable to create proc entry 'driver/aac/ac97'\n"); + remove_proc_entry( "driver/aac", NULL); + kfree( codec); + return 0; + } + + if ((codec->dev_mixer = register_sound_mixer( &aac_mixer_fops, -1)) < 0) { + printk(KERN_ERR "aac: couldn't register mixer!\n"); + kfree(codec); + return 0; + } + + g_codec = codec; + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "aac: aac_ac97_init() g_codec set to 0x%x dev_mixer=%x\n", + (unsigned int)g_codec, g_codec->dev_mixer)); + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "aac: aac_ac97_init()- 0\n")); + + return 1; +} + + +static int aac_hardware_init( void) +{ + unsigned int tmp; + gpioRegs_t *gpio = (gpioRegs_t *)IO_ADDRESS(GPIO_PHYS); + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, printk(KERN_INFO + "aac: aac_hardware_init()+\n") ); + + /* set GPIO:H pins as output */ + gpio->phddr = _BIT(6); + gpio->phdr = _BIT(6); + + /* make sure the AAC is enabled and standard codec is disabled */ + gpio->pinmux &= ~GPIO_PINMUX_CODECON; + + CS_DBGOUT( CS_INIT, 1, printk(KERN_INFO "aac: gpio:h ddr=0x%x pinmux=0x%x\n", + gpio->phddr, gpio->pinmux) ); + + /* initialize AC97 codec and register /dev/mixer */ + if( g_pm.flags & AAC_PM_IDLE) { + if (aac_ac97_init() <= 0) { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "aac: aac_ac97_init() failure\n") ); + return -EIO; + } + } + + /* enable Variable Rate Audio (VRA) mode */ + aac_ac97_set( NULL, AC97_EXTENDED_STATUS, 1); + + /* + * If IDLE then Power down the part. We will power components up + * when we need them. + */ + if( g_pm.flags & AAC_PM_IDLE) { + if( !g_enablePowerdown) { + if( (tmp = aac_powerup( AAC_POWER_DAC | AAC_POWER_ADC | AAC_POWER_MIXVON )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "aac: aac_powerup() failure (0x%x)\n",tmp) ); + return -EIO; + } + } else { + if( (tmp = aac_powerdown( AAC_POWER_DAC | AAC_POWER_ADC | + AAC_POWER_MIXVON, CS_FALSE )) ) + { + CS_DBGOUT(CS_ERROR | CS_INIT, 1, printk(KERN_INFO + "aac: aac_powerdown() failure (0x%x)\n",tmp) ); + return -EIO; + } + } + } + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, + printk(KERN_INFO "aac: aac_hardware_init()- 0\n")); + + return 0; +} + + + + +static int __devinit aac_probe( void) +{ + int i; + + CS_DBGOUT(CS_FUNCTION | CS_INIT, 2, + printk(KERN_INFO "aac: probe()+\n")); + + aac->Control = AAC_CTRL_ENABLE; /* enable the AAC */ + + DPRINTK( "waiting for Codec ready\n"); + + while( (aac->GlobalRawISR & AAC_IRQ_CODEC_READY) == 0) + barrier(); + + DPRINTK( "Got Codec Ready\n"); + + aac->Reset = AAC_RESET_TIMEDRESET; + + wait_for_power_ready(); + + DPRINTK( "Got Power Ready\n"); + + printk( aac_banner); + printk(KERN_INFO "Sharp LH7x AAC found at 0x%p.\n", aac); + + if( powerdown == 0) + g_enablePowerdown = 0; + + /* register /dev/dsp */ + if( (g_dev_audio = register_sound_dsp( &aac_fops, -1)) < 0) { + printk(KERN_ERR "aac: unable to register dsp\n"); + return -ENODEV; + } + + g_pm.flags |= AAC_PM_IDLE; + + for( i=0 ; i < 5 ; i++) { + if( aac_hardware_init() != 0) { + CS_DBGOUT(CS_ERROR, 4, printk( + "aac: ERROR in aac_hardware_init()... retrying\n")); + if( g_codec) { + unregister_sound_mixer( g_codec->dev_mixer); + kfree( g_codec); + g_codec = NULL; + } + mdelay( 10); + continue; + } + break; + } + + if( i >= 4) { + CS_DBGOUT(CS_PM | CS_ERROR, 1, printk( + "aac: aac_probe()- aac_hardware_init() failed, retried %d times.\n",i)); + unregister_sound_dsp(g_dev_audio); + return -ENODEV; + } + + CS_DBGOUT(CS_PM, 9, printk(KERN_INFO "aac: pm.flags=0x%x \n", + (unsigned)g_pm.flags)); + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "aac: probe()- device allocated successfully\n")); + + return 0; + +} /* aac_probe */ + + +int __init aac_module_init(void) +{ + int rtn = 0; + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, printk(KERN_INFO + "aac: aac_module_init()+ \n")); + + DUMP_REGS( "init"); + + rtn = aac_probe(); + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "aac: aac_module_init()- (%d)\n",rtn)); + + return rtn; +} + + +void __exit aac_module_exit(void) +{ + if( g_dev_audio) + unregister_sound_dsp( g_dev_audio); + + if( g_codec) { + unregister_sound_mixer( g_codec->dev_mixer); + kfree( g_codec); + } + + remove_proc_entry( "driver/aac", NULL); + remove_proc_entry( "driver/aac/ac97", NULL); + + CS_DBGOUT(CS_INIT | CS_FUNCTION, 2, + printk(KERN_INFO "aac: aac_module_exit() finished\n")); +} + +module_init( aac_module_init); +module_exit( aac_module_exit); + + +MODULE_AUTHOR("Duck "); +MODULE_DESCRIPTION("Sharp LH7x AAC/AC97 Audio Support"); +MODULE_LICENSE("GPL"); + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/sound/lh7a400-aac.h linux-2.4.21-rmk1-lh7a400/drivers/sound/lh7a400-aac.h --- linux-2.4.21-rmk1/drivers/sound/lh7a400-aac.h Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/sound/lh7a400-aac.h Thu Oct 16 16:03:20 2003 @@ -0,0 +1,126 @@ +/* + * drivers/sound/lh7a400-acc.h + * + * Common audio handling for the Advanced Audio Codec Controller + * found on the Sharp LH7A400 SoC. + * + * Portions Copyright (C) 2002, Embedix, Inc. + * + * Strongly based on sa1100-audio.h, which is + * Copyright (c) 2000 Nicolas Pitre + * + * Power Management portions based on cs46xxpm.h, which is + * Copyright (C) 2000,2001 Cirrus Logic Corp. + * + * 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 + * + */ + + +/* + * Buffer Management + */ + +typedef struct { + int size; /* buffer size */ + char *start; /* points to actual buffer */ + dma_addr_t dma_addr; /* physical buffer address */ + struct semaphore sem; /* down before touching the buffer */ + int master; /* owner for buffer allocation, contain size when true */ + struct audio_stream_s *stream; /* owning stream */ +} audio_buf_t; + + +typedef struct audio_stream_s { + audio_buf_t *buffers; /* pointer to audio buffer structures */ + audio_buf_t *buf; /* current buffer used by read/write */ + u_int buf_idx; /* index for the pointer above... */ + u_int fragsize; /* fragment i.e. buffer size */ + u_int nbfrags; /* nbr of fragments i.e. buffers */ + int bytecount; /* nbr of processed bytes */ + int fragcount; /* nbr of fragment transitions */ + dmach_t dma_ch; /* DMA channel ID */ + wait_queue_head_t wq; /* for poll */ + int mapped:1; /* mmap()'ed buffers */ + int active:1; /* actually in progress */ + int stopped:1; /* might be active but stopped */ +} audio_stream_t; + +/* + * State structure for one instance + */ +typedef struct { + audio_stream_t *output_stream; + audio_stream_t *input_stream; + dma_channel_t output_dma; + dma_channel_t input_dma; + char *output_id; + char *input_id; + int rd_ref:1; /* open reference for recording */ + int wr_ref:1; /* open reference for playback */ + int need_tx_for_rx:1; /* if data must be sent while receiving */ + int tx_spinning:1; /* tx spinning active */ + int skip_dma_init:1; /* hack for the SA1111 */ + void *data; + void (*hw_init)(void *); + void (*hw_shutdown)(void *); + int (*client_ioctl)(struct inode *, struct file *, uint, ulong); + struct pm_dev *pm_dev; + struct semaphore sem; /* to protect against races in attach() */ +} audio_state_t; + + +#define AAC_AC97_HIGHESTREGTORESTORE 0x26 +#define AAC_AC97_NUMBER_RESTORE_REGS (AAC_AC97_HIGHESTREGTORESTORE/2-1) + +/* PM state defintions */ +#define AAC_PM_NOT_REGISTERED 0x1000 +#define AAC_PM_IDLE 0x0001 +#define AAC_PM_SUSPENDING 0x0002 +#define AAC_PM_SUSPENDED 0x0004 +#define AAC_PM_RESUMING 0x0008 +#define AAC_PM_RESUMED 0x0010 + +#define AAC_POWER_DAC 0x0001 +#define AAC_POWER_ADC 0x0002 +#define AAC_POWER_MIXVON 0x0004 +#define AAC_POWER_MIXVOFF 0x0008 +#define AAC_AC97_POWER_CONTROL_ON 0xf000 /* always on bits (inverted) */ +#define AAC_AC97_POWER_CONTROL_ADC 0x0100 +#define AAC_AC97_POWER_CONTROL_DAC 0x0200 +#define AAC_AC97_POWER_CONTROL_MIXVON 0x0400 +#define AAC_AC97_POWER_CONTROL_MIXVOFF 0x0800 +#define AAC_AC97_POWER_CONTROL_ADC_ON 0x0001 +#define AAC_AC97_POWER_CONTROL_DAC_ON 0x0002 +#define AAC_AC97_POWER_CONTROL_MIXVON_ON 0x0004 +#define AAC_AC97_POWER_CONTROL_MIXVOFF_ON 0x0008 + +struct aac_pm { + unsigned long flags; + u32 u32SSPM_BITS; + u32 ac97[AAC_AC97_NUMBER_RESTORE_REGS]; + u32 u32AC97_master_volume, u32AC97_headphone_volume, u32AC97_master_volume_mono; + u32 u32AC97_pcm_out_volume, u32AC97_powerdown, u32AC97_general_purpose; + u32 u32hwptr_playback,u32hwptr_capture; +}; + +#if 0 +/* + * Functions exported by this module + */ +extern int aac_audio_attach( struct inode *inode, struct file *file, + audio_state_t *state); +#endif + diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/video/Config.in linux-2.4.21-rmk1-lh7a400/drivers/video/Config.in --- linux-2.4.21-rmk1/drivers/video/Config.in Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/video/Config.in Thu Oct 16 14:51:59 2003 @@ -40,6 +40,7 @@ dep_bool ' CLPS711X LCD support' CONFIG_FB_CLPS711X $CONFIG_ARCH_CLPS711X dep_bool ' SA-1100 LCD support' CONFIG_FB_SA1100 $CONFIG_ARCH_SA1100 dep_bool ' MX1ADS LCD support' CONFIG_FB_DBMX1 $CONFIG_ARCH_MX1ADS + dep_bool ' ARM PL110 LCD support' CONFIG_FB_PL110 $CONFIG_ARCH_LH7A400 if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF" = "y" ]; then choice 'CerfBoard LCD Display Size' \ "3.8_Color CONFIG_CERF_LCD_38_A \ @@ -50,6 +51,14 @@ if [ "$CONFIG_FB_SA1100" = "y" -a "$CONFIG_SA1100_CERF_CPLD" = "y" ]; then bool 'Cerfboard Backlight (CerfPDA)' CONFIG_SA1100_CERF_LCD_BACKLIGHT fi + if [ "$CONFIG_FB_PL110" = "y" ]; then + choice 'LCD Display panel' \ + "Sharp_LQ039Q2DS53-HR-TFT CONFIG_PL110_LQ39 \ + Sharp_LM057QCTT03-QVGA-STN CONFIG_PL110_LM57 \ + Sharp_LQ057Q3DC02-VGA/QVGA-TFT CONFIG_PL110_LQ57 \ + Sharp_LQ121S1DG31-800x600-TFT CONFIG_PL110_LQ121 \ + Sharp_LQ104V1DG11-640x480-TFT CONFIG_PL110_LQ104" Sharp_LQ039Q2DS53-HR-TFT + fi fi dep_tristate ' CyberPro 2000/2010/5000 support' CONFIG_FB_CYBER2000 $CONFIG_PCI if [ "$CONFIG_APOLLO" = "y" ]; then @@ -285,13 +294,14 @@ if [ "$CONFIG_FB_ACORN" = "y" -o "$CONFIG_FB_MAC" = "y" -o \ "$CONFIG_FB_SA1100" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \ - "$CONFIG_FB_DBMX1" = "y" ]; then + "$CONFIG_FB_DBMX1" = "y" -o "$CONFIG_FB_PL110" = "y" ]; then define_tristate CONFIG_FBCON_CFB2 y define_tristate CONFIG_FBCON_CFB4 y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_MAC" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ - "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_CLPS711X" = "m" ]; then + "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_CLPS711X" = "m" -o \ + "$CONFIG_FB_PL110" = "m" ]; then define_tristate CONFIG_FBCON_CFB2 m define_tristate CONFIG_FBCON_CFB4 m fi @@ -316,7 +326,7 @@ "$CONFIG_FB_MAXINE" = "y" -o "$CONFIG_FB_TX3912" = "y" -o \ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_NEOMAGIC" = "y" -o \ "$CONFIG_FB_STI" = "y" -o "$CONFIG_FB_HP300" = "y" -o \ - "$CONFIG_FB_INTEL" = "y" -o \ + "$CONFIG_FB_INTEL" = "y" -o "$CONFIG_FB_PL110" = "y" -o \ "$CONFIG_FB_DBMX1" = "y" ]; then define_tristate CONFIG_FBCON_CFB8 y else @@ -339,7 +349,8 @@ "$CONFIG_FB_MAXINE" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \ - "$CONFIG_FB_STI" = "m" -o "$CONFIG_FB_INTEL" = "m" ]; then + "$CONFIG_FB_STI" = "m" -o "$CONFIG_FB_INTEL" = "m" -o \ + "$CONFIG_FB_PL110" = "m" ]; then define_tristate CONFIG_FBCON_CFB8 m fi fi @@ -358,7 +369,7 @@ "$CONFIG_FB_SIS" = "y" -o "$CONFIG_FB_SA1100" = "y" -o \ "$CONFIG_FB_PVR2" = "y" -o "$CONFIG_FB_VOODOO1" = "y" -o \ "$CONFIG_FB_NEOMAGIC" = "y" -o "$CONFIG_FB_INTEL" = "y" -o \ - "$CONFIG_FB_ANAKIN" = "y" -o \ + "$CONFIG_FB_ANAKIN" = "y" -o "$CONFIG_FB_PL110" = "y" -o \ "$CONFIG_FB_DBMX1" = "y" ]; then define_tristate CONFIG_FBCON_CFB16 y else @@ -376,7 +387,8 @@ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \ - "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_INTEL" = "m" ]; then + "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_INTEL" = "m" -o \ + "$CONFIG_FB_PL110" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m fi fi diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/video/Makefile linux-2.4.21-rmk1-lh7a400/drivers/video/Makefile --- linux-2.4.21-rmk1/drivers/video/Makefile Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/video/Makefile Thu Oct 16 14:51:07 2003 @@ -15,7 +15,7 @@ fbcon-iplan2p8.o fbcon-vga-planes.o fbcon-cfb16.o \ fbcon-cfb2.o fbcon-cfb24.o fbcon-cfb32.o fbcon-cfb4.o \ fbcon-cfb8.o fbcon-mac.o fbcon-mfb.o \ - cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o + cyber2000fb.o sa1100fb.o fbcon-hga.o fbgen.o pl110fb.o # Each configuration option enables a list of files. @@ -134,6 +134,7 @@ obj-$(CONFIG_FB_PVR2) += pvr2fb.o obj-$(CONFIG_FB_VOODOO1) += sstfb.o obj-$(CONFIG_FB_ANAKIN) += anakinfb.o +obj-$(CONFIG_FB_PL110) += pl110fb.o # Generic Low Level Drivers diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/video/fbmem.c linux-2.4.21-rmk1-lh7a400/drivers/video/fbmem.c --- linux-2.4.21-rmk1/drivers/video/fbmem.c Thu Oct 16 10:10:09 2003 +++ linux-2.4.21-rmk1-lh7a400/drivers/video/fbmem.c Thu Oct 16 14:51:55 2003 @@ -109,6 +109,7 @@ extern int chips_init(void); extern int g364fb_init(void); extern int sa1100fb_init(void); +extern int pl110fb_init(void); extern int fm2fb_init(void); extern int fm2fb_setup(char*); extern int q40fb_init(void); @@ -300,6 +301,9 @@ #ifdef CONFIG_FB_SA1100 { "sa1100", sa1100fb_init, NULL }, #endif +#ifdef CONFIG_FB_PL110 + { "pl110", pl110fb_init, NULL }, +#endif #ifdef CONFIG_FB_SUN3 { "sun3", sun3fb_init, sun3fb_setup }, #endif diff -urN --exclude=CVS --exclude='.*' --exclude='*~' linux-2.4.21-rmk1/drivers/video/pl110fb.c linux-2.4.21-rmk1-lh7a400/drivers/video/pl110fb.c --- linux-2.4.21-rmk1/drivers/video/pl110fb.c Wed Dec 31 19:00:00 1969 +++ linux-2.4.21-rmk1-lh7a400/drivers/video/pl110fb.c Mon Oct 20 16:21:10 2003 @@ -0,0 +1,1624 @@ +/* + * linux/drivers/video/pl110fb.c + * + * ARM PrimeCell PL110 LCD Controller Frame Buffer Driver + * + * Copyright (C) 2002 Lineo, Inc. + * Based on sa1100fb.c, which is Copyright (C) Eric A. Thomas + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file COPYING in the main directory of this archive for + * more details. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include