diff -urN linux-2.4.26/arch/arm/boot/compressed/head.S linux-2.4.26-vrs1-lnode80/arch/arm/boot/compressed/head.S --- linux-2.4.26/arch/arm/boot/compressed/head.S 2005-11-02 16:54:16.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/boot/compressed/head.S 2005-11-02 17:37:31.000000000 -0400 @@ -17,6 +17,7 @@ * 100% relocatable. Any attempt to do so will result in a crash. * Please select one of the following when turning on debugging. */ +#define DEBUG #ifdef DEBUG #if defined(CONFIG_DEBUG_DC21285_PORT) .macro loadsp, rb @@ -81,6 +82,20 @@ */ str \rb, [r3, #0x14] @ UTDR .endm +#elif 1 /* Sharp LH79520-type */ + .macro loadsp, rb + ldr \rb, =0xfffc0000 @ UART1 base + .endm + .macro writeb, rb + strb \rb, [r3, #0] + .endm +#elif 0 /* Sharp LH7A400-type */ + .macro loadsp, rb + ldr \rb, =0x80000700 @ UART1 base + .endm + .macro writeb, rb + strb \rb, [r3, #0] + .endm #else #error no serial architecture defined #endif @@ -97,6 +112,7 @@ bl phex .endm +#undef DEBUG .macro debug_reloc_start #ifdef DEBUG kputc #'\n' @@ -140,7 +156,9 @@ .word 0x016f2818 @ Magic numbers to help the loader .word start @ absolute load/run zImage address .word _edata @ zImage end address -1: mov r7, r1 @ save architecture ID +1: @mov r7, r1 @ save architecture ID + mov r7, #0x300 + orr r7,r7,#0xe7 mov r8, #0 @ save r0 #ifndef __ARM_ARCH_2__ @@ -314,6 +332,11 @@ LC1: .word reloc_end - reloc_start .size LC0, . - LC0 + .type proc_lh7a400_type,#object +proc_lh7a400_type: + .word 0x41029220 + .size proc_lh7a400_type, . - proc_lh7a400_type + /* * Turn on the cache. We need to setup some page tables so that we * can have both the I and D caches on. diff -urN linux-2.4.26/arch/arm/boot/Makefile linux-2.4.26-vrs1-lnode80/arch/arm/boot/Makefile --- linux-2.4.26/arch/arm/boot/Makefile 2003-08-25 07:44:39.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/boot/Makefile 2005-11-02 17:37:31.000000000 -0400 @@ -101,6 +101,24 @@ INITRD_VIRT = 0x0C800000 endif +ifeq ($(CONFIG_ARCH_LH79520),y) + ZTEXTADDR = 0x20008000 + ZBSSADDR = 0x20200000 + ZRELADDR = 0x20008000 + INITRD_PHYS = 0x20400000 + INITRD_VIRT = 0xC0400000 + PARAMS_PHYS = 0x20110000 +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 linux-2.4.26/arch/arm/config.in linux-2.4.26-vrs1-lnode80/arch/arm/config.in --- linux-2.4.26/arch/arm/config.in 2005-11-02 16:54:16.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/config.in 2005-11-02 17:37:31.000000000 -0400 @@ -48,6 +48,8 @@ RiscPC CONFIG_ARCH_RPC \ RiscStation CONFIG_ARCH_RISCSTATION \ SA1100-based CONFIG_ARCH_SA1100 \ + LH79520-based CONFIG_ARCH_LH79520 \ + LH7A400-based CONFIG_ARCH_LH7A400 \ Shark CONFIG_ARCH_SHARK \ AT91RM9200-based CONFIG_ARCH_AT91RM9200 " RiscPC @@ -182,6 +184,17 @@ endmenu +mainmenu_option next_comment +comment 'Sharp LH79520 Implementations' +dep_bool ' LH79520 EVB' CONFIG_LH79520_EVB $CONFIG_ARCH_LH79520 +dep_bool ' 520 BOGUS EVB' CONFIG_BOGON_EVB $CONFIG_ARCH_LH79520 +endmenu + +mainmenu_option next_comment +comment 'Sharp LH7A400 Implementations' +dep_bool ' LH7A400 EVB' CONFIG_LH7A400_EVB $CONFIG_ARCH_LH7A400 +endmenu + # Definitions to make life easier if [ "$CONFIG_ARCH_ARCA5K" = "y" -o \ "$CONFIG_ARCH_RPC" = "y" ]; then @@ -295,6 +308,7 @@ # ARM720T if [ "$CONFIG_ARCH_CLPS711X" = "y" -o \ "$CONFIG_ARCH_L7200" = "y" -o \ + "$CONFIG_ARCH_LH79520" = "y" -o \ "$CONFIG_ARCH_CDB89712" = "y" ]; then define_bool CONFIG_CPU_ARM720T y else @@ -320,7 +334,8 @@ # ARM922T -if [ "$CONFIG_ARCH_CAMELOT" = "y" ]; then +if [ "$CONFIG_ARCH_CAMELOT" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" ]; then define_bool CONFIG_CPU_ARM922T y else if [ "$CONFIG_ARCH_INTEGRATOR" = "y" ]; then @@ -399,6 +414,7 @@ "$CONFIG_ARCH_TBOX" = "y" -o "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_NEXUSPCI" = "y" -o "$CONFIG_ARCH_CLPS711X" = "y" -o \ "$CONFIG_ARCH_INTEGRATOR" = "y" -o "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_LH79520" = "y" -o "$CONFIG_ARCH_LH7A400" = "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 @@ -440,6 +456,8 @@ # Select various configuration options depending on the machine type if [ "$CONFIG_ARCH_EDB7211" = "y" -o \ + "$CONFIG_ARCH_LH79520" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" -o \ "$CONFIG_ARCH_RISCSTATION" = "y" ]; then define_bool CONFIG_DISCONTIGMEM y @@ -473,6 +491,8 @@ "$CONFIG_ARCH_EBSA110" = "y" -o \ "$CONFIG_ARCH_CDB89712" = "y" -o \ "$CONFIG_ARCH_EDB7211" = "y" -o \ + "$CONFIG_ARCH_LH79520" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" ]; then define_bool CONFIG_ISA y else @@ -690,6 +710,8 @@ "$CONFIG_ARCH_TBOX" = "y" -o \ "$CONFIG_ARCH_CLPS7500" = "y" -o \ "$CONFIG_ARCH_P720T" = "y" -o \ + "$CONFIG_ARCH_LH79520" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" -o \ "$CONFIG_ARCH_ANAKIN" = "y" -o \ "$CONFIG_ARCH_MX1ADS" = "y" ]; then define_bool CONFIG_PC_KEYMAP y @@ -707,6 +729,8 @@ "$CONFIG_ARCH_TBOX" = "y" -o \ "$CONFIG_ARCH_SHARK" = "y" -o \ "$CONFIG_ARCH_SA1100" = "y" -o \ + "$CONFIG_ARCH_LH79520" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" -o \ "$CONFIG_PCI" = "y" ]; then mainmenu_option next_comment comment 'Sound' diff -urN linux-2.4.26/arch/arm/def-configs/lnode80 linux-2.4.26-vrs1-lnode80/arch/arm/def-configs/lnode80 --- linux-2.4.26/arch/arm/def-configs/lnode80 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/def-configs/lnode80 2005-11-03 09:11:23.000000000 -0400 @@ -0,0 +1,804 @@ +# +# 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 is not set + +# +# 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_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_LH79520=y +# CONFIG_ARCH_LH7A400 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 +# CONFIG_MACH_CSB337 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 LH79520 Implementations +# +CONFIG_LH79520_EVB=y +# CONFIG_BOGON_EVB is not set + +# +# Sharp LH7A400 Implementations +# +# CONFIG_LH7A400_EVB is not set +# CONFIG_ARCH_ACORN is not set +# CONFIG_PLD 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=y +# CONFIG_CPU_ARM920T is not set +# CONFIG_CPU_ARM922T is not set +# CONFIG_CPU_ARM926T is not set +# CONFIG_CPU_ARM1020 is not set +# CONFIG_CPU_ARM1020E is not set +# CONFIG_CPU_ARM1022 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=y +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_HOTPLUG is not set +# CONFIG_PCMCIA is not set +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=y +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_GEN_PROBE=y +CONFIG_MTD_CFI_ADV_OPTIONS=y +CONFIG_MTD_CFI_NOSWAP=y +# CONFIG_MTD_CFI_BE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_LE_BYTE_SWAP is not set +# CONFIG_MTD_CFI_GEOMETRY 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=y +CONFIG_MTD_PHYSMAP_START=40400000 +CONFIG_MTD_PHYSMAP_LEN=400000 +CONFIG_MTD_PHYSMAP_BUSWIDTH=2 +# 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_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_CISS_MONITOR_THREAD 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 is not set +# 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 is not set +# CONFIG_IP_PNP is not set +# CONFIG_NET_IPIP is not set +# CONFIG_NET_IPGRE is not set +# CONFIG_ARPD is not set +# CONFIG_INET_ECN is not set +# CONFIG_SYN_COOKIES is not set +# CONFIG_IPV6 is not set +# CONFIG_KHTTPD is not set + +# +# SCTP Configuration (EXPERIMENTAL) +# +# CONFIG_IP_SCTP 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 is not set + +# +# Amateur Radio support +# +# CONFIG_HAMRADIO is not set + +# +# IrDA (infrared) support +# +# CONFIG_IRDA is not set + +# +# ATA/ATAPI/MFM/RLL support +# +# CONFIG_IDE is not set +# CONFIG_BLK_DEV_HD 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 is not set +# CONFIG_INPUT_KEYBDEV is not set +# CONFIG_INPUT_MOUSEDEV is not set +# CONFIG_INPUT_JOYDEV is not set +# CONFIG_INPUT_EVDEV is not set +# CONFIG_INPUT_UINPUT is not set +# CONFIG_INPUT_MX1TS is not set + +# +# Character devices +# +CONFIG_VT=y +CONFIG_VT_CONSOLE=y +# CONFIG_SERIAL is not set +# CONFIG_SERIAL_EXTENDED is not set +# CONFIG_SERIAL_NONSTANDARD is not set + +# +# Serial drivers +# +# CONFIG_SERIAL_ANAKIN is not set +# CONFIG_SERIAL_ANAKIN_CONSOLE is not set +# CONFIG_SERIAL_AMBA is not set +# CONFIG_SERIAL_AMBA_CONSOLE is not set +CONFIG_SERIAL_AMBA_PL011=y +CONFIG_SERIAL_AMBA_PL011_CONSOLE=y +# CONFIG_SERIAL_LH7A400 is not set +# 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=256 + +# +# 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=y +CONFIG_PSMOUSE=y +# CONFIG_82C710_MOUSE is not set +# CONFIG_PC110_PAD is not set +# CONFIG_MK712_MOUSE is not set + +# +# Joysticks +# +# CONFIG_INPUT_GAMEPORT is not set + +# +# Input core support is needed for gameports +# + +# +# Input core support is needed for joysticks +# +# 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=y +# CONFIG_WATCHDOG_NOWAYOUT is not set +# CONFIG_ACQUIRE_WDT is not set +# CONFIG_ADVANTECH_WDT is not set +# CONFIG_ALIM1535_WDT is not set +# CONFIG_ALIM7101_WDT is not set +# CONFIG_SC520_WDT is not set +# CONFIG_PCWATCHDOG is not set +# CONFIG_21285_WATCHDOG is not set +# CONFIG_977_WATCHDOG is not set +# CONFIG_SA1100_WATCHDOG is not set +# CONFIG_LH79520_WATCHDOG is not set +# CONFIG_EPXA_WATCHDOG is not set +# CONFIG_OMAHA_WATCHDOG is not set +# CONFIG_AT91_WATCHDOG is not set +# CONFIG_EUROTECH_WDT is not set +# CONFIG_IB700_WDT is not set +# CONFIG_WAFER_WDT is not set +# CONFIG_I810_TCO is not set +# CONFIG_MIXCOMWD is not set +# CONFIG_60XX_WDT is not set +# CONFIG_SC1200_WDT is not set +# CONFIG_SCx200_WDT is not set +# CONFIG_SOFT_WATCHDOG is not set +# CONFIG_W83877F_WDT is not set +# CONFIG_WDT is not set +# CONFIG_WDTPCI is not set +# CONFIG_MACHZ_WDT is not set +# CONFIG_AMD7XX_TCO is not set +# CONFIG_SCx200 is not set +# CONFIG_SCx200_GPIO is not set +# CONFIG_LH79520_PWM is not set +# CONFIG_AMD_PM768 is not set +# CONFIG_NVRAM is not set +# CONFIG_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 + +# +# Direct Rendering Manager (XFree86 DRI support) +# +# CONFIG_DRM is not set + +# +# Multimedia devices +# +# CONFIG_VIDEO_DEV is not set + +# +# File systems +# +# CONFIG_QUOTA is not set +# CONFIG_QFMT_V2 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_HFSPLUS_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 is not set +# CONFIG_UMSDOS_FS is not set +CONFIG_VFAT_FS=y +# CONFIG_EFS_FS is not set +# CONFIG_JFFS_FS is not set +CONFIG_JFFS2_FS=y +CONFIG_JFFS2_FS_DEBUG=0 +# 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=y +# 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 is not set +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 +# CONFIG_XFS_FS is not set +# CONFIG_XFS_QUOTA is not set +# CONFIG_XFS_RT is not set +# CONFIG_XFS_TRACE is not set +# CONFIG_XFS_DEBUG is not set + +# +# Network File Systems +# +# CONFIG_CODA_FS is not set +# CONFIG_INTERMEZZO_FS is not set +# CONFIG_NFS_FS is not set +# CONFIG_NFS_V3 is not set +# CONFIG_NFS_DIRECTIO is not set +# CONFIG_ROOT_NFS is not set +# CONFIG_NFSD is not set +# CONFIG_NFSD_V3 is not set +# CONFIG_NFSD_TCP is not set +# CONFIG_SUNRPC is not set +# CONFIG_LOCKD is not set +# 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 is not set +CONFIG_MSDOS_PARTITION=y +# 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 is not set + +# +# Sound +# +# CONFIG_SOUND 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_LH79520 is not set +# CONFIG_EEPROM_LH79520 is not set +# CONFIG_7SEGMENT_LH79520 is not set + +# +# USB support +# +# CONFIG_USB is not set + +# +# Support for USB gadgets +# +# CONFIG_USB_GADGET 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_CRC32 is not set +CONFIG_ZLIB_INFLATE=y +CONFIG_ZLIB_DEFLATE=y diff -urN linux-2.4.26/arch/arm/kernel/debug-armv.S linux-2.4.26-vrs1-lnode80/arch/arm/kernel/debug-armv.S --- linux-2.4.26/arch/arm/kernel/debug-armv.S 2003-08-25 07:44:39.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/kernel/debug-armv.S 2005-11-02 17:37:31.000000000 -0400 @@ -470,6 +470,53 @@ +#elif defined(CONFIG_ARCH_LH79520) + + .macro addruart,rx + ldr \rx, =0xfffc1000 @UART1 base + .endm + + .macro senduart,rd,rx + strb \rd, [\rx] @ UART1_DR + .endm + + .macro busyuart,rd,rx @ spin while busy +1001: ldr \rd, [\rx, #0x18] @ UART1_FR + tst \rd, #1 << 3 @ BUSY ? + bne 1001b @ yes, spin + .endm + + .macro waituart,rd,rx @ wait for Tx FIFO room +1001: ldrb \rd, [\rx, #0x18] @ UART1_FR + tst \rd, #1 << 5 @ TXFF full? + bne 1001b @ yes, spin + .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 #endif diff -urN linux-2.4.26/arch/arm/kernel/entry-armv.S linux-2.4.26-vrs1-lnode80/arch/arm/kernel/entry-armv.S --- linux-2.4.26/arch/arm/kernel/entry-armv.S 2005-11-02 16:54:17.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/kernel/entry-armv.S 2005-11-02 17:37:31.000000000 -0400 @@ -615,6 +615,49 @@ .text .endm +#elif defined(CONFIG_ARCH_LH79520) +#include + + .macro disable_fiq + .endm + + .macro get_irqnr_and_base, irqnr, irqstat, base, tmp + ldr \irqstat, =VIC_BASE @ Virt addr IRQ regs + ldr \irqstat, [\irqstat, #0] @ get masked interrupt status + mov \irqnr, #0 +1001: tst \irqstat, #1 + addeq \irqnr, \irqnr, #1 + moveq \irqstat, \irqstat, lsr #1 + tsteq \irqnr, #32 + beq 1001b + teq \irqnr, #32 + .endm + + .macro irq_prio_table + .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 interrupt status + mov \irqnr, #0 +1001: tst \irqstat, #1 + bne 1002f + add \irqnr, \irqnr, #1 + mov \irqstat, \irqstat, lsr #1 + cmp \irqnr, #28 + bcc 1001b +1002: /* EQ will be set if we reach 28 */ + .endm + + .macro irq_prio_table + .endm + #else #error Unknown architecture #endif diff -urN linux-2.4.26/arch/arm/kernel/irq.c linux-2.4.26-vrs1-lnode80/arch/arm/kernel/irq.c --- linux-2.4.26/arch/arm/kernel/irq.c 2005-11-02 16:54:17.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/kernel/irq.c 2005-11-02 17:37:31.000000000 -0400 @@ -216,6 +216,18 @@ desc->triggered = 1; +#ifdef CONFIG_ARCH_LH79520 + if( irq < 8) { /* external interrupt */ + vicRegs_t *vic = (vicRegs_t *)VIC_BASE; + rcpcRegs_t *rcpc = (rcpcRegs_t *)IO_ADDRESS( RCPC_PHYS); + + rcpc->control |= RCPC_CTRL_WRTLOCK_ENABLED; /* unlock RCPC registers */ + barrier(); + rcpc->intClear = (1 << irq); /* clear corresponding IRQ */ + rcpc->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; /* lock RCPC registers */ + } +#endif + /* * Acknowledge and clear the IRQ, but (if its * a level-based IRQ, don't mask it) diff -urN linux-2.4.26/arch/arm/kernel/ptrace.c linux-2.4.26-vrs1-lnode80/arch/arm/kernel/ptrace.c --- linux-2.4.26/arch/arm/kernel/ptrace.c 2005-11-02 16:54:17.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/kernel/ptrace.c 2005-11-02 17:37:31.000000000 -0400 @@ -594,6 +594,9 @@ */ case PTRACE_POKETEXT: case PTRACE_POKEDATA: + if(data == 0xe7ffdefe) + data = 0xef9f0001; + ret = access_process_vm(child, addr, &data, sizeof(unsigned long), 1); if (ret == sizeof(unsigned long)) diff -urN linux-2.4.26/arch/arm/mach-lh79520/arch.c linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/arch.c --- linux-2.4.26/arch/arm/mach-lh79520/arch.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/arch.c 2005-11-03 10:30:56.000000000 -0400 @@ -0,0 +1,65 @@ +/* + * linux/arch/arm/mach-lh79520/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 + +extern void genarch_init_irq( void); +extern void lh79520_map_io( void); + +#ifdef CONFIG_ARCH_LH79520 + +static void __init +fixup_lh79520(struct machine_desc *desc, struct param_struct *unused, + char **cmdline, struct meminfo *mi) +{ + mi->nr_banks = 1; + mi->bank[0].start = PHYS_OFFSET; + mi->bank[0].size = (32*1024*1024); + mi->bank[0].node = 0; + + ROOT_DEV = MKDEV(RAMDISK_MAJOR,0); + setup_ramdisk( 1, 0, 0, CONFIG_BLK_DEV_RAM_SIZE); + setup_initrd( __phys_to_virt(0x20400000), 3 * 1024 * 1024); + + /* Serial Console on UART 1 */ + strcpy( *cmdline, "console=ttyAM1,115200"); +} + + +MACHINE_START(LH79520EVB, "Sharp LH79520 Evaluation Board") + MAINTAINER("Duck") + BOOT_MEM( 0x20000000, 0xff800000, 0xff800000) // pio, vio must be 8MB + FIXUP( fixup_lh79520) + MAPIO( lh79520_map_io) + INITIRQ( genarch_init_irq) +MACHINE_END +#endif diff -urN linux-2.4.26/arch/arm/mach-lh79520/dma.c linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/dma.c --- linux-2.4.26/arch/arm/mach-lh79520/dma.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/dma.c 2005-11-02 17:38:44.000000000 -0400 @@ -0,0 +1,841 @@ +/* + * arch/arm/mach-lh79520/dma-lh79520.c + * Copyright (C) 2002 Embedix, Inc. + * + * Support functions for the Sharp LH79520 internal DMA channels. + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#undef DEBUG + +#ifdef DEBUG +#define DPRINTK( s, arg... ) printk( "dma<%s>: " s, dma->device_id , ##arg ) +#define DUMPREGS(r,d) \ + printk( "regs=0x%x src=0x%x:%x dest=0x%x:%x count=%d control=0x%x tcnt=%d mask=0x%x status=0x%x\n", \ + (u32)r, r->srcHi, r->srcLow, r->destHi, r->destLow, r->count, r->control, r->termCnt, d->mask, d->status) +#define DUMPQ(d) dumpq(d) +#else +#define DPRINTK( x... ) +#define DUMPREGS(r,d) +#define DUMPQ(d) +#endif + +/* + * DMA channel registers structure + */ +typedef struct { + volatile u32 srcLow; /* Source base addr, low 16 bits */ + volatile u32 srcHi; /* Source base addr, hi 16 bits */ + volatile u32 destLow; /* Dest base addr, low 16 bits */ + volatile u32 destHi; /* Dest base addr, hi 16 bits */ + volatile u32 count; /* Maximum Count */ + volatile u32 control; /* Control */ + volatile u32 currSrcHi; /* Current src addr, hi 16 bits*/ + volatile u32 currSrcLow; /* Current src addr, low 16 bits*/ + volatile u32 currDstHi; /* Curr dest addr, hi 16 bits*/ + volatile u32 currDstLow; /* Curr src addr, low 16 bits*/ + volatile u32 termCnt; /* Terminal Count */ +} channelRegs_t; + + +/* + * Control Register Bit Field + */ +#define DMAC_CTRL_ENABLE _BIT(0) /* Enable DMA */ +#define DMAC_CTRL_SOINC _BIT(1) /* Source Reg inc.bit */ +#define DMAC_CTRL_DEINC _BIT(2) /* Dest Reg inc.bit */ +/* Source Size */ +#define DMAC_CTRL_SOSIZE_1BYTE _SBF(3,0) +#define DMAC_CTRL_SOSIZE_2BYTE _SBF(3,1) +#define DMAC_CTRL_SOSIZE_4BYTE _SBF(3,2) +/* Destination Size */ +#define DMAC_CTRL_DESIZE_1BYTE _SBF(7,0) +#define DMAC_CTRL_DESIZE_2BYTE _SBF(7,1) +#define DMAC_CTRL_DESIZE_4BYTE _SBF(7,2) +/* Peripheral Burst Sizes */ +#define DMAC_CTRL_SOBURST_SINGLE _SBF(5,0) /* Single */ +#define DMAC_CTRL_SOBURST_4INC _SBF(5,1) /* 4 incrementing */ +#define DMAC_CTRL_SOBURST_8INC _SBF(5,2) /* 8 incrementing */ +#define DMAC_CTRL_SOBURST_16INC _SBF(5,3) /* 16 incrementing */ +/* Address Modes */ +#define DMAC_CTRL_ADDR_MODE_WRAP _SBF(9,0) +#define DMAC_CTRL_ADDR_MODE_INCR _SBF(9,1) + +#define DMAC_CTRL_MEM2MEM _BIT(11) /* Memory to Memory */ +/* Direction */ +#define DMAC_CTRL_PERIPH_SOURCE _SBF(13,0) +#define DMAC_CTRL_PERIPH_DEST _SBF(13,1) + + +typedef struct { + channelRegs_t stream0; /* Data Stream 0 */ + volatile u32 reserved0[5]; + channelRegs_t stream1; /* Data Stream 1 */ + volatile u32 reserved1[5]; + channelRegs_t stream2; /* Data Stream 2 */ + volatile u32 reserved2[5]; + channelRegs_t stream3; /* Data Stream 3 */ + volatile u32 reserved3; + volatile u32 mask; + volatile u32 clear; + volatile u32 status; + volatile u32 reserved4; +} dmaRegs_t; + +channelRegs_t *streamRegs[] = { + &((dmaRegs_t *)IO_ADDRESS(DMAC_PHYS))->stream0, + &((dmaRegs_t *)IO_ADDRESS(DMAC_PHYS))->stream1, + &((dmaRegs_t *)IO_ADDRESS(DMAC_PHYS))->stream2, + &((dmaRegs_t *)IO_ADDRESS(DMAC_PHYS))->stream3 +}; + +/* + * mask - Mask Register Bit Fields + * clear - Clear Register Bit Fields + * status - Clear Register Bit Fields + * + * Writing DMAC_xN to mask register enables corresponding interrupt + * Writing DMAC_xN to clear register disables corresponding interrupt + * AND'ing DMAC_xN with status register yields status + * Note: "ACTIVEx" constants are only applicable to Status Register + */ +#define DMAC_INT0 _BIT(0) /* Stream 0 Interrupt */ +#define DMAC_INT1 _BIT(1) /* Stream 1 Interrupt */ +#define DMAC_INT2 _BIT(2) /* Stream 2 Interrupt */ +#define DMAC_INT3 _BIT(3) /* Stream 3 Interrupt */ +#define DMAC_ERRINT0 _BIT(4) /* Stream 0 Error Interrupt */ +#define DMAC_ERRINT1 _BIT(5) /* Stream 1 Error Interrupt */ +#define DMAC_ERRINT2 _BIT(6) /* Stream 2 Error Interrupt */ +#define DMAC_ERRINT3 _BIT(7) /* Stream 3 Error Interrupt */ +#define DMAC_ACTIVE0 _BIT(8) /* Stream 0 Active */ +#define DMAC_ACTIVE1 _BIT(9) /* Stream 1 Active */ +#define DMAC_ACTIVE2 _BIT(10) /* Stream 2 Active */ +#define DMAC_ACTIVE3 _BIT(11) /* Stream 3 Active */ + +/* all DMA error bits */ +#define DMAC_ERROR (DMAC_ERRINT0 | DMAC_ERRINT1 | DMAC_ERRINT2 | DMAC_ERRINT3 ) + +/* all DMA done bits */ +#define DMAC_DONE (DMAC_INT0 | DMAC_INT1 | DMAC_INT2 | DMAC_INT3) + +/* all the bits in the clear register */ +#define DMAC_CLEAR_ALL (DMAC_DONE | DMAC_ERROR) + + +#include "dma.h" + +lh79520_dma_t dma_chan[LH79520_DMA_CHANNELS]; + +/* + * Maximum physical DMA buffer size + */ +#define MAX_DMA_SIZE 0x3ffff +#define MAX_DMA_ORDER 18 + + +static inline void dumpq (lh79520_dma_t *dma) +{ + dma_buf_t *p=dma->tail; + + printk( "Q: curr=0x%p tail=0x%p head=0x%p bid: ", dma->curr, dma->tail, dma->head); + + while( p) { + printk( "(0x%p 0x%p) ", p, p->id); + p = p->next; + } + printk("\n"); +} + + +/* + * DMA processing... + */ + +static inline int start_lh79520_dma(lh79520_dma_t * dma, dma_addr_t dma_ptr, int size) +{ + dmaRegs_t *dmaRegs = (dmaRegs_t *)IO_ADDRESS(DMAC_PHYS); + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + channelRegs_t *regs = dma->regs; + int status; + + status = dmaRegs->status; + + /* If the DMA channel is active, there's nothing else we can do. */ + if( status & (DMAC_ACTIVE0 << dma->channel)) { + DPRINTK("start: st %#x busy\n", status); + return -EBUSY; + } + + /* If there's an interrupt pending, split now + * and let it happen. + */ + if( status & (DMAC_INT0 << dma->channel)) { + DPRINTK("start: st %#x IRQ pending\n", status); + return -EAGAIN; + } + + /* + * if we're goint to the uda1341, we have to tell the CPLD + * to start to send/receive via DMA. + */ + switch( dma->channel) { + case 2: + cpld->audio_control |= CPLD_DAC_DMA_ENABLE; + dmaRegs->mask |= DMAC_INT2; + break; + + case 3: + cpld->audio_control |= (CPLD_DAC_DMA_ENABLE | CPLD_DAC_USE_REQ1 ); + dmaRegs->mask |= DMAC_INT3; + break; + } + + /* + * set the source or destination registers, based on which + * direction the data's going. + */ + if( dma->direction == DMA_IN) { /* data coming from peripheral */ + regs->destLow = dma_ptr & 0xffff; + regs->destHi = (dma_ptr >> 16 ) & 0xffff; + } else { /* data going to peripheral */ + regs->srcLow = dma_ptr & 0xffff; + regs->srcHi = (dma_ptr >> 16 ) & 0xffff; + } + + regs->count = size >> 2; /* DDD assumes 4-byte transfer size */ + regs->control |= DMAC_CTRL_ENABLE; + + DPRINTK("audio_control=0x%x\n", cpld->audio_control); + DPRINTK("jif=%d start a=%#x sz=%d st=0x%x dma=0x%p dir=%d\n", + jiffies, dma_ptr, size, status, dma, dma->direction); + DUMPREGS(regs,dmaRegs); + +#if 0 + { + u32 *p = phys_to_virt(dma_ptr); + int i; + + for( i=0; i<8; i++) + printk( " %08x %08x %08x %08x\n", *p++, *p++, *p++, *p++); + } +#endif // 0 + + return 0; +} + + +static int start_dma(lh79520_dma_t *dma, dma_addr_t dma_ptr, int size) +{ + return start_lh79520_dma(dma, dma_ptr, size); +} + + +/* This must be called with IRQ disabled */ +static void process_dma(lh79520_dma_t * dma) +{ + dma_buf_t *buf; + int chunksize; + + DUMPQ(dma); + + for (;;) { + buf = dma->tail; + + if (!buf || dma->stopped) { + /* no more data available */ + DPRINTK("process: no more buf (dma %s) buf=0x%p stopped=%d\n", + dma->curr ? "active" : "inactive", buf, dma->stopped); + /* + * 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 (dma->spin_size && dma->spin_ref >= 0) { + chunksize = dma->spin_size; + if (chunksize > MAX_DMA_SIZE) + chunksize = (1 << MAX_DMA_ORDER); + while (start_dma(dma, dma->spin_addr, chunksize) == 0) + dma->spin_ref++; + if (dma->curr != NULL) + dma->spin_ref = -dma->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 (start_dma(dma, buf->dma_ptr, chunksize) != 0) + break; + + if (!dma->curr) { + dma->curr = buf; + DPRINTK("process: set curr %#p\n", dma->curr); + } + + buf->ref++; + buf->dma_ptr += chunksize; + buf->size -= chunksize; + if (buf->size == 0) { + /* current buffer is done: move tail to the next one */ + dma->tail = buf->next; + DPRINTK("process: set tail b=%#x\n", (int) dma->tail); + } + } + + DUMPQ(dma); +} + + +/* This must be called with IRQ disabled */ +void lh79520_dma_done (lh79520_dma_t *dma) +{ + dma_buf_t *buf = dma->curr; + + if (dma->spin_ref > 0) { + dma->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=%#p\n", buf->next); + dma->curr = buf->next; + if (dma->curr == NULL) + dma->spin_ref = -dma->spin_ref; + if (dma->head == buf) + dma->head = NULL; + if (dma->callback) { + int size = buf->dma_ptr - buf->dma_start; + dma->callback(buf->id, size); + } + kfree(buf); + } + } + + process_dma(dma); +} + + +static void dma_irq_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + dmaRegs_t *dmaRegs = (dmaRegs_t *)IO_ADDRESS(DMAC_PHYS); + lh79520_dma_t *dma = (lh79520_dma_t *) dev_id; + int status = dmaRegs->status; + + DPRINTK("jif=%d IRQ: irq=%d regs=0x%x bid=%#x st=%#x, dma=0x%p\n", + jiffies, irq, (u32)dma->regs, (int) dma->curr->id, status, dma); + + if (status & (DMAC_ERROR)) { + printk(KERN_ERR "DMA on \"%s\" caused an error\n", dma->device_id); + dmaRegs->clear = DMAC_ERROR; + } + + dmaRegs->clear = status & DMAC_DONE; + + if (status & DMAC_DONE) + lh79520_dma_done (dma); +} + + +/* + * DMA interface functions + */ + +static spinlock_t dma_list_lock; + +int lh79520_request_dma (dmach_t * channel, const char *device_id, dma_device_t device) +{ + lh79520_dma_t *dma = NULL; + cpldRegs_t *cpld = (cpldRegs_t *)CPLD_BASE; + channelRegs_t *regs; + int i, err; + + /* DMA address (physical) of audio device */ + void *cpldAudioAddr = (void *) &((cpldRegs_t *)CPLD_START)->adc_dac_left; + + +#ifdef DEBUG + printk( __FUNCTION__ "(channel=0x%x, device_id=0x%x device=0x%x)\n", + (u32)channel, (u32)device_id, device); +#endif + + *channel = -1; /* to be sure we catch the freeing of a misregistered channel */ + + err = 0; + spin_lock(&dma_list_lock); + + /* + * Allocate a channel. On the lh79520, channels 0 and 1 + * are dedicated to the SSP. Channels 2 and 3 are general purpose, + * but channel 3 can only be used for audio if the rework described + * in the User's Guide has been performed. + */ + switch( device) { + case DMA_Audio_Out: + dma = &dma_chan[2]; + regs = dma->regs; + + dma->direction = DMA_OUT; + + regs->destLow = (u32)cpldAudioAddr & 0xffff; + regs->destHi = ((u32)cpldAudioAddr >> 16) & 0xffff; + regs->control = DMAC_CTRL_SOINC | + DMAC_CTRL_SOSIZE_4BYTE | + DMAC_CTRL_DESIZE_4BYTE | + DMAC_CTRL_SOBURST_SINGLE | + DMAC_CTRL_ADDR_MODE_WRAP | + DMAC_CTRL_PERIPH_DEST; + break; + + case DMA_Audio_In: + dma = &dma_chan[3]; + regs = dma->regs; + + dma->direction = DMA_IN; + + regs->srcLow = (u32)cpldAudioAddr & 0xffff; + regs->srcHi = ((u32)cpldAudioAddr >> 16) & 0xffff; + regs->control = DMAC_CTRL_SOINC | + DMAC_CTRL_SOSIZE_4BYTE | + DMAC_CTRL_DESIZE_4BYTE | + DMAC_CTRL_SOBURST_SINGLE | + DMAC_CTRL_ADDR_MODE_WRAP | + DMAC_CTRL_PERIPH_SOURCE; + break; + + case DMA_SSP_Rx: /* not supported */ + case DMA_SSP_Tx: /* not supported */ + default: + err = -ENOSR; + break; + } + + if (!err) { + if (dma) + dma->in_use = 1; + else + err = -ENOSR; + } + spin_unlock(&dma_list_lock); + if (err) + return err; + + err = request_irq(dma->irq, dma_irq_handler, SA_INTERRUPT, + device_id, (void *) dma); + if (err) { + printk(KERN_ERR + "%s: unable to request IRQ %d for DMA channel. error=0x%x\n", + device_id, dma->irq, err); + return err; + } + + *channel = dma - dma_chan; + dma->device_id = device_id; + dma->device = device; + dma->callback = NULL; + dma->spin_size = 0; + + regs = dma->regs; + + DPRINTK( "channel=%d regs=0x%x\n", *channel, (u32)regs); + DPRINTK("requested\n"); + + return 0; +} + + +int lh79520_dma_set_callback(dmach_t channel, dma_callback_t cb) +{ + lh79520_dma_t *dma = &dma_chan[channel]; + + if ((unsigned)channel >= LH79520_DMA_CHANNELS || !dma->in_use) + return -EINVAL; + + dma->callback = cb; + DPRINTK("cb = %p\n", cb); + return 0; +} + + +int lh79520_dma_set_spin(dmach_t channel, dma_addr_t addr, int size) +{ + lh79520_dma_t *dma = &dma_chan[channel]; + int flags; + + if ((unsigned)channel >= LH79520_DMA_CHANNELS || !dma->in_use) + return -EINVAL; + + DPRINTK("set spin %d at %#x\n", size, addr); + local_irq_save(flags); + dma->spin_addr = addr; + dma->spin_size = size; + if (size) + process_dma(dma); + + local_irq_restore(flags); + return 0; +} + + +int lh79520_dma_queue_buffer(dmach_t channel, void *buf_id, + dma_addr_t data, int size) +{ + lh79520_dma_t *dma; + dma_buf_t *buf; + int flags; + + dma = &dma_chan[channel]; + if ((unsigned)channel >= LH79520_DMA_CHANNELS || !dma->in_use) + return -EINVAL; + + buf = kmalloc(sizeof(*buf), 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); + + DPRINTK("queueing bid=%#x a=%#x s=%d\n", (int) buf_id, data, size); + + if (dma->head) + dma->head->next = buf; + + dma->head = buf; + if (!dma->tail) + dma->tail = buf; + + process_dma(dma); + local_irq_restore(flags); + + return 0; +} + + +int lh79520_dma_get_current(dmach_t channel, void **buf_id, dma_addr_t *addr) +{ + int flags, ret; + lh79520_dma_t *dma = &dma_chan[channel]; + channelRegs_t *regs; + + if ((unsigned)channel >= LH79520_DMA_CHANNELS || !dma->in_use) + return -EINVAL; + + regs = dma->regs; + local_irq_save(flags); + if (dma->curr && dma->spin_ref <= 0) { + dma_buf_t *buf = dma->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; + + if( dma->direction == DMA_IN) + *addr = (regs->currDstHi << 16 ) | (regs->currDstLow); + else + *addr = (regs->currSrcHi << 16 ) | (regs->currSrcLow); + + /* + * 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)dma->curr->id, *addr); + ret = 0; + } else if (dma->tail && dma->stopped) { + dma_buf_t *buf = dma->tail; + if (buf_id) + *buf_id = buf->id; + *addr = buf->dma_ptr; + ret = 0; + } else { + if (buf_id) + *buf_id = NULL; + *addr = 0; + ret = -ENXIO; + } + local_irq_restore(flags); + return ret; +} + + +int lh79520_dma_stop(dmach_t channel) +{ + dmaRegs_t *dmaRegs = (dmaRegs_t *)IO_ADDRESS(DMAC_PHYS); + lh79520_dma_t *dma = &dma_chan[channel]; + int flags; + + DPRINTK( "lh79520_dma_stop channel=%d\n", channel); + + if (dma->stopped) + return 0; + + local_irq_save(flags); + dma->stopped = 1; + + /* + * Stop DMA and tweak state variables so everything could restart + * from there when resume/wakeup occurs. + */ + dma->regs->control &= ~DMAC_CTRL_ENABLE; + dmaRegs->mask &= ~((DMAC_INT0 << channel) | (DMAC_ERRINT0 << channel)); + + if (dma->curr) { + dma_buf_t *buf = dma->curr; + if (dma->spin_ref <= 0) { + dma_addr_t curpos; + lh79520_dma_get_current(channel, NULL, &curpos); + buf->size += buf->dma_ptr - curpos; + buf->dma_ptr = curpos; + } + buf->ref = 0; + dma->tail = buf; + dma->curr = NULL; + } + dma->spin_ref = 0; + process_dma(dma); + local_irq_restore(flags); + return 0; +} + + +int lh79520_dma_resume(dmach_t channel) +{ + lh79520_dma_t *dma = &dma_chan[channel]; + + if ((unsigned)channel >= LH79520_DMA_CHANNELS || !dma->in_use) + return -EINVAL; + + if (dma->stopped) { + int flags; + save_flags_cli(flags); + dma->stopped = 0; + dma->spin_ref = 0; + process_dma(dma); + restore_flags(flags); + } + return 0; +} + + +int lh79520_dma_flush_all(dmach_t channel) +{ + dmaRegs_t *dmaRegs = (dmaRegs_t *)IO_ADDRESS(DMAC_PHYS); + lh79520_dma_t *dma = &dma_chan[channel]; + dma_buf_t *buf, *next_buf; + int flags; + + DPRINTK("dma_flush_all channel=%d\n", channel); + DUMPQ(dma); + + if ((unsigned)channel >= LH79520_DMA_CHANNELS || !dma->in_use) + return -EINVAL; + + local_irq_save(flags); + + /* + * Disable the channel, and mask off its interrupts + */ + dma->regs->control &= ~(DMAC_CTRL_ENABLE); + dmaRegs->mask &= ~((DMAC_INT0 << channel) | (DMAC_ERRINT0 << channel)); + + buf = dma->curr; + if (!buf) + buf = dma->tail; + + dma->head = dma->tail = dma->curr = NULL; + dma->stopped = 0; + dma->spin_ref = 0; + process_dma(dma); + local_irq_restore(flags); + + while (buf) { + next_buf = buf->next; + kfree(buf); + buf = next_buf; + } + DPRINTK("flushed\n"); + return 0; +} + + +void lh79520_free_dma(dmach_t channel) +{ + lh79520_dma_t *dma; + + if ((unsigned)channel >= LH79520_DMA_CHANNELS) + return; + + dma = &dma_chan[channel]; + if (!dma->in_use) { + printk(KERN_ERR "Trying to free free DMA%d\n", channel); + return; + } + + lh79520_dma_set_spin(channel, 0, 0); + lh79520_dma_flush_all(channel); + + free_irq(dma->irq, (void *) dma); + dma->in_use = 0; + + DPRINTK("freed\n"); +} + + +EXPORT_SYMBOL(lh79520_request_dma); +EXPORT_SYMBOL(lh79520_dma_set_callback); +EXPORT_SYMBOL(lh79520_dma_set_spin); +EXPORT_SYMBOL(lh79520_dma_queue_buffer); +EXPORT_SYMBOL(lh79520_dma_get_current); +EXPORT_SYMBOL(lh79520_dma_stop); +EXPORT_SYMBOL(lh79520_dma_resume); +EXPORT_SYMBOL(lh79520_dma_flush_all); +EXPORT_SYMBOL(lh79520_free_dma); + + +#ifdef CONFIG_PM +/* Drivers should call this from their PM callback function */ + +int lh79520_dma_sleep(dmach_t channel) +{ + dmaRegs_t *dmaRegs = (dmaRegs_t *)IO_ADDRESS(DMAC_PHYS); + lh79520_dma_t *dma = &dma_chan[channel]; + int orig_state; + + if ((unsigned)channel >= LH79520_DMA_CHANNELS || !dma->in_use) + return -EINVAL; + + orig_state = dma->stopped; + lh79520_dma_stop(channel); + dma->regs->control &= ~DMAC_CTRL_ENABLE; + dmaRegs->mask &= ~((DMAC_INT0 << channel) | (DMAC_ERRINT0 << channel)); + + dma->stopped = orig_state; + dma->spin_ref = 0; + return 0; +} + +int lh79520_dma_wakeup(dmach_t channel) +{ + dmaRegs_t *dmaRegs = (dmaRegs_t *)IO_ADDRESS(DMAC_PHYS); + lh79520_dma_t *dma = &dma_chan[channel]; + int flags; + + if ((unsigned)channel >= LH79520_DMA_CHANNELS || !dma->in_use) + return -EINVAL; + + dma->regs->control &= ~DMAC_CTRL_ENABLE; + dmaRegs->mask &= ~((DMAC_INT0 << channel) | (DMAC_ERRINT0 << channel)); + + local_irq_save(flags); + process_dma(dma); + local_irq_restore(flags); + + return 0; +} + +EXPORT_SYMBOL(lh79520_dma_sleep); +EXPORT_SYMBOL(lh79520_dma_wakeup); + +#endif /* CONFIG_PM */ + + +static int __init lh79520_init_dma(void) +{ + int channel; + dmaRegs_t *dmaRegs = (dmaRegs_t *)IO_ADDRESS(DMAC_PHYS); + ioconRegs_t *ioconRegs = (ioconRegs_t *)IO_ADDRESS( IOCON_PHYS); + channelRegs_t *regs; + +#ifdef DEBUG + printk( __FUNCTION__ "\n"); +#endif + + dmaRegs->clear = DMAC_CLEAR_ALL; + dmaRegs->mask = 0; + + for (channel = 0; channel < LH79520_DMA_CHANNELS; channel++) { + dma_chan[channel].regs = regs = streamRegs[channel]; + + regs->control = 0; + regs->count = 0; + regs->srcHi = 0; + regs->srcLow = 0; + regs->destHi = 0; + regs->destLow = 0; + + dma_chan[channel].irq = IRQ_DMA; + dma_chan[channel].channel = channel; + +#ifdef DEBUG + printk( "dma channel %d at 0x%x\n", channel, (u32)regs); +#endif + } + + /* assign pins to DMA stream 2 */ + ioconRegs->DMAMux |= (DMAMUX_DCDEOT0 | DMAMUX_DCDREQ0) ; + + /* assign pins to DMA Stream 3 */ + // These two lines interfere with PWM Audio + // ioconRegs->MiscMux |= MISCMUX_DCDEOT1; + // ioconRegs->MiscMux &= ~MISCMUX_RCEII5; + + return 0; +} + +__initcall(lh79520_init_dma); diff -urN linux-2.4.26/arch/arm/mach-lh79520/dma.h linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/dma.h --- linux-2.4.26/arch/arm/mach-lh79520/dma.h 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/dma.h 2005-11-02 17:38:44.000000000 -0400 @@ -0,0 +1,61 @@ +/* + * 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 + * + * 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 + +/* + * DMA buffer structure + */ + +typedef struct dma_buf_s { + 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 */ + struct dma_buf_s *next; /* next buffer to process */ +} dma_buf_t; + +typedef enum { + DMA_OUT, + DMA_IN +} dma_direction_t; + +/* + * DMA channel structure. + */ +typedef struct { + unsigned int in_use; /* Device is allocated */ + const char *device_id; /* Device name */ + dma_device_t device; /* ... to which this channel is attached */ + dma_buf_t *head; /* where to insert buffers */ + dma_buf_t *tail; /* where to remove buffers */ + dma_buf_t *curr; /* buffer currently DMA'ed */ + int stopped; /* 1 if DMA is stalled */ + channelRegs_t *regs; /* points to appropriate DMA registers */ + int irq; /* IRQ used by the channel */ + dma_callback_t callback; /* ... 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 */ + int channel; /* channel number */ + dma_direction_t direction; /* DMA direction: 0=Out / 1=In */ +} lh79520_dma_t; + +extern lh79520_dma_t dma_chan[LH79520_DMA_CHANNELS]; + + +void lh79520_dma_done( lh79520_dma_t *dma); + + + + diff -urN linux-2.4.26/arch/arm/mach-lh79520/generic.c linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/generic.c --- linux-2.4.26/arch/arm/mach-lh79520/generic.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/generic.c 2005-11-02 17:38:09.000000000 -0400 @@ -0,0 +1,71 @@ +/* + * linux/arch/arm/mach-lh79520/generic.c + * + * Common code for all LH79520 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 + + +/* + * return the CPU clock frequency (FCLK) in Hz. + */ +unsigned int +cpufreq_get( int cpu) +{ + int divider; + rcpcRegs_t *RCPC = (rcpcRegs_t *)IO_ADDRESS(RCPC_PHYS); + + divider = RCPC->CpuClkPrescale * 2; + if( divider == 0) + divider = 1; + return PLL_CLOCK / divider;; +} +EXPORT_SYMBOL(cpufreq_get); + + +/* + * return the bus clock frequency (HCLK) in Hz. + */ +unsigned int +hclkfreq_get( void) +{ + int divider; + rcpcRegs_t *RCPC = (rcpcRegs_t *)IO_ADDRESS(RCPC_PHYS); + + divider = RCPC->HCLKPrescale * 2; /* HCLK prescale value */ + + if( divider == 0) /* no prescalar == divide by 1 */ + divider = 1; + + return PLL_CLOCK / divider; +} + + diff -urN linux-2.4.26/arch/arm/mach-lh79520/generic.h linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/generic.h --- linux-2.4.26/arch/arm/mach-lh79520/generic.h 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/generic.h 2005-11-02 17:38:09.000000000 -0400 @@ -0,0 +1,24 @@ +/* + * linux/arch/arm/mach-lh79520/generic.h + * + * Common code for all LH79520 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 + */ + +unsigned int cpufreq_get( int cpu); +unsigned int hclkfreq_get( void); diff -urN linux-2.4.26/arch/arm/mach-lh79520/Makefile linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/Makefile --- linux-2.4.26/arch/arm/mach-lh79520/Makefile 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/Makefile 2005-11-02 17:38:09.000000000 -0400 @@ -0,0 +1,24 @@ +# +# 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 := lh79520.o + +# Object file lists. + +obj-y := arch.o mm.o generic.o dma.o +obj-m := +obj-n := +obj- := + +export-objs := generic.o dma.o + +# obj-$(CONFIG_LEDS) += leds.o +# obj-$(CONFIG_PCI) += pci_v3.o pci.o + +include $(TOPDIR)/Rules.make diff -urN linux-2.4.26/arch/arm/mach-lh79520/mm.c linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/mm.c --- linux-2.4.26/arch/arm/mach-lh79520/mm.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/mach-lh79520/mm.c 2005-11-02 17:38:09.000000000 -0400 @@ -0,0 +1,38 @@ +/* + * linux/arch/arm/mach-lh79520/mm.c + * + * 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 version 2 as + * published by the Free Software Foundation. + */ +#include +#include +#include + +#include +#include +#include + +#include + +static struct map_desc lh79520_io_desc[] __initdata = { + /* virt phys size r w c b */ + { FLASH_BASE, FLASH_START, FLASH_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { CPLD_BASE, CPLD_START, CPLD_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { CS8900_BASE, CS8900_START, CS8900_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { IDE_BASE, IDE_START, IDE_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { IDE2_BASE, IDE2_START, IDE2_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { INT_SRAM_BASE, INT_SRAM_START, INT_SRAM_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { APB_BASE, APB_START, APB_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { AHB_BASE, AHB_START, AHB_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + { VIC_BASE, VIC_START, VIC_SIZE, DOMAIN_IO, 0, 1, 0, 0 }, + LAST_DESC +}; + +void __init lh79520_map_io(void) +{ + iotable_init( lh79520_io_desc); +} + diff -urN linux-2.4.26/arch/arm/Makefile linux-2.4.26-vrs1-lnode80/arch/arm/Makefile --- linux-2.4.26/arch/arm/Makefile 2005-11-02 16:54:16.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/Makefile 2005-11-02 17:37:31.000000000 -0400 @@ -160,6 +160,16 @@ MACHINE = anakin endif +ifeq ($(CONFIG_ARCH_LH79520),y) +# C0008000 is the default, so not needed -- DDD +# DDD TEXTADDR = 0xC0008000 +MACHINE = lh79520 +endif + +ifeq ($(CONFIG_ARCH_LH7A400),y) +MACHINE = lh7a400 +endif + ifeq ($(CONFIG_ARCH_OMAHA),y) MACHINE = omaha endif diff -urN linux-2.4.26/arch/arm/tools/mach-types linux-2.4.26-vrs1-lnode80/arch/arm/tools/mach-types --- linux-2.4.26/arch/arm/tools/mach-types 2005-11-02 16:54:18.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/arch/arm/tools/mach-types 2005-11-02 17:37:31.000000000 -0400 @@ -525,3 +525,5 @@ omap_osk MACH_OMAP_OSK OMAP_OSK 515 rg100v3 MACH_RG100V3 RG100V3 516 mx2ads MACH_MX2ADS MX2ADS 517 +lh79520evb LH79520_EVB LH79520EVB 999 +lh7a400evb LH7A400_EVB LH7A400EVB 998 diff -urN linux-2.4.26/Documentation/Configure.help linux-2.4.26-vrs1-lnode80/Documentation/Configure.help --- linux-2.4.26/Documentation/Configure.help 2005-11-02 16:54:16.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/Documentation/Configure.help 2005-11-02 17:37:31.000000000 -0400 @@ -25531,6 +25531,136 @@ a debugging option; you probably do not want to set it unless you are an S390 port maintainer. +Sharp LH79520 based bords +CONFIG_ARCH_LH79520 + Say Y here to support the Sharp LH79520 System on Chip. + +Sharp LH79520 Evaluation Board (Isis) +CONFIG_LH79520_EVB + Say Y here to support the Sharp LH79520 Evaluation Board. + +Sharp LH79520 Watchdog Timer +CONFIG_LH79520_WATCHDOG + Say Y here to include support for the LH79520 watchdog timer. + The watchdog timer will reboot your system when the timeout is reached. + Note that once enabled, this timer cannot be disabled. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + If you want to compile it as a module, say M here and read + Documentation/modules.txt. The module will be called lh79520_wdt.o. + + If unsure, say N. + +Sharp LH79520 PWM controller +CONFIG_LH79520_PWM + Say Y here to include support for the PWM device. + PWM0 is for the LCD backlight intensity, and + PWM1 is for audio. The major number is dynamically assigned unless + module parameter is provided. Device nodes must exist to control + the ioctls. + /dev/pwm0 c 254 0 + /dev/pwm1 c 254 1 + 254 may or may not be the major number for your driver. + Check /proc/devices for major number of pwm520. + + If unsure, say N. + +Sharp LH79520 7-segment display +CONFIG_7SEGMENT_LH79520 + Say Y here to include support for the LH79520 7-segment display. + + If unsure, say N. + +Sharp LH79520 Touchscreen +CONFIG_TOUCHSCREEN_LH79520 + Say Y here to include support for the LH79520 touchscreen. + + If unsure, say N. + +Sharp LH79520 LCD EEPROM +CONFIG_EEPROM_LH79520 + Say Y here to include support for the EEPROM on the LCD + board on the Sharp LH79520 EVB. + + If unsure, say N. + +ARM PrimeCell PL011 UART +CONFIG_SERIAL_AMBA_PL011 + Say Y here to include support for the ARM PrimeCell PL011 UART. + + If unsure, say N. + +Console on ARM PL011 UART +CONFIG_SERIAL_AMBA_PL011_CONSOLE + Say Y here to support a serial console on an ARM PrimeCell PL011 UART. + + If unsure, say N. + +ARM PrimeCell PL110 LCD Controller +CONFIG_FB_PL110 + Say Y here to include support the ARM PrimeCell PL110 + LCD controller. + + If unsure, say N. + +Sharp LQ039Q2DS53-HR-TFT LCD panel +CONFIG_PL110_LQ39 + Say Y here to if you've got a Sharp LQ039Q2DS53-HR-TFT + LCD panel connected to an ARM PL110 LCD controller. + + If unsure, say N. + +Sharp LM057QCTT03-QVGA-STN LCD panel +CONFIG_PL110_LM57 + Say Y here to if you've got a Sharp LM057QCTT03-QVGA-STN + LCD panel connected to an ARM PL110 LCD controller. + + If unsure, say N. + +Sharp LQ057Q3DC02-VGA/QVGA-TFT LCD panel +CONFIG_PL110_LQ57 + Say Y here to if you've got a Sharp LQ057Q3DC02-VGA/QVGA-TFT + LCD panel connected to an ARM PL110 LCD controller. + + If unsure, say N + +Sharp LQ121S1DG31-800x600-TFT LCD panel +CONFIG_PL110_LQ121 + Say Y here to if you've got a Sharp LQ121S1DG31-800x600-TFT + LCD panel connected to an ARM PL110 LCD controller. + + If unsure, say N + +Sharp LQ104V1DG11-640x480-TFT LCD panel +CONFIG_PL110_LQ104 + Say Y here to if you've got a Sharp LQ104V1DG11-640x480-TFT + LCD panel connected to an ARM PL110 LCD controller. + + If unsure, say N + +Sharp LH7A400 based bords +CONFIG_ARCH_LH7A400 + Say Y here to support the Sharp LH7A400 System on Chip. + +Sharp LH7A400 Evaluation Board (Aruba) +CONFIG_LH7A400_EVB + 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. + # # ARM options # diff -urN linux-2.4.26/drivers/char/Config.in linux-2.4.26-vrs1-lnode80/drivers/char/Config.in --- linux-2.4.26/drivers/char/Config.in 2005-11-02 16:54:20.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/char/Config.in 2005-11-02 17:37:31.000000000 -0400 @@ -253,6 +253,7 @@ dep_tristate ' DC21285 watchdog' CONFIG_21285_WATCHDOG $CONFIG_FOOTBRIDGE dep_tristate ' NetWinder WB83C977 watchdog' CONFIG_977_WATCHDOG $CONFIG_ARCH_NETWINDER dep_tristate ' SA1100 watchdog' CONFIG_SA1100_WATCHDOG $CONFIG_ARCH_SA1100 + dep_tristate ' Sharp LH79520 watchdog' CONFIG_LH79520_WATCHDOG $CONFIG_ARCH_LH79520 dep_tristate ' EPXA watchdog' CONFIG_EPXA_WATCHDOG $CONFIG_ARCH_CAMELOT dep_tristate ' Omaha watchdog' CONFIG_OMAHA_WATCHDOG $CONFIG_ARCH_OMAHA dep_tristate ' AT91RM9200 watchdog' CONFIG_AT91_WATCHDOG $CONFIG_ARCH_AT91RM9200 @@ -304,6 +305,11 @@ if [ "$CONFIG_X86" = "y" -o "$CONFIG_X86_64" = "y" ]; then dep_tristate 'AMD 768/8111 Random Number Generator support' CONFIG_AMD_RNG $CONFIG_PCI fi + +if [ "$CONFIG_ARCH_LH79520" = "y" ]; then + tristate 'LH79520 PWM support' CONFIG_LH79520_PWM +fi + if [ "$CONFIG_X86" = "y" -o "$CONFIG_IA64" = "y" ]; then dep_tristate 'Intel i8x0 Random Number Generator support' CONFIG_INTEL_RNG $CONFIG_PCI fi diff -urN linux-2.4.26/drivers/char/console.c linux-2.4.26-vrs1-lnode80/drivers/char/console.c --- linux-2.4.26/drivers/char/console.c 2005-11-02 16:54:20.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/char/console.c 2005-11-02 17:37:31.000000000 -0400 @@ -169,7 +169,7 @@ int console_blanked; static int vesa_blank_mode; /* 0:none 1:suspendV 2:suspendH 3:powerdown */ -static int blankinterval = 10*60*HZ; +static int blankinterval = 0; // 10*60*HZ; static int vesa_off_interval; static struct tq_struct console_callback_tq = { diff -urN linux-2.4.26/drivers/char/cradle.c linux-2.4.26-vrs1-lnode80/drivers/char/cradle.c --- linux-2.4.26/drivers/char/cradle.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/char/cradle.c 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,486 @@ +/* +** cradle.c +** +** Device driver for the cradle interface on the Touchblock device. +** +** Copyright (C) 2002 The PTR Group, 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 + +static ssize_t cradle_read(struct file *filp, char *buf, size_t count, loff_t *f_pos); +static int cradle_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg); +static int cradle_open(struct inode *inode, struct file *filp); +static int cradle_release(struct inode *inode, struct file *filp); +static int cradle_fasync(int fd, struct file *filp, int mode ); +static unsigned int cradle_poll(struct file *filp, poll_table *wait); + + +static char read_docking_state(void); +static inline void cradle_update_buffer(volatile char **index, int delta, char *buf, int size); + +#if 0 +void cradle_do_tasklet_docked(unsigned long data); +DECLARE_TASKLET( cradle_tasklet_docked, cradle_do_tasklet_docked,0); +void cradle_do_tasklet_undocked(unsigned long data); +DECLARE_TASKLET( cradle_tasklet_undocked, cradle_do_tasklet_undocked,0); +#endif + +//#define min(a,b) (((a)<(b))?(a):(b)) + +#define CRADLE_IBUF_SIZE 2 + +typedef struct +{ + int users; + int ready; + volatile char *ibuf_wp; + volatile char *ibuf_rp; + char *ibuf; + wait_queue_head_t wait_inq; + struct fasync_struct *fasync; /* asynchronous readers */ +} cradle_dev_t; + +static cradle_dev_t cradle_dev; + +struct file_operations cradle_fops = { +// NULL, // seek +read: cradle_read, // read +// NULL, // write +// NULL, // readdir +poll: cradle_poll, // poll/select +ioctl: cradle_ioctl, // ioctl +// NULL, // mmap +open: cradle_open, // open +// NULL, // flush +release: cradle_release, // release +// NULL, // fsync +fasync: cradle_fasync, // fasync +}; + +/************************************************************************ +** Read the docking state from the hardware +************************************************************************/ +static char read_docking_state(void) +{ + + return( (GPIOG->dr & 0x10) ? CRADLE_UNDOCKED_STATE : CRADLE_DOCKED_STATE ); +} + +/************************************************************************ +** Manipulate the buffer pointers safely without using locks +************************************************************************/ +static inline void cradle_update_buffer(volatile char **index, int delta, char *buf, int size) +{ + volatile char *new = *index + delta; + barrier(); + *index=(new >= (buf+size)) ? buf : new; +} + + +#if 0 +/************************************************************************ +** Enable the interrupt(s) associated with the cradle +************************************************************************/ +static void cradle_enable_interrupt(void) +{ + /* printk(KERN_INFO "cradle: interrupts enabled\n"); */ +} + +/************************************************************************ +** Disable the interrupt(s) associated with the cradle +************************************************************************/ +static void cradle_disable_interrupt(void) +{ + /* printk(KERN_INFO "cradle: interrupts disabled\n"); */ +} + +/************************************************************************ +** +************************************************************************/ +static void cradle_docked_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + cradle_dev_t *dev=dev_id; + + /* printk(KERN_INFO "cradle: docked irq\n"); */ + + /* Reset the interrupt request */ + + /* Get the state */ + *dev->ibuf_wp=read_docking_state(); + cradle_update_buffer(&dev->ibuf_wp, 1, dev->ibuf, CRADLE_IBUF_SIZE); + + /* Notify any asynchronous readers */ + if( dev->fasync ) + { + /* printk(KERN_INFO "cradle: kill_fasync()\n"); */ + kill_fasync(dev->fasync, SIGIO, POLL_IN); + } + + wake_up_interruptible( &dev->wait_inq ); + + /* Schedule the bottom-half */ + /* tasklet_schedule(&cradle_tasklet_docked); */ +} + +/************************************************************************ +** +************************************************************************/ +static void cradle_undocked_interrupt_handler(int irq, void *dev_id, struct pt_regs *regs) +{ + cradle_dev_t *dev=dev_id; + + /* printk(KERN_INFO "cradle: undocked irq\n"); */ + + /* Reset the interrupt request */ + + /* Get the state */ + *dev->ibuf_wp=read_docking_state(); + cradle_update_buffer(&dev->ibuf_wp, 1, dev->ibuf, CRADLE_IBUF_SIZE); + + /* Notify any asynchronous readers */ + if( dev->fasync ) + { + /* printk(KERN_INFO "cradle: kill_fasync()\n"); */ + kill_fasync(dev->fasync, SIGIO, POLL_IN); + } + + wake_up_interruptible( &dev->wait_inq ); + + /* Schedule the bottom-half */ + /* tasklet_schedule(&cradle_tasklet_undocked); */ +} + +/************************************************************************* +** Bottom-half processing +*************************************************************************/ +void cradle_do_tasklet_docked(unsigned long data) +{ + printk(KERN_INFO "cradle: tasklet\n"); +} + + +/************************************************************************* +** Bottom-half processing +*************************************************************************/ +void cradle_do_tasklet_undocked(unsigned long data) +{ + printk(KERN_INFO "cradle: tasklet undocked\n"); +} +#endif + +/************************************************************************ +** Open the cradle device +************************************************************************/ +static int cradle_open(struct inode *inode, struct file *filp) +{ + cradle_dev_t *dev; + int status; + + /* printk(KERN_INFO "cradle: open()\n"); */ + + /* Initialize the device information */ + dev=(cradle_dev_t *)filp->private_data; + if(!dev) + { + dev=&cradle_dev; + filp->private_data=dev; + } + + if( dev->users++ ) return 0; + + MOD_INC_USE_COUNT; + + /* allocate the buffers */ + dev->ibuf=(char *)kmalloc(CRADLE_IBUF_SIZE,GFP_KERNEL); + if( !dev->ibuf ) + { + MOD_DEC_USE_COUNT; + return -ENOMEM; + } + + /* clear the buffers */ + dev->ibuf_wp=dev->ibuf_rp=dev->ibuf; + + /* mark the device ready */ + dev->ready=1; + + /* Install the interrupt handler(s) */ + + /* Enable the interrupts */ + //cradle_enable_interrupt(); + + + return 0; +} + +/************************************************************************ +** Release the cradle device +************************************************************************/ +static int cradle_release(struct inode *inode, struct file *filp) +{ + + cradle_dev_t *dev=(cradle_dev_t *)filp->private_data; + + /* printk(KERN_INFO "cradle: release\n"); */ + + if( --dev->users ) return 0; + + //cradle_disable_interrupt(); + + //free the irq + + /* release any asynchronous readers */ + cradle_fasync(-1,filp,0); + + /* free up resources */ + kfree(dev->ibuf); + + + MOD_DEC_USE_COUNT; + + return 0; +} + +/************************************************************************ +** Read the cradle device +** +** This implementation supports both non-blocking and blocking i/o. +************************************************************************/ +static ssize_t cradle_read(struct file *filp, char *buf, size_t count, loff_t *f_pos) +{ + cradle_dev_t *dev=(cradle_dev_t *)filp->private_data; + wait_queue_t wait; + + /* printk(KERN_INFO "cradle: read()\n"); */ + + /* unseekable device */ + if( f_pos!=&filp->f_pos ) + return -ESPIPE; + + /* + ** safe implementation of sleeping that avoids race conditions + */ + + /* init our local wait queue */ + init_waitqueue_entry(&wait, current); + + /* add out queue to the drivers queue */ + add_wait_queue(&dev->wait_inq, &wait); + + while( 1 ) + { + /* tell the schedule we are asleep (even though we aren't yet) */ + set_current_state(TASK_INTERRUPTIBLE); + + /* check for available data */ + if( dev->ibuf_wp != dev->ibuf_rp ) + { + break; + } + + if( filp->f_flags & O_NONBLOCK ) + { + remove_wait_queue(&dev->wait_inq, &wait); + set_current_state(TASK_RUNNING); + return -EAGAIN; + /* return -EWOULDBLOCK; */ + } + + /* check to see if it is a signal */ + if( signal_pending(current)) + { + remove_wait_queue(&dev->wait_inq, &wait); + set_current_state(TASK_RUNNING); + return -ERESTARTSYS; + } + + /* allow other processes to run (we'll go to sleep) */ + schedule(); + } + + set_current_state(TASK_RUNNING); + remove_wait_queue(&dev->wait_inq, &wait); + + /* calculate how much data is available */ + if( dev->ibuf_wp > dev->ibuf_rp ) + count=min(count, dev->ibuf_wp - dev->ibuf_rp ); + else + count=min(count, (dev->ibuf+CRADLE_IBUF_SIZE) - dev->ibuf_rp ); + + /* printk("cradle: read() %d available\n", count); */ + + /* copy the data to user space */ + if( copy_to_user(buf, dev->ibuf_rp, count) ) + { + return -EFAULT; + } + + /* manager the buffer pointers */ + cradle_update_buffer(&dev->ibuf_rp, count, dev->ibuf, CRADLE_IBUF_SIZE); + + + return count; +} + +/************************************************************************ +** Poll/select the cradle device +************************************************************************/ +static unsigned int cradle_poll(struct file *filp, poll_table *wait) +{ + cradle_dev_t *dev=filp->private_data; + unsigned int mask=0; + + poll_wait(filp, &dev->wait_inq, wait); + + /* check for readable */ + if( dev->ibuf_wp != dev->ibuf_rp ) + mask |= POLLIN | POLLRDNORM; + + return mask; +} + +/************************************************************************ +** IOCTL interface for the cradle device +************************************************************************/ +static int cradle_ioctl(struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int docking_state; + int retval=0; + + /* printk(KERN_INFO "cradle: ioct %d\n", cmd); */ + + switch(cmd) + { + case CRADLE_GET_DOCKING_STATE_IOCTL: + docking_state=read_docking_state(); + //this code is here temporarily until + // a timer is added to check the state and set + // the LED automatically + if(docking_state == CRADLE_DOCKED_STATE) + { + // turn on dock led + GPIOF->dr |= 0x40; + } + else + { + // turn off dock led + GPIOF->dr &= ~0x40; + } + + retval=put_user(docking_state, (int *)arg); + + break; + default: + printk(KERN_INFO "cradle: unknown ioctl %d\n", cmd); + retval=-1; + break; + } + + return retval; +} + +/************************************************************************ +** Aynchronous i/o support for the cradle device +************************************************************************/ +static int cradle_fasync(int fd, struct file *filp, int on ) +{ + int retval; + cradle_dev_t *dev=filp->private_data; + + /* + printk(KERN_INFO "cradle: fasync fd=%d filp=0x%08x mode=%d\n", + fd, (unsigned int) filp, on ); + */ + + retval=fasync_helper(fd, filp, on, &dev->fasync); + if( retval < 0 ) + return retval; + else + return 0; +} + +/************************************************************************ +** Initialize the cradle interface and the hardware associated with the +** cradle. +** +** This configuration is specific to the hardware design for the +** Touchblock device. Moreover, this configuration *must* match the +** configuration of the MIPS interrupt handler. +************************************************************************/ +void cradle_init(void) +{ + int retval; + int cradle_major = 0; + + /* register the device */ + retval=register_chrdev( cradle_major, "cradle", &cradle_fops ); + if( retval < 0 ) + { + printk(KERN_WARNING "cradle: Failed to register device\n"); + } + if (cradle_major == 0) + { + cradle_major = retval; /* Dynamic Allocation of major number */ + printk("<4>Cradle Dynamic Major Number %d\n",cradle_major); + } + + + /* initialize the device structure */ + memset( &cradle_dev, 0, sizeof( cradle_dev_t ) ); + init_waitqueue_head(&cradle_dev.wait_inq); + + + /* printk(KERN_INFO "cradle: initalized\n"); */ +} + +/************************************************************************ +** +** Since the cradle device is statically compiled into the kernel this +** is not really used. However, when the driver switches to loadable +** modules this should be the basis of the +** module cleanup routine. +************************************************************************/ +void cradle_cleanup(void) +{ + /* unregister the device */ + unregister_chrdev( CRADLE_MAJOR, "cradle"); + + + /* printk(KERN_INFO "cradle: cleanup\n"); */ +} + + +module_init(cradle_init); +module_exit(cradle_cleanup); diff -urN linux-2.4.26/drivers/char/lh79520_wdt.c linux-2.4.26-vrs1-lnode80/drivers/char/lh79520_wdt.c --- linux-2.4.26/drivers/char/lh79520_wdt.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/char/lh79520_wdt.c 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,259 @@ +/* + * Watchdog driver for the LH79520 + * + * (c) Copyright 2000 Oleg Drokin + * Based on SoftDog driver by Alan Cox + * + * 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. + * + * Neither Oleg Drokin nor iXcelerator.com admit liability nor provide + * warranty for any of this software. This material is provided + * "AS-IS" and at no charge. + * + * (c) Copyright 2000 Oleg Drokin + * + * 27/11/2000 Initial release + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lh79520_wdt.h" + +unsigned int hclkfreq_get( void); + +#define TIMER_MARGIN 60 /* default in seconds */ +#ifdef OLDWAY +#define PCLK 51609600 /* ticks per second of AHB clock, 51MHz */ +#else +#define PCLK hclkfreq_get() +#endif +#define SLEEP_TIME 10 /* number of seconds between each counter reload */ + +static int lh79520_margin = TIMER_MARGIN; /* in seconds */ +static int lh79520wdt_users; /* mutex */ +#ifdef FIQ_ENABLED +static int irq = 0x1c; /* FIQ. Normally 0x18 for standard irq */ +#else +static int irq = 0x18; /* IRQ. Normally the FIQ is 0x1c */ +#endif + +#define WDTBase 0xFFFE3000L /* Base Address for all LH79520 Watchdog Registers */ +WDTIMERREGS *wtdregs = (WDTIMERREGS *) WDTBase; + +#ifdef MODULE +MODULE_PARM(lh79520_margin,"i"); +#endif + +/* + * Allow only one person to hold it open + */ + +static int lh79520dog_open(struct inode *inode, struct file *file) +{ + if(test_and_set_bit(1,&lh79520wdt_users)) + return -EBUSY; + MOD_INC_USE_COUNT; + + if ((lh79520_margin > (PCLK / 0xffffffff)) || /* 83 seconds max, 20 sec min margin */ + (lh79520_margin <= SLEEP_TIME * 2)) + lh79520_margin = TIMER_MARGIN; + +/* setting bits 7-4 of WDCTLR to 0x0 through 0xF sets the *initial* counter value upon a reset */ +/* 0x0 is 2^16 tics of PCLK, or reset immediatly, 0x10 is 2^17 tics of PCLK, ... */ +/* 0xF is 2^31 tics of PCLK, if PCLK is 51 MHz, 2^31 / 51 MHz = 41.6 seconds */ +/* WDCTLR=0xF, the F sets initial counter to 41.6 seconds (assuming PCLK is 51 MHz) */ +/* The counter will be set to the user selected margin the first time a reload occurs */ + wtdregs->wdctlr |= 0xF0; + + /* Activate LH79520 Watchdog timer */ + wtdregs->wdctlr |= WDT_CTRL_ENABLE; + ///wtdregs->wdctlr |= WDT_CTRL_FRZ_ENABLE; + // The 1 sets the enable bit (bit 0) to 1 enabling the watchdog fuctionality + // The freeze or lock bit (bit 4) makes bit 0 read-only (to avoid accidental disabling) + // Bit 1 is left at 0 signifing that when the counter reaches 0, a machine reset occurs + // If bit 1 were 1, then the first time the counter reached 0 an interrupt occurs, and + // the second time the counter reaches 0 the machine is reset. + + // Now reset Watchdog to let the above settings take effect + wtdregs->wdcntr = WDT_WDCNTR; // 0x1984 is a special reset value + return 0; +} + +static int lh79520dog_release(struct inode *inode, struct file *file) +{ + /* + * Shut off the timer. + * Lock it in if it's a module and we defined ...NOWAYOUT + */ + ///wtdregs->wdctr |= 0x0; // turns off bit 4 the freeze lock so we can write to bit 0 + wtdregs->wdctlr |= WDT_CTRL_DISABLE; // turns off watchdog bit 0 + + lh79520wdt_users = 0; + MOD_DEC_USE_COUNT; + return 0; +} + +static ssize_t lh79520dog_write(struct file *file, const char *data, size_t len, loff_t *ppos) +{ + /* Can't seek (pwrite) on this device */ + if (ppos != &file->f_pos) + return -ESPIPE; + + /* Refresh/reload counter */ + if(len) { + unsigned int count = (lh79520_margin * PCLK); + wtdregs->wdcnt3 = count && 0xFF000000; + wtdregs->wdcnt2 = count && 0x00FF0000; + wtdregs->wdcnt1 = count && 0x0000FF00; + wtdregs->wdcnt0 = count && 0x000000FF; + return 1; + } + return 0; +} + +static int lh79520dog_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + static struct watchdog_info ident = { + identity: "LH79520 Watchdog", + }; + + switch(cmd){ + default: + return -ENOIOCTLCMD; + case WDIOC_GETSUPPORT: + return copy_to_user((struct watchdog_info *)arg, &ident, sizeof(ident)); + case WDIOC_GETSTATUS: + return put_user(0,(int *)arg); + case WDIOC_GETBOOTSTATUS: /* 1 = last reboot was cause by watchdog, 0 means no */ + return put_user( ! (wtdregs->wdtstr & WDT_WD_NWDRES), (int *)arg); + case WDIOC_KEEPALIVE: + { + unsigned int count = (lh79520_margin * PCLK); + wtdregs->wdcnt3 = count && 0xFF000000; + wtdregs->wdcnt2 = count && 0x00FF0000; + wtdregs->wdcnt1 = count && 0x0000FF00; + wtdregs->wdcnt0 = count && 0x000000FF; + } + return 0; + } +} + +/** + * lh79520dog_interrupt: + * @irq: Interrupt number + * @dev_id: Unused as we don't allow multiple devices. + * @regs: Unused. + * + * Handle an interrupt from the board. These are raised when the status + * map changes in what the board considers an interesting way. That means + * a failure condition occuring. + */ + +void lh79520dog_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + /* + * Read the status register see what is up and + * then printk it. + */ + + unsigned char status=wtdregs->wdtstr; + +/* status|=FEATUREMAP1; + status&=~FEATUREMAP2; */ + + printk(KERN_CRIT "WDT status %d\n", status); + + wtdregs->wdcntr = WDT_WDCNTR; // 0x1984 is a special reset value +/* + if(!(status&WDC_SR_TGOOD)) + printk(KERN_CRIT "Overheat alarm.(%d)\n",inb_p(WDT_RT)); + if(!(status&WDC_SR_PSUOVER)) + printk(KERN_CRIT "PSU over voltage.\n"); + if(!(status&WDC_SR_PSUUNDR)) + printk(KERN_CRIT "PSU under voltage.\n"); + if(!(status&WDC_SR_FANGOOD)) + printk(KERN_CRIT "Possible fan fault.\n"); + if(!(status&WDC_SR_WCCR)) +#ifdef SOFTWARE_REBOOT +#ifdef ONLY_TESTING + printk(KERN_CRIT "Would Reboot.\n"); +#else + printk(KERN_CRIT "Initiating system reboot.\n"); + machine_restart(NULL); +#endif +#else + printk(KERN_CRIT "Reset in 5ms.\n"); +#endif +*/ +} + + +static struct file_operations lh79520dog_fops= +{ + owner: THIS_MODULE, + write: lh79520dog_write, + ioctl: lh79520dog_ioctl, + open: lh79520dog_open, + release: lh79520dog_release, +}; + +static struct miscdevice lh79520dog_miscdev= +{ + WATCHDOG_MINOR, + "LH79520 watchdog", + &lh79520dog_fops +}; + +static int __init lh79520dog_init(void) +{ + int ret; + + ret = misc_register(&lh79520dog_miscdev); + + if (ret) + { + goto out; + } + +// ret = request_irq(irq, lh79520dog_interrupt, SA_INTERRUPT, "lh79520wdt", NULL); +// if(ret) { +// printk(KERN_ERR "wdt: IRQ %d is not free.\n", irq); +// goto outmisc; +// } + + printk("LH79520 Watchdog Timer: timer margin %d sec\n", lh79520_margin); + + ret=0; + out: + return ret; + + outmisc: + misc_deregister(&lh79520dog_miscdev); + goto out; + +} + +static void __exit lh79520dog_exit(void) +{ + misc_deregister(&lh79520dog_miscdev); +} + +module_init(lh79520dog_init); +module_exit(lh79520dog_exit); diff -urN linux-2.4.26/drivers/char/lh79520_wdt.h linux-2.4.26-vrs1-lnode80/drivers/char/lh79520_wdt.h --- linux-2.4.26/drivers/char/lh79520_wdt.h 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/char/lh79520_wdt.h 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,63 @@ +/********************************************************************** + * $Workfile: LH79520_wdt.h $ + * $Revision: 1.1.1.1 $ + * $Author: brad $ + * $Date: 2003/01/04 17:20:29 $ + * + * Project: LH79520 headers + * + * Description: + * This file contains the structure definitions and manifest + * constants for LH79520 component: + * Watchdog Timer + * + * References: + * (1) ARM Isis Technical Reference Manual, System on Chip Group, + * ARM SC063-TRM-0001-B + * + * COPYRIGHT (C) 2001 SHARP MICROELECTRONICS OF THE AMERICAS, INC. + * CAMAS, WA + *********************************************************************/ + +#ifndef LH79520_WDT_H +#define LH79520_WDT_H + +/* + * Watchdog Timer Module Register Structure + */ +typedef struct { + volatile unsigned int wdctlr; /* Control */ + volatile unsigned int wdcntr; /* Counter Reset */ + volatile unsigned int wdtstr; /* Test */ + volatile unsigned int wdcnt0; /* Counter Bits [7:0] */ + volatile unsigned int wdcnt1; /* Counter Bits [15:8] */ + volatile unsigned int wdcnt2; /* Counter Bits [23:16] */ + volatile unsigned int wdcnt3; /* Counter Bits [31:24] */ +} WDTIMERREGS; + +/********************************************************************** + * Watchdog Timer Register Bit Fields + *********************************************************************/ + +/********************************************************************** + * Watchdog Control Register Bit Fields + *********************************************************************/ +#define WDT_CTRL_DISABLE 0 +#define WDT_CTRL_ENABLE _SBF(0,1) +#define WDT_CTRL_RSP_FIQ _SBF(1,0) +#define WDT_CTRL_RSP_RESET _SBF(1,1) +#define WDT_CTRL_FRZ_ENABLE _BIT(3) +#define WDT_CTRL_TOP _SBF(4,((n)&0xF) + +/********************************************************************** + * Watchdog Counter Reset Register Bit Fields + *********************************************************************/ +#define WDT_WDCNTR (0x1984) + +/********************************************************************** + * Watchdog Register Bit Fields + *********************************************************************/ +#define WDT_WD_NWDFIQ _BIT(7) +#define WDT_WD_NWDRES _BIT(6) + +#endif /* LH79520_WDT_H */ diff -urN linux-2.4.26/drivers/char/Makefile linux-2.4.26-vrs1-lnode80/drivers/char/Makefile --- linux-2.4.26/drivers/char/Makefile 2005-11-02 16:54:20.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/char/Makefile 2005-11-02 17:37:31.000000000 -0400 @@ -16,7 +16,7 @@ O_TARGET := char.o -obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o +obj-y += mem.o tty_io.o n_tty.o tty_ioctl.o raw.o pty.o misc.o random.o cradle.o # All of the (potential) objects that export symbols. # This list comes from 'grep -l EXPORT_SYMBOL *.[hc]'. @@ -349,6 +349,7 @@ obj-$(CONFIG_SCx200_WDT) += scx200_wdt.o obj-$(CONFIG_WAFER_WDT) += wafer5823wdt.o obj-$(CONFIG_SA1100_WATCHDOG) += sa1100_wdt.o +obj-$(CONFIG_LH79520_WATCHDOG) += lh79520_wdt.o obj-$(CONFIG_EPXA_WATCHDOG) += epxa_wdt.o obj-$(CONFIG_OMAHA_WATCHDOG) += omaha_wdt.o obj-$(CONFIG_SOFT_WATCHDOG) += softdog.o @@ -359,6 +360,12 @@ # I2C char devices obj-$(CONFIG_I2C_DS1307) += ds1307.o +# Specific to the LH79520 Sharp dev board. +# Controls both PWM0 and PWM1 +# PWM0 is the backlighting +# PWM1 is the audio +obj-$(CONFIG_LH79520_PWM) += pwm520.o + subdir-$(CONFIG_MWAVE) += mwave ifeq ($(CONFIG_MWAVE),y) obj-y += mwave/mwave.o diff -urN linux-2.4.26/drivers/char/pwm520.c linux-2.4.26-vrs1-lnode80/drivers/char/pwm520.c --- linux-2.4.26/drivers/char/pwm520.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/char/pwm520.c 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,870 @@ +/* + * linux/drivers/char/pwm520.c + * + * Copyright (C) 2002 Lineo. + * + * 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 PWM audio and backlighting. + * Jumps for backlighting and audio must be set correctly on the LH79520 + * Board for this module to work properly. See Sharp LH79520 Documentation + * for jumper settings. + */ +//#define MODULES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include + +#include "pwm520.h" + +pwmRegs_t *pwmregs = (pwmRegs_t *) IO_ADDRESS( PWM_PHYS); +ioconRegs_t *ioconregs = (ioconRegs_t *)IO_ADDRESS( IOCON_PHYS); +rcpcRegs_t *rcpcregs = (rcpcRegs_t *)IO_ADDRESS( RCPC_PHYS); + +#define TYPE(dev) (MINOR(dev) >> 4) /* high nibble */ +#define NUM(dev) (MINOR(dev) & 0xf) /* low nibble */ +#if OLDWAY +#define PCLK 51609600 /* ticks per second of AHB clock, 51MHz */ +static int pwm_xtal_freq = XTAL_IN; // From hardware.h +static int pwm_clkin_freq = 0; // PLL_CLOCK? LH79520_CLKIN_FREQ; +#else +unsigned int hclkfreq_get( void); +#endif + +static int pwm_major = 0; // Major Number for Driver 0 indicates dynamic assignment +static int pwm_prescale = 1; + +// Default Freq and Duty Cycles +static int pwm_audio_freq = 440; // Freq of tone +static int pwm_audio_dcycle = 50; // Duty Cycle for Audio +static int pwm_audio_duration = 100000;// Delay (udelay) for beep + +static int pwm_backlight_dcycle = 100;// DC for Backlight +static int pwm_backlight_mode = 0; // Normal Mode +static int pwm_backlight_freq = BACKLIGHT_INVERTER_PWM_FREQUENCY; // Freq of backlight + +#ifdef MODULES +MODULE_PARM(pwm_major,"i"); +MODULE_PARM(pwm_prescale,"i"); +MODULE_PARM(pwm_xtal_freq,"i"); +MODULE_PARM(pwm_clkin_freq,"i"); +MODULE_PARM(pwm_audio_freq,"i"); +MODULE_PARM(pwm_audio_dcycle,"i"); +MODULE_PARM(pwm_audio_duration,"i"); +MODULE_PARM(pwm_backlight_dcycle,"i"); +MODULE_PARM(pwm_backlight_mode,"i"); +MODULE_PARM(pwm_backlight_freq,"i"); +#endif + + +//void showPWM0Registers(); + +#if OLDWAY +/********************************************************************** +* +* Function: rcpc_get_bus_clock - From Sharp Source +* +* Purpose: +* return the frequency of the bus clock. +* +* Processing: +* this function returns the frequency of the bus clock in Hz +* based on the value of frequencies passed in and the value +* of the RCPC control register CLK_SEL bit. +* +* Parameters: +* xtalin: the frequency at the XTALIN pin; use 0 if there is no +* crystal or external clock driving the pin. +* clkin: the frequency driving the CLKIN pin; use 0 if that pin +* is not driven. +* +* Outputs: None +* +* Returns: +* The bus clock frequency in Hz +* +* Notes: +* The nominal crystal input frequency in 14745600 Hz. +* +**********************************************************************/ +volatile unsigned long rcpc_get_bus_clock(unsigned long xtalin, unsigned long clkin) +{ + unsigned long timebase, divider; + + if ( (rcpcregs->control & RCPC_CTRL_CLKSEL_EXT) + == RCPC_CTRL_CLKSEL_EXT) + { + /* clock source is external clock */ + timebase = clkin; + } + else + { + /* clock source is from PLL output */ + timebase = xtalin * 21; + } + + divider = rcpcregs->HCLKPrescale * 2; + if (divider == 0) + divider = 1; + + return timebase / divider; +} +#endif // OLDWAY + +/********************************************************************** +* +* Function: pwm1_enable - Taken for Sharp Driver Example code +* +* Purpose: +* Enable PWM output on the PWM1 channel of the LH79520 +* +* Processing: +* N/A +* +* Parameters: None +* +* Outputs: None +* +* Returns: Nothing +* +* Notes: +* +**********************************************************************/ +inline volatile void pwm1_enable(void) +{ + pwmregs->pwm1.enable = PWM_EN_ENABLE; +} + +/********************************************************************** +* +* Function: pwm1_disable - Taken for Sharp Driver Example code +* +* Purpose: +* Disable PWM output on the PWM1 channel of the LH79520 +* +* Processing: +* N/A +* +* Parameters: None +* +* Outputs: None +* +* Returns: Nothing +* +* Notes: +* +**********************************************************************/ +inline volatile void pwm1_disable(void) +{ + pwmregs->pwm1.enable = ~PWM_EN_ENABLE; +} + +/********************************************************************** +* +* Function: pwm0_enable - Taken for Sharp Driver Example code +* +* Purpose: +* Enable PWM output on the PWM0 channel of the LH79520 +* +* Processing: +* N/A +* +* Parameters: None +* +* Outputs: None +* +* Returns: Nothing +* +* Notes: +* +**********************************************************************/ +inline volatile void pwm0_enable(void) +{ + pwmregs->pwm0.enable = PWM_EN_ENABLE; +} + +/********************************************************************** +* +* Function: pwm0_disable - Taken for Sharp Driver Example code +* +* Purpose: +* Disable PWM output on the PWM0 channel of the LH79520 +* +* Processing: +* N/A +* +* Parameters: None +* +* Outputs: None +* +* Returns: Nothing +* +* Notes: +* +**********************************************************************/ +inline volatile void pwm0_disable(void) +{ + pwmregs->pwm0.enable = ~PWM_EN_ENABLE; +} + +/********************************************************************** +* +* Function: pwm0_normal - Taken for Sharp Driver Example code146 +* +* Purpose: +* Restores the normal sense of the PWM output signal on the PWM0 +* channel of the LH79520 +* +* Processing: +* N/A +* +* Parameters: None +* +* Outputs: None +* +* Returns: Nothing +* +* Notes: +* +**********************************************************************/ +inline volatile void pwm0_normal(void) +{ + pwmregs->pwm0.invert = ~PWM_INV_INVERT; +} + + +/********************************************************************** +* +* Function: pwm1_frequency - Taken for Sharp Driver Example code +* +* Purpose: +* Sets the PWM1 output frequency to the value specified +* +* Processing: +* Compute the prescale and period count to be programmed from the +* PCLK frequency. If the frequency value is too high or too low to +* be programmed within the permissible ranges of prescale and period, +* signal an error. +* +* Parameters: +* freq - Desired frequency, in Hz +* +* Outputs: None +* +* Returns: +* -1 - if frequency specified is zero +* -1 - if prescale is zero (an impossible condition) +* -1 - if the frequency is out of bounds +* 0 - if the frequency is changed successfully +* +* Notes: +* This function depends on the values of LH79520_XTAL_FREQ and +* LH79520_CLKIN_FREQ to be set correctly in the LH79520_evb.h file. +* If external clock is used, LH79520_CLKIN_FREQ should be set +* to the external clock frequency. Otherwise, this function will +* fail. +* +* +**********************************************************************/ +long pwm1_frequency(unsigned long freq) +{ + unsigned long pclk, pwm1clk, prescale; + unsigned long div; + + if (0 == freq) { + return -1; + } + +#if OLDWAY + pclk = rcpc_get_bus_clock(pwm_xtal_freq,pwm_clkin_freq); +#else + pclk = hclkfreq_get(); +#endif + prescale = rcpcregs->PWM1Prescale; + if (prescale > 0) { + pwm1clk = pclk / (prescale * 2); + } else { + printk("<4>THIS IS BAD. SHOULD NOT GET HERE...\n"); + //this should not happen + return -1; + } + div = pwm1clk / freq; + rcpcregs->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + + while (div > USHRT_MAX && prescale <= SHRT_MAX) { + prescale += 1; + rcpcregs->PWM1Prescale = prescale; + pwm1clk = pclk / (prescale * 2); + div = pwm1clk / freq; + } + rcpcregs->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + pwmregs->pwm1.tc = div; + + return 0; +} + + +/********************************************************************** +* +* Function: pwm1_duty_cycle - Taken for Sharp Driver Example code +* +* Purpose: +* Sets the PWM1 duty cycle to the value specified +* +* Processing: +* Compute the duty cycle count to program into the dc register +* from the percentage specified and the tc count. Accounts for +* integer division truncation errors. +* +* Parameters: +* dcpercent - Desired duty cycle as a percentage of the total period +* +* Outputs: None +* +* Returns: +* the previous value of the duty cycle, as a percentage +* +* Notes: +* +**********************************************************************/ +long pwm1_duty_cycle(short dcpercent) +{ + unsigned short period; + unsigned long duty_cycle, prev_dc, prev_dc_percent; + period = (unsigned short) pwmregs->pwm1.tc; + prev_dc = pwmregs->pwm1.dc; + if (period > 0) { + prev_dc_percent = ((prev_dc * 100) + (period >> 1)) / period; + } else { + prev_dc_percent = 100; + } + duty_cycle = ((dcpercent * period) + 50) / 100; + pwmregs->pwm1.dc = duty_cycle; + return(long)prev_dc_percent; +} + +/********************************************************************** +* +* Function: pwm0_frequency - Taken for Sharp Driver Example code +* +* Purpose: +* Sets the PWM0 output frequency to the value specified +* +* Processing: +* Compute the prescale and period count to be programmed from the +* PCLK frequency. If the frequency value is too high or too low to +* be programmed within the permissible ranges of prescale and period, +* signal an error. +* +* Parameters: +* freq - Desired frequency, in Hz +* +* Outputs: None +* +* Returns: +* -1 - if frequency specified is zero +* -1 - if prescale is zero (an impossible condition) +* -1 - if the frequency is out of bounds +* 0 - if the frequency is changed successfully +* +* Notes: +* This function depends on the values of LH79520_XTAL_FREQ and +* LH79520_CLKIN_FREQ to be set correctly in the LH79520_evb.h file. +* If external clock is used, LH79520_CLKIN_FREQ should be set +* to the external clock frequency. Otherwise, this function will +* fail. +* +* +**********************************************************************/ +long pwm0_frequency(unsigned long freq) +{ + unsigned long pclk, pwm0clk, prescale; + unsigned long div; + + if (0 == freq) { + return -1; + } + +#if OLDWAY + pclk = rcpc_get_bus_clock(pwm_xtal_freq,pwm_clkin_freq); +#else + pclk = hclkfreq_get(); +#endif + prescale = rcpcregs->PWM0Prescale; + if (prescale > 0) { + pwm0clk = pclk / (prescale * 2); + } else { + printk("<4>THIS IS BAD. SHOULD NOT GET HERE...\n"); + //this should not happen + return -1; + } + div = pwm0clk / freq; + rcpcregs->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + + //FJB hack for orderite + rcpcregs->PWM0Prescale = 0x0a; +#if 0 + while (div > USHRT_MAX && prescale <= SHRT_MAX) { + prescale += 1; + rcpcregs->PWM0Prescale = prescale; + pwm0clk = pclk / (prescale * 2); + div = pwm0clk / freq; + } +#endif + rcpcregs->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + //pwmregs->pwm0.tc = div; + pwmregs->pwm0.tc = 0x285; + + return 0; +} + + +/********************************************************************** +* +* Function: pwm0_duty_cycle - Taken for Sharp Driver Example code +* +* Purpose: +* Sets the PWM0 duty cycle to the value specified +* +* Processing: +* Compute the duty cycle count to program into the dc register +* from the percentage specified and the tc count. Accounts for +* integer division truncation errors. +* +* Parameters: +* dcpercent - Desired duty cycle as a percentage of the total period +* +* Outputs: None +* +* Returns: +* the previous value of the duty cycle, as a percentage +* +* Notes: +* +**********************************************************************/ +long pwm0_duty_cycle(short dcpercent) +{ + unsigned short period; + unsigned long duty_cycle, prev_dc, prev_dc_percent; + period = (unsigned short) pwmregs->pwm0.tc; + prev_dc = pwmregs->pwm0.dc; + if (period > 0) { + prev_dc_percent = ((prev_dc * 100) + (period >> 1)) / period; + } else { + prev_dc_percent = 100; + } + duty_cycle = ((dcpercent * period) + 50) / 100; + pwmregs->pwm0.dc = duty_cycle; + return(long)prev_dc_percent; +} + +/********************************************************************** +* +* Function: backlight_decrease_brightness +* +* Purpose: +* Decrease the LCD backlight brightness +* +* Processing: +* Decrement static variable holding current brightness level and +* set the PWM duty cycle. +* +* Parameters: None +* +* Outputs: None +* +* Returns: Nothing +* +* Notes: +* +**********************************************************************/ +void backlight_increase_brightness(void) +{ + pwm_backlight_dcycle--; + if (pwm_backlight_dcycle < 0) + { + pwm_backlight_dcycle = 0; + } + pwm0_duty_cycle(pwm_backlight_dcycle); +} + +/********************************************************************** +* +* Function: backlight_increase_brightness +* +* Purpose: +* Increase the LCD backlight brightness +* +* Processing: +* Increment static variable holding current brightness level and +* set the PWM duty cycle. +* +* Parameters: None +* +* Outputs: None +* +* Returns: Nothing +* +* Notes: +* +**********************************************************************/ +void backlight_decrease_brightness(void) +{ + pwm_backlight_dcycle++; + if (pwm_backlight_dcycle > 100) + { + pwm_backlight_dcycle = 100; + } + pwm0_duty_cycle(pwm_backlight_dcycle); +} + +/********************************************************************** +* +* Function: backlight_set_brightness +* +* Purpose: +* Set the LCD backlight brightness to the level specified +* +* Processing: +* N/A +* +* Parameters: +* bright - desired brightness level as a percentage of maximum +* brightness +* +* Outputs: None +* +* Returns: Nothing +* +* Notes: +* +**********************************************************************/ +void backlight_set_brightness(int bright) +{ + //bright = 0 means least brightness + //bright = 100 means max brightness + if (bright > 100) + { + bright = 100; + } + if (bright < 0) + { + bright = 0; + } + + pwm_backlight_dcycle = 100 - bright; + pwm0_duty_cycle(pwm_backlight_dcycle); +} + + +/**************************************************************************** + * Open Function - Open the device either the Backlight or the Audio + * /dev/pwm0 c 254 1 is the Backlighting + * /dev/pwm1 c 254 0 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 pwm_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: // Audio + rcpcregs->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + rcpcregs->periphClkCtrl &= ~RCPC_CLKCTRL_PWM0_DISABLE; + rcpcregs->PWM0Prescale = ((~_BIT(15)) & pwm_prescale); + rcpcregs->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + ioconregs->MiscMux |= MISCMUX_PWM0; + break; +#if 0 + case 1: // Backlight + rcpcregs->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + rcpcregs->periphClkCtrl &= ~RCPC_CLKCTRL_PWM1_DISABLE; + rcpcregs->PWM0Prescale = ((~_BIT(15)) & pwm_prescale); + rcpcregs->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + ioconregs->MiscMux |= MISCMUX_PWM1; + + if (pwm_backlight_mode) { + pwmregs->pwm0.sync = PWM_SYNC_SYNC; + ioconregs->MiscMux |= MISCMUX_PWM0SYNC; + } + else + { + pwmregs->pwm0.sync = PWM_SYNC_NORMAL; + } + + pwm0_frequency(pwm_backlight_freq); + pwm0_duty_cycle(pwm_backlight_dcycle); + pwm0_normal(); + pwm0_enable(); + break; +#endif + default: + printk("<4>Minor device unknown %d\n",NUM(inode->i_rdev)); + break; + } + + return 0; +} + +/**************************************************************************** + * + */ +int pwm_release(struct inode *inode, struct file * filp) +{ +// printk("<4>release pwm...\n"); + switch (NUM(inode->i_rdev)) { + case 0: // Audio + rcpcregs->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + rcpcregs->periphClkCtrl |= RCPC_CLKCTRL_PWM0_DISABLE; + rcpcregs->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + ioconregs->MiscMux &= ~MISCMUX_PWM0; + pwm0_disable(); + break; + case 1: // Should be backlight of touchscreen + //rcpcregs->control |= RCPC_CTRL_WRTLOCK_ENABLED; + //barrier(); + //rcpcregs->periphClkCtrl |= RCPC_CLKCTRL_PWM0_DISABLE; + //rcpcregs->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + //ioconregs->MiscMux &= ~MISCMUX_PWM0; + //pwmregs->pwm0.enable = ~PWM_EN_ENABLE; + break; + + default: + printk("<4>Minor device unknown %d\n",NUM(inode->i_rdev)); + break; + } + + MOD_DEC_USE_COUNT; + return 0; +} + +/**************************************************************************** + * + */ +ssize_t pwm_read(struct file * file, char * buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +/**************************************************************************** + * + */ +ssize_t pwm_write(struct file * file, const char * buf, + size_t count, loff_t *ppos) +{ + return 0; +} + +/**************************************************************************** + * + */ +int pwm_ioctl(struct inode *inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + //int err = 0, size = _IOC_SIZE(cmd); + + if (_IOC_TYPE(cmd) != PWM520_IOC_MAGIC) { + return -EINVAL; + } + if (_IOC_NR(cmd) > PWM520_IOC_MAXNR) { + return -EINVAL; + } + + /* + Should check for direction bits see page 101 in "Linux Device Drivers Book" + size and err used here. + */ + + switch (NUM(inode->i_rdev)) { + case 0: // Audio + switch (cmd) { + case PWM520_IOCBEEP: + pwm0_frequency(pwm_audio_freq); + pwm0_duty_cycle(pwm_audio_dcycle); + pwm0_enable(); + udelay(pwm_audio_duration); + pwm0_disable(); + break; + + case PWM520_IOCSTARTSND: + pwm0_frequency(pwm_audio_freq); + pwm0_duty_cycle(pwm_audio_dcycle); + pwm0_enable(); + break; + + case PWM520_IOCSTOPSND: + pwm0_disable(); + break; + + case PWM520_IOCSETFREQ: // Set Frequency + pwm_audio_freq = arg; + break; + + case PWM520_IOCSETDCYCLE: // Set Duty Cycle + pwm_audio_dcycle = arg; + break; + + case PWM520_IOCGETFREQ: // Get Frequency + __put_user(pwm_audio_freq, (int *) arg); + break; + + case PWM520_IOCGETDCYCLE: // Get Duty Cycle + __put_user(pwm_audio_dcycle, (int *) arg); + break; + } + break; +#if 0 + case 1: // Should be backlight of touchscreen + switch (cmd) { + case PWM520_IOCRESET: +// printk("Reset pwm0\n"); + pwm_backlight_dcycle = 100;// DC for Backlight + pwm_backlight_mode = 0; // Normal Mode + pwm_backlight_freq = BACKLIGHT_INVERTER_PWM_FREQUENCY; // Freq of backlight + break; + case PWM520_IOCSTOPPWM0: // Stop PWM0 + rcpcregs->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + rcpcregs->periphClkCtrl |= RCPC_CLKCTRL_PWM0_DISABLE; + rcpcregs->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + ioconregs->MiscMux &= ~MISCMUX_PWM0; + pwmregs->pwm0.enable = ~PWM_EN_ENABLE; + break; + case PWM520_IOCINCREASEBL: +// printk("Brighter\n"); + backlight_increase_brightness(); + break; + + case PWM520_IOCDECREASEBL: +// printk("Lighter\n"); + backlight_decrease_brightness(); + break; + + case PWM520_IOCSETBL: +// printk("Set to %ld\n",arg); + backlight_set_brightness(arg); + break; + } + break; +#endif + + } + + return 0; +} + + +/**************************************************************************** + * + */ +struct file_operations pwm_fops = { + owner: THIS_MODULE, + llseek: no_llseek, + read: pwm_read, + write: pwm_write, + ioctl: pwm_ioctl, + open: pwm_open, + release: pwm_release, +}; + +#if 0 +void test_pwm1() +{ + printk("TEST CASE PLEASE REMOVE ONCE DONE\n"); + + rcpcregs->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + rcpcregs->periphClkCtrl &= ~RCPC_CLKCTRL_PWM1_DISABLE; + rcpcregs->PWM1Prescale = ((~_BIT(15)) & pwm_prescale); + rcpcregs->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + ioconregs->MiscMux |= MISCMUX_PWM1; + + pwm1_frequency(pwm_audio_freq); + pwm1_duty_cycle(pwm_audio_dcycle); + pwm1_enable(); +} + +void showPWM1Registers() +{ + printk("PWM1 Registers\n"); + printk("=============\n\n"); + printk("pwm1.tc = %x\n",pwmregs->pwm1.tc); + printk("pwm1.dc = %x\n",pwmregs->pwm1.dc); + printk("pwm1.enable = %x\n",pwmregs->pwm1.enable); + printk("pwm1.invert = %x\n",pwmregs->pwm1.invert); + printk("pwm1.sync = %x\n",pwmregs->pwm1.sync); +} + +void showPWM0Registers() +{ + printk("PWM0 Registers\n"); + printk("=============\n\n"); + printk("pwm0.tc = %d\n",pwmregs->pwm0.tc); + printk("pwm0.dc = %d\n",pwmregs->pwm0.dc); + printk("pwm0.enable = 0x%x\n",pwmregs->pwm0.enable); + printk("pwm0.invert = 0x%x\n",pwmregs->pwm0.invert); + printk("pwm0.sync = 0x%x\n",pwmregs->pwm0.sync); +} + +#endif + +/**************************************************************************** + * + */ +static int __init pwm_init_module(void) +{ + int result; + + //printk("<1>Start PWM Module\n"); + printk("<1>Sharp LH79520 PWM Driver Copyright 2002 Lineo\n"); + + result = register_chrdev(pwm_major,"pwm",&pwm_fops); + if (result < 0) { + printk("<4>pwm: can't get major number %d\n",pwm_major); + return result; + } + if (pwm_major == 0) { + pwm_major = result; /* Dynamic Allocation of major number */ + printk("<4>PWM Dynamic Major Number %d\n",pwm_major); + } + + return 0; +} + +/**************************************************************************** + * + */ +static void __exit pwm_cleanup_module(void) +{ + int result; + + printk("<1>End PWM Module...\n"); + result = unregister_chrdev(pwm_major,"pwm"); +} + +module_init(pwm_init_module); +module_exit(pwm_cleanup_module); diff -urN linux-2.4.26/drivers/char/pwm520.h linux-2.4.26-vrs1-lnode80/drivers/char/pwm520.h --- linux-2.4.26/drivers/char/pwm520.h 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/char/pwm520.h 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,58 @@ +/* + * linux/drivers/char/pwm520.h + * + * Copyright (C) 2002 Lineo. + * + * 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 PWM audio and backlighting. + * Jumps for backlighting and audio must be set correctly on the LH79520 + * Board for this module to work properly. See Sharp LH79520 Documentation + * for jumper settings. + */ +#ifndef __PWM520_H +#define __PWM520_H + +typedef struct { + volatile unsigned int tc; + volatile unsigned int dc; + volatile unsigned int enable; + volatile unsigned int invert; + volatile unsigned int sync; + volatile unsigned int res[3]; +} pwmXRegs_t; + +typedef struct { + volatile pwmXRegs_t pwm0; + volatile pwmXRegs_t pwm1; +} pwmRegs_t; + +extern pwmRegs_t *pwmregs; + +#define PWM_EN_ENABLE _BIT(0) +#define PWM_INV_INVERT _BIT(0) +#define PWM_SYNC_SYNC _SBF(0,1) +#define PWM_SYNC_NORMAL _SBF(0,0) + +#define BACKLIGHT_INVERTER_PWM_FREQUENCY (200) // 200Hz + +// IOCTL's +#define PWM520_IOC_MAGIC 'p' +#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 linux-2.4.26/drivers/misc/ads784x.c linux-2.4.26-vrs1-lnode80/drivers/misc/ads784x.c --- linux-2.4.26/drivers/misc/ads784x.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/misc/ads784x.c 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,1064 @@ +/* vi: set sw=4 ts=4 ai: */ + +// #define MODULE + +#define TS_DATA_QTOPIA +#undef CONFIG_ADS7846 + +/********************************************************************** +* 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 + +#undef DEBUG +#undef VERBOSE +#define DRVNAME "ads_784x" +#include + +#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,0x1) /* Read X value */ +#define CTRL_Y _SBF(4,0x5) /* Read Y value */ +#ifdef CONFIG_ADS7846 +#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 */ +#endif // CONFIG_ADS7846 + +// #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_X | CTRL_12BIT | CTRL_DFR | 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) +#ifdef CONFIG_ADS7846 +#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) +#endif // CONFIG_ADS7846 + +/********************************************************************** +* 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_LH79X +#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 + +/* +QTopia data format: +unsigned char data2[5]; +data.status=data2[0]; // bit 0x40 is "touch"/left mouse +data.xpos=(data2[1] << 8) | data2[2]; +data.ypos=(data2[3] << 8) | data2[4]; +*/ + +#ifdef TS_DATA_QTOPIA +#define TS_DATA_STRUCT +struct tsData_t { + unsigned char pressure; + unsigned char xhigh; + unsigned char xlow; + unsigned char yhigh; + unsigned char ylow; +} __attribute__ ((packed)); +#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 10 +#define Y_DELTA_MAX 10 + +/* Define the readings we are to take per second (default to 50) */ +#define SAMPLES_PER_SECOND 10 + +/* +* 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); + void (*chipselect_enable)(void); + void (*chipselect_disable)(void); + void (*chipselect_manual)(void); + + 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) + +/********************************************************************** +* 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; + long xcoff, ycoff; + + vdprintk("ENTER: ads_784x_tsData_add()\n"); + next_head = (adsContext->tsDataHead + 1) & (MAX_TS_DATA - 1); + if (next_head != adsContext->tsDataTail) { +#ifndef TS_DATA_QTOPIA + 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 +#else // TS_DATA_QTOPIA + adsContext->tsData[adsContext->tsDataHead].pressure = pressure ? 0x40 : 0; + adsContext->tsData[adsContext->tsDataHead].xlow = x & 0xFF; + adsContext->tsData[adsContext->tsDataHead].xhigh = x >> 8; + adsContext->tsData[adsContext->tsDataHead].ylow = y & 0xFF; + adsContext->tsData[adsContext->tsDataHead].yhigh = y >> 8; +#endif // TS_DATA_QTOPIA + 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 x_last, y_last; +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"); + +#define TS_AVG_ITERS 8 + + /* + * 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 + */ + //FJB + adsContext->chipselect_enable(); +#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); + x_1 = adsContext->read(sspContext); + adsContext->write(sspContext, ADS_784x_READ_Y); + 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); + x_2 = adsContext->read(sspContext); + adsContext->write(sspContext, ADS_784x_READ_Y); + y_2 = adsContext->read(sspContext); + + //FJB + adsContext->chipselect_disable(); + + /* 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)) + || (x_1 == 0) || (y_1 == 0) || (x_2 == 0) || (y_2 == 0)); + + +#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; + + // normalize values + // very subject to experimentation + +#if 0 + if((x == 0) || (y == 0)) + { + x = x_last; + y = y_last; + } + else + { + x_last = x; + y_last = y; + } +#endif + + y = (1 << 12) - y; + vdprintk("LEAVE: ads_784x_Read_tsData(x=0x%03x, y=0x%03x)\n", x, y); + ads_784x_tsData_add(adsContext, 0x40, x, y); // generate pen up/pen down sequence + ads_784x_tsData_add(adsContext, 0x00, 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); + vdprintk("TSThrPD: %d\t", pen_down); + /* 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 0 + 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; + } +#endif + 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; +#if 0 + else + printk("ads_784x_read: P: %02X X: %4d Y: %4d\n", + tsData->pressure & 0x40, (tsData->xhigh << 8) + tsData->xlow, (tsData->yhigh << 8) + tsData->ylow); +#endif + + 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; + void *ads784x_sspContext = adsContext->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(ads784x_sspContext, SSP_DEV_TOUCHSCREEN); + + //FJB + adsContext->chipselect_enable(); + + adsContext->write(ads784x_sspContext, ADS_784x_READ_BATTERY); + sample = adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(ads784x_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(ads784x_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(ads784x_sspContext, SSP_DEV_TOUCHSCREEN); + } + sample /= count; + milliVolts = (sample * 1000 * 10) / 4096; + volts = milliVolts / 1000; + hundredthsVolts = (milliVolts - (volts * 1000)) / 10; + size = sprintf(buf, "battery: %i %i.%02iV\n", sample, volts, hundredthsVolts); + + /* Do a dummy read to turn off the internal reference voltage */ + /* MUST lock the SSP before accessing it */ + adsContext->lock(ads784x_sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_X); + sample = adsContext->read(ads784x_sspContext); + + //FJB + adsContext->chipselect_disable(); + + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(ads784x_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(ads784x_sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->enable_pen_down_irq(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(ads784x_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; + void *ads784x_sspContext = adsContext->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(ads784x_sspContext, SSP_DEV_TOUCHSCREEN); + + //FJB + adsContext->chipselect_enable(); + + adsContext->write(ads784x_sspContext, ADS_784x_READ_TEMP0); + sample1 = adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(ads784x_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(ads784x_sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_TEMP0); + sample1 += adsContext->read(ads784x_sspContext); + adsContext->write(ads784x_sspContext, ADS_784x_READ_TEMP1); + sample91 += adsContext->read(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(ads784x_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(ads784x_sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->write(ads784x_sspContext, ADS_784x_READ_X); + sample1 = adsContext->read(ads784x_sspContext); + + //FJB + adsContext->chipselect_disable(); + + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(ads784x_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(ads784x_sspContext, SSP_DEV_TOUCHSCREEN); + adsContext->enable_pen_down_irq(ads784x_sspContext); + /* MUST unlock the SSP after it has been locked */ + adsContext->unlock(ads784x_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; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "chipselect_enable"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->chipselect_enable = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "chipselect_disable"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->chipselect_disable = vp; + + vp = ssp_request_pointer(SSP_DEV_TOUCHSCREEN, "chipselect_manual"); + if ( ! vp ) + sts = ASSOCIATION_ERROR; + adsContext->chipselect_manual = 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->chipselect_manual(); + 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 linux-2.4.26/drivers/misc/Config.in linux-2.4.26-vrs1-lnode80/drivers/misc/Config.in --- linux-2.4.26/drivers/misc/Config.in 2005-11-02 16:54:22.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/misc/Config.in 2005-11-02 17:37:31.000000000 -0400 @@ -15,3 +15,14 @@ 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" ]; then + tristate 'LH79590 touchscreen support' CONFIG_TOUCHSCREEN_LH79520 + tristate 'LH79590 serial eeprom support' CONFIG_EEPROM_LH79520 + tristate 'LH79590 7-segment support' CONFIG_7SEGMENT_LH79520 +fi + +endmenu diff -urN linux-2.4.26/drivers/misc/eeprom-lh7x.c linux-2.4.26-vrs1-lnode80/drivers/misc/eeprom-lh7x.c --- linux-2.4.26/drivers/misc/eeprom-lh7x.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/misc/eeprom-lh7x.c 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,709 @@ +/* vi: set sw=4 ts=4 ai: */ + +// #define MODULE + +#define READ_AFTER_WRITE + +/********************************************************************** +* linux/drivers/misc/eeprom-lh79x.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-lh79x" +#include + +#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); + void (*ssp_chipselect_automatic)(void); + void (*ssp_chipselect_manual)(void); + void (*ssp_chipselect_enable)(void); + void (*ssp_chipselect_disable)(void); + 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_lh79x_erase_write_enable +* Function: eeprom_lh79x_erase_write_disable +**********************************************************************/ +static void +eeprom_lh79x_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); + + /* EEPROM Writes must be done using manual control of the ChipSelect */ + eepromContext->ssp_chipselect_manual(); + eepromContext->ssp_chipselect_enable(); + + 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); + + /* Reset back to automatic control of the EEPROM ChipSelect */ + eepromContext->ssp_chipselect_disable(); + eepromContext->ssp_chipselect_automatic(); + + /* Unlock the SSP after it has been locked */ + eepromContext->unlock(sspContext, SSP_DEV_EEPROM); + + return; +} + +static void +eeprom_lh79x_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); + + /* EEPROM Writes must be done using manual control of the ChipSelect */ + eepromContext->ssp_chipselect_manual(); + eepromContext->ssp_chipselect_enable(); + + 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); + + /* Reset back to automatic control of the EEPROM ChipSelect */ + eepromContext->ssp_chipselect_disable(); + eepromContext->ssp_chipselect_automatic(); + + /* Unlock the SSP after it has been locked */ + eepromContext->unlock(sspContext, SSP_DEV_EEPROM); + + return; +} + +/********************************************************************** +* Function: eeprom_lh79x_read_device_word +**********************************************************************/ +static void +eeprom_lh79x_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); + + /* EEPROM Reads must be done using manual control of the ChipSelect */ + eepromContext->ssp_chipselect_manual(); + eepromContext->ssp_chipselect_enable(); + + /* 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 */ + + /* Reset back to automatic control of the EEPROM ChipSelect */ + eepromContext->ssp_chipselect_disable(); + eepromContext->ssp_chipselect_automatic(); + + /* 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_lh79x_write_device_word +**********************************************************************/ +static void +eeprom_lh79x_write_device_word(eepromContext_t *eepromContext, int offset_w) +{ + void *sspContext = eepromContext->sspContext; + uint16_t word; + long timeoutJiffies; + + /* 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); + + /* EEPROM Writes must be done using manual control of the ChipSelect */ + eepromContext->ssp_chipselect_manual(); + eepromContext->ssp_chipselect_enable(); + + /* Write modified cache data to the eeprom */ + eepromContext->write(sspContext, EEPROM_WRITE(offset_w)); + eepromContext->write(sspContext, word); + + /* Reset back to automatic control of the EEPROM ChipSelect */ + eepromContext->ssp_chipselect_disable(); + eepromContext->ssp_chipselect_automatic(); + + 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 */ + + return; +} + +/********************************************************************** +* Function: eeprom_lh79x_read_device +**********************************************************************/ +static void +eeprom_lh79x_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_lh79x_read_device_word(eepromContext, offset_w); + } + scwp++; + } + + return; +} + +/********************************************************************** +* Function: eeprom_lh79x_write_device +**********************************************************************/ +static void +eeprom_lh79x_write_device(eepromContext_t *eepromContext) +{ + uint16_t *scwp; + int offset_w; + int timeoutJiffies; + + /* Enable erase/write of the eeprom */ + eeprom_lh79x_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_lh79x_write_device_word(eepromContext, offset_w); + } + scwp++; + } + + /* Disable erase/write of the eeprom */ + eeprom_lh79x_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_lh79x_read_device(eepromContext); +#endif /* READ_AFTER_WRITE */ + + return; +} + +/********************************************************************** +* ***************************************************** +* *** User space "file operation" driver interfaces *** +* ***************************************************** +* Function: lh79x_eeprom_llseek +* Function: lh79x_eeprom_read +* Function: lh79x_eeprom_write +* Function: lh79x_eeprom_poll ( NOT USED --- YET ) +* Function: lh79x_eeprom_ioctl ( NOT USED --- YET ) +* Function: lh79x_eeprom_open +* Function: lh79x_eeprom_flush ( NOT USED --- YET ) +* Function: lh79x_eeprom_release ( NOT USED --- YET ) +* Function: lh79x_eeprom_fsync ( NOT USED --- YET ) +* Function: lh79x_eeprom_fasync ( NOT USED --- YET ) +* Function: lh79x_eeprom_lock ( NOT USED --- YET ) +**********************************************************************/ + +static loff_t +lh79x_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 +lh79x_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: lh79x_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_lh79x_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: lh79x_eeprom_read(%d)\n", sts); + + return(sts); +} + +static ssize_t +lh79x_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: lh79x_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_lh79x_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_lh79x_write_device(eepromContext); + *offsetp += count; + sts = count; + } else { + sts = -EFAULT; + } + } + vdprintk("LEAVE: lh79x_eeprom_write(%d)\n", sts); + + return(sts); +} + +#if (0) /* NOT USED --- YET */ +static unsigned int +lh79x_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 +lh79x_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 +lh79x_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 +lh79x_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 +lh79x_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 +lh79x_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 +lh79x_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 +lh79x_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 lh79x_eeprom_fops = { + owner: THIS_MODULE, + llseek: lh79x_eeprom_llseek, + read: lh79x_eeprom_read, + write: lh79x_eeprom_write, +// poll: lh79x_eeprom_poll, +// ioctl: lh79x_eeprom_ioctl, + open: lh79x_eeprom_open, +// flush: lh79x_eeprom_flush, +// release: lh79x_eeprom_release, +// fsync: lh79x_eeprom_fsync, +// fasync: lh79x_eeprom_fasync, +// lock: lh79x_eeprom_lock, +}; + +static struct miscdevice lh79x_eeprom_dev = { +minor: 22, +name: "eeprom", +fops: &lh79x_eeprom_fops, +}; + +/********************************************************************** +* Function: lh79x_eeprom_make_ssp_association +* +* Purpose: +* Make the association between the eeprom driver and the ssp driver +**********************************************************************/ +static int lh79x_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: lh79x_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; + + 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; + + 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: lh79x_eeprom_make_ssp_association(%d)\n", sts); + + return(sts); +} + +/********************************************************************** +* Function: lh79x_eeprom_init +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +static int lh79x_eeprom_init(void) +{ + eepromContext_t *eepromContext = &eepromContext_l; + int sts = 0; + dprintk("ENTER: lh79x_eeprom_init()\n"); + init_waitqueue_head(&eepromContext->read_and_write_wait); + /* Retrieve the service information from the SSP driver */ + sts = lh79x_eeprom_make_ssp_association(eepromContext); + if (sts == 0) { + /* Ensure the eeprom cache is valid */ + eeprom_lh79x_read_device(eepromContext); + sts = misc_register(&lh79x_eeprom_dev); + } + dprintk("LEAVE: lh79x_eeprom_init(%d)\n", sts); + return(sts); +} + +/********************************************************************** +* Function: lh79x_eeprom_exit +* +* Purpose: +* Un-Register & Cleanup the module +**********************************************************************/ +static void lh79x_eeprom_exit(void) +{ + dprintk("ENTER: lh79x_eeprom_exit()\n"); + misc_deregister(&lh79x_eeprom_dev); + dprintk("LEAVE: lh79x_eeprom_exit()\n"); + return; +} + +module_init(lh79x_eeprom_init); +module_exit(lh79x_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 linux-2.4.26/drivers/misc/lh7x-7seg.c linux-2.4.26-vrs1-lnode80/drivers/misc/lh7x-7seg.c --- linux-2.4.26/drivers/misc/lh7x-7seg.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/misc/lh7x-7seg.c 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,649 @@ +/* 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 + +#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: lh79x_7seg_read_raw_display +* Function: lh79x_7seg_read_raw_display_lsb +* Function: lh79x_7seg_read_raw_display_msb +**********************************************************************/ +uint16_t lh79x_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("lh79x_7seg_read_raw_display(0x%04X)\n", raw_val); + + return(raw_val); +} + +u_char lh79x_7seg_read_raw_display_lsb(void) +{ + uint16_t raw_val; + u_char raw_lsb; + + raw_val = lh79x_7seg_read_raw_display(); + raw_lsb = (u_char)(raw_val & 0xFF); + + return(raw_lsb); +} + +u_char lh79x_7seg_read_raw_display_msb(void) +{ + uint16_t raw_val; + u_char raw_msb; + + raw_val = lh79x_7seg_read_raw_display(); + raw_msb = (u_char)((raw_val >> 8) & 0xFF); + + return(raw_msb); +} + +/********************************************************************** +* Function: lh79x_7seg_read_display +* Function: lh79x_7seg_read_display_lsb +* Function: lh79x_7seg_read_display_msb +**********************************************************************/ +uint16_t lh79x_7seg_read_display(void) +{ + uint16_t raw_val, val; + u_char raw_lsb, lsb; + u_char raw_msb, msb; + + raw_val = lh79x_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 lh79x_7seg_read_display_lsb(void) +{ + u_char raw_lsb, lsb; + + raw_lsb = lh79x_7seg_read_raw_display_lsb(); + lsb = raw_val_to_val(raw_lsb); + + return(lsb); +} + +u_char lh79x_7seg_read_display_msb(void) +{ + u_char raw_msb, msb; + + raw_msb = lh79x_7seg_read_raw_display_msb(); + msb = raw_val_to_val(raw_msb); + + return(msb); +} + +/********************************************************************** +* Function: lh79x_7seg_write_raw_display +* Function: lh79x_7seg_write_raw_display_lsb +* Function: lh79x_7seg_write_raw_display_msb +**********************************************************************/ +void lh79x_7seg_write_raw_display(uint16_t raw_val) +{ + sevenSegmentContext_t *sevenSegmentContext = &sevenSegmentContext_l; + + vdprintk("lh79x_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 lh79x_7seg_write_raw_display_lsb(u_char raw_lsb) +{ + uint16_t raw_val; + + raw_val = lh79x_7seg_read_raw_display(); + raw_val &= 0xFF00; + raw_val &= ((uint16_t)raw_lsb) & 0x00FF; + lh79x_7seg_write_raw_display(raw_val); + + return; +} + +void lh79x_7seg_write_raw_display_msb(u_char raw_msb) +{ + uint16_t raw_val; + + raw_val = lh79x_7seg_read_raw_display(); + raw_val &= 0x00FF; + raw_val &= (((uint16_t)raw_msb) << 8) & 0xFF00; + lh79x_7seg_write_raw_display(raw_val); + + return; +} + +/********************************************************************** +* Function: lh79x_7seg_write_display +* Function: lh79x_7seg_write_display_lsb +* Function: lh79x_7seg_write_display_msb +* Function: lh79x_7seg_write_display_str +**********************************************************************/ +void lh79x_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); + lh79x_7seg_write_raw_display(raw_val); + + return; +} + +void lh79x_7seg_write_display_lsb(u_char lsb) +{ + u_char raw_lsb; + + raw_lsb = val_to_raw_val(lsb); + lh79x_7seg_write_raw_display_lsb(raw_lsb); + + return; +} + +void lh79x_7seg_write_display_msb(u_char msb) +{ + u_char raw_msb; + + raw_msb = val_to_raw_val(msb); + lh79x_7seg_write_raw_display_msb(raw_msb); + + return; +} + +void lh79x_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 = lh79x_7seg_read_display(); + val <<= 8; + val &= 0xFF00; + c16 = c & 0x00FF; + val |= c16; + lh79x_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 = lh79x_7seg_read_display_lsb(); + break; + case ACCESSMODE_MSB: + c = lh79x_7seg_read_display_msb(); + break; + case ACCESSMODE_SHIFT: + default: + c16 = lh79x_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 = lh79x_7seg_read_raw_display(); + } else { + val = lh79x_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) { + lh79x_7seg_write_raw_display(val); + } else { + lh79x_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: lh79x_7seg_init +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +static int lh79x_7seg_init(void) +{ + sevenSegmentContext_t *sevenSegmentContext = &sevenSegmentContext_l; + int sts = 0; + dprintk("ENTER: lh79x_7seg_init()\n"); + init_waitqueue_head(&sevenSegmentContext->read_and_write_wait); + sts = misc_register(&sevenSegment_dev); + lh79x_7seg_write_display_str((u_char *)"HI"); + dprintk("LEAVE: lh79x_7seg_init(%d)\n", sts); + return(sts); +} + +/********************************************************************** +* Function: lh79x_7seg_exit +* +* Purpose: +* Un-Register & Cleanup the module +**********************************************************************/ +static void lh79x_7seg_exit(void) +{ + dprintk("ENTER: lh79x_7seg_exit()\n"); + misc_deregister(&sevenSegment_dev); + lh79x_7seg_write_display_str((u_char *)"BY"); + dprintk("LEAVE: lh79x_7seg_exit()\n"); + return; +} + +module_init(lh79x_7seg_init); +module_exit(lh79x_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 linux-2.4.26/drivers/misc/Makefile linux-2.4.26-vrs1-lnode80/drivers/misc/Makefile --- linux-2.4.26/drivers/misc/Makefile 2005-11-02 16:54:22.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/misc/Makefile 2005-11-02 17:37:31.000000000 -0400 @@ -18,6 +18,9 @@ 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_TOUCHSCREEN_LH79520) += ads784x.o marm-lh7x.o +obj-$(CONFIG_EEPROM_LH79520) += eeprom-lh7x.o +obj-$(CONFIG_7SEGMENT_LH79520) += lh7x-7seg.o include $(TOPDIR)/Rules.make diff -urN linux-2.4.26/drivers/misc/marm-lh7x.c linux-2.4.26-vrs1-lnode80/drivers/misc/marm-lh7x.c --- linux-2.4.26/drivers/misc/marm-lh7x.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/misc/marm-lh7x.c 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,521 @@ +/* vi: set sw=4 ts=4 ai: */ + +// #define MODULE + +/********************************************************************** +* 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. +* +**********************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef DEBUG +#undef VERBOSE +#define DRVNAME "marm_lh7x" +#include + +#include +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +#endif /* MODULE */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "ssp.h" + +// global set by pl110fb driver +unsigned short marm_backlight; + +#undef BACKLIGHT +#define BACKLIGHT marm_backlight + +#define MARM_TS_INT 3 +#define MARM_TS_IOBIT 6 + +static volatile u16 *gpioa = (volatile u16 *) GPOUT16_BASE; +static gpioARegs_t *gpioadr = (gpioARegs_t *) GPIO0_BASE; +static ioconRegs_t *iocon = (ioconRegs_t *)IOCON_PHYS; +static vicRegs_t *vic = (vicRegs_t *)VIC_BASE; +static rcpcRegs_t *rcpc = (rcpcRegs_t *) RCPC_PHYS; + +/********************************************************************** +* Function: ssp_busy_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) +{ + vdprintk("ENTER: ssp_busy_wait()\n"); +}; + +/********************************************************************** +* 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) +{ + vdprintk("ENTER: ssp_flush_tx_fifo()\n"); +}; + +static void ssp_flush_rx_fifo(sspContext_t *sspContext) +{ + vdprintk("ENTER: ssp_flush_rx_fifo()\n"); +}; + +/********************************************************************** +* 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) +{ + vdprintk("ENTER: ssp_chipselect_enable()\n"); +}; + +static void ssp_chipselect_disable(void) +{ + vdprintk("ENTER: ssp_chipselect_disable()\n"); +}; + +static void ssp_chipselect_manual(void) +{ + vdprintk("ENTER: ssp_chipselect_manual()\n"); + + gpioadr->ddr &= ~(1 << MARM_TS_IOBIT); // make sure PA is input + iocon->MiscMux &= ~(MISCMUX_RCEII0); // make it PA6 instead of IRQ0 + + // ensure TS IRQ pin is interrupt + iocon->LCDMux &= ~(MISCMUX_PWM0SYNC); // assumes irq 3 +}; + +static void ssp_chipselect_automatic(void) +{ + vdprintk("ENTER: ssp_chipselect_automatic()\n"); + ssp_chipselect_manual(); +}; + +/********************************************************************** +* Function: ssp_lh7x_write16 +* +* Purpose: +* Write the LH7x SSP data register +**********************************************************************/ +static void ssp_lh7x_write16(sspContext_t *sspContext, + unsigned int data) +{ + int i; + int ndata = data & 0xFF; + int pdata, qdata; + + vdprintk("ENTER: ssp_lh7x_write16() 0x%04X\n", data); + + udelay(10); + pdata = BACKLIGHT; // keep on backlight + *gpioa = pdata; // assert nCS + + for (i = 8; i > 0; i--) + { + *gpioa = qdata = pdata | ((ndata & 0x80) ? TS_DIN : 0); // strobe out bit + udelay(1); + *gpioa = qdata | TS_DCLK | nLED; // raise clock + udelay(1); + *gpioa = qdata; // lower clock + udelay(1); + + ndata <<= 1; + } + udelay(50); // leave enough time for conversion + + *gpioa = pdata; +}; + +/********************************************************************** +* Function: ssp_lh7x_read16 +* +* Purpose: +* Read the LH7x SSP data register +**********************************************************************/ +static unsigned int ssp_lh7x_read16(sspContext_t *sspContext) +{ + int i; + int pdata, ndata; + + pdata = BACKLIGHT; + ndata = 0; + + for (i = 16; i > 0; i--) + { + *gpioa = pdata; + udelay(1); + *gpioa = pdata | TS_DCLK | nLED; + udelay(1); + + if (gpioadr->dr & (1 << MARM_TS_IOBIT)) + ndata |= 1; + + ndata <<= 1; + } + + vdprintk("LEAVE: ssp_lh7x_read16() 0x%04X (%04d norm) raw\n", ndata, ndata >> 4); + return(ndata >> 4); +}; + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down +**********************************************************************/ +static int ssp_lh7x_ts_pen_down(sspContext_t *sspContext) +{ + int pen_down = vic->RawIntr & (1 << MARM_TS_INT); //look for IRQ + vdprintk("ssp_lh7x_ts_pen_down(%d)\n", pen_down); + return (pen_down); +} + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down_irq_enable +**********************************************************************/ +static int ssp_lh7x_ts_pen_down_irq_enable(sspContext_t *sspContext) +{ + int lastState = vic->IntEnable & (1 << MARM_TS_INT); + vdprintk("ssp_lh7x_ts_pen_down_irq_enable: lastState %d\n", lastState); +#if 0 + //enable_irq(MARM_TS_INT); + rcpc->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + rcpc->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; +#endif + sspContext->irq_state = 1; + return(lastState); +} + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down_irq_disable +**********************************************************************/ +static int ssp_lh7x_ts_pen_down_irq_disable( + sspContext_t *sspContext) +{ + int lastState = vic->IntEnable & (1 << MARM_TS_INT); + vdprintk("ssp_lh7x_ts_pen_down_irq_disable: lastState %d\n", lastState); + //disable_irq(MARM_TS_INT); + rcpc->control |= RCPC_CTRL_WRTLOCK_ENABLED; + barrier(); + rcpc->intClear = (1 << MARM_TS_INT); + rcpc->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; + sspContext->irq_state = 0; + return(lastState); +} + +/********************************************************************** +* 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 */ + vdprintk("ENTER: ssp_lh7x_ts_pen_down_irq()\n"); + ssp_lh7x_ts_pen_down_irq_disable(sspContext); + vdprintk("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; + + vdprintk("ENTER: ssp_lh7x_irq_handler()\n"); + if ((sspContext) && (sspContext->irq_wait_ptr)) { + if (ssp_lh7x_ts_pen_down(sspContext)) + ssp_lh7x_ts_pen_down_irq(irq, sspContext, regs); + else +#if defined(VERBOSE) && defined(DEBUG) + printk("ssp_lh7x_irq_handler() --- Not our interrupt\n"); +#else + ; +#endif + } // if(sspContext) ... +#if defined(VERBOSE) && defined(DEBUG) + else { + printk("ssp_lh7x_irq_handler( NO ACTION )\n"); + } +#endif + return; +} + +/********************************************************************** +* 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) +{ + vdprintk("ENTER: ssp_lh7x_lock()\n"); + return -1; +}; + +static int ssp_lh7x_unlock(sspContext_t *sspContext, int device) +{ + vdprintk("ENTER: ssp_lh7x_unlock()\n"); + return -1; +}; + +/********************************************************************** +* 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) +{ + vdprintk("ENTER: ssp_lh7x_disable()\n"); +}; + +/********************************************************************** +* 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"); + 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; + + vdprintk("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 (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 (device == SSP_DEV_EEPROM) { + vp = NULL; + } + vdprintk("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; + + vdprintk("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; + } + vdprintk("LEAVE: ssp_provide_pointer(0x%08X)\n", (unsigned int)vp); + + return(vp); +} + +/********************************************************************** +* Function: ssp_lh7x_init +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +static int __init ssp_lh7x_init(void) +{ + sspContext_t *sspContext = &sspContext_l; + int sts = 0; + int result; + + vdprintk("ENTER: ssp_lh7x_init()\n"); + + /* + * Disconnect I/O pins from the SSP module + * and disable the SSP peripheral and its clocks. + */ + ssp_lh7x_disable(); + + /* Flush the transmit FIFO */ + ssp_flush_tx_fifo(sspContext); + + /* Flush the receive FIFO */ + ssp_flush_rx_fifo(sspContext); + + ssp_chipselect_automatic(); + /* + * Connect I/O pins from the SSP module + * and enable the SSP peripheral and its clocks. + */ + ssp_lh7x_enable(); + + /* + * Request IRQ and attach it to the touchscreen pen_down line and enable it + */ + sspContext->haveIrq = 0; + result = request_irq(MARM_TS_INT, ssp_lh7x_irq_handler, + SA_SAMPLE_RANDOM, DRVNAME, sspContext); + if (result < 0) { + printk("%s: cannot get requested IRQ(MARM_TS_INT)\n", DRVNAME); + } else { + sspContext->haveIrq = 1; + vdprintk("%s: got requested IRQ(MARM_TS_INT)\n", DRVNAME); + } + ssp_lh7x_ts_pen_down_irq_enable(sspContext); + + 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; + + vdprintk("ENTER: ssp_lh7x_exit()\n"); + + /* + * Disable & Return IRQ + */ + lock_kernel(); + ssp_lh7x_ts_pen_down_irq_disable(sspContext); + if (sspContext->haveIrq) { + free_irq(MARM_TS_INT, sspContext); + sspContext->haveIrq = 0; + } + unlock_kernel(); + + 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 linux-2.4.26/drivers/misc/ssp.h linux-2.4.26-vrs1-lnode80/drivers/misc/ssp.h --- linux-2.4.26/drivers/misc/ssp.h 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/misc/ssp.h 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,29 @@ +/* vi: set sw=4 ts=4 ai: */ + +/********************************************************************** +* 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 linux-2.4.26/drivers/misc/ssp-lh7x.c linux-2.4.26-vrs1-lnode80/drivers/misc/ssp-lh7x.c --- linux-2.4.26/drivers/misc/ssp-lh7x.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/misc/ssp-lh7x.c 2005-11-02 17:37:31.000000000 -0400 @@ -0,0 +1,1024 @@ +/* vi: set sw=4 ts=4 ai: */ + +// #define MODULE + +/********************************************************************** +* 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. +* +**********************************************************************/ + +#include +#include +#include +#include +#include +//#include +#include +#include +#include +//#include +//#include + +#undef DEBUG +#undef VERBOSE +#undef DRVNAME //"ssp_lh7x" +#include + +#include +#ifdef MODULE +char kernel_version[] = UTS_RELEASE; +#endif /* MODULE */ + +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include "ssp.h" + +unsigned int hclkfreq_get( void); + +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; +static sspRegs_t *ssp = (sspRegs_t *)SSP_BASE; +static vicRegs_t *vic = (vicRegs_t *)VIC_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; + +/********************************************************************** +* 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 + +/********************************************************************** +* Function: ssp_busy_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; +} + +/********************************************************************** +* 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; +} + +/********************************************************************** +* 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"); +#ifdef ORDERITE_REV4 + //FJBgpioa->dr &= ~(SSPFRM_GPIO_BIT); /* LOW == Enabled */ + gpioa->dr &= ~(SSPEN_GPIO_BIT); /* LOW == Enabled */ +#else + gpioa->dr &= ~(SSPFRM_GPIO_BIT); /* LOW == Enabled */ +#endif + return; +} + +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"); +#ifdef ORDERITE_REV4 + //FJBgpioa->dr |= SSPFRM_GPIO_BIT; /* HIGH == Disabled */ + gpioa->dr |= SSPEN_GPIO_BIT; /* HIGH == Disabled */ +#else + gpioa->dr |= SSPFRM_GPIO_BIT; /* HIGH == Disabled */ +#endif + return; +} + +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 */ +#ifdef ORDERITE_REV4 + //FJBgpioa->ddr |= SSPFRM_GPIO_BIT; /* Make GPIO an output */ + gpioa->ddr |= SSPEN_GPIO_BIT; /* Make GPIO an output */ + //FJBiocon->SSIMux &= ~SSIMUX_SSPFRM; + iocon->SSIMux &= ~SSIMUX_SSPENB; +#else + gpioa->ddr |= SSPFRM_GPIO_BIT; /* Make GPIO an output */ + iocon->SSIMux &= ~SSIMUX_SSPFRM; +#endif + ssp_chipselect_disable(); + return; +} + +static void ssp_chipselect_automatic(void) +{ + /* First, disable the ChipSelect */ + ssp_chipselect_disable(); +#ifdef ORDERITE_REV4 + /* Set up muxing so the SSP automatically controls the ChipSelect pin */ + //FJBiocon->SSIMux |= SSIMUX_SSPFRM; + iocon->SSIMux |= SSIMUX_SSPENB; +#else + iocon->SSIMux |= SSIMUX_SSPFRM; +#endif + return; +} + +/********************************************************************** +* 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); +} + +#if OLDWAY +/********************************************************************** +* Function: ssp_lh7x_get_hclk_freq +* +* Purpose: +* Get the HCLK (bus clock) frequency in Hz +**********************************************************************/ +static unsigned int ssp_lh7x_get_hclk_freq(void) +{ +#define XTAL_IN 14745600 /* 14.7456 MHz crystal */ +#define PLL_CLOCK (XTAL_IN * 21) /* 309 MHz PLL clock */ + int divider; + unsigned int _hclk_freq; + + vdprintk("ENTER: ssp_lh7x_get_hclk_freq()\n"); + divider = rcpc->HCLKPrescale * 2; /* HCLK prescale value */ + if( divider == 0) /* No prescalar == divide by 1 */ + divider = 1; + _hclk_freq = PLL_CLOCK / divider; + vdprintk("LEAVE: ssp_lh7x_get_hclk_freq(%u)\n", _hclk_freq); + + return(_hclk_freq); +} +#endif + + +/********************************************************************** +* Function: ssp_lh7x_get_speed +* +* Purpose: +* Get the SSP speed in bits per second +**********************************************************************/ +static int ssp_lh7x_get_speed(void) +{ + int bps; + int rcpc_prescale; + int ssp_prescale; + int ssp_divider; + + vdprintk("ENTER: ssp_lh7x_get_speed()\n"); + 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) ); + vdprintk("LEAVE: ssp_lh7x_get_speed(%d bps)\n", bps); + + return(bps); +} + +/********************************************************************** +* 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 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 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()); +} + +/********************************************************************** +* Function: ssp_lh7x_write16 +* +* Purpose: +* Write the LH7x SSP data register +**********************************************************************/ +static void ssp_lh7x_write16(sspContext_t *sspContext, + unsigned int data) +{ + int i; + + //if (sspContext->ssp_dev_sel == SSP_EEPROM) { //JMG + //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_txTimeout; ((i>0) && ((ssp->sr&SSP_SR_RNE) == 0)); i--) { + barrier(); + } + if (ssp->sr & SSP_SR_RNE) { + if (sspContext->ssp_dev_sel == SSP_EEPROM) { + data = (unsigned int)ssp->dr; /* EEPROM */ + //printk("LEAVE: ssp_lh7x_read16(ee: 0x%04X)\n", data); + } else { + data = (((unsigned int)ssp->dr) >> 4) & 0x0FFF; /* TOUCHSCREEN */ + //printk("LEAVE: ssp_lh7x_read16(ts: 0x%04X)\n", data); + } + } else { + //printk("%s: read timout\n", DRVNAME); + } + + return(data); +} + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down +**********************************************************************/ +static int ssp_lh7x_ts_pen_down(sspContext_t *sspContext) +{ + + //int pen_down = vic->IRQStatus & 0x01; //look for IRQ0 + int pen_down = vic->RawIntr & 0x01; //look for IRQ0 + dprintk("ssp_lh7x_ts_pen_down(%d)\n", pen_down); + return (pen_down); +} + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down_irq_enable +**********************************************************************/ +static int ssp_lh7x_ts_pen_down_irq_enable(sspContext_t *sspContext) +{ + int lastState = vic->IntEnable & 1; + dprintk("ssp_lh7x_ts_pen_down_irq_enable\n"); + //vic->IntEnable = 1; + enable_irq(0); + sspContext->irq_state = 1; + return(lastState); +} + +/********************************************************************** +* Macro: ssp_lh7x_ts_pen_down_irq_disable +**********************************************************************/ +static int ssp_lh7x_ts_pen_down_irq_disable( + sspContext_t *sspContext) +{ + int lastState = vic->IntEnable & 1; + dprintk("ssp_lh7x_ts_pen_down_irq_disable\n"); + //vic->IntEnClear = 1; + disable_irq(0); + sspContext->irq_state = 0; + return(lastState); +} + +/********************************************************************** +* 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; + if ((sspContext) && (sspContext->irq_wait_ptr)) { + //if (ssp_lh7x_ts_pen_down(sspContext)) { + if (1) { + 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; +} + +/********************************************************************** +* 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); +} + +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"); + // 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"); + // sts = 0; + } + //cpld->ssp_dev_sel = sspContext->ssp_dev_sel; + + 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) +{ + int rcpcLockState; + + vdprintk("ENTER: ssp_lh7x_disable()\n"); + + /* 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); + + /* 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"); + + /* 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 + ); + + + 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; + + 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 (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 (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; + } 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; + } 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); +} + +/********************************************************************** +* Function: ssp_lh7x_init +* +* Purpose: +* Register & Initialize the module +**********************************************************************/ +static int __init ssp_lh7x_init(void) +{ + sspContext_t *sspContext = &sspContext_l; + int sts = 0; + int rcpcLockState; + int result; + + vdprintk("ENTER: ssp_lh7x_init()\n"); + + vdprintk("ssp = 0x%08X\n", (unsigned int)ssp); + + /* Determine the HCLK (bus clock) frequency in Hz */ +#ifdef OLDWAY + hclk_freq = ssp_lh7x_get_hclk_freq(); +#else + hclk_freq = hclkfreq_get(); +#endif + + /* + * Disconnect I/O pins from the SSP module + * and disable the SSP peripheral and its clocks. + */ + ssp_lh7x_disable(); + + /* Initialize the RCPC SSP clock & prescaler */ + rcpcLockState = rcpc_lh7x_lock(RCPC_UNLOCK); + rcpc->rcpc_sspClkPrescale = 0; /* As fast as possible */ + rcpc->rcpc_sspClkControl &= ~RCPC_SCLKSEL_SSPCLK; /* Enable SSP clock */ + (void) rcpc_lh7x_lock(rcpcLockState); + + ssp->cpsr = SSP_CPSR_CPDVSR(SSP_PRESCALE_MIN); + + /* 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 */ + ); + + /* 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; + //cpld->ssp_dev_sel = sspContext->ssp_dev_sel; + + /* 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); + + ssp_chipselect_automatic(); + /* + * Connect I/O pins from the SSP module + * and enable the SSP peripheral and its clocks. + */ + ssp_lh7x_enable(); + + /* + * Request IRQ2 and attach it to the touchscreen pen_down line and enable it + */ + sspContext->haveIrq = 0; + result = request_irq(0, ssp_lh7x_irq_handler, + SA_SAMPLE_RANDOM, DRVNAME, sspContext); + if (result < 0) { + printk("%s: cannot get requested IRQ(0)\n", DRVNAME); + } else { + sspContext->haveIrq = 1; + dprintk("%s: got requested IRQ(0)\n", DRVNAME); + } + ssp_lh7x_ts_pen_down_irq_enable(sspContext); + + 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; + int rcpcLockState; + + 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); + + /* + * Disable & Return IRQ 2 + */ + lock_kernel(); + ssp_lh7x_ts_pen_down_irq_disable(sspContext); + if (sspContext->haveIrq) { + free_irq(0, 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); + + /* Turn off the RCPC SSP clock */ + rcpcLockState = rcpc_lh7x_lock(RCPC_UNLOCK); + rcpc->rcpc_sspClkControl |= RCPC_SCLKSEL_SSPCLK; /* Disable SSP clock */ + (void) rcpc_lh7x_lock(rcpcLockState); + + 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 linux-2.4.26/drivers/serial/amba_pl011.c linux-2.4.26-vrs1-lnode80/drivers/serial/amba_pl011.c --- linux-2.4.26/drivers/serial/amba_pl011.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/serial/amba_pl011.c 2005-11-02 17:37:32.000000000 -0400 @@ -0,0 +1,854 @@ +/* + * linux/drivers/char/serial_amba_pl011.c + * + * Driver for AMBA PrimeCell PL011 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 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_SERIAL_AMBA_PL011_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ) +#define SUPPORT_SYSRQ +#endif + +#include + +#include + +#ifdef CONFIG_ARCH_LH79520 +#include +#include +#include +#endif + +#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 *amba11_table[UART_NR]; +static struct termios *amba11_termios[UART_NR], *amba11_termios_locked[UART_NR]; +#ifdef SUPPORT_SYSRQ +static struct console amba11_console; +#endif +static void amba11uart_tx_chars(struct uart_port *port); + +#define AMBA_ISR_PASS_LIMIT 256 + +/* + * Access macros for the AMBA UARTs + */ +#define UART_PUT_ICR(p, c) writel((c), (p)->membase + AMBA_UARTICR) +#define UART_GET_CHAR(p) readb((p)->membase + AMBA_UARTDR) +#define UART_PUT_CHAR(p, c) writel((c), (p)->membase + AMBA_UARTDR) +#define UART_GET_RSR(p) readb((p)->membase + AMBA_UARTRSR) +#define UART_GET_LCRH(p) readb((p)->membase + AMBA_UARTLCR_H) +#define UART_PUT_LCRH(p,c) writel((c), (p)->membase + AMBA_UARTLCR_H) + +#define UART_RX_DATA(s) (((s) & AMBA_UARTFR_RXFE) == 0) +#define UART_TX_READY(s) (((s) & AMBA_UARTFR_TXFF) == 0) +#define UART_TX_EMPTY(p) ((UART_GET_FR(p) & AMBA_UARTFR_TMSK) == 0) + +#define UART_GET_INT_STATUS(p) readw((p)->membase + AMBA_UARTMIS) +#define UART_GET_FR(p) readw((p)->membase + AMBA_UARTFR) +#define UART_GET_CR(p) readl((p)->membase + AMBA_UARTCR) +#define UART_PUT_CR(p,c) writel((c), (p)->membase + AMBA_UARTCR) +#define UART_GET_IMSC(p) readl((p)->membase + AMBA_UARTIMSC) +#define UART_PUT_IMSC(p,c) writel((c), (p)->membase + AMBA_UARTIMSC) +#define UART_GET_IBRD(p) readl((p)->membase + AMBA_UARTIBRD) +#define UART_PUT_IBRD(p,c) writel((c), (p)->membase + AMBA_UARTIBRD) + + +#define UART_DUMMY_RSR_RX 256 +#define UART_PORT_SIZE 64 + +/* + * Our private driver data mappings. + */ +#define drv_old_status driver_priv + +struct uart_amba11_port { + struct uart_port port; + unsigned int old_status; +}; + +static void amba11uart_stop_tx(struct uart_port *port, unsigned int tty_stop) +{ + unsigned int mask; + + mask = UART_GET_IMSC( port); + mask &= ~AMBA_UARTIMSC_TXIM; + UART_PUT_IMSC( port, mask); /* disable Tx interrupts */ +} + + +static void amba11uart_start_tx(struct uart_port *port, unsigned int tty_start) +{ + unsigned int mask; + + mask = UART_GET_IMSC(port); + if( (mask & AMBA_UARTIMSC_TXIM) == 0) { /* not already enabled */ + mask |= AMBA_UARTIMSC_TXIM; /* enable Tx interrupts */ + UART_PUT_IMSC(port, mask); + + amba11uart_tx_chars(port); /* start transmiting */ + } + +} + + +static void amba11uart_stop_rx(struct uart_port *port) +{ + unsigned int mask; + + mask = UART_GET_IMSC(port); + mask &= ~(AMBA_UARTIMSC_RXIM | AMBA_UARTIMSC_RTIM); + UART_PUT_IMSC(port, mask); /* disable Rx interrupts */ +} + + +static void amba11uart_enable_ms(struct uart_port *port) +{ + unsigned int mask; + + mask = UART_GET_IMSC( port); + mask |= AMBA_UARTIMSC_Modem; + UART_PUT_IMSC(port, mask); /* Disable modem interrupts */ +} + +static void +#ifdef SUPPORT_SYSRQ +amba11uart_rx_chars(struct uart_port *port, struct pt_regs *regs) +#else +amba11uart_rx_chars(struct uart_port *port) +#endif +{ + struct tty_struct *tty = port->info->tty; + unsigned int status, ch, rsr, 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; + *tty->flip.flag_buf_ptr = TTY_NORMAL; + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + rsr = UART_GET_RSR(port) | UART_DUMMY_RSR_RX; + if (rsr & AMBA_UARTRSR_ANY) { + if (rsr & AMBA_UARTRSR_BE) { + rsr &= ~(AMBA_UARTRSR_FE | AMBA_UARTRSR_PE); + port->icount.brk++; + if (uart_handle_sysrq_char(port, ch, regs)) + goto ignore_char; + } else if (rsr & AMBA_UARTRSR_PE) + port->icount.parity++; + else if (rsr & AMBA_UARTRSR_FE) + port->icount.frame++; + if (rsr & AMBA_UARTRSR_OE) + port->icount.overrun++; + + rsr &= port->read_status_mask; + + if (rsr & AMBA_UARTRSR_BE) + *tty->flip.flag_buf_ptr = TTY_BREAK; + else if (rsr & AMBA_UARTRSR_PE) + *tty->flip.flag_buf_ptr = TTY_PARITY; + else if (rsr & AMBA_UARTRSR_FE) + *tty->flip.flag_buf_ptr = TTY_FRAME; + } + + if (uart_handle_sysrq_char(port, ch, regs)) + goto ignore_char; + + if ((rsr & port->ignore_status_mask) == 0) { + tty->flip.flag_buf_ptr++; + tty->flip.char_buf_ptr++; + tty->flip.count++; + } + if ((rsr & AMBA_UARTRSR_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 amba11uart_tx_chars(struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + int count; + int status; + + if (port->x_char) { + UART_PUT_CHAR(port, port->x_char); + port->icount.tx++; + port->x_char = 0; + return; + } + if (uart_circ_empty(xmit) || uart_tx_stopped(port)) { + amba11uart_stop_tx(port, 0); + return; + } + + count = port->fifosize >> 1; + do { + UART_PUT_CHAR(port, xmit->buf[xmit->tail]); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + if (uart_circ_empty(xmit)) + break; + status = UART_GET_FR(port); + } while (UART_TX_READY(status)); + //FJBwhile (--count > 0); + + if (uart_circ_chars_pending(xmit) < + WAKEUP_CHARS) + uart_write_wakeup(port); + + if (uart_circ_empty(xmit)) + amba11uart_stop_tx(port, 0); +} + +static void amba11uart_modem_status(struct uart_port *port) +{ + struct uart_amba11_port *uap = (struct uart_amba11_port *) port; + unsigned int status, delta; + + UART_PUT_ICR(&uap->port, 0x3ff); + + status = UART_GET_FR(&uap->port) & AMBA_UARTFR_MODEM_ANY; + //FJB - check CTS on modem port only (port 1) + if(port == (struct uart_port *)UART1_PHYS) + { + if(GPIOG->dr & 0x01) + { + //CTS is high meaning STOP SENDING + status |= AMBA_UARTFR_CTS; + } + } + + delta = status ^ uap->old_status; + uap->old_status = status; + + if (!delta) + return; + + if (delta & AMBA_UARTFR_DCD) + uart_handle_dcd_change(&uap->port, (status & AMBA_UARTFR_DCD) == 0); + + if ((delta & AMBA_UARTFR_DSR) == 0) + uap->port.icount.dsr++; + + if (delta & AMBA_UARTFR_CTS) + uart_handle_cts_change(&uap->port, (status & AMBA_UARTFR_CTS) == 0); + + wake_up_interruptible(&uap->port.info->delta_msr_wait); +} + +static void amba11uart_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 & (AMBA_UART_IS_RT | AMBA_UART_IS_RX)) + +#ifdef SUPPORT_SYSRQ + amba11uart_rx_chars(port, regs); +#else + amba11uart_rx_chars(port); +#endif + + if (status & AMBA_UART_IS_TX) + amba11uart_tx_chars(port); + + + if (status & AMBA_UART_IS_MI) + amba11uart_modem_status(port); + + if (pass_counter-- == 0) + break; + + status = UART_GET_INT_STATUS(port); + } while (status & (AMBA_UART_IS_RT | AMBA_UART_IS_RX | + AMBA_UART_IS_TX)); +} + +static unsigned int amba11uart_tx_empty(struct uart_port *port) +{ + return UART_GET_FR(port) & AMBA_UARTFR_BUSY ? 0 : TIOCSER_TEMT; +} + +static unsigned int amba11uart_get_mctrl(struct uart_port *port) +{ + unsigned int result = 0; + unsigned int status; + + status = UART_GET_FR(port); + if ((status & AMBA_UARTFR_DCD) == 0) + result |= TIOCM_CAR; + if ((status & AMBA_UARTFR_DSR) == 0) + result |= TIOCM_DSR; + if ((status & AMBA_UARTFR_CTS) == 0) + result |= TIOCM_CTS; + + return result; +} + +static void amba11uart_set_mctrl(struct uart_port *port, unsigned int mctrl) +{ + u_int cr; + + cr = UART_GET_CR( port); + + if (mctrl & TIOCM_RTS) + cr &= ~AMBA_UARTCR_RTS; + else + cr |= AMBA_UARTCR_RTS; + + if (mctrl & TIOCM_DTR) + cr &= ~AMBA_UARTCR_DTR; + else + cr |= AMBA_UARTCR_DTR; + + UART_PUT_CR( port, cr); +} + + +static void amba11uart_break_ctl(struct uart_port *port, int break_state) +{ + unsigned int lcr_h; + unsigned long flags; + + spin_lock_irqsave(&port->lock, flags); + lcr_h = UART_GET_LCRH(port); + if (break_state == -1) + lcr_h |= AMBA_UARTLCR_H_BRK; + else + lcr_h &= ~AMBA_UARTLCR_H_BRK; + UART_PUT_LCRH(port, lcr_h); + spin_unlock_irqrestore(&port->lock, flags); +} + +static int amba11uart_startup(struct uart_port *port) +{ + int retval; + struct uart_amba11_port *uap = (struct uart_amba11_port *)port; + + /* + * Allocate the IRQ + */ + retval = request_irq(port->irq, amba11uart_int, 0, "amba", port); + if (retval) + return retval; + + /* + * initialise the old status of the modem signals + */ + uap->old_status = UART_GET_FR(port) & AMBA_UARTFR_MODEM_ANY; + + /* + * Finally, enable interrupts + */ +#ifdef CONFIG_ARCH_LH79520 + { + /* + * enable the clock to the serial ports + */ + rcpcRegs_t *rcpc = (rcpcRegs_t *)IO_ADDRESS( RCPC_PHYS); + ioconRegs_t *iocon = (ioconRegs_t *)IO_ADDRESS( IOCON_PHYS); + + rcpc->control |= RCPC_CTRL_WRTLOCK_ENABLED; /* unlock RCPC registers */ + barrier(); + + rcpc->periphClkCtrl &= ~(RCPC_CLKCTRL_U0_DISABLE | RCPC_CLKCTRL_U1_DISABLE | RCPC_CLKCTRL_U2_DISABLE) ; + rcpc->control &= ~RCPC_CTRL_WRTLOCK_ENABLED; /* lock RCPC registers */ + + /* set multiplexed pins for UART0 use */ + iocon->UARTMux |= (UARTMUX_UT0TXD | UARTMUX_UT0RXD); + } +#endif /* CONFIG_ARCH_LH79520 */ + + /* + * 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 + */ + + UART_PUT_IMSC( port, (AMBA_UARTIMSC_RXIM | AMBA_UARTIMSC_RTIM) ); + UART_PUT_CR( port, (AMBA_UARTCR_UARTEN | AMBA_UARTCR_RXE | AMBA_UARTCR_TXE)); + + return 0; +} + +static void amba11uart_shutdown(struct uart_port *port) +{ + /* + * Free the interrupt + */ + free_irq(port->irq, port); + + /* + * disable all interrupts, disable the port + */ + UART_PUT_CR(port, 0); + + /* disable break condition and fifos */ + UART_PUT_LCRH(port, UART_GET_LCRH(port) & + ~(AMBA_UARTLCR_H_BRK | AMBA_UARTLCR_H_FEN)); +} + +static void amba11uart_change_speed(struct uart_port *port, u_int cflag, u_int iflag, u_int quot) +{ + unsigned int lcr_h, old_cr; + unsigned long flags; + unsigned long old_imsc; + +#if DEBUG + printk("amba11uart_set_cflag(0x%x) called\n", cflag); +#endif + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: lcr_h = AMBA_UARTLCR_H_WLEN_5; break; + case CS6: lcr_h = AMBA_UARTLCR_H_WLEN_6; break; + case CS7: lcr_h = AMBA_UARTLCR_H_WLEN_7; break; + default: lcr_h = AMBA_UARTLCR_H_WLEN_8; break; // CS8 + } + if (cflag & CSTOPB) + lcr_h |= AMBA_UARTLCR_H_STP2; + if (cflag & PARENB) { + lcr_h |= AMBA_UARTLCR_H_PEN; + if (!(cflag & PARODD)) + lcr_h |= AMBA_UARTLCR_H_EPS; + } + if (port->fifosize > 1) + lcr_h |= AMBA_UARTLCR_H_FEN; + + spin_lock_irqsave(&port->lock, flags); + + port->read_status_mask = AMBA_UARTRSR_OE; + if (iflag & INPCK) + port->read_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; + if (iflag & (BRKINT | PARMRK)) + port->read_status_mask |= AMBA_UARTRSR_BE; + + /* + * Characters to ignore + */ + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= AMBA_UARTRSR_FE | AMBA_UARTRSR_PE; + if (iflag & IGNBRK) { + port->ignore_status_mask |= AMBA_UARTRSR_BE; + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + port->ignore_status_mask |= AMBA_UARTRSR_OE; + } + + /* + * Ignore all characters if CREAD is not set. + */ + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_RSR_RX; + + old_cr = UART_GET_CR( port); + old_imsc = UART_GET_IMSC( port) & ~AMBA_UARTIMSC_Modem; + + if (UART_ENABLE_MS(port, cflag)) + old_imsc |= AMBA_UARTIMSC_Modem; + + /* Set baud rate */ + UART_PUT_IBRD( port, quot); + + /* + * ----------v----------v----------v----------v----- + * NOTE: MUST BE WRITTEN AFTER UARTLCR_M & UARTLCR_L + * ----------^----------^----------^----------^----- + */ + UART_PUT_LCRH(port, lcr_h); + UART_PUT_IMSC( port, old_imsc); + UART_PUT_CR(port, old_cr); + + spin_unlock_irqrestore(&port->lock, flags); +} + +static const char *amba11uart_type(struct uart_port *port) +{ + return port->type == PORT_AMBA_PL011 ? "AMBA PrimeCell PL011" : NULL; +} + +/* + * Release the memory region(s) being used by 'port' + */ +static void amba11uart_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 amba11uart_request_port(struct uart_port *port) +{ + return request_mem_region(port->mapbase, UART_PORT_SIZE, "serial_amba") + != NULL ? 0 : -EBUSY; +} + +/* + * Configure/autoconfigure the port. + */ +static void amba11uart_config_port(struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_AMBA_PL011; + amba11uart_request_port(port); + } +} + +/* + * verify the new serial_struct (for TIOCSSERIAL). + */ +static int amba11uart_verify_port(struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_AMBA_PL011) + 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 amba11_pops = { + tx_empty: amba11uart_tx_empty, + set_mctrl: amba11uart_set_mctrl, + get_mctrl: amba11uart_get_mctrl, + stop_tx: amba11uart_stop_tx, + start_tx: amba11uart_start_tx, + stop_rx: amba11uart_stop_rx, + enable_ms: amba11uart_enable_ms, + break_ctl: amba11uart_break_ctl, + startup: amba11uart_startup, + shutdown: amba11uart_shutdown, + change_speed: amba11uart_change_speed, + type: amba11uart_type, + release_port: amba11uart_release_port, + request_port: amba11uart_request_port, + config_port: amba11uart_config_port, + verify_port: amba11uart_verify_port, +}; + +static struct uart_amba11_port amba11_ports[UART_NR] = { + { + .port = { + .membase= (void *)IO_ADDRESS(UART0_PHYS), // VA + .mapbase= UART0_PHYS, + .iotype= SERIAL_IO_MEM, + .irq= IRQ_UART0, + .uartclk= 14745600, + .fifosize= 16, + .ops= &amba11_pops, + .flags= ASYNC_BOOT_AUTOCONF, + .line= 0, + }, + }, + { + .port = { + .membase= (void *)IO_ADDRESS(UART1_PHYS), + .mapbase= UART1_PHYS, + .iotype= SERIAL_IO_MEM, + .irq= IRQ_UART1, + .uartclk= 14745600, + .fifosize= 16, + .ops= &amba11_pops, + .flags= ASYNC_BOOT_AUTOCONF, + .line= 1, + }, + }, + { + .port = { + .membase= (void *)IO_ADDRESS(UART2_PHYS), + .mapbase= UART2_PHYS, + .iotype= SERIAL_IO_MEM, + .irq= IRQ_UART2, + .uartclk= 14745600, + .fifosize= 16, + .ops= &amba11_pops, + .flags= ASYNC_BOOT_AUTOCONF, + .line= 2, + }, + }, +}; + + +#ifdef CONFIG_SERIAL_AMBA_PL011_CONSOLE +#ifdef used_and_not_const_char_pointer +static int amba11uart_console_read(struct uart_port *port, char *s, u_int count) +{ + unsigned int status; + int c; +#if DEBUG + printk("amba11uart_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 amba11uart_console_write(struct console *co, const char *s, u_int count) +{ + struct uart_port *port = &amba11_ports[co->index].port; + unsigned int status; + int i; + + /* + * First save the CR then disable the interrupts + */ + unsigned int old_imsc; + old_imsc = UART_GET_IMSC( port); + UART_PUT_IMSC( 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 & AMBA_UARTFR_BUSY); + UART_PUT_IMSC( port, old_imsc); +} + +static kdev_t amba11uart_console_device(struct console *co) +{ + return MKDEV(SERIAL_AMBA_MAJOR, SERIAL_AMBA_MINOR + co->index); +} + +static int amba11uart_console_wait_key(struct console *co) +{ + struct uart_port *port = &amba11_ports[co->index].port; + unsigned int status; + + do { + status = UART_GET_FR(port); + } while (!UART_RX_DATA(status)); + return UART_GET_CHAR(port); +} + +static void __init +amba11uart_console_get_options(struct uart_port *port, int *baud, int *parity, int *bits) +{ + if (UART_GET_CR(port) & AMBA_UARTCR_UARTEN) { + unsigned int lcr_h, quot; + lcr_h = UART_GET_LCRH(port); + + *parity = 'n'; + if (lcr_h & AMBA_UARTLCR_H_PEN) { + if (lcr_h & AMBA_UARTLCR_H_EPS) + *parity = 'e'; + else + *parity = 'o'; + } + + if ((lcr_h & 0x60) == AMBA_UARTLCR_H_WLEN_7) + *bits = 7; + else + *bits = 8; + + quot = UART_GET_IBRD(port); + *baud = port->uartclk / (16 * quot ); + } +} + +static int __init amba11uart_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. + */ + if (co->index >= UART_NR) + co->index = 0; + port = &amba11_ports[co->index].port; + + if (options) + uart_parse_options(options, &baud, &parity, &bits, &flow); + else + amba11uart_console_get_options(port, &baud, &parity, &bits); + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct console amba11_console = { + name: "ttyAM", + write: amba11uart_console_write, +#ifdef used_and_not_const_char_pointer + read: amba11uart_console_read, +#endif + device: amba11uart_console_device, + setup: amba11uart_console_setup, + flags: CON_PRINTBUFFER, + index: -1, +}; + +void __init amba11uart_console_init(void) +{ + register_console(&amba11_console); +} + +#define AMBA_CONSOLE &amba11_console +#else +#define AMBA_CONSOLE NULL +#endif + +static struct uart_driver amba11_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: amba11_table, + termios: amba11_termios, + termios_locked: amba11_termios_locked, + minor: SERIAL_AMBA_MINOR, + nr: UART_NR, + cons: AMBA_CONSOLE, +}; + +static int __init amba11uart_init(void) +{ + int ret; + + ret = uart_register_driver(&amba11_reg); + if (ret == 0) { + int i; + + for (i = 0; i < UART_NR; i++) + uart_add_one_port(&amba11_reg, &amba11_ports[i].port); + } + return ret; +}; + +static void __exit amba11uart_exit(void) +{ + int i; + + for (i = 0; i < UART_NR; i++) + uart_remove_one_port(&amba11_reg, &amba11_ports[i].port); + + uart_unregister_driver(&amba11_reg); +}; + +module_init(amba11uart_init); +module_exit(amba11uart_exit); + +EXPORT_NO_SYMBOLS; + +MODULE_AUTHOR("Lineo, Inc."); +MODULE_DESCRIPTION("ARM AMBA PrimeCell PL011 serial port driver"); +MODULE_LICENSE("GPL"); + diff -urN linux-2.4.26/drivers/serial/Config.in linux-2.4.26-vrs1-lnode80/drivers/serial/Config.in --- linux-2.4.26/drivers/serial/Config.in 2005-11-02 16:54:25.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/serial/Config.in 2005-11-02 17:37:31.000000000 -0400 @@ -20,6 +20,22 @@ 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 +73,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 +85,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 +98,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 linux-2.4.26/drivers/serial/core.c linux-2.4.26-vrs1-lnode80/drivers/serial/core.c --- linux-2.4.26/drivers/serial/core.c 2005-11-02 16:54:25.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/serial/core.c 2005-11-02 17:37:32.000000000 -0400 @@ -1938,6 +1938,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); @@ -1970,6 +1971,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 linux-2.4.26/drivers/serial/Makefile linux-2.4.26-vrs1-lnode80/drivers/serial/Makefile --- linux-2.4.26/drivers/serial/Makefile 2005-11-02 16:54:25.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/serial/Makefile 2005-11-02 17:37:31.000000000 -0400 @@ -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) += serial_lh7a400.o obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o obj-$(CONFIG_SERIAL_SA1100) += sa1100.o obj-$(CONFIG_SERIAL_UART00) += uart00.o diff -urN linux-2.4.26/drivers/video/Config.in linux-2.4.26-vrs1-lnode80/drivers/video/Config.in --- linux-2.4.26/drivers/video/Config.in 2005-11-02 16:54:25.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/video/Config.in 2005-11-02 17:37:32.000000000 -0400 @@ -40,6 +40,11 @@ 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 + if [ "$CONFIG_ARCH_LH79520" = "y" -o \ + "$CONFIG_ARCH_LH7A400" = "y" ];then + bool ' ARM PL110 LCD support' CONFIG_FB_PL110 + fi + 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 +55,15 @@ 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' \ + "Panasonic CONFIG_PL110_PAN78 \ + 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 @@ -280,7 +294,8 @@ "$CONFIG_FB_MAC" = "y" -o "$CONFIG_FB_RETINAZ3" = "y" -o \ "$CONFIG_FB_VIRGE" = "y" -o "$CONFIG_FB_VIRTUAL" = "y" -o \ "$CONFIG_FB_BWTWO" = "y" -o "$CONFIG_FB_CLGEN" = "y" -o \ - "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_CLPS711X" = "y" ]; then + "$CONFIG_FB_TX3912" = "y" -o "$CONFIG_FB_CLPS711X" = "y" -o \ + "$CONFIG_FB_PL110" = "y" ]; then define_tristate CONFIG_FBCON_MFB y else if [ "$CONFIG_FB_ACORN" = "m" -o "$CONFIG_FB_AMIGA" = "m" -o \ @@ -288,20 +303,22 @@ "$CONFIG_FB_MAC" = "m" -o "$CONFIG_FB_RETINAZ3" = "m" -o \ "$CONFIG_FB_VIRGE" = "m" -o "$CONFIG_FB_VIRTUAL" = "m" -o \ "$CONFIG_FB_BWTWO" = "m" -o "$CONFIG_FB_CLGEN" = "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_MFB m fi fi 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 @@ -329,6 +346,7 @@ "$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_PL110" = "y" -o \ "$CONFIG_FB_DBMX1" = "y" ]; then define_tristate CONFIG_FBCON_CFB8 y else @@ -352,6 +370,7 @@ "$CONFIG_FB_RADEON" = "m" -o "$CONFIG_FB_INTEL" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ "$CONFIG_FB_TX3912" = "m" -o "$CONFIG_FB_NEOMAGIC" = "m" -o \ + "$CONFIG_FB_PL110" = "m" -o \ "$CONFIG_FB_STI" = "m" -o "$CONFIG_FB_INTEL" = "m" ]; then define_tristate CONFIG_FBCON_CFB8 m fi @@ -373,6 +392,7 @@ "$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_PL110" = "y" -o \ "$CONFIG_FB_DBMX1" = "y" ]; then define_tristate CONFIG_FBCON_CFB16 y else @@ -390,6 +410,7 @@ "$CONFIG_FB_CYBER2000" = "m" -o "$CONFIG_FB_SIS" = "m" -o \ "$CONFIG_FB_SA1100" = "m" -o "$CONFIG_FB_RADEON" = "m" -o \ "$CONFIG_FB_INTEL" = "m" -o \ + "$CONFIG_FB_PL110" = "m" -o \ "$CONFIG_FB_PVR2" = "m" -o "$CONFIG_FB_VOODOO1" = "m" -o \ "$CONFIG_FB_NEOMAGIC" = "m" -o "$CONFIG_FB_INTEL" = "m" ]; then define_tristate CONFIG_FBCON_CFB16 m diff -urN linux-2.4.26/drivers/video/fbcon.c linux-2.4.26-vrs1-lnode80/drivers/video/fbcon.c --- linux-2.4.26/drivers/video/fbcon.c 2003-08-25 07:44:42.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/video/fbcon.c 2005-11-02 17:37:32.000000000 -0400 @@ -2401,9 +2401,9 @@ p->type == FB_TYPE_INTERLEAVED_PLANES)) { /* monochrome */ - unsigned char inverse = p->inverse || p->visual == FB_VISUAL_MONO01 - ? 0x00 : 0xff; - + //FJBunsigned char inverse = p->inverse || p->visual == FB_VISUAL_MONO01 + //FJB ? 0x00 : 0xff; + unsigned char inverse = 0; int is_hga = !strncmp(p->fb_info->modename, "HGA", 3); /* can't use simply memcpy because need to apply inverse */ for( y1 = 0; y1 < LOGO_H; y1++ ) { diff -urN linux-2.4.26/drivers/video/fbmem.c linux-2.4.26-vrs1-lnode80/drivers/video/fbmem.c --- linux-2.4.26/drivers/video/fbmem.c 2005-11-02 16:54:25.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/video/fbmem.c 2005-11-02 17:37:32.000000000 -0400 @@ -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); @@ -305,6 +306,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 linux-2.4.26/drivers/video/Makefile linux-2.4.26-vrs1-lnode80/drivers/video/Makefile --- linux-2.4.26/drivers/video/Makefile 2005-11-02 16:54:25.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/video/Makefile 2005-11-02 17:37:32.000000000 -0400 @@ -4,6 +4,14 @@ O_TARGET := video.o +# +# The following is VERY IMPORTANT for the pl110; newer gccs won't compile the driver +# properly and it will hang at "Console: switching to colour frame buffer device ..." +# +ifeq ($(CONFIG_FB_PL110),y) +EXTRA_CFLAGS =-O1 +endif + mod-subdirs := matrox sti # All of the (potential) objects that export symbols. @@ -15,7 +23,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. @@ -137,6 +145,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 linux-2.4.26/drivers/video/pl110fb.c linux-2.4.26-vrs1-lnode80/drivers/video/pl110fb.c --- linux-2.4.26/drivers/video/pl110fb.c 1969-12-31 20:00:00.000000000 -0400 +++ linux-2.4.26-vrs1-lnode80/drivers/video/pl110fb.c 2005-11-02 17:37:32.000000000 -0400 @@ -0,0 +1,1719 @@ +/* + * 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